fix: align sample registration, freight scope, and OA datetime display

Let customer-service quick register write storage, certificate, and insurance separately without extra menu or data-scope checks. List freight by document data scope like the web admin, allow protocol staff outside the collection region, and pad OA datetimes to seconds so PC date pickers can show historical minute values.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
zlwuandCursor committed 2026-10-20 17:30:30 +08:00
1 parent 03fcc01d6d
commit ac8e471aca
41 files changed
+16929 -14162

No files matched your search

File diff suppressed because it is too large. Load diff
+51 -28
View File
@@ -12164,35 +12164,35 @@
"label": "fetchUpdateFullmoonHandle()",
"file_type": "code",
"source_file": "api/sample-info-handle.ts",
"source_location": "L47"
"source_location": "L55"
},
{
"id": "api_sample_info_handle_fetchsamplestoragecert",
"label": "fetchSampleStorageCert()",
"file_type": "code",
"source_file": "api/sample-info-handle.ts",
"source_location": "L59"
"source_location": "L67"
},
{
"id": "api_sample_info_handle_fetchupdatesamplestoragecert",
"label": "fetchUpdateSampleStorageCert()",
"file_type": "code",
"source_file": "api/sample-info-handle.ts",
"source_location": "L63"
"source_location": "L71"
},
{
"id": "api_sample_info_handle_fetchsampleinsurance",
"label": "fetchSampleInsurance()",
"file_type": "code",
"source_file": "api/sample-info-handle.ts",
"source_location": "L80"
"source_location": "L88"
},
{
"id": "api_sample_info_handle_fetchupdatesampleinsurance",
"label": "fetchUpdateSampleInsurance()",
"file_type": "code",
"source_file": "api/sample-info-handle.ts",
"source_location": "L84"
"source_location": "L92"
},
{
"id": "api_production_task_set_ts",
@@ -18541,7 +18541,7 @@
"label": "if()",
"file_type": "code",
"source_file": "views/cell-storage/sample-info/SampleInfoQuickRegisterDialog.vue",
"source_location": "L302"
"source_location": "L405"
},
{
"id": "views_cell_storage_sample_info_unifiedsampleinfopage_vue",
@@ -18550,6 +18550,20 @@
"source_file": "views/cell-storage/sample-info/UnifiedSampleInfoPage.vue",
"source_location": "L1"
},
{
"id": "views_cell_storage_sample_info_quickregisterattachmentfield_vue",
"label": "QuickRegisterAttachmentField.vue",
"file_type": "code",
"source_file": "views/cell-storage/sample-info/QuickRegisterAttachmentField.vue",
"source_location": "L1"
},
{
"id": "sample_info_quickregisterattachmentfield_for",
"label": "for()",
"file_type": "code",
"source_file": "views/cell-storage/sample-info/QuickRegisterAttachmentField.vue",
"source_location": "L205"
},
{
"id": "views_cell_storage_sample_reception_info_index_vue",
"label": "index.vue",
@@ -50561,7 +50575,7 @@
"relation": "contains",
"confidence": "EXTRACTED",
"source_file": "api/sample-info-handle.ts",
"source_location": "L47",
"source_location": "L55",
"weight": 1.0
},
{
@@ -50570,7 +50584,7 @@
"relation": "contains",
"confidence": "EXTRACTED",
"source_file": "api/sample-info-handle.ts",
"source_location": "L59",
"source_location": "L67",
"weight": 1.0
},
{
@@ -50579,7 +50593,7 @@
"relation": "contains",
"confidence": "EXTRACTED",
"source_file": "api/sample-info-handle.ts",
"source_location": "L63",
"source_location": "L71",
"weight": 1.0
},
{
@@ -50588,7 +50602,7 @@
"relation": "contains",
"confidence": "EXTRACTED",
"source_file": "api/sample-info-handle.ts",
"source_location": "L80",
"source_location": "L88",
"weight": 1.0
},
{
@@ -50597,7 +50611,7 @@
"relation": "contains",
"confidence": "EXTRACTED",
"source_file": "api/sample-info-handle.ts",
"source_location": "L84",
"source_location": "L92",
"weight": 1.0
},
{
@@ -59849,7 +59863,7 @@
"relation": "imports_from",
"confidence": "EXTRACTED",
"source_file": "views/cell-storage/sample-info/SampleInfoQuickRegisterDialog.vue",
"source_location": "L215",
"source_location": "L304",
"weight": 1.0
},
{
@@ -59858,16 +59872,7 @@
"relation": "imports_from",
"confidence": "EXTRACTED",
"source_file": "views/cell-storage/sample-info/SampleInfoQuickRegisterDialog.vue",
"source_location": "L216",
"weight": 1.0
},
{
"source": "views_cell_storage_sample_info_sampleinfoquickregisterdialog_vue",
"target": "users_wuzilong_work_00code_zkxw_web_admin_src_api_business",
"relation": "imports_from",
"confidence": "EXTRACTED",
"source_file": "views/cell-storage/sample-info/SampleInfoQuickRegisterDialog.vue",
"source_location": "L217",
"source_location": "L305",
"weight": 1.0
},
{
@@ -59876,7 +59881,7 @@
"relation": "imports_from",
"confidence": "EXTRACTED",
"source_file": "views/cell-storage/sample-info/SampleInfoQuickRegisterDialog.vue",
"source_location": "L218",
"source_location": "L306",
"weight": 1.0
},
{
@@ -59885,7 +59890,7 @@
"relation": "imports_from",
"confidence": "EXTRACTED",
"source_file": "views/cell-storage/sample-info/SampleInfoQuickRegisterDialog.vue",
"source_location": "L219",
"source_location": "L307",
"weight": 1.0
},
{
@@ -59894,7 +59899,16 @@
"relation": "imports_from",
"confidence": "EXTRACTED",
"source_file": "views/cell-storage/sample-info/SampleInfoQuickRegisterDialog.vue",
"source_location": "L223",
"source_location": "L308",
"weight": 1.0
},
{
"source": "views_cell_storage_sample_info_sampleinfoquickregisterdialog_vue",
"target": "views_cell_storage_sample_info_quickregisterattachmentfield_vue",
"relation": "imports_from",
"confidence": "EXTRACTED",
"source_file": "views/cell-storage/sample-info/SampleInfoQuickRegisterDialog.vue",
"source_location": "L309",
"weight": 1.0
},
{
@@ -59903,7 +59917,16 @@
"relation": "contains",
"confidence": "EXTRACTED",
"source_file": "views/cell-storage/sample-info/SampleInfoQuickRegisterDialog.vue",
"source_location": "L302",
"source_location": "L405",
"weight": 1.0
},
{
"source": "views_cell_storage_sample_info_quickregisterattachmentfield_vue",
"target": "sample_info_quickregisterattachmentfield_for",
"relation": "contains",
"confidence": "EXTRACTED",
"source_file": "views/cell-storage/sample-info/QuickRegisterAttachmentField.vue",
"source_location": "L205",
"weight": 1.0
},
{
@@ -83870,7 +83893,7 @@
"confidence": "INFERRED",
"confidence_score": 0.8,
"source_file": "api/sample-info-handle.ts",
"source_location": "L60",
"source_location": "L68",
"weight": 1.0
},
{
@@ -83880,7 +83903,7 @@
"confidence": "INFERRED",
"confidence_score": 0.8,
"source_file": "api/sample-info-handle.ts",
"source_location": "L81",
"source_location": "L89",
"weight": 1.0
},
{
+112 -145
View File
@@ -1,10 +1,10 @@
# Graph Report - src (2026-10-17)
# Graph Report - src (2026-10-19)
## Corpus Check
- Large corpus: 1036 files · ~687,728 words. Semantic extraction will be expensive (many Claude tokens). Consider running on a subfolder, or use --no-semantic to run AST-only.
- Large corpus: 1037 files · ~689,168 words. Semantic extraction will be expensive (many Claude tokens). Consider running on a subfolder, or use --no-semantic to run AST-only.
## Summary
- 3834 nodes · 5593 edges · 66 communities detected
- 3836 nodes · 5595 edges · 61 communities detected
- Extraction: 76% EXTRACTED · 24% INFERRED · 0% AMBIGUOUS · INFERRED: 1336 edges (avg confidence: 0.8)
- Token cost: 0 input · 0 output
@@ -52,29 +52,24 @@
- [[_COMMUNITY_Community 40|Community 40]]
- [[_COMMUNITY_Community 41|Community 41]]
- [[_COMMUNITY_Community 42|Community 42]]
- [[_COMMUNITY_Community 43|Community 43]]
- [[_COMMUNITY_Community 44|Community 44]]
- [[_COMMUNITY_Community 45|Community 45]]
- [[_COMMUNITY_Community 46|Community 46]]
- [[_COMMUNITY_Community 48|Community 48]]
- [[_COMMUNITY_Community 51|Community 51]]
- [[_COMMUNITY_Community 49|Community 49]]
- [[_COMMUNITY_Community 50|Community 50]]
- [[_COMMUNITY_Community 52|Community 52]]
- [[_COMMUNITY_Community 53|Community 53]]
- [[_COMMUNITY_Community 54|Community 54]]
- [[_COMMUNITY_Community 55|Community 55]]
- [[_COMMUNITY_Community 56|Community 56]]
- [[_COMMUNITY_Community 57|Community 57]]
- [[_COMMUNITY_Community 58|Community 58]]
- [[_COMMUNITY_Community 60|Community 60]]
- [[_COMMUNITY_Community 61|Community 61]]
- [[_COMMUNITY_Community 64|Community 64]]
- [[_COMMUNITY_Community 65|Community 65]]
- [[_COMMUNITY_Community 67|Community 67]]
- [[_COMMUNITY_Community 63|Community 63]]
- [[_COMMUNITY_Community 68|Community 68]]
- [[_COMMUNITY_Community 72|Community 72]]
- [[_COMMUNITY_Community 75|Community 75]]
- [[_COMMUNITY_Community 78|Community 78]]
- [[_COMMUNITY_Community 71|Community 71]]
- [[_COMMUNITY_Community 73|Community 73]]
- [[_COMMUNITY_Community 89|Community 89]]
- [[_COMMUNITY_Community 92|Community 92]]
- [[_COMMUNITY_Community 93|Community 93]]
- [[_COMMUNITY_Community 96|Community 96]]
- [[_COMMUNITY_Community 97|Community 97]]
## God Nodes (most connected - your core abstractions)
1. `get()` - 345 edges
@@ -96,35 +91,35 @@
- `isStorageSlotAvailable()` --calls--> `Number()` [INFERRED]
utils/storage-slot-options.ts → views/cell-storage/payment-info/PaymentBySampleTab.vue
- `handleBatchDelete()` --calls--> `withFullscreenLoading()` [INFERRED]
views/system/tenant/index.vue → utils/fullscreen-loading.ts
views/operations/exhibition-appointment/index.vue → utils/fullscreen-loading.ts
- `handleBatchDelete()` --calls--> `withFullscreenLoading()` [INFERRED]
views/system/unit/index.vue → utils/fullscreen-loading.ts
views/basic-info/cell-sample-type/index.vue → utils/fullscreen-loading.ts
## Communities
### Community 0 - "Community 0"
Cohesion: 0.0
Nodes (214): fetchAccessLogList(), fetchActiveRegions(), fetchCategoryList(), fetchCategoryParameters(), fetchCellProductPriceList(), fetchCellProductSpecList(), fetchCellProductTypeList(), fetchChannelAccount() (+206 more)
Nodes (225): fetchAccessLogList(), fetchActiveRegions(), fetchCategoryList(), fetchCategoryParameters(), fetchCellProductPriceList(), fetchCellProductSpecList(), fetchCellProductTypeList(), fetchChannelAccount() (+217 more)
### Community 1 - "Community 1"
Cohesion: 0.02
Nodes (131): handleFocus(), handleInput(), if(), Number(), applyPreferentialContractForV1Mode(), createEmptyTransport(), datetimeToYmd(), defaultInstallmentStartDateYmd() (+123 more)
Nodes (136): fetchMarkQcMaterialUsageFullyUsed(), if(), Number(), applyPreferentialContractForV1Mode(), createEmptyTransport(), datetimeToYmd(), defaultInstallmentStartDateYmd(), if() (+128 more)
### Community 2 - "Community 2"
Cohesion: 0.02
Nodes (89): fetchAddTaskStep(), fetchCopyTaskStep(), fetchDeleteTaskStep(), fetchDispatchProductionTaskSteps(), fetchForwardProductionTask(), fetchProductionTaskDetail(), fetchProductionTaskEditorInit(), fetchProductionTaskList() (+81 more)
Nodes (109): fetchMyProductionTasks(), fetchMyQcTaskList(), fetchQcTaskDetail(), fetchQcTaskList(), buildTemporaryViewSections(), buildInsertedSiblingCard(), fetchMineTasksForWorkOrders(), resolveShowProtocolPaymentAtGroup() (+101 more)
### Community 3 - "Community 3"
Cohesion: 0.02
Nodes (92): fetchMyProductionTasks(), fetchMyQcTaskList(), fetchQcTaskDetail(), fetchQcTaskList(), buildTemporaryViewSections(), buildInsertedSiblingCard(), fetchMineTasksForWorkOrders(), resolveShowProtocolPaymentAtGroup() (+84 more)
Nodes (87): fetchAddTaskStep(), fetchCopyTaskStep(), fetchDeleteTaskStep(), fetchDispatchProductionTaskSteps(), fetchForwardProductionTask(), fetchProductionTaskDetail(), fetchProductionTaskEditorInit(), fetchProductionTaskList() (+79 more)
### Community 4 - "Community 4"
Cohesion: 0.02
Nodes (81): fetchBatchDeleteOaReceiveAccounts(), fetchBatchMarkOaCcTasksRead(), fetchCreateOaReceiveAccount(), fetchDeleteOaReceiveAccount(), fetchMarkOaCcTaskRead(), fetchOaAppDraft(), fetchOaAppList(), fetchOaBankReceipts() (+73 more)
Nodes (94): batchSavePilotCheckup(), deletePilotCheckupActualItem(), fetchCheckupInstitutionList(), fetchCheckupInstitutionPackageDetail(), fetchCheckupInstitutionPackages(), fetchPilotCheckupDetail(), fetchPilotCheckupList(), fetchUpdatePostBoundRoles() (+86 more)
### Community 5 - "Community 5"
Cohesion: 0.02
Nodes (89): batchSavePilotCheckup(), deletePilotCheckupActualItem(), fetchCheckupInstitutionList(), fetchCheckupInstitutionPackageDetail(), fetchCheckupInstitutionPackages(), fetchPilotCheckupDetail(), fetchPilotCheckupList(), fetchUpdatePostBoundRoles() (+81 more)
Nodes (73): fetchBatchDeleteOaReceiveAccounts(), fetchBatchMarkOaCcTasksRead(), fetchCreateOaReceiveAccount(), fetchDeleteOaReceiveAccount(), fetchMarkOaCcTaskRead(), fetchOaAppDraft(), fetchOaBankReceipts(), fetchOaCcUnreadCount() (+65 more)
### Community 6 - "Community 6"
Cohesion: 0.03
@@ -132,7 +127,7 @@ Nodes (80): fetchUploadAttachment(), FireworkSystem, handleReportUpload(), handl
### Community 7 - "Community 7"
Cohesion: 0.02
Nodes (84): fetchCellSampleTypeList(), fetchCheckupInstitutionInvoices(), fetchCheckupInstitutionProjects(), fetchCreateCellSampleType(), fetchCreateCheckupInstitution(), fetchCreateCheckupInstitutionInvoice(), fetchCreateCheckupInstitutionProject(), fetchCreateExhibitionAppointment() (+76 more)
Nodes (80): fetchCheckupInstitutionInvoices(), fetchCheckupInstitutionProjects(), fetchCreateCheckupInstitution(), fetchCreateCheckupInstitutionInvoice(), fetchCreateCheckupInstitutionProject(), fetchCreateItemUnit(), fetchDeleteItemUnit(), fetchItemUnitList() (+72 more)
### Community 8 - "Community 8"
Cohesion: 0.03
@@ -140,91 +135,91 @@ Nodes (34): fetchGetMenuList(), ComponentLoader, IframeRouteManager, MenuProcess
### Community 9 - "Community 9"
Cohesion: 0.03
Nodes (57): handleBlur(), handleFocus(), handleInput(), fetchCreatePaymentTransfer(), fetchDeletePaymentTransfer(), fetchPaymentChaseList(), fetchPaymentTransferList(), fetchPaymentTransferReceiptConfirmedList() (+49 more)
Nodes (54): useSettingsHandlers(), useSettingsPanel(), useSettingsState(), useCeremony(), useTheme(), if(), chipTitle(), confirmPicker() (+46 more)
### Community 10 - "Community 10"
Cohesion: 0.03
Nodes (62): fetchOaRelatedSummaries(), useSettingsHandlers(), useSettingsPanel(), useSettingsState(), useCeremony(), useTheme(), if(), loadAllAppointmentsForExport() (+54 more)
Cohesion: 0.04
Nodes (55): handleBlur(), handleFocus(), handleInput(), fetchCreatePaymentTransfer(), fetchDeletePaymentTransfer(), fetchPaymentChaseList(), fetchPaymentTransferList(), fetchPaymentTransferReceiptConfirmedList() (+47 more)
### Community 11 - "Community 11"
Cohesion: 0.04
Nodes (71): fetchDeptTree(), fetchUserList(), fetchOaFlowPreview(), fetchOaTemplateDetail(), branchConditionLines(), remoteSearchHandoverUsers(), collectConditionReferencedFields(), collectFormConditionReferencedFields() (+63 more)
Cohesion: 0.03
Nodes (52): fetchAttachmentDownloadUrl(), formatProtocolAmount(), handleAttachmentPreview(), resolveFileUrl(), showStepContent(), visibleFields(), qcAttachmentFullUrl(), qcDownloadAttachment() (+44 more)
### Community 12 - "Community 12"
Cohesion: 0.03
Nodes (54): fetchDictDataOptions(), fetchAttachmentDownloadUrl(), fetchUpdateSampleFreight(), formatProtocolAmount(), handleAttachmentPreview(), resolveFileUrl(), showStepContent(), visibleFields() (+46 more)
Cohesion: 0.04
Nodes (70): fetchDeptTree(), fetchUserList(), fetchOaFlowPreview(), fetchOaTemplateDetail(), openForDraft(), remoteSearchHandoverUsers(), applySchema(), flowNeedsInitiatorSelect() (+62 more)
### Community 13 - "Community 13"
Cohesion: 0.04
Nodes (58): fetchOaInstanceDetail(), fetchOaTasks(), buildFilterParams(), currentPrinterName(), handleReset(), handleSearch(), load(), openDetail() (+50 more)
Nodes (49): fetchCreateMenu(), fetchDeleteMenu(), fetchMenuTree(), fetchUpdateMenu(), collectIds(), buildInboundBasicSection(), buildInboundCellStorageViewSections(), buildInboundResearchDonationViewSections() (+41 more)
### Community 14 - "Community 14"
Cohesion: 0.04
Nodes (45): buildBaseFields(), buildInboundBasicSection(), buildInboundCellStorageProductionViewSections(), buildInboundResearchDonationProductionViewSections(), buildOutboundBasicExperimentProductionViewSections(), buildOutboundClinicalProductionViewSections(), buildOutboundDetail(), buildOutboundPilotProductionViewSections() (+37 more)
Nodes (46): buildBaseFields(), buildFeeSection(), buildInboundBasicSection(), buildInboundCellStorageProductionViewSections(), buildInboundResearchDonationProductionViewSections(), buildOutboundBasicExperimentProductionViewSections(), buildOutboundClinicalProductionViewSections(), buildOutboundDetail() (+38 more)
### Community 15 - "Community 15"
Cohesion: 0.04
Nodes (51): fetchCreateItemUnit(), fetchCreateMenu(), fetchCreateTenant(), fetchDeleteItemUnit(), fetchDeleteMenu(), fetchDeleteTenant(), fetchItemUnitList(), fetchMenuTree() (+43 more)
### Community 16 - "Community 16"
Cohesion: 0.04
Nodes (57): fetchCollectionRegionList(), fetchCreateCollectionRegion(), fetchCreateHospital(), fetchCreateRegionStaff(), fetchDeleteCollectionRegion(), fetchDeleteHospital(), fetchDeleteRegionStaff(), fetchHospitalList() (+49 more)
### Community 17 - "Community 17"
### Community 16 - "Community 16"
Cohesion: 0.05
Nodes (53): fetchGetMenuCodes(), fetchGetUserInfo(), fetchLogin(), fetchRefreshToken(), fetchUpdateProfile(), fetchUploadProfileAvatar(), fetchWxQrStatus(), fetchUserInfo() (+45 more)
### Community 17 - "Community 17"
Cohesion: 0.04
Nodes (18): fetchProductionWorkOrderQcInfo(), fetchSampleInsurance(), fetchSampleStorageCert(), fetchUpdateSampleStorageCert(), dash(), fmtMoney(), auditorDisplay(), dash() (+10 more)
### Community 18 - "Community 18"
Cohesion: 0.04
Nodes (40): fetchDeleteMaterialBatch(), fetchMaterialBatchList(), fetchMaterialBatchOptions(), fetchMaterialList(), fetchMaterialOptions(), fetchUpdateMaterialBatch(), fetchMaterialUsageList(), fetchMyMaterialUsageList() (+32 more)
### Community 19 - "Community 19"
Cohesion: 0.04
Nodes (18): fetchProductionWorkOrderQcInfo(), fetchSampleInsurance(), fetchSampleStorageCert(), fetchUpdateSampleStorageCert(), dash(), fmtMoney(), auditorDisplay(), dash() (+10 more)
Cohesion: 0.05
Nodes (56): fetchOaRelatedSummaries(), buildFormRows(), buildOaPrintFilename(), buildOaPrintModel(), canvasToPdf(), ensurePlainObject(), exportOaApprovalPdf(), extractUrls() (+48 more)
### Community 20 - "Community 20"
Cohesion: 0.05
Nodes (34): fetchClinicalPaymentDetail(), fetchClinicalPayments(), fetchClinicalReceiptConfirmed(), fetchClinicalReceiptPending(), fetchClinicalRefundConfirmed(), fetchClinicalRefundPending(), fetchOrderAdjusts(), fetchOrderDetail() (+26 more)
Cohesion: 0.04
Nodes (41): fetchCreateExhibitionAppointment(), fetchDeleteExhibitionAppointment(), fetchExhibitionAppointmentList(), fetchUpdateExhibitionAppointment(), fetchMineQcWorkOrderTabUnfinishedCounts(), fetchOutboundQcDetail(), fetchQcWorkOrderDetail(), fetchQcWorkOrderList() (+33 more)
### Community 21 - "Community 21"
Cohesion: 0.06
Nodes (40): buildInboundBasicSection(), buildInboundCellStorageViewSections(), buildInboundResearchDonationViewSections(), buildReceptionSection(), buildTransportSection(), resolveInboundProtocolStatus(), appendTaskResultSections(), batchTasksForPanelSlot() (+32 more)
Cohesion: 0.05
Nodes (34): fetchClinicalPaymentDetail(), fetchClinicalPayments(), fetchClinicalReceiptConfirmed(), fetchClinicalReceiptPending(), fetchClinicalRefundConfirmed(), fetchClinicalRefundPending(), fetchOrderAdjusts(), fetchOrderDetail() (+26 more)
### Community 22 - "Community 22"
Cohesion: 0.05
Nodes (39): fetchCreateQcInspectionItemTemplate(), fetchDeleteQcInspectionItemTemplate(), fetchQcInspectionItemTemplateDetail(), fetchQcInspectionItemTemplateList(), fetchQcInspectionItemTemplatesActive(), fetchUpdateQcInspectionItemTemplate(), fetchQcLabTestItemList(), fetchQcLabTestItemsActive() (+31 more)
### Community 23 - "Community 23"
Cohesion: 0.06
Nodes (25): fetchQcMaterialBatchDetail(), fetchQcMaterialBatchList(), fetchQcMaterialBatchOptions(), fetchQcMaterialList(), fetchQcMaterialOptions(), fetchUpdateQcMaterialBatch(), fetchMarkQcMaterialUsageFullyUsed(), financeAttachmentsToUrlString() (+17 more)
### Community 24 - "Community 24"
Cohesion: 0.1
Nodes (2): WebSocketClient, TableCache
### Community 25 - "Community 25"
Cohesion: 0.06
Nodes (20): fetchEthnicList(), fetchSampleFreightDetail(), fetchSampleFreightList(), fetchSampleFreightSampleOptions(), applyDonationBundleToForm(), createEmptyTransport(), ensureEthnicOptionInList(), handleOpenForAdd() (+12 more)
### Community 26 - "Community 26"
### Community 24 - "Community 24"
Cohesion: 0.09
Nodes (8): getDefaultLanguage(), checkStorageCompatibility(), StorageConfig, getSystemStorage(), getSysVersion(), StorageKeyManager, StorageCompatibilityManager, validateStorageData()
### Community 27 - "Community 27"
Cohesion: 0.08
Nodes (20): createEmptySnapshots(), normalizeConfiguredReagents(), normalizeConsumables(), normalizeDataCollections(), normalizeReagents(), normalizeStepOutputs(), serializeAttachments(), serializeEquipmentIds() (+12 more)
### Community 28 - "Community 28"
### Community 25 - "Community 25"
Cohesion: 0.08
Nodes (22): fetchMineProductionWorkOrderTabStepCounts(), fetchMineProductionWorkOrderTabStepCountsDeduped(), fetchProductionWorkOrderCellProductOptions(), fetchProductionWorkOrderDetail(), fetchProductionWorkOrderList(), fetchProductionWorkOrderQcDispatchOptions(), fetchProductionWorkOrderTabStepCounts(), fetchProductionWorkOrderTabStepCountsDeduped() (+14 more)
### Community 29 - "Community 29"
### Community 26 - "Community 26"
Cohesion: 0.08
Nodes (20): createEmptySnapshots(), normalizeConfiguredReagents(), normalizeConsumables(), normalizeDataCollections(), normalizeReagents(), normalizeStepOutputs(), serializeAttachments(), serializeEquipmentIds() (+12 more)
### Community 27 - "Community 27"
Cohesion: 0.09
Nodes (22): fetchOaAppList(), fetchOaGroupList(), fetchPublishOaApp(), loadData(), loadGroups(), resetForm(), onSuccess(), goBack() (+14 more)
### Community 28 - "Community 28"
Cohesion: 0.11
Nodes (25): completePilotApplication(), deletePilotApplication(), fetchPilotApplicationList(), startPilotApplication(), voidPilotApplication(), clearTableSelection(), handleBatchComplete(), handleBatchStart() (+17 more)
### Community 30 - "Community 30"
### Community 29 - "Community 29"
Cohesion: 0.09
Nodes (12): fetchMineQcWorkOrderTabUnfinishedCounts(), fetchOutboundQcDetail(), fetchQcWorkOrderDetail(), fetchQcWorkOrderList(), fetchQcWorkOrdersBySample(), fetchQcWorkOrderTabUnfinishedCounts(), reload(), reloadTabCounts() (+4 more)
Nodes (16): fetchEthnicList(), applyDonationBundleToForm(), createEmptyTransport(), ensureEthnicOptionInList(), handleOpenForAdd(), loadEthnicOptions(), normalizeSampleRow(), resetForm() (+8 more)
### Community 30 - "Community 30"
Cohesion: 0.07
Nodes (11): fetchQcMaterialBatchDetail(), fetchQcMaterialBatchList(), fetchQcMaterialBatchOptions(), fetchQcMaterialList(), fetchQcMaterialOptions(), fetchUpdateQcMaterialBatch(), financeAttachmentsToUrlString(), ensureTabMounted() (+3 more)
### Community 31 - "Community 31"
Cohesion: 0.11
@@ -235,188 +230,160 @@ Cohesion: 0.1
Nodes (12): fetchOutboundReleaseMaterial(), fetchOutboundReleaseReviewDetail(), fetchOutboundReleaseReviewList(), fetchReleaseReviewList(), handleReset(), handleSearch(), handleTabChange(), handleToggleSelect() (+4 more)
### Community 33 - "Community 33"
Cohesion: 0.13
Nodes (19): fetchCellSampleTypeList(), fetchCreateCellSampleType(), fetchDeleteCellSampleType(), fetchUpdateCellSampleType(), handleAdd(), handleBatchDelete(), handleDelete(), handleDropdownCommand() (+11 more)
### Community 34 - "Community 34"
Cohesion: 0.12
Nodes (15): addCopyButton(), highlightCode(), insertLineNumbers(), isBlockProcessed(), markBlockAsProcessed(), processBlock(), setupHighlightDirective(), setupRippleDirective() (+7 more)
### Community 34 - "Community 34"
### Community 35 - "Community 35"
Cohesion: 0.2
Nodes (14): applyFlagToRule(), applySchema(), countRules(), getActiveRule(), getDesigner(), getSetupState(), onMessage(), readFlag() (+6 more)
### Community 35 - "Community 35"
Cohesion: 0.16
Nodes (14): fetchCreateEnvDetectItem(), fetchDeleteEnvDetectItem(), fetchEnvDetectItemDetail(), fetchEnvDetectItemList(), fetchEnvDetectItemsActive(), fetchUpdateEnvDetectItem(), handleAdd(), handleBatchDelete() (+6 more)
### Community 36 - "Community 36"
Cohesion: 0.16
Nodes (16): fetchCreateTenant(), fetchDeleteTenant(), fetchTenantList(), fetchUpdateTenant(), handleAdd(), handleDelete(), handleDropdownCommand(), handleEdit() (+8 more)
### Community 37 - "Community 37"
Cohesion: 0.12
Nodes (6): setupOaConfirmationKit(), ensureOaKitMenu(), setupOaLeaveKit(), setupOaOvertimeKit(), setupOaResignationKit(), setupOaTripKit()
### Community 37 - "Community 37"
### Community 38 - "Community 38"
Cohesion: 0.16
Nodes (10): useTable(), useTableImpl(), getColumnChecks(), useTableColumns(), createErrorHandler(), createSmartDebounce(), defaultResponseAdapter(), extractPagination() (+2 more)
### Community 38 - "Community 38"
### Community 39 - "Community 39"
Cohesion: 0.27
Nodes (14): useChart(), useChartComponent(), useChartOps(), colourBlend(), getCssVar(), getDarkColor(), getLightColor(), handleElementThemeColor() (+6 more)
### Community 39 - "Community 39"
Cohesion: 0.13
Nodes (4): fetchPresignOrderDetail(), fetchPresignOrderList(), fetchPresignTransferReceiptConfirmedList(), fetchPresignTransferReceiptConfirmList()
### Community 40 - "Community 40"
Cohesion: 0.25
Nodes (12): buildFlowItems(), isCcProgressItem(), peopleDisplayNames(), progressNodeStatusText(), progressPersonLinesFromItem(), statusText(), displayName(), formatProgressPersonLines() (+4 more)
### Community 41 - "Community 41"
Cohesion: 0.33
Nodes (13): buildProtocolPaymentFlowSteps(), dash(), financeReceiptTime(), formatAmount(), hasFinanceReceipt(), hasFinanceRefund(), hasReceiptSubmit(), hasRefundSubmit() (+5 more)
### Community 42 - "Community 42"
### Community 41 - "Community 41"
Cohesion: 0.19
Nodes (6): fetchServiceOrderTxnList(), handleReset(), handleSearch(), handleTabChange(), loadData(), switchTab()
### Community 43 - "Community 43"
### Community 42 - "Community 42"
Cohesion: 0.24
Nodes (10): buildPrintDocumentHtml(), cleanupPrintIframe(), embedSopImagesAsDataUrls(), getSopA4ContentHeightPx(), getSopA4EditorHeightPx(), normalizeSopCheckboxes(), prepareSopHtmlForPrint(), printSopHtml() (+2 more)
### Community 45 - "Community 45"
### Community 44 - "Community 44"
Cohesion: 0.26
Nodes (8): fetchSampleStorageCertQc(), saveSampleStorageCertQc(), applyDetail(), handleSave(), loadDetail(), resetFormKeys(), resolveStorageCertQcTypeKey(), supportsStorageCertQc()
### Community 46 - "Community 46"
### Community 45 - "Community 45"
Cohesion: 0.25
Nodes (2): handleTouchEnd(), setTransition()
### Community 48 - "Community 48"
Cohesion: 0.28
Nodes (5): fetchMyProductionMaterialConsumptions(), displayConsumptionQty(), handleReset(), handleSearch(), loadData()
### Community 51 - "Community 51"
### Community 49 - "Community 49"
Cohesion: 0.39
Nodes (6): isIgnorableScriptError(), normalizeErrorMessage(), registerPromiseErrorHandler(), registerResourceErrorHandler(), scriptErrorHandler(), setupErrorHandle()
### Community 52 - "Community 52"
### Community 50 - "Community 50"
Cohesion: 0.36
Nodes (1): TableHeightCalculator
### Community 54 - "Community 54"
### Community 52 - "Community 52"
Cohesion: 0.33
Nodes (2): logApiCryptoBootInfo(), maskSecret()
### Community 55 - "Community 55"
Cohesion: 0.29
Nodes (1): fetchQcMonthTemplateList()
### Community 53 - "Community 53"
Cohesion: 0.38
Nodes (4): handleFocus(), handleInput(), parseDecimalToNumber(), sanitizeDecimalInput()
### Community 56 - "Community 56"
Cohesion: 0.29
Nodes (2): fetchStorageReleaseReviewDetail(), fetchStorageReleaseReviewList()
### Community 57 - "Community 57"
### Community 54 - "Community 54"
Cohesion: 0.4
Nodes (2): isUnfinishedQcWorkOrder(), resolveQcWorkOrderUnfinishedBadgeCount()
### Community 58 - "Community 58"
### Community 55 - "Community 55"
Cohesion: 0.5
Nodes (2): parseEquipmentIds(), syncEquipmentNamesFromOptions()
### Community 60 - "Community 60"
### Community 57 - "Community 57"
Cohesion: 0.5
Nodes (2): focusInput(), handleKeydown()
### Community 61 - "Community 61"
Cohesion: 0.4
Nodes (1): fetchQcMaterialAmountAuthUsers()
### Community 64 - "Community 64"
### Community 60 - "Community 60"
Cohesion: 0.67
Nodes (2): isCurrentPending(), isNotReached()
### Community 65 - "Community 65"
### Community 61 - "Community 61"
Cohesion: 0.67
Nodes (2): if(), logSidebarMenu()
### Community 67 - "Community 67"
### Community 63 - "Community 63"
Cohesion: 0.5
Nodes (1): fetchStorageEntrySmsList()
### Community 68 - "Community 68"
Cohesion: 0.5
Nodes (1): fetchQcSmsList()
### Community 72 - "Community 72"
Cohesion: 1.0
Nodes (2): getSettingDefaults(), resetToDefaults()
### Community 75 - "Community 75"
### Community 71 - "Community 71"
Cohesion: 1.0
Nodes (2): copyTextToClipboard(), copyTextWithFallback()
### Community 78 - "Community 78"
### Community 73 - "Community 73"
Cohesion: 1.0
Nodes (2): getSourceProtocolAttachment(), normalizeAttachmentFiles()
### Community 93 - "Community 93"
### Community 89 - "Community 89"
Cohesion: 1.0
Nodes (2): emptyTabCounts(), useProductionWorkOrderTabStepCounts()
### Community 96 - "Community 96"
### Community 92 - "Community 92"
Cohesion: 1.0
Nodes (2): initialProgress(), useQcWorkOrderAttachmentExport()
### Community 97 - "Community 97"
### Community 93 - "Community 93"
Cohesion: 1.0
Nodes (2): emptyTabCounts(), useQcWorkOrderTabUnfinishedCounts()
## Knowledge Gaps
- **Thin community `Community 24`** (42 nodes): `WebSocketClient`, `.calculateReconnectDelay()`, `.clearAllTimers()`, `.clearConnectionTimers()`, `.clearTimer()`, `.close()`, `.closeCurrentSocketForReconnect()`, `.connect()`, `.connectionStatusText()`, `.constructor()`, `.destroyInstance()`, `.flushMessageQueue()`, `.getInstance()`, `.getReadyStateText()`, `.handleClose()`, `.handleConnectionTimeout()`, `.handleError()`, `.handleMessage()`, `.handleOpen()`, `.init()`, `.isWebSocketConnected()`, `.reconnect()`, `.resetHeartbeat()`, `.send()`, `.startHeartbeat()`, `.startPing()`, `TableCache`, `.cleanupExpired()`, `.clear()`, `.clearByTags()`, `.clearCurrentSearch()`, `.clearPagination()`, `.constructor()`, `.evictLRU()`, `.generateKey()`, `.generateTags()`, `.get()`, `.getStats()`, `.log()`, `.set()`, `index.ts`, `tableCache.ts`
- **Thin community `Community 23`** (42 nodes): `WebSocketClient`, `.calculateReconnectDelay()`, `.clearAllTimers()`, `.clearConnectionTimers()`, `.clearTimer()`, `.close()`, `.closeCurrentSocketForReconnect()`, `.connect()`, `.connectionStatusText()`, `.constructor()`, `.destroyInstance()`, `.flushMessageQueue()`, `.getInstance()`, `.getReadyStateText()`, `.handleClose()`, `.handleConnectionTimeout()`, `.handleError()`, `.handleMessage()`, `.handleOpen()`, `.init()`, `.isWebSocketConnected()`, `.reconnect()`, `.resetHeartbeat()`, `.send()`, `.startHeartbeat()`, `.startPing()`, `TableCache`, `.cleanupExpired()`, `.clear()`, `.clearByTags()`, `.clearCurrentSearch()`, `.clearPagination()`, `.constructor()`, `.evictLRU()`, `.generateKey()`, `.generateTags()`, `.get()`, `.getStats()`, `.log()`, `.set()`, `index.ts`, `tableCache.ts`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 46`** (9 nodes): `cleanupEventListeners()`, `handleTouchEnd()`, `handleTouchMove()`, `handleTouchStart()`, `handleWheelScroll()`, `if()`, `setTransition()`, `setupEventListeners()`, `index.vue`
- **Thin community `Community 45`** (9 nodes): `cleanupEventListeners()`, `handleTouchEnd()`, `handleTouchMove()`, `handleTouchStart()`, `handleWheelScroll()`, `if()`, `setTransition()`, `setupEventListeners()`, `index.vue`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 52`** (8 nodes): `TableHeightCalculator`, `.calculate()`, `.calculateOffset()`, `.calculatePaginationOffset()`, `.constructor()`, `.getHeaderHeight()`, `useTableHeight()`, `useTableHeight.ts`
- **Thin community `Community 50`** (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 54`** (7 nodes): `App.vue`, `main.ts`, `refreshButtonAutoIcons()`, `refreshPanelTitleIcons()`, `logApiCryptoBootInfo()`, `maskSecret()`, `console.ts`
- **Thin community `Community 52`** (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 55`** (7 nodes): `fetchConfirmQcMonthImport()`, `fetchCreateQcMonthTemplate()`, `fetchDeleteQcMonthTemplate()`, `fetchPreviewQcMonthImport()`, `fetchQcMonthTemplateList()`, `fetchUpdateQcMonthTemplate()`, `qc-material-month-template.ts`
- **Thin community `Community 54`** (6 nodes): `formatQcWorkOrderUnfinishedBadgeCount()`, `isUnfinishedQcWorkOrder()`, `qcWorkOrderUnfinishedBadgeTitle()`, `resolveQcWorkOrderUnfinishedBadgeCount()`, `sumQcWorkOrderGroupUnfinishedBadgeCount()`, `qc-work-order-unfinished-badge.ts`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 56`** (7 nodes): `batchReviewStorageRelease()`, `batchStoreSample()`, `fetchStorageReleaseReviewDetail()`, `fetchStorageReleaseReviewList()`, `storeSample()`, `submitStorageReleaseReview()`, `storage-release-review.ts`
- **Thin community `Community 55`** (5 nodes): `equipmentOptionLabel()`, `joinEquipmentIds()`, `parseEquipmentIds()`, `syncEquipmentNamesFromOptions()`, `equipment-select.ts`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 57`** (6 nodes): `formatQcWorkOrderUnfinishedBadgeCount()`, `isUnfinishedQcWorkOrder()`, `qcWorkOrderUnfinishedBadgeTitle()`, `resolveQcWorkOrderUnfinishedBadgeCount()`, `sumQcWorkOrderGroupUnfinishedBadgeCount()`, `qc-work-order-unfinished-badge.ts`
- **Thin community `Community 57`** (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 58`** (5 nodes): `equipmentOptionLabel()`, `joinEquipmentIds()`, `parseEquipmentIds()`, `syncEquipmentNamesFromOptions()`, `equipment-select.ts`
- **Thin community `Community 60`** (4 nodes): `isCurrentPending()`, `isNotReached()`, `mergeProgressWithComments()`, `oa-progress-merge-comments.ts`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 60`** (5 nodes): `focusInput()`, `handleKeydown()`, `if()`, `search()`, `index.vue`
- **Thin community `Community 61`** (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 61`** (5 nodes): `fetchBatchRevokeQcMaterialAmountAuth()`, `fetchGrantQcMaterialAmountAuth()`, `fetchQcMaterialAmountAuthUsers()`, `fetchRevokeQcMaterialAmountAuth()`, `qc-material-amount-auth.ts`
- **Thin community `Community 63`** (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 64`** (4 nodes): `isCurrentPending()`, `isNotReached()`, `mergeProgressWithComments()`, `oa-progress-merge-comments.ts`
- **Thin community `Community 68`** (3 nodes): `getSettingDefaults()`, `resetToDefaults()`, `setting.ts`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 65`** (4 nodes): `if()`, `logSidebarMenu()`, `index.vue`, `SidebarSubmenu.vue`
- **Thin community `Community 71`** (3 nodes): `copyTextToClipboard()`, `copyTextWithFallback()`, `copy-text.ts`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 67`** (4 nodes): `fetchGenerateStorageEntrySms()`, `fetchStorageEntrySmsList()`, `fetchToggleStorageEntrySmsNotified()`, `storage-entry-sms-notification.ts`
- **Thin community `Community 73`** (3 nodes): `getSourceProtocolAttachment()`, `normalizeAttachmentFiles()`, `protocol-source-attachment.ts`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 68`** (4 nodes): `fetchGenerateQcSms()`, `fetchQcSmsList()`, `fetchToggleQcSmsNotified()`, `qc-sms-notification.ts`
- **Thin community `Community 89`** (3 nodes): `emptyTabCounts()`, `useProductionWorkOrderTabStepCounts()`, `useProductionWorkOrderTabStepCounts.ts`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 72`** (3 nodes): `getSettingDefaults()`, `resetToDefaults()`, `setting.ts`
- **Thin community `Community 92`** (3 nodes): `initialProgress()`, `useQcWorkOrderAttachmentExport()`, `useQcWorkOrderAttachmentExport.ts`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 75`** (3 nodes): `copyTextToClipboard()`, `copyTextWithFallback()`, `copy-text.ts`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 78`** (3 nodes): `getSourceProtocolAttachment()`, `normalizeAttachmentFiles()`, `protocol-source-attachment.ts`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 93`** (3 nodes): `emptyTabCounts()`, `useProductionWorkOrderTabStepCounts()`, `useProductionWorkOrderTabStepCounts.ts`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 96`** (3 nodes): `initialProgress()`, `useQcWorkOrderAttachmentExport()`, `useQcWorkOrderAttachmentExport.ts`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 97`** (3 nodes): `emptyTabCounts()`, `useQcWorkOrderTabUnfinishedCounts()`, `useQcWorkOrderTabUnfinishedCounts.ts`
- **Thin community `Community 93`** (3 nodes): `emptyTabCounts()`, `useQcWorkOrderTabUnfinishedCounts()`, `useQcWorkOrderTabUnfinishedCounts.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 `push()` connect `Community 6` to `Community 0`, `Community 1`, `Community 2`, `Community 3`, `Community 4`, `Community 5`, `Community 7`, `Community 9`, `Community 10`, `Community 11`, `Community 12`, `Community 13`, `Community 14`, `Community 17`, `Community 18`, `Community 19`, `Community 21`, `Community 22`, `Community 24`, `Community 27`, `Community 28`, `Community 30`, `Community 40`?**
_High betweenness centrality (0.292) - this node is a cross-community bridge._
- **Why does `get()` connect `Community 0` to `Community 1`, `Community 2`, `Community 3`, `Community 4`, `Community 5`, `Community 6`, `Community 7`, `Community 9`, `Community 10`, `Community 11`, `Community 12`, `Community 13`, `Community 15`, `Community 16`, `Community 17`, `Community 18`, `Community 19`, `Community 20`, `Community 21`, `Community 22`, `Community 23`, `Community 25`, `Community 28`, `Community 29`, `Community 30`, `Community 31`, `Community 32`, `Community 35`, `Community 39`, `Community 42`, `Community 45`, `Community 48`, `Community 55`, `Community 56`, `Community 61`, `Community 67`, `Community 68`?**
_High betweenness centrality (0.272) - this node is a cross-community bridge._
- **Why does `Number()` connect `Community 1` to `Community 0`, `Community 3`, `Community 4`, `Community 6`, `Community 7`, `Community 9`, `Community 10`, `Community 11`, `Community 12`, `Community 13`, `Community 14`, `Community 17`, `Community 18`, `Community 19`, `Community 21`, `Community 23`, `Community 25`, `Community 27`, `Community 38`, `Community 41`, `Community 48`?**
_High betweenness centrality (0.151) - this node is a cross-community bridge._
- **Why does `push()` connect `Community 6` to `Community 0`, `Community 1`, `Community 2`, `Community 3`, `Community 4`, `Community 5`, `Community 7`, `Community 9`, `Community 10`, `Community 11`, `Community 12`, `Community 13`, `Community 14`, `Community 16`, `Community 17`, `Community 18`, `Community 19`, `Community 20`, `Community 22`, `Community 23`, `Community 25`, `Community 26`, `Community 27`?**
_High betweenness centrality (0.276) - this node is a cross-community bridge._
- **Why does `get()` connect `Community 0` to `Community 1`, `Community 2`, `Community 3`, `Community 4`, `Community 5`, `Community 6`, `Community 7`, `Community 9`, `Community 10`, `Community 12`, `Community 13`, `Community 15`, `Community 16`, `Community 17`, `Community 18`, `Community 19`, `Community 20`, `Community 21`, `Community 22`, `Community 25`, `Community 27`, `Community 28`, `Community 29`, `Community 30`, `Community 31`, `Community 32`, `Community 33`, `Community 36`, `Community 41`, `Community 44`, `Community 63`?**
_High betweenness centrality (0.258) - this node is a cross-community bridge._
- **Why does `Number()` connect `Community 1` to `Community 0`, `Community 2`, `Community 3`, `Community 4`, `Community 5`, `Community 6`, `Community 7`, `Community 9`, `Community 10`, `Community 12`, `Community 13`, `Community 14`, `Community 16`, `Community 17`, `Community 18`, `Community 19`, `Community 26`, `Community 29`, `Community 39`, `Community 40`, `Community 53`?**
_High betweenness centrality (0.159) - this node is a cross-community bridge._
- **Are the 344 inferred relationships involving `get()` (e.g. with `resolveStorageSlotRangeFill()` and `buildNodeCodePathFromFlat()`) actually correct?**
_`get()` has 344 INFERRED edges - model-reasoned connections that need verification._
- **Are the 127 inferred relationships involving `push()` (e.g. with `refreshQcMenuBadges()` and `collectLeafFacilityNodesInTreeOrder()`) actually correct?**
+4 -4
View File
@@ -57,12 +57,12 @@
</div>
<div id="legend"></div>
</div>
<div id="stats">3834 nodes &middot; 5593 edges &middot; 404 communities</div>
<div id="stats">3836 nodes &middot; 5595 edges &middot; 399 communities</div>
</div>
<script>
const RAW_NODES = [{"id": "app_vue", "label": "App.vue", "color": {"background": "#59A14F", "border": "#59A14F", "highlight": {"background": "#ffffff", "border": "#59A14F"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "App.vue", "community": 54, "community_name": "Community 54", "source_file": "App.vue", "file_type": "code", "degree": 3}, {"id": "src_app_refreshbuttonautoicons", "label": "refreshButtonAutoIcons()", "color": {"background": "#59A14F", "border": "#59A14F", "highlight": {"background": "#ffffff", "border": "#59A14F"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "refreshButtonAutoIcons()", "community": 54, "community_name": "Community 54", "source_file": "App.vue", "file_type": "code", "degree": 1}, {"id": "src_app_refreshpaneltitleicons", "label": "refreshPanelTitleIcons()", "color": {"background": "#59A14F", "border": "#59A14F", "highlight": {"background": "#ffffff", "border": "#59A14F"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "refreshPanelTitleIcons()", "community": 54, "community_name": "Community 54", "source_file": "App.vue", "file_type": "code", "degree": 1}, {"id": "main_ts", "label": "main.ts", "color": {"background": "#59A14F", "border": "#59A14F", "highlight": {"background": "#ffffff", "border": "#59A14F"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "main.ts", "community": 54, "community_name": "Community 54", "source_file": "main.ts", "file_type": "code", "degree": 4}, {"id": "src_main_masksecret", "label": "maskSecret()", "color": {"background": "#59A14F", "border": "#59A14F", "highlight": {"background": "#ffffff", "border": "#59A14F"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "maskSecret()", "community": 54, "community_name": "Community 54", "source_file": "main.ts", "file_type": "code", "degree": 2}, {"id": "src_main_logapicryptobootinfo", "label": "logApiCryptoBootInfo()", "color": {"background": "#59A14F", "border": "#59A14F", "highlight": {"background": "#ffffff", "border": "#59A14F"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "logApiCryptoBootInfo()", "community": 54, "community_name": "Community 54", "source_file": "main.ts", "file_type": "code", "degree": 2}, {"id": "env_d_ts", "label": "env.d.ts", "color": {"background": "#59A14F", "border": "#59A14F", "highlight": {"background": "#ffffff", "border": "#59A14F"}}, "size": 10.0, "font": {"size": 0, "color": "#ffffff"}, "title": "env.d.ts", "community": 144, "community_name": "Community 144", "source_file": "env.d.ts", "file_type": "code", "degree": 0}, {"id": "shims_loose_d_ts", "label": "shims-loose.d.ts", "color": {"background": "#EDC948", "border": "#EDC948", "highlight": {"background": "#ffffff", "border": "#EDC948"}}, "size": 10.0, "font": {"size": 0, "color": "#ffffff"}, "title": "shims-loose.d.ts", "community": 145, "community_name": "Community 145", "source_file": "shims-loose.d.ts", "file_type": "code", "degree": 0}, {"id": "directives_index_ts", "label": "index.ts", "color": {"background": "#76B7B2", "border": "#76B7B2", "highlight": {"background": "#ffffff", "border": "#76B7B2"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "index.ts", "community": 33, "community_name": "Community 33", "source_file": "directives/index.ts", "file_type": "code", "degree": 1}, {"id": "directives_index_setupglobdirectives", "label": "setupGlobDirectives()", "color": {"background": "#76B7B2", "border": "#76B7B2", "highlight": {"background": "#ffffff", "border": "#76B7B2"}}, "size": 10.4, "font": {"size": 0, "color": "#ffffff"}, "title": "setupGlobDirectives()", "community": 33, "community_name": "Community 33", "source_file": "directives/index.ts", "file_type": "code", "degree": 5}, {"id": "directives_core_roles_ts", "label": "roles.ts", "color": {"background": "#76B7B2", "border": "#76B7B2", "highlight": {"background": "#ffffff", "border": "#76B7B2"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "roles.ts", "community": 33, "community_name": "Community 33", "source_file": "directives/core/roles.ts", "file_type": "code", "degree": 3}, {"id": "core_roles_checkrolepermission", "label": "checkRolePermission()", "color": {"background": "#76B7B2", "border": "#76B7B2", "highlight": {"background": "#ffffff", "border": "#76B7B2"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "checkRolePermission()", "community": 33, "community_name": "Community 33", "source_file": "directives/core/roles.ts", "file_type": "code", "degree": 2}, {"id": "core_roles_removeelement", "label": "removeElement()", "color": {"background": "#76B7B2", "border": "#76B7B2", "highlight": {"background": "#ffffff", "border": "#76B7B2"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "removeElement()", "community": 33, "community_name": "Community 33", "source_file": "directives/core/roles.ts", "file_type": "code", "degree": 2}, {"id": "core_roles_setuprolesdirective",Line truncated
const RAW_EDGES = [{"from": "app_vue", "to": "src_app_refreshbuttonautoicons", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "app_vue", "to": "src_app_refreshpaneltitleicons", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "app_vue", "to": "main_ts", "label": "imports_from", "title": "imports_from [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_ts", "to": "utils_sys_console_ts", "label": "imports_from", "title": "imports_from [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_ts", "to": "src_main_masksecret", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_ts", "to": "src_main_logapicryptobootinfo", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "src_main_masksecret", "to": "src_main_logapicryptobootinfo", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_index_ts", "to": "directives_index_setupglobdirectives", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_index_setupglobdirectives", "to": "core_auth_setupauthdirective", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "directives_index_setupglobdirectives", "to": "core_roles_setuprolesdirective", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "directives_index_setupglobdirectives", "to": "business_highlight_setuphighlightdirective", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "directives_index_setupglobdirectives", "to": "business_ripple_setuprippledirective", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "directives_core_roles_ts", "to": "core_roles_checkrolepermission", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_core_roles_ts", "to": "core_roles_removeelement", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_core_roles_ts", "to": "core_roles_setuprolesdirective", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_roles_checkrolepermission", "to": "core_roles_removeelement", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_core_auth_ts", "to": "core_auth_checkauthpermission", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_core_auth_ts", "to": "core_auth_removeelement", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_core_auth_ts", "to": "core_auth_setupauthdirective", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_checkauthpermission", "to": "core_auth_removeelement", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_business_ripple_ts", "to": "business_ripple_setuprippledirective", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_business_highlight_ts", "to": "business_highlight_highlightcode", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_business_highlight_ts", "to": "business_highlight_insertlinenumbers", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_business_highlight_ts", "to": "business_highlight_addcopybutton", "label": "contains", "title": "contains [EXTRACTED]", "dLine truncated
const LEGEND = [{"cid": 0, "color": "#4E79A7", "label": "Community 0", "count": 568}, {"cid": 1, "color": "#F28E2B", "label": "Community 1", "count": 186}, {"cid": 2, "color": "#E15759", "label": "Community 2", "count": 155}, {"cid": 3, "color": "#76B7B2", "label": "Community 3", "count": 143}, {"cid": 4, "color": "#59A14F", "label": "Community 4", "count": 132}, {"cid": 5, "color": "#EDC948", "label": "Community 5", "count": 129}, {"cid": 6, "color": "#B07AA1", "label": "Community 6", "count": 126}, {"cid": 7, "color": "#FF9DA7", "label": "Community 7", "count": 123}, {"cid": 8, "color": "#9C755F", "label": "Community 8", "count": 102}, {"cid": 9, "color": "#BAB0AC", "label": "Community 9", "count": 88}, {"cid": 10, "color": "#4E79A7", "label": "Community 10", "count": 87}, {"cid": 11, "color": "#F28E2B", "label": "Community 11", "count": 86}, {"cid": 12, "color": "#E15759", "label": "Community 12", "count": 86}, {"cid": 13, "color": "#76B7B2", "label": "Community 13", "count": 85}, {"cid": 14, "color": "#59A14F", "label": "Community 14", "count": 78}, {"cid": 15, "color": "#EDC948", "label": "Community 15", "count": 77}, {"cid": 16, "color": "#B07AA1", "label": "Community 16", "count": 73}, {"cid": 17, "color": "#FF9DA7", "label": "Community 17", "count": 70}, {"cid": 18, "color": "#9C755F", "label": "Community 18", "count": 68}, {"cid": 19, "color": "#BAB0AC", "label": "Community 19", "count": 68}, {"cid": 20, "color": "#4E79A7", "label": "Community 20", "count": 61}, {"cid": 21, "color": "#F28E2B", "label": "Community 21", "count": 58}, {"cid": 22, "color": "#E15759", "label": "Community 22", "count": 57}, {"cid": 23, "color": "#76B7B2", "label": "Community 23", "count": 46}, {"cid": 24, "color": "#59A14F", "label": "Community 24", "count": 42}, {"cid": 25, "color": "#EDC948", "label": "Community 25", "count": 38}, {"cid": 26, "color": "#B07AA1", "label": "Community 26", "count": 37}, {"cid": 27, "color": "#FF9DA7", "label": "Community 27", "count": 35}, {"cid": 28, "color": "#9C755F", "label": "Community 28", "count": 35}, {"cid": 29, "color": "#BAB0AC", "label": "Community 29", "count": 30}, {"cid": 30, "color": "#4E79A7", "label": "Community 30", "count": 25}, {"cid": 31, "color": "#F28E2B", "label": "Community 31", "count": 24}, {"cid": 32, "color": "#E15759", "label": "Community 32", "count": 24}, {"cid": 33, "color": "#76B7B2", "label": "Community 33", "count": 22}, {"cid": 34, "color": "#59A14F", "label": "Community 34", "count": 19}, {"cid": 35, "color": "#EDC948", "label": "Community 35", "count": 19}, {"cid": 36, "color": "#B07AA1", "label": "Community 36", "count": 17}, {"cid": 37, "color": "#FF9DA7", "label": "Community 37", "count": 17}, {"cid": 38, "color": "#9C755F", "label": "Community 38", "count": 16}, {"cid": 39, "color": "#BAB0AC", "label": "Community 39", "count": 15}, {"cid": 40, "color": "#4E79A7", "label": "Community 40", "count": 14}, {"cid": 41, "color": "#F28E2B", "label": "Community 41", "count": 14}, {"cid": 42, "color": "#E15759", "label": "Community 42", "count": 14}, {"cid": 43, "color": "#76B7B2", "label": "Community 43", "count": 13}, {"cid": 44, "color": "#59A14F", "label": "Community 44", "count": 13}, {"cid": 45, "color": "#EDC948", "label": "Community 45", "count": 12}, {"cid": 46, "color": "#B07AA1", "label": "Community 46", "count": 9}, {"cid": 47, "color": "#FF9DA7", "label": "Community 47", "count": 9}, {"cid": 48, "color": "#9C755F", "label": "Community 48", "count": 9}, {"cid": 49, "color": "#BAB0AC", "label": "Community 49", "count": 9}, {"cid": 50, "color": "#4E79A7", "label": "Community 50", "count": 9}, {"cid": 51, "color": "#F28E2B", "label": "Community 51", "count": 8}, {"cid": 52, "color": "#E15759", "label": "Community 52", "count": 8}, {"cid": 53, "color": "#76B7B2", "label": "Community 53", "count": 8}, {"cid": 54, "color": "#59A14F", "label": "Community 54", "count": 7}, {"cid": 55, "color": "#EDC948", "label": "Community 55", "count": 7}, {"cid": 56, "color": "#B07AA1", "label": "Community 56", "count": 7}, {"cid": 57, "color": "#FF9DA7", "label": "Community 57", "count": 6}, {"cid": 58, "color": "#9C755F", "label": "Community 58", "count": 5}, {"cid": 59, "color": "#BAB0AC", "label": "Community 59", "count": 5}, {"cid": 60, "color": "#4E79A7", "label": "Community 60", "count": 5}, {"cid": 61, "color": "#F28E2B", "label": "Community 61", "count": 5}, {"cid": 62, "color": "#E15759", "label": "Community 62", "count": 4}, {"cid": 63, "color": "#76B7B2", "label": "Community 63", "count": 4}, {"cid": 64, "color": "#59A14F", "label": "Community 64", "count": 4}, {"cid": 65, "color": "#EDC948", "label": "Community 65", "count": 4}, {"cid": 66, "color": "#B07AA1", "label": "Community 66", "count": 4}, {"cid": 67, "color": "#FF9DA7", "label": "Community 67", "count": 4}, {"cid": 68, "color": "#9C755F", "label": "Community 68", "count": 4}, {"cid": 69, "color": "#BAB0AC", "label": "Community 69", "count": 4}, {"cid": 70, "color": "#4E79A7", "label": "CommunLine truncated
const RAW_NODES = [{"id": "app_vue", "label": "App.vue", "color": {"background": "#E15759", "border": "#E15759", "highlight": {"background": "#ffffff", "border": "#E15759"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "App.vue", "community": 52, "community_name": "Community 52", "source_file": "App.vue", "file_type": "code", "degree": 3}, {"id": "src_app_refreshbuttonautoicons", "label": "refreshButtonAutoIcons()", "color": {"background": "#E15759", "border": "#E15759", "highlight": {"background": "#ffffff", "border": "#E15759"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "refreshButtonAutoIcons()", "community": 52, "community_name": "Community 52", "source_file": "App.vue", "file_type": "code", "degree": 1}, {"id": "src_app_refreshpaneltitleicons", "label": "refreshPanelTitleIcons()", "color": {"background": "#E15759", "border": "#E15759", "highlight": {"background": "#ffffff", "border": "#E15759"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "refreshPanelTitleIcons()", "community": 52, "community_name": "Community 52", "source_file": "App.vue", "file_type": "code", "degree": 1}, {"id": "main_ts", "label": "main.ts", "color": {"background": "#E15759", "border": "#E15759", "highlight": {"background": "#ffffff", "border": "#E15759"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "main.ts", "community": 52, "community_name": "Community 52", "source_file": "main.ts", "file_type": "code", "degree": 4}, {"id": "src_main_masksecret", "label": "maskSecret()", "color": {"background": "#E15759", "border": "#E15759", "highlight": {"background": "#ffffff", "border": "#E15759"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "maskSecret()", "community": 52, "community_name": "Community 52", "source_file": "main.ts", "file_type": "code", "degree": 2}, {"id": "src_main_logapicryptobootinfo", "label": "logApiCryptoBootInfo()", "color": {"background": "#E15759", "border": "#E15759", "highlight": {"background": "#ffffff", "border": "#E15759"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "logApiCryptoBootInfo()", "community": 52, "community_name": "Community 52", "source_file": "main.ts", "file_type": "code", "degree": 2}, {"id": "env_d_ts", "label": "env.d.ts", "color": {"background": "#BAB0AC", "border": "#BAB0AC", "highlight": {"background": "#ffffff", "border": "#BAB0AC"}}, "size": 10.0, "font": {"size": 0, "color": "#ffffff"}, "title": "env.d.ts", "community": 139, "community_name": "Community 139", "source_file": "env.d.ts", "file_type": "code", "degree": 0}, {"id": "shims_loose_d_ts", "label": "shims-loose.d.ts", "color": {"background": "#4E79A7", "border": "#4E79A7", "highlight": {"background": "#ffffff", "border": "#4E79A7"}}, "size": 10.0, "font": {"size": 0, "color": "#ffffff"}, "title": "shims-loose.d.ts", "community": 140, "community_name": "Community 140", "source_file": "shims-loose.d.ts", "file_type": "code", "degree": 0}, {"id": "directives_index_ts", "label": "index.ts", "color": {"background": "#59A14F", "border": "#59A14F", "highlight": {"background": "#ffffff", "border": "#59A14F"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "index.ts", "community": 34, "community_name": "Community 34", "source_file": "directives/index.ts", "file_type": "code", "degree": 1}, {"id": "directives_index_setupglobdirectives", "label": "setupGlobDirectives()", "color": {"background": "#59A14F", "border": "#59A14F", "highlight": {"background": "#ffffff", "border": "#59A14F"}}, "size": 10.4, "font": {"size": 0, "color": "#ffffff"}, "title": "setupGlobDirectives()", "community": 34, "community_name": "Community 34", "source_file": "directives/index.ts", "file_type": "code", "degree": 5}, {"id": "directives_core_roles_ts", "label": "roles.ts", "color": {"background": "#59A14F", "border": "#59A14F", "highlight": {"background": "#ffffff", "border": "#59A14F"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "roles.ts", "community": 34, "community_name": "Community 34", "source_file": "directives/core/roles.ts", "file_type": "code", "degree": 3}, {"id": "core_roles_checkrolepermission", "label": "checkRolePermission()", "color": {"background": "#59A14F", "border": "#59A14F", "highlight": {"background": "#ffffff", "border": "#59A14F"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "checkRolePermission()", "community": 34, "community_name": "Community 34", "source_file": "directives/core/roles.ts", "file_type": "code", "degree": 2}, {"id": "core_roles_removeelement", "label": "removeElement()", "color": {"background": "#59A14F", "border": "#59A14F", "highlight": {"background": "#ffffff", "border": "#59A14F"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "removeElement()", "community": 34, "community_name": "Community 34", "source_file": "directives/core/roles.ts", "file_type": "code", "degree": 2}, {"id": "core_roles_setuprolesdirective",Line truncated
const RAW_EDGES = [{"from": "app_vue", "to": "src_app_refreshbuttonautoicons", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "app_vue", "to": "src_app_refreshpaneltitleicons", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "app_vue", "to": "main_ts", "label": "imports_from", "title": "imports_from [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_ts", "to": "utils_sys_console_ts", "label": "imports_from", "title": "imports_from [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_ts", "to": "src_main_masksecret", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "main_ts", "to": "src_main_logapicryptobootinfo", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "src_main_masksecret", "to": "src_main_logapicryptobootinfo", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_index_ts", "to": "directives_index_setupglobdirectives", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_index_setupglobdirectives", "to": "core_auth_setupauthdirective", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "directives_index_setupglobdirectives", "to": "core_roles_setuprolesdirective", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "directives_index_setupglobdirectives", "to": "business_highlight_setuphighlightdirective", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "directives_index_setupglobdirectives", "to": "business_ripple_setuprippledirective", "label": "calls", "title": "calls [INFERRED]", "dashes": true, "width": 1, "color": {"opacity": 0.35}, "confidence": "INFERRED"}, {"from": "directives_core_roles_ts", "to": "core_roles_checkrolepermission", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_core_roles_ts", "to": "core_roles_removeelement", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_core_roles_ts", "to": "core_roles_setuprolesdirective", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_roles_checkrolepermission", "to": "core_roles_removeelement", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_core_auth_ts", "to": "core_auth_checkauthpermission", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_core_auth_ts", "to": "core_auth_removeelement", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_core_auth_ts", "to": "core_auth_setupauthdirective", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "core_auth_checkauthpermission", "to": "core_auth_removeelement", "label": "calls", "title": "calls [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_business_ripple_ts", "to": "business_ripple_setuprippledirective", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_business_highlight_ts", "to": "business_highlight_highlightcode", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_business_highlight_ts", "to": "business_highlight_insertlinenumbers", "label": "contains", "title": "contains [EXTRACTED]", "dashes": false, "width": 2, "color": {"opacity": 0.7}, "confidence": "EXTRACTED"}, {"from": "directives_business_highlight_ts", "to": "business_highlight_addcopybutton", "label": "contains", "title": "contains [EXTRACTED]", "dLine truncated
const LEGEND = [{"cid": 0, "color": "#4E79A7", "label": "Community 0", "count": 608}, {"cid": 1, "color": "#F28E2B", "label": "Community 1", "count": 189}, {"cid": 2, "color": "#E15759", "label": "Community 2", "count": 167}, {"cid": 3, "color": "#76B7B2", "label": "Community 3", "count": 146}, {"cid": 4, "color": "#59A14F", "label": "Community 4", "count": 138}, {"cid": 5, "color": "#EDC948", "label": "Community 5", "count": 129}, {"cid": 6, "color": "#B07AA1", "label": "Community 6", "count": 126}, {"cid": 7, "color": "#FF9DA7", "label": "Community 7", "count": 119}, {"cid": 8, "color": "#9C755F", "label": "Community 8", "count": 102}, {"cid": 9, "color": "#BAB0AC", "label": "Community 9", "count": 88}, {"cid": 10, "color": "#4E79A7", "label": "Community 10", "count": 86}, {"cid": 11, "color": "#F28E2B", "label": "Community 11", "count": 85}, {"cid": 12, "color": "#E15759", "label": "Community 12", "count": 84}, {"cid": 13, "color": "#76B7B2", "label": "Community 13", "count": 83}, {"cid": 14, "color": "#59A14F", "label": "Community 14", "count": 79}, {"cid": 15, "color": "#EDC948", "label": "Community 15", "count": 73}, {"cid": 16, "color": "#B07AA1", "label": "Community 16", "count": 70}, {"cid": 17, "color": "#FF9DA7", "label": "Community 17", "count": 68}, {"cid": 18, "color": "#9C755F", "label": "Community 18", "count": 68}, {"cid": 19, "color": "#BAB0AC", "label": "Community 19", "count": 67}, {"cid": 20, "color": "#4E79A7", "label": "Community 20", "count": 63}, {"cid": 21, "color": "#F28E2B", "label": "Community 21", "count": 61}, {"cid": 22, "color": "#E15759", "label": "Community 22", "count": 57}, {"cid": 23, "color": "#76B7B2", "label": "Community 23", "count": 42}, {"cid": 24, "color": "#59A14F", "label": "Community 24", "count": 37}, {"cid": 25, "color": "#EDC948", "label": "Community 25", "count": 35}, {"cid": 26, "color": "#B07AA1", "label": "Community 26", "count": 35}, {"cid": 27, "color": "#FF9DA7", "label": "Community 27", "count": 33}, {"cid": 28, "color": "#9C755F", "label": "Community 28", "count": 30}, {"cid": 29, "color": "#BAB0AC", "label": "Community 29", "count": 29}, {"cid": 30, "color": "#4E79A7", "label": "Community 30", "count": 28}, {"cid": 31, "color": "#F28E2B", "label": "Community 31", "count": 24}, {"cid": 32, "color": "#E15759", "label": "Community 32", "count": 24}, {"cid": 33, "color": "#76B7B2", "label": "Community 33", "count": 23}, {"cid": 34, "color": "#59A14F", "label": "Community 34", "count": 22}, {"cid": 35, "color": "#EDC948", "label": "Community 35", "count": 19}, {"cid": 36, "color": "#B07AA1", "label": "Community 36", "count": 19}, {"cid": 37, "color": "#FF9DA7", "label": "Community 37", "count": 17}, {"cid": 38, "color": "#9C755F", "label": "Community 38", "count": 17}, {"cid": 39, "color": "#BAB0AC", "label": "Community 39", "count": 16}, {"cid": 40, "color": "#4E79A7", "label": "Community 40", "count": 14}, {"cid": 41, "color": "#F28E2B", "label": "Community 41", "count": 14}, {"cid": 42, "color": "#E15759", "label": "Community 42", "count": 13}, {"cid": 43, "color": "#76B7B2", "label": "Community 43", "count": 13}, {"cid": 44, "color": "#59A14F", "label": "Community 44", "count": 12}, {"cid": 45, "color": "#EDC948", "label": "Community 45", "count": 9}, {"cid": 46, "color": "#B07AA1", "label": "Community 46", "count": 9}, {"cid": 47, "color": "#FF9DA7", "label": "Community 47", "count": 9}, {"cid": 48, "color": "#9C755F", "label": "Community 48", "count": 9}, {"cid": 49, "color": "#BAB0AC", "label": "Community 49", "count": 8}, {"cid": 50, "color": "#4E79A7", "label": "Community 50", "count": 8}, {"cid": 51, "color": "#F28E2B", "label": "Community 51", "count": 8}, {"cid": 52, "color": "#E15759", "label": "Community 52", "count": 7}, {"cid": 53, "color": "#76B7B2", "label": "Community 53", "count": 7}, {"cid": 54, "color": "#59A14F", "label": "Community 54", "count": 6}, {"cid": 55, "color": "#EDC948", "label": "Community 55", "count": 5}, {"cid": 56, "color": "#B07AA1", "label": "Community 56", "count": 5}, {"cid": 57, "color": "#FF9DA7", "label": "Community 57", "count": 5}, {"cid": 58, "color": "#9C755F", "label": "Community 58", "count": 4}, {"cid": 59, "color": "#BAB0AC", "label": "Community 59", "count": 4}, {"cid": 60, "color": "#4E79A7", "label": "Community 60", "count": 4}, {"cid": 61, "color": "#F28E2B", "label": "Community 61", "count": 4}, {"cid": 62, "color": "#E15759", "label": "Community 62", "count": 4}, {"cid": 63, "color": "#76B7B2", "label": "Community 63", "count": 4}, {"cid": 64, "color": "#59A14F", "label": "Community 64", "count": 4}, {"cid": 65, "color": "#EDC948", "label": "Community 65", "count": 4}, {"cid": 66, "color": "#B07AA1", "label": "Community 66", "count": 4}, {"cid": 67, "color": "#FF9DA7", "label": "Community 67", "count": 3}, {"cid": 68, "color": "#9C755F", "label": "Community 68", "count": 3}, {"cid": 69, "color": "#BAB0AC", "label": "Community 69", "count": 3}, {"cid": 70, "color": "#4E79A7", "label": "CommuniLine truncated
// HTML-escape helper — prevents XSS when injecting graph data into innerHTML
function esc(s) {
+5 -4
View File
@@ -17,8 +17,8 @@
"/Users/wuzilong/work/00code/zkxw/web-admin/src/types/common/index.ts": 1781272556.3597305,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/types/directive/directive.d.ts": 1781272556.3601494,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/types/api/api.d.ts": 1781272556.3606477,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/types/import/components.d.ts": 1792226504.1699305,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/types/import/auto-imports.d.ts": 1792225926.2998207,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/types/import/components.d.ts": 1792377603.7593923,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/types/import/auto-imports.d.ts": 1792376809.475621,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/types/store/index.ts": 1787887312.735774,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/types/router/index.ts": 1787887320.8486114,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/composables/useAttachmentActions.ts": 1788162977.6691713,
@@ -412,7 +412,7 @@
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/leave.ts": 1781272556.654047,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/sample-reception-check-item.ts": 1781272556.654672,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production.ts": 1785145511.6866825,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/sample-info-handle.ts": 1791860612.992672,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/sample-info-handle.ts": 1792377682.8071346,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-task-set.ts": 1788231763.140203,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/infusion-schedule-handover.ts": 1781272556.6558568,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/outbound-release-review.ts": 1785303420.050366,
@@ -480,8 +480,9 @@
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/SamplePaymentPanel.vue": 1792078851.1718132,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/protocol/ProtocolAuditDialog.vue": 1782893854.3675368,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/sample-info/index.vue": 1791187848.6336563,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/sample-info/SampleInfoQuickRegisterDialog.vue": 1791872507.1851428,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/sample-info/SampleInfoQuickRegisterDialog.vue": 1792377727.9778452,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/sample-info/UnifiedSampleInfoPage.vue": 1791868912.5231571,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/sample-info/QuickRegisterAttachmentField.vue": 1792377594.7399898,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/sample-reception-info/index.vue": 1791200162.920515,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/payment-info/index.vue": 1791504621.1780708,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/cell-storage/payment-info/PaymentBySampleTab.vue": 1792202727.257655,
+12
View File
@@ -29,6 +29,18 @@ export function fetchSampleInfoQuickRegister(data: {
handlerUserId?: string
attachments?: string
remark?: string
storageHandleTime?: string
storageHandlerUserId?: string
storageAttachments?: string
storageRemark?: string
certHandleTime?: string
certHandlerUserId?: string
certAttachments?: string
certRemark?: string
insuranceHandleTime?: string
insuranceHandlerUserId?: string
insuranceAttachments?: string
insuranceRemark?: string
mailCertTime?: string
policySendTime?: string
smsSendDate?: string
@@ -0,0 +1,380 @@
<template>
<div
class="attachment-upload"
:class="{ 'is-dragover': isAttachDragover }"
v-bind="attachDropHandlers"
>
<div class="attachment-list">
<el-upload
ref="attachmentUploadRef"
:auto-upload="false"
:show-file-list="false"
:multiple="true"
accept="image/*,video/*,.pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.txt,.zip,.rar"
@change="onFileChange"
>
<div class="upload-card">
<el-icon :size="28" color="#047857"><Plus /></el-icon>
<span class="upload-card-text">上传附件</span>
</div>
</el-upload>
<div
v-for="(file, index) in files"
:key="file.id || index"
class="attachment-item"
:class="{ 'is-uploading': file._uploading }"
>
<div
class="attachment-preview"
@click="isImageFile(file) && file.fileUrl ? handlePreviewAttachment(file) : undefined"
>
<template v-if="isImageFile(file) && file.fileUrl">
<img :src="fullFileUrl(file.fileUrl)" :alt="file.fileName" />
</template>
<template v-else-if="isImageFile(file) && !file.fileUrl">
<el-icon :size="24" color="#94a3b8"><Loading /></el-icon>
</template>
<template v-else-if="isVideoFile(file)">
<div class="attachment-preview__icon attachment-preview__icon--video">
<el-icon :size="28"><VideoPlay /></el-icon>
</div>
</template>
<template v-else>
<div class="attachment-preview__icon attachment-preview__icon--doc">
<el-icon :size="28"><Document /></el-icon>
</div>
</template>
</div>
<div class="attachment-footer">
<span class="attachment-name" :title="file.fileName">{{ file.fileName }}</span>
<div class="attachment-actions">
<el-icon class="action-btn" title="下载" @click="handleDownloadAttachment(file)">
<Download />
</el-icon>
<el-icon
class="action-btn action-btn--danger"
title="删除"
@click="files.splice(index, 1)"
>
<Delete />
</el-icon>
</div>
</div>
</div>
</div>
<span class="upload-hint"
>支持拖拽或点击上传图片、视频、PDF、Word、Excel等文件,单文件不超过 20MB</span
>
</div>
<el-dialog
v-model="previewVisible"
title="文件预览"
width="800px"
align-center
append-to-body
destroy-on-close
>
<div v-if="previewType === 'image'" class="preview-container">
<img
:src="previewUrl"
alt="预览"
style="max-width: 100%; max-height: 70vh; display: block; margin: 0 auto"
/>
</div>
<div v-else class="preview-container">
<video
:src="previewUrl"
controls
style="max-width: 100%; max-height: 70vh; display: block; margin: 0 auto"
/>
</div>
</el-dialog>
</template>
<script setup lang="ts">
import { Delete, Document, Download, Loading, Plus, VideoPlay } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'
import { fetchUploadAttachment } from '@/api/business'
import { attachmentFullUrl } from '@/composables/useAttachmentActions'
import { useAttachmentDropZone } from '@/composables/useAttachmentDropZone'
import { downloadAttachmentFile } from '@/utils/download-attachment'
export type QuickRegisterAttachmentItem = {
id: string
fileName: string
fileUrl: string
fileSize?: number
fileType?: string
_uploading?: boolean
}
const props = defineProps<{ folder: string }>()
const files = defineModel<QuickRegisterAttachmentItem[]>({ required: true })
const MAX_FILE_BYTES = 20 * 1024 * 1024
const attachmentUploadRef = ref<{ clearFiles?: () => void } | null>(null)
const previewVisible = ref(false)
const previewUrl = ref('')
const previewType = ref<'image' | 'video'>('image')
function isImageFile(file: QuickRegisterAttachmentItem) {
const url = (file.fileUrl || '').toLowerCase()
const name = (file.fileName || '').toLowerCase()
return (
/\.(jpg|jpeg|png|gif|bmp|webp|svg)(\?|$)/.test(url) ||
/\.(jpg|jpeg|png|gif|bmp|webp|svg)$/.test(name) ||
(file.fileType || '').startsWith('image/')
)
}
function isVideoFile(file: QuickRegisterAttachmentItem) {
const url = (file.fileUrl || '').toLowerCase()
const name = (file.fileName || '').toLowerCase()
return (
/\.(mp4|webm|ogg|mov|avi)(\?|$)/.test(url) ||
/\.(mp4|webm|ogg|mov|avi)$/.test(name) ||
(file.fileType || '').startsWith('video/')
)
}
function fullFileUrl(suffix: string) {
return attachmentFullUrl(suffix)
}
function handlePreviewAttachment(file: QuickRegisterAttachmentItem) {
if (file._uploading || !file.fileUrl) return
previewUrl.value = fullFileUrl(file.fileUrl)
previewType.value = isVideoFile(file) ? 'video' : 'image'
previewVisible.value = true
}
function handleDownloadAttachment(file: QuickRegisterAttachmentItem) {
downloadAttachmentFile(file, { fullFileUrl })
}
async function onFileChange(uploadFile: any) {
const file = uploadFile.raw || uploadFile
if (!file) return
if (file.size > MAX_FILE_BYTES) {
ElMessage.error('单文件不超过 20MB')
nextTick(() => attachmentUploadRef.value?.clearFiles?.())
return
}
const tempId = `temp_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`
files.value.push({
id: tempId,
fileName: file.name || '附件',
fileUrl: '',
fileSize: file.size,
fileType: file.type || '',
_uploading: true
})
try {
const fd = new FormData()
fd.append('folder', props.folder)
fd.append('file', file)
const res = (await fetchUploadAttachment(fd)) as {
id?: string
fileName?: string
fileUrl?: string
fileType?: string
}
const idx = files.value.findIndex((item) => item.id === tempId)
if (idx < 0) return
files.value[idx] = {
id: String(res.id || tempId),
fileName: file.name || res.fileName || '附件',
fileUrl: res.fileUrl || '',
fileSize: file.size,
fileType: res.fileType || file.type || '',
_uploading: false
}
} catch {
ElMessage.error('文件上传失败')
const idx = files.value.findIndex((item) => item.id === tempId)
if (idx >= 0) files.value.splice(idx, 1)
} finally {
nextTick(() => attachmentUploadRef.value?.clearFiles?.())
}
}
const { isDragover: isAttachDragover, dropZoneHandlers: attachDropHandlers } =
useAttachmentDropZone({
onFiles: (dropped) => {
for (const file of dropped) {
void onFileChange({ raw: file })
}
}
})
</script>
<style scoped lang="scss">
.attachment-upload {
width: 100%;
}
.upload-card {
width: 140px;
height: 96px;
border: 1px dashed #a8d4c4;
border-radius: 8px;
background: #f0fdf4;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 6px;
cursor: pointer;
transition:
border-color 0.15s,
background 0.15s;
&:hover {
border-color: #047857;
border-style: solid;
background: #e8f4ee;
}
}
.upload-card-text {
font-size: 12px;
color: #047857;
font-weight: 500;
line-height: 1;
}
.upload-hint {
display: block;
font-size: 11px;
color: var(--mint-text-muted, #334155);
line-height: 1;
margin-top: 8px;
}
.attachment-list {
display: flex;
flex-wrap: wrap;
gap: 12px;
}
.attachment-item {
width: 140px;
display: flex;
flex-direction: column;
border: 1px solid #e2e8f0;
border-radius: 8px;
background: #fff;
overflow: hidden;
transition:
border-color 0.15s,
box-shadow 0.15s;
&:hover {
border-color: #047857;
box-shadow: 0 2px 8px rgba(4, 120, 87, 0.1);
}
&.is-uploading {
opacity: 0.6;
pointer-events: none;
}
}
.attachment-preview {
width: 100%;
height: 96px;
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: center;
background: #f8fafc;
overflow: hidden;
cursor: pointer;
img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
}
}
.attachment-preview__icon {
width: 48px;
height: 48px;
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
&--video {
background: #ede9fe;
color: #7c3aed;
}
&--doc {
background: #e0f2fe;
color: #0284c7;
}
}
.attachment-footer {
display: flex;
flex-direction: column;
flex: 1;
padding: 6px 8px;
}
.attachment-name {
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
font-size: 11px;
color: #334155;
line-height: 1.4;
word-break: break-all;
min-height: calc(11px * 1.4 * 2);
}
.attachment-actions {
display: flex;
justify-content: center;
align-items: center;
gap: 8px;
margin-top: 4px;
flex-shrink: 0;
}
.action-btn {
width: 22px;
height: 22px;
border-radius: 4px;
display: flex;
align-items: center;
justify-content: center;
font-size: 12px;
color: var(--mint-text-muted, #334155);
cursor: pointer;
background: #f1f5f9;
transition:
background 0.15s,
color 0.15s;
&:hover {
background: #047857;
color: #fff;
}
&--danger:hover {
background: #ef4444;
color: #fff;
}
}
.preview-container {
text-align: center;
}
</style>
@@ -14,8 +14,7 @@
<el-form label-position="top" class="biz-dialog-form" @submit.prevent>
<p class="quick-register-hint">{{ selectionHint }}</p>
<template v-if="showHandleBlock">
<div v-if="kind === 'all'" class="section-title">储存证 / 保险办理</div>
<template v-if="showSingleHandle">
<div class="form-grid-2">
<el-form-item :label="'办理时间'" :required="handleRequired">
<el-date-picker
@@ -64,34 +63,168 @@
/>
</el-form-item>
<el-form-item v-if="showAttachment" :label="attachmentLabel" class="form-col-span-2">
<div class="attachment-upload">
<div class="attachment-list">
<el-upload
:auto-upload="false"
:show-file-list="false"
:multiple="true"
accept="image/*,video/*,.pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.txt,.zip,.rar"
@change="onFileChange"
>
<div class="upload-card">
<el-icon :size="28" color="#047857"><Plus /></el-icon>
<span class="upload-card-text">上传附件</span>
</div>
</el-upload>
<div v-for="(file, index) in files" :key="file.id || index" class="attachment-item">
<div class="attachment-footer">
<span class="attachment-name" :title="file.fileName">{{ file.fileName }}</span>
<el-icon class="action-btn--danger" @click="files.splice(index, 1)">
<Delete />
</el-icon>
</div>
</div>
</div>
<span class="upload-hint">支持图片、PDF、Office 等,单文件不超过 20MB</span>
</div>
<QuickRegisterAttachmentField v-model="files" :folder="singleAttachmentFolder" />
</el-form-item>
<el-form-item v-if="showAttachment" label="备注" class="form-col-span-2">
<el-input v-model="form.remark" type="textarea" :rows="2" maxlength="500" show-word-limit />
<el-input
v-model="form.remark"
type="textarea"
:rows="2"
maxlength="500"
show-word-limit
/>
</el-form-item>
</div>
</template>
<template v-if="kind === 'all'">
<div class="section-title">登记入库</div>
<div class="form-grid-2">
<el-form-item label="办理时间">
<el-date-picker
v-model="form.storageHandleTime"
type="datetime"
placeholder="不填则不登记入库"
value-format="YYYY-MM-DD HH:mm:ss"
style="width: 100%"
/>
</el-form-item>
<el-form-item label="办理人员">
<el-select
v-model="form.storageHandlerUserId"
filterable
remote
clearable
placeholder="输入姓名检索"
:remote-method="searchUsers"
:loading="userLoading"
style="width: 100%"
>
<el-option
v-for="u in userOptions"
:key="'storage-' + u.id"
:label="u.nickName || u.userName"
:value="u.id"
/>
</el-select>
</el-form-item>
<el-form-item label="入库附件" class="form-col-span-2">
<QuickRegisterAttachmentField v-model="storageFiles" folder="sample-storage" />
</el-form-item>
<el-form-item label="备注" class="form-col-span-2">
<el-input
v-model="form.storageRemark"
type="textarea"
:rows="2"
maxlength="500"
show-word-limit
/>
</el-form-item>
</div>
<div class="section-title">储存证办理</div>
<div class="form-grid-2">
<el-form-item label="办理时间">
<el-date-picker
v-model="form.certHandleTime"
type="datetime"
placeholder="不填则不登记储存证"
value-format="YYYY-MM-DD HH:mm:ss"
style="width: 100%"
/>
</el-form-item>
<el-form-item label="办理人员">
<el-select
v-model="form.certHandlerUserId"
filterable
remote
clearable
placeholder="输入姓名检索"
:remote-method="searchUsers"
:loading="userLoading"
style="width: 100%"
>
<el-option
v-for="u in userOptions"
:key="u.id"
:label="u.nickName || u.userName"
:value="u.id"
/>
</el-select>
</el-form-item>
<el-form-item label="邮寄储存证时间">
<el-date-picker
v-model="form.mailCertTime"
type="datetime"
placeholder="可选"
value-format="YYYY-MM-DD HH:mm:ss"
style="width: 100%"
/>
</el-form-item>
<el-form-item label="储存证附件" class="form-col-span-2">
<QuickRegisterAttachmentField v-model="certFiles" folder="storage-cert" />
</el-form-item>
<el-form-item label="备注" class="form-col-span-2">
<el-input
v-model="form.certRemark"
type="textarea"
:rows="2"
maxlength="500"
show-word-limit
/>
</el-form-item>
</div>
<div class="section-title">保险办理</div>
<div class="form-grid-2">
<el-form-item label="办理时间">
<el-date-picker
v-model="form.insHandleTime"
type="datetime"
placeholder="不填则不登记保险"
value-format="YYYY-MM-DD HH:mm:ss"
style="width: 100%"
/>
</el-form-item>
<el-form-item label="办理人员">
<el-select
v-model="form.insHandlerUserId"
filterable
remote
clearable
placeholder="输入姓名检索"
:remote-method="searchUsers"
:loading="userLoading"
style="width: 100%"
>
<el-option
v-for="u in userOptions"
:key="'ins-' + u.id"
:label="u.nickName || u.userName"
:value="u.id"
/>
</el-select>
</el-form-item>
<el-form-item label="保单发送时间">
<el-date-picker
v-model="form.policySendTime"
type="datetime"
placeholder="可选"
value-format="YYYY-MM-DD HH:mm:ss"
style="width: 100%"
/>
</el-form-item>
<el-form-item label="保险附件" class="form-col-span-2">
<QuickRegisterAttachmentField v-model="insFiles" folder="fullmoon-todo" />
</el-form-item>
<el-form-item label="备注" class="form-col-span-2">
<el-input
v-model="form.insRemark"
type="textarea"
:rows="2"
maxlength="500"
show-word-limit
/>
</el-form-item>
</div>
</template>
@@ -211,16 +344,15 @@
</template>
<script setup lang="ts">
import { Check, Close, Delete, Plus } from '@element-plus/icons-vue'
import { Check, Close } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'
import { fetchUserList } from '@/api/admin'
import { fetchUploadAttachment } from '@/api/business'
import { fetchCustomerServiceDict } from '@/api/customer-service-dict'
import {
fetchSampleInfoQuickRegister,
type QuickRegisterKind
} from '@/api/sample-info-handle'
import { fetchSampleInfoQuickRegister, type QuickRegisterKind } from '@/api/sample-info-handle'
import { useUserStore } from '@/store/modules/user'
import QuickRegisterAttachmentField, {
type QuickRegisterAttachmentItem
} from './QuickRegisterAttachmentField.vue'
defineOptions({ name: 'SampleInfoQuickRegisterDialog' })
@@ -236,11 +368,16 @@
(e: 'saved'): void
}>()
type AttachmentItem = QuickRegisterAttachmentItem
const userStore = useUserStore()
const saving = ref(false)
const userLoading = ref(false)
const userOptions = ref<Array<{ id: string; nickName?: string; userName?: string }>>([])
const files = ref<Array<{ id: string; fileName: string; fileUrl: string }>>([])
const files = ref<AttachmentItem[]>([])
const storageFiles = ref<AttachmentItem[]>([])
const certFiles = ref<AttachmentItem[]>([])
const insFiles = ref<AttachmentItem[]>([])
const smsOptions = ref<string[]>([])
const microbeOptions = ref<string[]>([])
const fullmoonOptions = ref<string[]>([])
@@ -250,6 +387,15 @@
handleTime: '',
handlerUserId: '',
remark: '',
storageHandleTime: '',
storageHandlerUserId: '',
storageRemark: '',
certHandleTime: '',
certHandlerUserId: '',
certRemark: '',
insHandleTime: '',
insHandlerUserId: '',
insRemark: '',
mailCertTime: '',
policySendTime: '',
smsSendDate: '',
@@ -279,14 +425,20 @@
const showHandleBlock = computed(() =>
['storage', 'storage_cert', 'insurance', 'all'].includes(props.kind)
)
const showSingleHandle = computed(() => showHandleBlock.value && props.kind !== 'all')
const handleRequired = computed(() =>
['storage', 'storage_cert', 'insurance'].includes(props.kind)
)
const showMailCert = computed(() => ['storage_cert', 'all'].includes(props.kind))
const showPolicySend = computed(() => ['insurance', 'all'].includes(props.kind))
const showMailCert = computed(() => props.kind === 'storage_cert')
const showPolicySend = computed(() => props.kind === 'insurance')
const showAttachment = computed(() =>
['storage', 'storage_cert', 'insurance', 'all'].includes(props.kind)
['storage', 'storage_cert', 'insurance'].includes(props.kind)
)
const singleAttachmentFolder = computed(() => {
if (props.kind === 'storage_cert') return 'storage-cert'
if (props.kind === 'insurance') return 'fullmoon-todo'
return 'sample-storage'
})
const showSmsBlock = computed(() => ['sms', 'all'].includes(props.kind))
const showFollowupBlock = computed(() => ['followup', 'all'].includes(props.kind))
const showFulfillmentBlock = computed(() => ['fulfillment', 'all'].includes(props.kind))
@@ -294,7 +446,6 @@
const attachmentLabel = computed(() => {
if (props.kind === 'storage_cert') return '储存证附件'
if (props.kind === 'insurance') return '保险附件'
if (props.kind === 'all') return '办理附件(证/保险共用本次上传)'
return '入库附件'
})
@@ -349,15 +500,170 @@
])
}
function cellText(row: Record<string, unknown>, key: string) {
return String(row[key] ?? '').trim()
}
function fileNameFromUrl(url: string) {
const base = url.split('?')[0].split('/').pop() || '附件'
try {
return decodeURIComponent(base) || '附件'
} catch {
return base || '附件'
}
}
function filesFromUrls(raw: string): AttachmentItem[] {
const seen = new Set<string>()
const items: AttachmentItem[] = []
raw
.split(',')
.map((part) => part.trim())
.filter(Boolean)
.forEach((url) => {
if (seen.has(url)) return
seen.add(url)
items.push({
id: `echo-${items.length}-${url}`,
fileName: fileNameFromUrl(url),
fileUrl: url
})
})
return items
}
function ensureUserOption(id: string, name: string) {
if (!id || userOptions.value.some((user) => user.id === id)) return
userOptions.value.unshift({
id,
nickName: name || id,
userName: name || id
})
}
function applyHandleEcho(
target: 'single' | 'storage' | 'cert' | 'ins',
source: {
handleTime: string
handlerUserId: string
handlerName: string
attachments: string
remark: string
}
) {
const echoedFiles = filesFromUrls(source.attachments)
if (target === 'storage') {
if (source.handleTime) form.storageHandleTime = source.handleTime
if (source.handlerUserId) {
form.storageHandlerUserId = source.handlerUserId
ensureUserOption(source.handlerUserId, source.handlerName)
}
if (source.remark) form.storageRemark = source.remark
if (echoedFiles.length) storageFiles.value = echoedFiles
return
}
if (target === 'cert') {
if (source.handleTime) form.certHandleTime = source.handleTime
if (source.handlerUserId) {
form.certHandlerUserId = source.handlerUserId
ensureUserOption(source.handlerUserId, source.handlerName)
}
if (source.remark) form.certRemark = source.remark
if (echoedFiles.length) certFiles.value = echoedFiles
return
}
if (target === 'ins') {
if (source.handleTime) form.insHandleTime = source.handleTime
if (source.handlerUserId) {
form.insHandlerUserId = source.handlerUserId
ensureUserOption(source.handlerUserId, source.handlerName)
}
if (source.remark) form.insRemark = source.remark
if (echoedFiles.length) insFiles.value = echoedFiles
return
}
if (source.handleTime) form.handleTime = source.handleTime
if (source.handlerUserId) {
form.handlerUserId = source.handlerUserId
ensureUserOption(source.handlerUserId, source.handlerName)
}
if (source.remark) form.remark = source.remark
if (echoedFiles.length) files.value = echoedFiles
}
function applyCustomerServiceEcho(row: Record<string, unknown>) {
if (showSmsBlock.value) {
form.smsSendDate = cellText(row, 'smsSendDate')
form.smsSendStatus = cellText(row, 'smsSendStatus')
}
if (showFollowupBlock.value) {
form.microbeFollowupDate = cellText(row, 'microbeFollowupDate')
form.microbeFollowupStatus = cellText(row, 'microbeFollowupStatus')
form.fullmoonFollowupDate = cellText(row, 'fullmoonFollowupDate')
form.fullmoonFollowupStatus = cellText(row, 'fullmoonFollowupStatus')
form.householdRegistered = cellText(row, 'householdRegistered')
}
if (showFulfillmentBlock.value) {
form.einvoiceSendTime = cellText(row, 'einvoiceSendTime')
form.effectiveAddress = cellText(row, 'effectiveAddress')
}
}
function applySavedEcho() {
const row = props.rows[0]
if (!row) return
if (props.kind === 'storage' || props.kind === 'all') {
applyHandleEcho(props.kind === 'all' ? 'storage' : 'single', {
handleTime: cellText(row, 'storageTime'),
handlerUserId: cellText(row, 'storageBy'),
handlerName: cellText(row, 'storageByName'),
attachments: cellText(row, 'storageAttachments'),
remark: cellText(row, 'storageRemark')
})
if (props.kind === 'storage') return
}
if (props.kind === 'storage_cert' || props.kind === 'all') {
applyHandleEcho(props.kind === 'all' ? 'cert' : 'single', {
handleTime: cellText(row, 'storageCertHandleTime'),
handlerUserId: cellText(row, 'storageCertHandlerUserId'),
handlerName: cellText(row, 'storageCertHandlerName'),
attachments: cellText(row, 'storageCertAttachments'),
remark: cellText(row, 'storageCertRemark')
})
form.mailCertTime = cellText(row, 'mailCertTime')
}
if (props.kind === 'insurance' || props.kind === 'all') {
applyHandleEcho(props.kind === 'all' ? 'ins' : 'single', {
handleTime: cellText(row, 'insuranceHandleTime'),
handlerUserId: cellText(row, 'insuranceHandlerUserId'),
handlerName: cellText(row, 'insuranceHandlerName'),
attachments: cellText(row, 'insuranceAttachments'),
remark: cellText(row, 'insuranceRemark')
})
form.policySendTime = cellText(row, 'policySendTime')
}
applyCustomerServiceEcho(row)
}
function resetForm() {
const currentUser = userStore.getUserInfo as Record<string, any>
const uid = String(currentUser?.id || currentUser?.userId || '')
const name = String(
currentUser?.realName || currentUser?.userName || currentUser?.username || ''
)
form.handleTime = showHandleBlock.value ? nowStr() : ''
form.handlerUserId = showHandleBlock.value ? uid : ''
const now = showHandleBlock.value ? nowStr() : ''
form.handleTime = showSingleHandle.value ? now : ''
form.handlerUserId = showSingleHandle.value ? uid : ''
form.remark = ''
form.storageHandleTime = props.kind === 'all' ? now : ''
form.storageHandlerUserId = props.kind === 'all' ? uid : ''
form.storageRemark = ''
form.certHandleTime = props.kind === 'all' ? now : ''
form.certHandlerUserId = props.kind === 'all' ? uid : ''
form.certRemark = ''
form.insHandleTime = props.kind === 'all' ? now : ''
form.insHandlerUserId = props.kind === 'all' ? uid : ''
form.insRemark = ''
form.mailCertTime = ''
form.policySendTime = ''
form.smsSendDate = ''
@@ -370,13 +676,19 @@
form.einvoiceSendTime = ''
form.effectiveAddress = ''
files.value = []
storageFiles.value = []
certFiles.value = []
insFiles.value = []
if (uid) {
userOptions.value = [{ id: uid, nickName: name, userName: name }]
} else {
userOptions.value = []
}
if (showSmsBlock.value || showFollowupBlock.value) {
void loadDicts()
if (props.modelValue) {
applySavedEcho()
if (showSmsBlock.value || showFollowupBlock.value) {
void loadDicts()
}
}
}
@@ -391,34 +703,45 @@
userLoading.value = true
try {
const res = await fetchUserList({ page: 1, pageSize: 50, keyword: kw || '', status: '1' })
userOptions.value = ((res as any)?.list || []).map((u: any) => ({
const fetched = ((res as any)?.list || []).map((u: any) => ({
id: String(u.id),
nickName: u.nickName,
userName: u.userName
}))
const selectedIds = [
form.handlerUserId,
form.storageHandlerUserId,
form.certHandlerUserId,
form.insHandlerUserId
].filter(Boolean)
const kept = userOptions.value.filter((user) => selectedIds.includes(user.id))
const merged = new Map<string, { id: string; nickName?: string; userName?: string }>()
for (const user of [...kept, ...fetched]) merged.set(user.id, user)
userOptions.value = [...merged.values()]
} finally {
userLoading.value = false
}
}
async function onFileChange(uploadFile: any) {
const file = uploadFile.raw || uploadFile
if (!file) return
const folder =
props.kind === 'storage_cert'
? 'storage-cert'
: props.kind === 'insurance'
? 'fullmoon-todo'
: 'sample-storage'
const fd = new FormData()
fd.append('folder', folder)
fd.append('file', file)
const res = (await fetchUploadAttachment(fd)) as { id?: string; fileName?: string; fileUrl?: string }
files.value.push({
id: String(res.id || Date.now()),
fileName: file.name || res.fileName || '附件',
fileUrl: res.fileUrl || ''
})
function attachmentUrls(list: AttachmentItem[]) {
return list
.filter((item) => item.fileUrl && !item._uploading)
.map((item) => item.fileUrl)
.join(',')
}
function sectionTouched(
handleTime: string,
remark: string,
extraTime: string,
list: AttachmentItem[]
) {
return (
nonempty(handleTime) ||
nonempty(remark) ||
nonempty(extraTime) ||
list.some((item) => item.fileUrl)
)
}
async function handleSubmit() {
@@ -448,10 +771,52 @@
ElMessage.warning('请至少填写一项')
return
}
if (props.kind === 'all' && !nonempty(form.handleTime) && !csFilled) {
const storageTouched = sectionTouched(
form.storageHandleTime,
form.storageRemark,
'',
storageFiles.value
)
const certTouched = sectionTouched(
form.certHandleTime,
form.certRemark,
form.mailCertTime,
certFiles.value
)
const insTouched = sectionTouched(
form.insHandleTime,
form.insRemark,
form.policySendTime,
insFiles.value
)
if (props.kind === 'all' && !storageTouched && !certTouched && !insTouched && !csFilled) {
ElMessage.warning('请至少填写一项登记信息')
return
}
if (props.kind === 'all' && storageTouched && !nonempty(form.storageHandleTime)) {
ElMessage.warning('请填写入库办理时间')
return
}
if (props.kind === 'all' && storageTouched && !nonempty(form.storageHandlerUserId)) {
ElMessage.warning('请指定入库办理人员')
return
}
if (props.kind === 'all' && certTouched && !nonempty(form.certHandleTime)) {
ElMessage.warning('请填写储存证办理时间')
return
}
if (props.kind === 'all' && certTouched && !nonempty(form.certHandlerUserId)) {
ElMessage.warning('请指定储存证办理人员')
return
}
if (props.kind === 'all' && insTouched && !nonempty(form.insHandleTime)) {
ElMessage.warning('请填写保险办理时间')
return
}
if (props.kind === 'all' && insTouched && !nonempty(form.insHandlerUserId)) {
ElMessage.warning('请指定保险办理人员')
return
}
const items = props.rows
.map((row) => ({
@@ -464,38 +829,64 @@
return
}
if (
[...files.value, ...storageFiles.value, ...certFiles.value, ...insFiles.value].some(
(item) => item._uploading
)
) {
ElMessage.warning('附件上传中,请稍候')
return
}
saving.value = true
try {
const urls = files.value.map((f) => f.fileUrl).filter(Boolean).join(',')
const payload: Parameters<typeof fetchSampleInfoQuickRegister>[0] = {
kind: props.kind,
receptionSource: props.receptionSource,
items
}
if (showHandleBlock.value && nonempty(form.handleTime)) {
if (props.kind === 'all') {
payload.storageHandleTime = form.storageHandleTime
payload.storageHandlerUserId = form.storageHandlerUserId
payload.storageAttachments = attachmentUrls(storageFiles.value)
payload.storageRemark = form.storageRemark
payload.certHandleTime = form.certHandleTime
payload.certHandlerUserId = form.certHandlerUserId
payload.certAttachments = attachmentUrls(certFiles.value)
payload.certRemark = form.certRemark
payload.insuranceHandleTime = form.insHandleTime
payload.insuranceHandlerUserId = form.insHandlerUserId
payload.insuranceAttachments = attachmentUrls(insFiles.value)
payload.insuranceRemark = form.insRemark
if (nonempty(form.mailCertTime)) payload.mailCertTime = form.mailCertTime
if (nonempty(form.policySendTime)) payload.policySendTime = form.policySendTime
} else if (showSingleHandle.value && nonempty(form.handleTime)) {
payload.handleTime = form.handleTime
payload.handlerUserId = form.handlerUserId
payload.attachments = urls
payload.attachments = attachmentUrls(files.value)
payload.remark = form.remark
}
if (showMailCert.value && nonempty(form.mailCertTime)) {
payload.mailCertTime = form.mailCertTime
}
if (showPolicySend.value && nonempty(form.policySendTime)) {
payload.policySendTime = form.policySendTime
if (showMailCert.value && nonempty(form.mailCertTime)) {
payload.mailCertTime = form.mailCertTime
}
if (showPolicySend.value && nonempty(form.policySendTime)) {
payload.policySendTime = form.policySendTime
}
}
if (showSmsBlock.value) {
if (nonempty(form.smsSendDate)) payload.smsSendDate = form.smsSendDate
if (nonempty(form.smsSendStatus)) payload.smsSendStatus = form.smsSendStatus
}
if (showFollowupBlock.value) {
if (nonempty(form.microbeFollowupDate)) payload.microbeFollowupDate = form.microbeFollowupDate
if (nonempty(form.microbeFollowupDate))
payload.microbeFollowupDate = form.microbeFollowupDate
if (nonempty(form.microbeFollowupStatus))
payload.microbeFollowupStatus = form.microbeFollowupStatus
if (nonempty(form.fullmoonFollowupDate)) payload.fullmoonFollowupDate = form.fullmoonFollowupDate
if (nonempty(form.fullmoonFollowupDate))
payload.fullmoonFollowupDate = form.fullmoonFollowupDate
if (nonempty(form.fullmoonFollowupStatus))
payload.fullmoonFollowupStatus = form.fullmoonFollowupStatus
if (nonempty(form.householdRegistered)) payload.householdRegistered = form.householdRegistered
if (nonempty(form.householdRegistered))
payload.householdRegistered = form.householdRegistered
}
if (showFulfillmentBlock.value) {
if (nonempty(form.einvoiceSendTime)) payload.einvoiceSendTime = form.einvoiceSendTime
@@ -548,71 +939,4 @@
background: var(--mint-primary, #047857);
}
}
.action-btn--danger {
cursor: pointer;
color: var(--el-color-danger);
}
.attachment-upload {
width: 100%;
}
.upload-card {
width: 140px;
height: 96px;
border: 1px dashed #a7f3d0;
border-radius: 8px;
background: #f0fdf4;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 6px;
cursor: pointer;
}
.upload-card-text {
font-size: 12px;
color: #047857;
font-weight: 500;
}
.upload-hint {
display: block;
font-size: 11px;
color: var(--mint-text-muted, #64748b);
margin-top: 8px;
}
.attachment-list {
display: flex;
flex-wrap: wrap;
gap: 12px;
}
.attachment-item {
width: 140px;
border: 1px solid #e2e8f0;
border-radius: 8px;
background: #fff;
overflow: hidden;
}
.attachment-footer {
display: flex;
align-items: center;
justify-content: space-between;
gap: 6px;
padding: 8px;
}
.attachment-name {
flex: 1;
min-width: 0;
font-size: 12px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
</style>