This commit is contained in:
zlwu committed 2026-08-28 17:38:37 +08:00
1 parent 3d98104455
commit 0d52442902
76 files changed
+21994 -12642

No files matched your search

File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+161 -133
View File
@@ -1,11 +1,11 @@
# Graph Report - src (2026-08-28)
## Corpus Check
- Large corpus: 992 files · ~652,997 words. Semantic extraction will be expensive (many Claude tokens). Consider running on a subfolder, or use --no-semantic to run AST-only.
- Large corpus: 993 files · ~655,581 words. Semantic extraction will be expensive (many Claude tokens). Consider running on a subfolder, or use --no-semantic to run AST-only.
## Summary
- 3550 nodes · 5051 edges · 68 communities detected
- Extraction: 78% EXTRACTED · 22% INFERRED · 0% AMBIGUOUS · INFERRED: 1109 edges (avg confidence: 0.8)
- 3573 nodes · 5087 edges · 72 communities detected
- Extraction: 78% EXTRACTED · 22% INFERRED · 0% AMBIGUOUS · INFERRED: 1115 edges (avg confidence: 0.8)
- Token cost: 0 input · 0 output
## Community Hubs (Navigation)
@@ -56,31 +56,35 @@
- [[_COMMUNITY_Community 45|Community 45]]
- [[_COMMUNITY_Community 46|Community 46]]
- [[_COMMUNITY_Community 47|Community 47]]
- [[_COMMUNITY_Community 49|Community 49]]
- [[_COMMUNITY_Community 52|Community 52]]
- [[_COMMUNITY_Community 48|Community 48]]
- [[_COMMUNITY_Community 50|Community 50]]
- [[_COMMUNITY_Community 53|Community 53]]
- [[_COMMUNITY_Community 55|Community 55]]
- [[_COMMUNITY_Community 54|Community 54]]
- [[_COMMUNITY_Community 56|Community 56]]
- [[_COMMUNITY_Community 57|Community 57]]
- [[_COMMUNITY_Community 58|Community 58]]
- [[_COMMUNITY_Community 59|Community 59]]
- [[_COMMUNITY_Community 60|Community 60]]
- [[_COMMUNITY_Community 61|Community 61]]
- [[_COMMUNITY_Community 62|Community 62]]
- [[_COMMUNITY_Community 66|Community 66]]
- [[_COMMUNITY_Community 72|Community 72]]
- [[_COMMUNITY_Community 75|Community 75]]
- [[_COMMUNITY_Community 64|Community 64]]
- [[_COMMUNITY_Community 65|Community 65]]
- [[_COMMUNITY_Community 69|Community 69]]
- [[_COMMUNITY_Community 71|Community 71]]
- [[_COMMUNITY_Community 76|Community 76]]
- [[_COMMUNITY_Community 78|Community 78]]
- [[_COMMUNITY_Community 79|Community 79]]
- [[_COMMUNITY_Community 80|Community 80]]
- [[_COMMUNITY_Community 82|Community 82]]
- [[_COMMUNITY_Community 83|Community 83]]
- [[_COMMUNITY_Community 95|Community 95]]
- [[_COMMUNITY_Community 98|Community 98]]
- [[_COMMUNITY_Community 84|Community 84]]
- [[_COMMUNITY_Community 88|Community 88]]
- [[_COMMUNITY_Community 99|Community 99]]
- [[_COMMUNITY_Community 102|Community 102]]
- [[_COMMUNITY_Community 103|Community 103]]
## God Nodes (most connected - your core abstractions)
1. `get()` - 315 edges
2. `push()` - 123 edges
1. `get()` - 316 edges
2. `push()` - 125 edges
3. `emit()` - 29 edges
4. `WebSocketClient` - 26 edges
5. `set()` - 21 edges
@@ -95,86 +99,86 @@
views/quality-inspection/storage-release-review/index.vue → utils/fullscreen-loading.ts
- `handleBatchDelete()` --calls--> `withFullscreenLoading()` [INFERRED]
views/basic-info/customer/index.vue → utils/fullscreen-loading.ts
- `formatDetectMethods()` --calls--> `push()` [INFERRED]
utils/qc-work-order-card-meta.ts → views/operations/storage-facility/index.vue
- `buildCellStorageGroupContext()` --calls--> `push()` [INFERRED]
utils/qc-work-order-card-meta.ts → views/operations/storage-facility/index.vue
- `buildDonationGroupContext()` --calls--> `push()` [INFERRED]
utils/qc-work-order-card-meta.ts → views/operations/storage-facility/index.vue
- `onPick()` --calls--> `ensureOvertimeKitRuleProps()` [INFERRED]
components/oa-approval/OaStartFormDialog.vue → utils/oa-overtime-kit-runtime.ts
- `formatReceiveAccountLine()` --calls--> `push()` [INFERRED]
utils/oa-receive-account-value.ts → views/operations/storage-facility/index.vue
- `displayCell()` --calls--> `formatDisplayOrDash()` [INFERRED]
views/production/waste-output/index.vue → utils/datetime-display.ts
## Communities
### Community 0 - "Community 0"
Cohesion: 0.0
Nodes (200): fetchAccessLogList(), fetchActiveRegions(), fetchCategoryList(), fetchCategoryParameters(), fetchCellProductPriceList(), fetchCellProductSpecList(), fetchCellProductTypeList(), fetchChannelAccount() (+192 more)
Nodes (201): fetchAccessLogList(), fetchActiveRegions(), fetchCategoryList(), fetchCategoryParameters(), fetchCellProductPriceList(), fetchCellProductSpecList(), fetchCellProductTypeList(), fetchChannelAccount() (+193 more)
### Community 1 - "Community 1"
Cohesion: 0.02
Nodes (101): fetchUploadAttachment(), fetchMyQcTaskList(), fetchQcTaskDetail(), fetchQcTaskList(), FireworkSystem, handleReportUpload(), handleReportUpload(), walk() (+93 more)
Cohesion: 0.03
Nodes (87): batchSavePilotCheckup(), deletePilotCheckupActualItem(), fetchCheckupInstitutionList(), fetchCheckupInstitutionPackageDetail(), fetchCheckupInstitutionPackages(), fetchPilotCheckupDetail(), fetchPilotCheckupList(), markPilotCheckupChecked() (+79 more)
### Community 2 - "Community 2"
Cohesion: 0.03
Nodes (88): batchSavePilotCheckup(), deletePilotCheckupActualItem(), fetchCheckupInstitutionList(), fetchCheckupInstitutionPackageDetail(), fetchCheckupInstitutionPackages(), fetchPilotCheckupDetail(), fetchPilotCheckupList(), fetchUpdatePostBoundRoles() (+80 more)
Nodes (84): fetchUploadAttachment(), handleReportUpload(), handleReportUpload(), walk(), if(), async(), addDispatchItem(), createDispatchItem() (+76 more)
### Community 3 - "Community 3"
Cohesion: 0.03
Nodes (79): fetchEthnicList(), formatNowDatetime(), applyDonationBundleToForm(), createEmptyTransport(), ensureEthnicOptionInList(), handleOpenForAdd(), if(), loadEthnicOptions() (+71 more)
Cohesion: 0.02
Nodes (65): fetchBatchDeleteOaReceiveAccounts(), fetchBatchMarkOaCcTasksRead(), fetchCreateOaReceiveAccount(), fetchDeleteOaReceiveAccount(), fetchMarkOaCcTaskRead(), fetchOaAppDraft(), fetchOaCcUnreadCount(), fetchOaInstanceDetail() (+57 more)
### Community 4 - "Community 4"
Cohesion: 0.03
Nodes (60): fetchBatchDeleteOaReceiveAccounts(), fetchBatchMarkOaCcTasksRead(), fetchCreateOaReceiveAccount(), fetchDeleteOaReceiveAccount(), fetchMarkOaCcTaskRead(), fetchOaAppDraft(), fetchOaCcUnreadCount(), fetchOaInstanceDetail() (+52 more)
Nodes (79): fetchEthnicList(), formatNowDatetime(), applyDonationBundleToForm(), createEmptyTransport(), ensureEthnicOptionInList(), handleOpenForAdd(), if(), loadEthnicOptions() (+71 more)
### Community 5 - "Community 5"
Cohesion: 0.03
Nodes (34): fetchGetMenuList(), ComponentLoader, IframeRouteManager, MenuProcessor, RoutePermissionValidator, RouteRegistry, RouteTransformer, useAppMode() (+26 more)
Nodes (66): fetchFullmoonTodoList(), fetchUpdateFullmoonTodoInsurance(), fetchCollectionProtocolAuditList(), fetchCollectionProtocolDetail(), fetchCollectionProtocolList(), fetchCreateProtocolInvoiceRequest(), fetchInvoiceEligiblePayments(), fetchPaymentDetailList() (+58 more)
### Community 6 - "Community 6"
Cohesion: 0.03
Nodes (48): handleBlur(), handleFocus(), handleInput(), fetchClinicalPaymentDetail(), fetchClinicalPayments(), fetchClinicalReceiptConfirmed(), fetchClinicalReceiptPending(), fetchClinicalRefundConfirmed() (+40 more)
Nodes (47): handleBlur(), handleFocus(), handleInput(), fetchClinicalPaymentDetail(), fetchClinicalPayments(), fetchClinicalReceiptConfirmed(), fetchClinicalReceiptPending(), fetchClinicalRefundConfirmed() (+39 more)
### Community 7 - "Community 7"
Cohesion: 0.04
Nodes (76): fetchDeptTree(), fetchOaFlowPreview(), fetchOaTemplateDetail(), branchConditionLines(), collectConditionReferencedFields(), collectFormConditionReferencedFields(), flattenFormRules(), formatConditionPreview() (+68 more)
Cohesion: 0.03
Nodes (59): buildInboundBasicSection(), buildInboundCellStorageViewSections(), buildInboundResearchDonationViewSections(), buildReceptionSection(), buildTemporaryViewSections(), buildTransportSection(), resolveInboundProtocolStatus(), buildInsertedSiblingCard() (+51 more)
### Community 8 - "Community 8"
Cohesion: 0.03
Nodes (59): fetchCheckupInstitutionInvoices(), fetchCheckupInstitutionProjects(), fetchCreateCheckupInstitution(), fetchCreateCheckupInstitutionInvoice(), fetchCreateCheckupInstitutionProject(), fetchUpdateCheckupInstitution(), fetchUpdateCheckupInstitutionInvoice(), fetchUpdateCheckupInstitutionProject() (+51 more)
Nodes (54): useSettingsHandlers(), useSettingsPanel(), useSettingsState(), useCeremony(), useTheme(), if(), nodeSummary(), createDefaultFlow() (+46 more)
### Community 9 - "Community 9"
Cohesion: 0.03
Nodes (50): fetchProductionWorkOrderQcInfo(), dash(), fmtMoney(), attachmentFullUrl(), dash(), handleAttachmentDownload(), handleAttachmentPreview(), auditorDisplay() (+42 more)
Nodes (59): fetchCheckupInstitutionInvoices(), fetchCheckupInstitutionProjects(), fetchCreateCheckupInstitution(), fetchCreateCheckupInstitutionInvoice(), fetchCreateCheckupInstitutionProject(), fetchUpdateCheckupInstitution(), fetchUpdateCheckupInstitutionInvoice(), fetchUpdateCheckupInstitutionProject() (+51 more)
### Community 10 - "Community 10"
Cohesion: 0.03
Nodes (59): fetchMyProductionTasks(), useInboundSiblingNavigation(), shouldApplyTriggerSourceFilter(), useQcWorkOrderTabPage(), buildMineTableRows(), buildPresetTasksMap(), buildWorkOrderFromTasks(), fetchAllMineProductionTasks() (+51 more)
Nodes (42): fetchGetMenuList(), fetchGetMenuCodes(), fetchGetUserInfo(), fetchLogin(), fetchUpdateProfile(), fetchUploadProfileAvatar(), MenuProcessor, RoutePermissionValidator (+34 more)
### Community 11 - "Community 11"
Cohesion: 0.03
Nodes (58): fetchFullmoonTodoList(), fetchUpdateFullmoonTodoInsurance(), fetchCollectionProtocolAuditList(), fetchCollectionProtocolDetail(), fetchCollectionProtocolList(), fetchCreateProtocolInvoiceRequest(), fetchInvoiceEligiblePayments(), fetchPaymentDetailList() (+50 more)
Cohesion: 0.04
Nodes (45): buildBaseFields(), buildFeeSection(), buildInboundBasicSection(), buildInboundCellStorageProductionViewSections(), buildInboundResearchDonationProductionViewSections(), buildOutboundBasicExperimentProductionViewSections(), buildOutboundClinicalProductionViewSections(), buildOutboundDetail() (+37 more)
### Community 12 - "Community 12"
Cohesion: 0.04
Nodes (44): buildBaseFields(), buildInboundBasicSection(), buildInboundCellStorageProductionViewSections(), buildInboundResearchDonationProductionViewSections(), buildOutboundBasicExperimentProductionViewSections(), buildOutboundClinicalProductionViewSections(), buildOutboundDetail(), buildOutboundPilotProductionViewSections() (+36 more)
Nodes (53): fetchMyProductionTasks(), fetchMyQcTaskList(), fetchQcTaskDetail(), fetchQcTaskList(), fetchMineTasksForWorkOrders(), useInboundSiblingNavigation(), shouldApplyTriggerSourceFilter(), useQcWorkOrderTabPage() (+45 more)
### Community 13 - "Community 13"
Cohesion: 0.03
Nodes (49): useSettingsHandlers(), useSettingsPanel(), useSettingsState(), useCeremony(), useTheme(), if(), nodeSummary(), createDefaultFlow() (+41 more)
Cohesion: 0.04
Nodes (65): fetchDeptTree(), fetchOaFlowPreview(), fetchOaTemplateDetail(), branchConditionLines(), collectConditionReferencedFields(), collectFormConditionReferencedFields(), flattenFormRules(), formatConditionPreview() (+57 more)
### Community 14 - "Community 14"
Cohesion: 0.04
Nodes (45): fetchUserList(), fetchAddTaskStep(), fetchCopyTaskStep(), fetchDeleteTaskStep(), fetchDispatchProductionTaskSteps(), fetchForwardProductionTask(), fetchProductionTaskDetail(), fetchProductionTaskEditorInit() (+37 more)
Nodes (52): fetchCreateCustomer(), fetchCustomerList(), fetchDeleteCustomer(), fetchUpdateCustomer(), updateInfusionScheduleStatus(), handleDialogClose(), handleAdd(), handleBatchDelete() (+44 more)
### Community 15 - "Community 15"
Cohesion: 0.04
Nodes (49): fetchCreateCustomer(), fetchCustomerList(), fetchDeleteCustomer(), fetchUpdateCustomer(), updateInfusionScheduleStatus(), handleDialogClose(), handleAdd(), handleBatchDelete() (+41 more)
Nodes (35): dash(), fmtMoney(), attachmentFullUrl(), dash(), handleAttachmentDownload(), handleAttachmentPreview(), auditorDisplay(), dash() (+27 more)
### Community 16 - "Community 16"
Cohesion: 0.05
Nodes (53): fetchGetMenuCodes(), fetchGetUserInfo(), fetchLogin(), fetchRefreshToken(), fetchUpdateProfile(), fetchUploadProfileAvatar(), toLogin(), fetchUserInfo() (+45 more)
Cohesion: 0.04
Nodes (43): fetchCellSampleTypeList(), fetchCreateCellSampleType(), fetchCreateMenu(), fetchDeleteCellSampleType(), fetchDeleteMenu(), fetchMenuTree(), fetchUpdateCellSampleType(), fetchUpdateMenu() (+35 more)
### Community 17 - "Community 17"
Cohesion: 0.04
Nodes (38): fetchCellSampleTypeList(), fetchCreateCellSampleType(), fetchCreateMenu(), fetchDeleteCellSampleType(), fetchDeleteMenu(), fetchMenuTree(), fetchUpdateCellSampleType(), fetchUpdateMenu() (+30 more)
Nodes (45): fetchUserList(), fetchAddTaskStep(), fetchCopyTaskStep(), fetchDeleteTaskStep(), fetchDispatchProductionTaskSteps(), fetchForwardProductionTask(), fetchProductionTaskDetail(), fetchProductionTaskEditorInit() (+37 more)
### Community 18 - "Community 18"
Cohesion: 0.06
@@ -185,52 +189,52 @@ Cohesion: 0.05
Nodes (39): fetchCreateQcInspectionItemTemplate(), fetchDeleteQcInspectionItemTemplate(), fetchQcInspectionItemTemplateDetail(), fetchQcInspectionItemTemplateList(), fetchQcInspectionItemTemplatesActive(), fetchUpdateQcInspectionItemTemplate(), fetchQcLabTestItemList(), fetchQcLabTestItemsActive() (+31 more)
### Community 20 - "Community 20"
Cohesion: 0.05
Nodes (23): fetchQcMaterialBatchDetail(), fetchQcMaterialBatchList(), fetchQcMaterialBatchOptions(), fetchQcMaterialList(), fetchQcMaterialOptions(), fetchUpdateQcMaterialBatch(), fetchMarkQcMaterialUsageFullyUsed(), financeAttachmentsToUrlString() (+15 more)
### Community 21 - "Community 21"
Cohesion: 0.08
Nodes (37): formatDatetimeToMinute(), handleChineseDatetimePaste(), parseChineseDatetimeText(), parseBirthOrder(), parseChineseNumeral(), addSampleHint(), earliestCollectTime(), isMaternalBloodEmpty() (+29 more)
### Community 21 - "Community 21"
Cohesion: 0.06
Nodes (22): fetchQcMaterialBatchDetail(), fetchQcMaterialBatchList(), fetchQcMaterialBatchOptions(), fetchQcMaterialList(), fetchQcMaterialOptions(), fetchUpdateQcMaterialBatch(), fetchMarkQcMaterialUsageFullyUsed(), financeAttachmentsToUrlString() (+14 more)
### Community 22 - "Community 22"
Cohesion: 0.1
Nodes (2): WebSocketClient, TableCache
### Community 23 - "Community 23"
Cohesion: 0.08
Nodes (33): fetchRefreshToken(), toLogin(), base64ToBytes(), bytesToBase64(), decryptJson(), deriveKey(), encryptJson(), fromBase64Url() (+25 more)
### Community 24 - "Community 24"
Cohesion: 0.07
Nodes (24): fetchMineProductionWorkOrderTabStepCounts(), fetchMineProductionWorkOrderTabStepCountsDeduped(), fetchProductionWorkOrderCellProductOptions(), fetchProductionWorkOrderDetail(), fetchProductionWorkOrderList(), fetchProductionWorkOrderQcDispatchOptions(), fetchProductionWorkOrderQcInfo(), fetchProductionWorkOrderTabStepCounts() (+16 more)
### Community 25 - "Community 25"
Cohesion: 0.09
Nodes (8): getDefaultLanguage(), checkStorageCompatibility(), StorageConfig, getSystemStorage(), getSysVersion(), StorageKeyManager, StorageCompatibilityManager, validateStorageData()
### Community 24 - "Community 24"
### Community 26 - "Community 26"
Cohesion: 0.08
Nodes (12): ComponentLoader, IframeRouteManager, RouteTransformer, getFirstMenuPath(), getFirstSecondLevelMenuPath(), isIframe(), isNavigableMenuItem(), isWorkbenchMenuItem() (+4 more)
### Community 27 - "Community 27"
Cohesion: 0.08
Nodes (20): createEmptySnapshots(), normalizeConfiguredReagents(), normalizeConsumables(), normalizeDataCollections(), normalizeReagents(), normalizeStepOutputs(), serializeAttachments(), serializeEquipmentIds() (+12 more)
### Community 25 - "Community 25"
### Community 28 - "Community 28"
Cohesion: 0.07
Nodes (19): fetchDeleteMaterialBatch(), fetchMaterialBatchList(), fetchMaterialBatchOptions(), fetchMaterialList(), fetchMaterialOptions(), fetchUpdateMaterialBatch(), fetchMaterialUsageList(), fetchMyMaterialUsageList() (+11 more)
### Community 26 - "Community 26"
Cohesion: 0.09
Nodes (28): completePilotApplication(), deletePilotApplication(), fetchPilotApplicationList(), startPilotApplication(), voidPilotApplication(), clearTableSelection(), handleBatchComplete(), handleBatchStart() (+20 more)
### Community 27 - "Community 27"
Cohesion: 0.09
Nodes (18): fetchProductionReceptionBySampleCode(), fetchProductionReceptionSubmit(), fetchProductionReceptionUpdate(), onUserSelectVisible(), remoteSearchUsers(), buildPayload(), ensureDefaultHandler(), initDialog() (+10 more)
### Community 28 - "Community 28"
Cohesion: 0.09
Nodes (22): fetchMineProductionWorkOrderTabStepCounts(), fetchMineProductionWorkOrderTabStepCountsDeduped(), fetchProductionWorkOrderCellProductOptions(), fetchProductionWorkOrderDetail(), fetchProductionWorkOrderList(), fetchProductionWorkOrderQcDispatchOptions(), fetchProductionWorkOrderTabStepCounts(), fetchProductionWorkOrderTabStepCountsDeduped() (+14 more)
### Community 29 - "Community 29"
Cohesion: 0.1
Nodes (20): buildInboundBasicSection(), buildInboundCellStorageViewSections(), buildInboundResearchDonationViewSections(), buildReceptionSection(), buildTransportSection(), resolveInboundProtocolStatus(), appendTaskResultSections(), batchTasksForPanelSlot() (+12 more)
Cohesion: 0.08
Nodes (19): fetchProductionReceptionBySampleCode(), fetchProductionReceptionSubmit(), fetchProductionReceptionUpdate(), onUserSelectVisible(), remoteSearchUsers(), buildPayload(), ensureDefaultHandler(), initDialog() (+11 more)
### Community 30 - "Community 30"
Cohesion: 0.09
Nodes (22): fetchOaAppList(), fetchOaGroupList(), fetchPublishOaApp(), loadData(), loadGroups(), resetForm(), onSuccess(), goBack() (+14 more)
Nodes (28): completePilotApplication(), deletePilotApplication(), fetchPilotApplicationList(), startPilotApplication(), voidPilotApplication(), clearTableSelection(), handleBatchComplete(), handleBatchStart() (+20 more)
### Community 31 - "Community 31"
Cohesion: 0.05
Nodes (8): fetchQcMaterialAmountAuthUsers(), fetchQcMonthTemplateList(), fetchNextDonationSampleCode(), fetchResearchDonationAuditList(), fetchResearchDonationDetail(), fetchResearchDonationList(), fetchSampleSmsNotificationList(), fetchStorageEntrySmsList()
Cohesion: 0.09
Nodes (22): fetchOaAppList(), fetchOaGroupList(), fetchPublishOaApp(), loadData(), loadGroups(), resetForm(), onSuccess(), goBack() (+14 more)
### Community 32 - "Community 32"
Cohesion: 0.1
@@ -253,25 +257,25 @@ Cohesion: 0.19
Nodes (15): fetchAttachmentDownloadUrl(), attachmentFullUrl(), ensureUniqueZipEntryName(), fetchAttachmentBlob(), getAttachmentExtension(), resolveAttachmentFileName(), sanitizeZipPathSegment(), applyInboundLabStorageCodePrefix() (+7 more)
### Community 37 - "Community 37"
Cohesion: 0.13
Nodes (8): chipTitle(), confirmPicker(), memberOptionLabel(), removeUser(), resolveUser(), signBadge(), signBadgeText(), updateSelect()
### Community 38 - "Community 38"
Cohesion: 0.2
Nodes (14): applyFlagToRule(), applySchema(), countRules(), getActiveRule(), getDesigner(), getSetupState(), onMessage(), readFlag() (+6 more)
### Community 39 - "Community 39"
### Community 38 - "Community 38"
Cohesion: 0.12
Nodes (6): setupOaConfirmationKit(), ensureOaKitMenu(), setupOaLeaveKit(), setupOaOvertimeKit(), setupOaResignationKit(), setupOaTripKit()
### Community 40 - "Community 40"
### Community 39 - "Community 39"
Cohesion: 0.16
Nodes (10): useTable(), useTableImpl(), getColumnChecks(), useTableColumns(), createErrorHandler(), createSmartDebounce(), defaultResponseAdapter(), extractPagination() (+2 more)
### Community 41 - "Community 41"
### Community 40 - "Community 40"
Cohesion: 0.27
Nodes (14): useChart(), useChartComponent(), useChartOps(), colourBlend(), getCssVar(), getDarkColor(), getLightColor(), handleElementThemeColor() (+6 more)
### Community 41 - "Community 41"
Cohesion: 0.33
Nodes (13): buildProtocolPaymentFlowSteps(), dash(), financeReceiptTime(), formatAmount(), hasFinanceReceipt(), hasFinanceRefund(), hasReceiptSubmit(), hasRefundSubmit() (+5 more)
### Community 42 - "Community 42"
Cohesion: 0.19
Nodes (6): fetchServiceOrderTxnList(), handleReset(), handleSearch(), handleTabChange(), loadData(), switchTab()
@@ -281,154 +285,178 @@ Cohesion: 0.24
Nodes (10): buildPrintDocumentHtml(), cleanupPrintIframe(), embedSopImagesAsDataUrls(), getSopA4ContentHeightPx(), getSopA4EditorHeightPx(), normalizeSopCheckboxes(), prepareSopHtmlForPrint(), printSopHtml() (+2 more)
### Community 45 - "Community 45"
Cohesion: 0.24
Nodes (8): fullFileUrl(), handlePreviewAttachment(), isVideoFile(), normalizeDisplayValue(), resolveReviewCellType(), resolveReviewQuantity(), resolveReviewSpecText(), uniqueJoined()
Cohesion: 0.15
Nodes (4): fetchNextDonationSampleCode(), fetchResearchDonationAuditList(), fetchResearchDonationDetail(), fetchResearchDonationList()
### Community 46 - "Community 46"
Cohesion: 0.31
Nodes (4): isSlotAvailable(), resolveStorageSlotRangeFill(), slotFacilityNodeId(), sortBoxSlots()
### Community 47 - "Community 47"
Cohesion: 0.28
Nodes (1): FireworkSystem
### Community 48 - "Community 48"
Cohesion: 0.25
Nodes (2): handleTouchEnd(), setTransition()
### Community 49 - "Community 49"
### Community 50 - "Community 50"
Cohesion: 0.28
Nodes (4): fetchMyProductionMaterialConsumptions(), handleReset(), handleSearch(), loadData()
Nodes (4): isActiveHistoryInstance(), isUploadPreviewLabel(), previewColumnMinWidth(), syncWorktabTitle()
### Community 52 - "Community 52"
### Community 53 - "Community 53"
Cohesion: 0.39
Nodes (6): isIgnorableScriptError(), normalizeErrorMessage(), registerPromiseErrorHandler(), registerResourceErrorHandler(), scriptErrorHandler(), setupErrorHandle()
### Community 53 - "Community 53"
### Community 54 - "Community 54"
Cohesion: 0.36
Nodes (1): TableHeightCalculator
### Community 55 - "Community 55"
### Community 56 - "Community 56"
Cohesion: 0.33
Nodes (2): logApiCryptoBootInfo(), maskSecret()
### Community 56 - "Community 56"
### Community 57 - "Community 57"
Cohesion: 0.38
Nodes (4): handleFocus(), handleInput(), parseDecimalToNumber(), sanitizeDecimalInput()
### Community 57 - "Community 57"
### Community 58 - "Community 58"
Cohesion: 0.29
Nodes (1): fetchQcMonthTemplateList()
### Community 59 - "Community 59"
Cohesion: 0.4
Nodes (2): isUnfinishedQcWorkOrder(), resolveQcWorkOrderUnfinishedBadgeCount()
### Community 58 - "Community 58"
### Community 60 - "Community 60"
Cohesion: 0.47
Nodes (3): isPaymentDueWithinWarnWindow(), parsePaymentDueYmd(), startOfLocalDay()
### Community 59 - "Community 59"
### Community 61 - "Community 61"
Cohesion: 0.5
Nodes (2): formatProtocolDocDeleteConfirm(), formatProtocolDocSubject()
### Community 60 - "Community 60"
### Community 62 - "Community 62"
Cohesion: 0.5
Nodes (2): parseEquipmentIds(), syncEquipmentNamesFromOptions()
### Community 62 - "Community 62"
### Community 64 - "Community 64"
Cohesion: 0.5
Nodes (2): focusInput(), handleKeydown()
### Community 66 - "Community 66"
### Community 65 - "Community 65"
Cohesion: 0.4
Nodes (1): fetchQcMaterialAmountAuthUsers()
### Community 69 - "Community 69"
Cohesion: 0.67
Nodes (2): if(), logSidebarMenu()
### Community 72 - "Community 72"
Cohesion: 1.0
Nodes (2): getSettingDefaults(), resetToDefaults()
### Community 75 - "Community 75"
Cohesion: 1.0
Nodes (2): buildOvertimeKitChildren(), uniqueId()
### Community 71 - "Community 71"
Cohesion: 0.5
Nodes (1): fetchSampleSmsNotificationList()
### Community 76 - "Community 76"
Cohesion: 1.0
Nodes (2): buildLeaveKitChildren(), uniqueId()
### Community 78 - "Community 78"
Cohesion: 1.0
Nodes (2): buildConfirmationKitChildren(), uniqueId()
Nodes (2): getSettingDefaults(), resetToDefaults()
### Community 79 - "Community 79"
Cohesion: 1.0
Nodes (2): buildResignationKitChildren(), uniqueId()
Nodes (2): buildOvertimeKitChildren(), uniqueId()
### Community 80 - "Community 80"
Cohesion: 1.0
Nodes (2): copyTextToClipboard(), copyTextWithFallback()
Nodes (2): buildLeaveKitChildren(), uniqueId()
### Community 82 - "Community 82"
Cohesion: 1.0
Nodes (2): buildConfirmationKitChildren(), uniqueId()
### Community 83 - "Community 83"
Cohesion: 1.0
Nodes (2): buildResignationKitChildren(), uniqueId()
### Community 84 - "Community 84"
Cohesion: 1.0
Nodes (2): copyTextToClipboard(), copyTextWithFallback()
### Community 88 - "Community 88"
Cohesion: 1.0
Nodes (2): getSourceProtocolAttachment(), normalizeAttachmentFiles()
### Community 95 - "Community 95"
### Community 99 - "Community 99"
Cohesion: 1.0
Nodes (2): emptyTabCounts(), useProductionWorkOrderTabStepCounts()
### Community 98 - "Community 98"
### Community 102 - "Community 102"
Cohesion: 1.0
Nodes (2): initialProgress(), useQcWorkOrderAttachmentExport()
### Community 99 - "Community 99"
### Community 103 - "Community 103"
Cohesion: 1.0
Nodes (2): emptyTabCounts(), useQcWorkOrderTabUnfinishedCounts()
## Knowledge Gaps
- **Thin community `Community 22`** (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 47`** (9 nodes): `cleanupEventListeners()`, `handleTouchEnd()`, `handleTouchMove()`, `handleTouchStart()`, `handleWheelScroll()`, `if()`, `setTransition()`, `setupEventListeners()`, `index.vue`
- **Thin community `Community 47`** (9 nodes): `FireworkSystem`, `.constructor()`, `.createFirework()`, `.createParticle()`, `.getAvailableParticle()`, `.initializePool()`, `.preloadAllImages()`, `.preloadImage()`, `index.vue`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 53`** (8 nodes): `TableHeightCalculator`, `.calculate()`, `.calculateOffset()`, `.calculatePaginationOffset()`, `.constructor()`, `.getHeaderHeight()`, `useTableHeight()`, `useTableHeight.ts`
- **Thin community `Community 48`** (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 55`** (7 nodes): `App.vue`, `main.ts`, `refreshButtonAutoIcons()`, `refreshPanelTitleIcons()`, `logApiCryptoBootInfo()`, `maskSecret()`, `console.ts`
- **Thin community `Community 54`** (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 57`** (6 nodes): `formatQcWorkOrderUnfinishedBadgeCount()`, `isUnfinishedQcWorkOrder()`, `qcWorkOrderUnfinishedBadgeTitle()`, `resolveQcWorkOrderUnfinishedBadgeCount()`, `sumQcWorkOrderGroupUnfinishedBadgeCount()`, `qc-work-order-unfinished-badge.ts`
- **Thin community `Community 56`** (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 59`** (5 nodes): `formatProtocolDocBatchDeleteConfirm()`, `formatProtocolDocDeleteConfirm()`, `formatProtocolDocSubject()`, `getProtocolDocTypeLabel()`, `protocol-doc-label.ts`
- **Thin community `Community 58`** (7 nodes): `fetchConfirmQcMonthImport()`, `fetchCreateQcMonthTemplate()`, `fetchDeleteQcMonthTemplate()`, `fetchPreviewQcMonthImport()`, `fetchQcMonthTemplateList()`, `fetchUpdateQcMonthTemplate()`, `qc-material-month-template.ts`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 60`** (5 nodes): `equipmentOptionLabel()`, `joinEquipmentIds()`, `parseEquipmentIds()`, `syncEquipmentNamesFromOptions()`, `equipment-select.ts`
- **Thin community `Community 59`** (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 62`** (5 nodes): `focusInput()`, `handleKeydown()`, `if()`, `search()`, `index.vue`
- **Thin community `Community 61`** (5 nodes): `formatProtocolDocBatchDeleteConfirm()`, `formatProtocolDocDeleteConfirm()`, `formatProtocolDocSubject()`, `getProtocolDocTypeLabel()`, `protocol-doc-label.ts`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 66`** (4 nodes): `if()`, `logSidebarMenu()`, `index.vue`, `SidebarSubmenu.vue`
- **Thin community `Community 62`** (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 72`** (3 nodes): `getSettingDefaults()`, `resetToDefaults()`, `setting.ts`
- **Thin community `Community 64`** (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 75`** (3 nodes): `buildOvertimeKitChildren()`, `oa-overtime-kit-rule.ts`, `uniqueId()`
- **Thin community `Community 65`** (5 nodes): `fetchBatchRevokeQcMaterialAmountAuth()`, `fetchGrantQcMaterialAmountAuth()`, `fetchQcMaterialAmountAuthUsers()`, `fetchRevokeQcMaterialAmountAuth()`, `qc-material-amount-auth.ts`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 76`** (3 nodes): `buildLeaveKitChildren()`, `oa-leave-kit-rule.ts`, `uniqueId()`
- **Thin community `Community 69`** (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 78`** (3 nodes): `buildConfirmationKitChildren()`, `oa-confirmation-kit-rule.ts`, `uniqueId()`
- **Thin community `Community 71`** (4 nodes): `fetchGenerateSms()`, `fetchSampleSmsNotificationList()`, `fetchToggleSmsNotified()`, `sample-sms-notification.ts`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 79`** (3 nodes): `buildResignationKitChildren()`, `oa-resignation-kit-rule.ts`, `uniqueId()`
- **Thin community `Community 76`** (3 nodes): `getSettingDefaults()`, `resetToDefaults()`, `setting.ts`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 80`** (3 nodes): `copyTextToClipboard()`, `copyTextWithFallback()`, `copy-text.ts`
- **Thin community `Community 79`** (3 nodes): `buildOvertimeKitChildren()`, `oa-overtime-kit-rule.ts`, `uniqueId()`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 83`** (3 nodes): `getSourceProtocolAttachment()`, `normalizeAttachmentFiles()`, `protocol-source-attachment.ts`
- **Thin community `Community 80`** (3 nodes): `buildLeaveKitChildren()`, `oa-leave-kit-rule.ts`, `uniqueId()`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 95`** (3 nodes): `emptyTabCounts()`, `useProductionWorkOrderTabStepCounts()`, `useProductionWorkOrderTabStepCounts.ts`
- **Thin community `Community 82`** (3 nodes): `buildConfirmationKitChildren()`, `oa-confirmation-kit-rule.ts`, `uniqueId()`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 98`** (3 nodes): `initialProgress()`, `useQcWorkOrderAttachmentExport()`, `useQcWorkOrderAttachmentExport.ts`
- **Thin community `Community 83`** (3 nodes): `buildResignationKitChildren()`, `oa-resignation-kit-rule.ts`, `uniqueId()`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 99`** (3 nodes): `emptyTabCounts()`, `useQcWorkOrderTabUnfinishedCounts()`, `useQcWorkOrderTabUnfinishedCounts.ts`
- **Thin community `Community 84`** (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 88`** (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 99`** (3 nodes): `emptyTabCounts()`, `useProductionWorkOrderTabStepCounts()`, `useProductionWorkOrderTabStepCounts.ts`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 102`** (3 nodes): `initialProgress()`, `useQcWorkOrderAttachmentExport()`, `useQcWorkOrderAttachmentExport.ts`
Too small to be a meaningful cluster - may be noise or needs more connections extracted.
- **Thin community `Community 103`** (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 1` to `Community 0`, `Community 2`, `Community 3`, `Community 4`, `Community 7`, `Community 8`, `Community 9`, `Community 10`, `Community 11`, `Community 12`, `Community 13`, `Community 14`, `Community 16`, `Community 18`, `Community 19`, `Community 21`, `Community 22`, `Community 24`, `Community 26`, `Community 28`, `Community 29`, `Community 30`, `Community 32`, `Community 33`, `Community 36`, `Community 37`?**
_High betweenness centrality (0.281) - this node is a cross-community bridge._
- **Why does `get()` connect `Community 0` to `Community 1`, `Community 2`, `Community 3`, `Community 4`, `Community 6`, `Community 7`, `Community 8`, `Community 9`, `Community 10`, `Community 11`, `Community 13`, `Community 14`, `Community 15`, `Community 16`, `Community 17`, `Community 18`, `Community 19`, `Community 20`, `Community 25`, `Community 26`, `Community 27`, `Community 28`, `Community 29`, `Community 30`, `Community 31`, `Community 33`, `Community 34`, `Community 42`, `Community 46`, `Community 49`?**
_High betweenness centrality (0.243) - this node is a cross-community bridge._
- **Why does `handleDynamicRoutes()` connect `Community 5` to `Community 33`, `Community 4`, `Community 16`, `Community 18`, `Community 28`?**
_High betweenness centrality (0.032) - this node is a cross-community bridge._
- **Are the 314 inferred relationships involving `get()` (e.g. with `resolveStorageSlotRangeFill()` and `buildNodeCodePathFromFlat()`) actually correct?**
_`get()` has 314 INFERRED edges - model-reasoned connections that need verification._
- **Are the 122 inferred relationships involving `push()` (e.g. with `refreshQcMenuBadges()` and `collectLeafFacilityNodesInTreeOrder()`) actually correct?**
_`push()` has 122 INFERRED edges - model-reasoned connections that need verification._
- **Why does `push()` connect `Community 2` to `Community 0`, `Community 1`, `Community 3`, `Community 4`, `Community 5`, `Community 7`, `Community 8`, `Community 9`, `Community 11`, `Community 12`, `Community 13`, `Community 15`, `Community 16`, `Community 17`, `Community 18`, `Community 19`, `Community 20`, `Community 22`, `Community 23`, `Community 24`, `Community 27`, `Community 30`, `Community 31`, `Community 32`, `Community 33`, `Community 36`, `Community 47`?**
_High betweenness centrality (0.306) - this node is a cross-community bridge._
- **Why does `get()` connect `Community 0` to `Community 1`, `Community 3`, `Community 4`, `Community 5`, `Community 6`, `Community 7`, `Community 8`, `Community 9`, `Community 10`, `Community 12`, `Community 13`, `Community 14`, `Community 16`, `Community 17`, `Community 18`, `Community 19`, `Community 21`, `Community 24`, `Community 28`, `Community 29`, `Community 30`, `Community 31`, `Community 33`, `Community 34`, `Community 42`, `Community 45`, `Community 46`, `Community 58`, `Community 65`, `Community 71`?**
_High betweenness centrality (0.232) - this node is a cross-community bridge._
- **Why does `handleDynamicRoutes()` connect `Community 10` to `Community 33`, `Community 3`, `Community 18`, `Community 24`, `Community 26`?**
_High betweenness centrality (0.030) - this node is a cross-community bridge._
- **Are the 315 inferred relationships involving `get()` (e.g. with `resolveStorageSlotRangeFill()` and `buildNodeCodePathFromFlat()`) actually correct?**
_`get()` has 315 INFERRED edges - model-reasoned connections that need verification._
- **Are the 124 inferred relationships involving `push()` (e.g. with `refreshQcMenuBadges()` and `collectLeafFacilityNodesInTreeOrder()`) actually correct?**
_`push()` has 124 INFERRED edges - model-reasoned connections that need verification._
- **Are the 28 inferred relationships involving `emit()` (e.g. with `handleSubmit()` and `handleDialogClose()`) actually correct?**
_`emit()` has 28 INFERRED edges - model-reasoned connections that need verification._
- **Are the 20 inferred relationships involving `set()` (e.g. with `buildNodeCodePathFromFlat()` and `collectLeafFacilityNodesInTreeOrder()`) actually correct?**
+4 -4
View File
@@ -57,12 +57,12 @@
</div>
<div id="legend"></div>
</div>
<div id="stats">3550 nodes &middot; 5051 edges &middot; 393 communities</div>
<div id="stats">3573 nodes &middot; 5087 edges &middot; 396 communities</div>
</div>
<script>
const RAW_NODES = [{"id": "app_vue", "label": "App.vue", "color": {"background": "#EDC948", "border": "#EDC948", "highlight": {"background": "#ffffff", "border": "#EDC948"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "App.vue", "community": 55, "community_name": "Community 55", "source_file": "App.vue", "file_type": "code", "degree": 3}, {"id": "src_app_refreshbuttonautoicons", "label": "refreshButtonAutoIcons()", "color": {"background": "#EDC948", "border": "#EDC948", "highlight": {"background": "#ffffff", "border": "#EDC948"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "refreshButtonAutoIcons()", "community": 55, "community_name": "Community 55", "source_file": "App.vue", "file_type": "code", "degree": 1}, {"id": "src_app_refreshpaneltitleicons", "label": "refreshPanelTitleIcons()", "color": {"background": "#EDC948", "border": "#EDC948", "highlight": {"background": "#ffffff", "border": "#EDC948"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "refreshPanelTitleIcons()", "community": 55, "community_name": "Community 55", "source_file": "App.vue", "file_type": "code", "degree": 1}, {"id": "main_ts", "label": "main.ts", "color": {"background": "#EDC948", "border": "#EDC948", "highlight": {"background": "#ffffff", "border": "#EDC948"}}, "size": 10.4, "font": {"size": 0, "color": "#ffffff"}, "title": "main.ts", "community": 55, "community_name": "Community 55", "source_file": "main.ts", "file_type": "code", "degree": 4}, {"id": "src_main_masksecret", "label": "maskSecret()", "color": {"background": "#EDC948", "border": "#EDC948", "highlight": {"background": "#ffffff", "border": "#EDC948"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "maskSecret()", "community": 55, "community_name": "Community 55", "source_file": "main.ts", "file_type": "code", "degree": 2}, {"id": "src_main_logapicryptobootinfo", "label": "logApiCryptoBootInfo()", "color": {"background": "#EDC948", "border": "#EDC948", "highlight": {"background": "#ffffff", "border": "#EDC948"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "logApiCryptoBootInfo()", "community": 55, "community_name": "Community 55", "source_file": "main.ts", "file_type": "code", "degree": 2}, {"id": "env_d_ts", "label": "env.d.ts", "color": {"background": "#9C755F", "border": "#9C755F", "highlight": {"background": "#ffffff", "border": "#9C755F"}}, "size": 10.0, "font": {"size": 0, "color": "#ffffff"}, "title": "env.d.ts", "community": 148, "community_name": "Community 148", "source_file": "env.d.ts", "file_type": "code", "degree": 0}, {"id": "shims_loose_d_ts", "label": "shims-loose.d.ts", "color": {"background": "#BAB0AC", "border": "#BAB0AC", "highlight": {"background": "#ffffff", "border": "#BAB0AC"}}, "size": 10.0, "font": {"size": 0, "color": "#ffffff"}, "title": "shims-loose.d.ts", "community": 149, "community_name": "Community 149", "source_file": "shims-loose.d.ts", "file_type": "code", "degree": 0}, {"id": "directives_index_ts", "label": "index.ts", "color": {"background": "#EDC948", "border": "#EDC948", "highlight": {"background": "#ffffff", "border": "#EDC948"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "index.ts", "community": 35, "community_name": "Community 35", "source_file": "directives/index.ts", "file_type": "code", "degree": 1}, {"id": "directives_index_setupglobdirectives", "label": "setupGlobDirectives()", "color": {"background": "#EDC948", "border": "#EDC948", "highlight": {"background": "#ffffff", "border": "#EDC948"}}, "size": 10.5, "font": {"size": 0, "color": "#ffffff"}, "title": "setupGlobDirectives()", "community": 35, "community_name": "Community 35", "source_file": "directives/index.ts", "file_type": "code", "degree": 5}, {"id": "directives_core_roles_ts", "label": "roles.ts", "color": {"background": "#EDC948", "border": "#EDC948", "highlight": {"background": "#ffffff", "border": "#EDC948"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "roles.ts", "community": 35, "community_name": "Community 35", "source_file": "directives/core/roles.ts", "file_type": "code", "degree": 3}, {"id": "core_roles_checkrolepermission", "label": "checkRolePermission()", "color": {"background": "#EDC948", "border": "#EDC948", "highlight": {"background": "#ffffff", "border": "#EDC948"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "checkRolePermission()", "community": 35, "community_name": "Community 35", "source_file": "directives/core/roles.ts", "file_type": "code", "degree": 2}, {"id": "core_roles_removeelement", "label": "removeElement()", "color": {"background": "#EDC948", "border": "#EDC948", "highlight": {"background": "#ffffff", "border": "#EDC948"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "removeElement()", "community": 35, "community_name": "Community 35", "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": 545}, {"cid": 1, "color": "#F28E2B", "label": "Community 1", "count": 161}, {"cid": 2, "color": "#E15759", "label": "Community 2", "count": 121}, {"cid": 3, "color": "#76B7B2", "label": "Community 3", "count": 110}, {"cid": 4, "color": "#59A14F", "label": "Community 4", "count": 104}, {"cid": 5, "color": "#EDC948", "label": "Community 5", "count": 101}, {"cid": 6, "color": "#B07AA1", "label": "Community 6", "count": 97}, {"cid": 7, "color": "#FF9DA7", "label": "Community 7", "count": 93}, {"cid": 8, "color": "#9C755F", "label": "Community 8", "count": 92}, {"cid": 9, "color": "#BAB0AC", "label": "Community 9", "count": 91}, {"cid": 10, "color": "#4E79A7", "label": "Community 10", "count": 90}, {"cid": 11, "color": "#F28E2B", "label": "Community 11", "count": 89}, {"cid": 12, "color": "#E15759", "label": "Community 12", "count": 83}, {"cid": 13, "color": "#76B7B2", "label": "Community 13", "count": 80}, {"cid": 14, "color": "#59A14F", "label": "Community 14", "count": 72}, {"cid": 15, "color": "#EDC948", "label": "Community 15", "count": 70}, {"cid": 16, "color": "#B07AA1", "label": "Community 16", "count": 69}, {"cid": 17, "color": "#FF9DA7", "label": "Community 17", "count": 67}, {"cid": 18, "color": "#9C755F", "label": "Community 18", "count": 60}, {"cid": 19, "color": "#BAB0AC", "label": "Community 19", "count": 57}, {"cid": 20, "color": "#4E79A7", "label": "Community 20", "count": 49}, {"cid": 21, "color": "#F28E2B", "label": "Community 21", "count": 47}, {"cid": 22, "color": "#E15759", "label": "Community 22", "count": 42}, {"cid": 23, "color": "#76B7B2", "label": "Community 23", "count": 37}, {"cid": 24, "color": "#59A14F", "label": "Community 24", "count": 36}, {"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": 34}, {"cid": 28, "color": "#9C755F", "label": "Community 28", "count": 34}, {"cid": 29, "color": "#BAB0AC", "label": "Community 29", "count": 33}, {"cid": 30, "color": "#4E79A7", "label": "Community 30", "count": 33}, {"cid": 31, "color": "#F28E2B", "label": "Community 31", "count": 33}, {"cid": 32, "color": "#E15759", "label": "Community 32", "count": 31}, {"cid": 33, "color": "#76B7B2", "label": "Community 33", "count": 25}, {"cid": 34, "color": "#59A14F", "label": "Community 34", "count": 24}, {"cid": 35, "color": "#EDC948", "label": "Community 35", "count": 22}, {"cid": 36, "color": "#B07AA1", "label": "Community 36", "count": 20}, {"cid": 37, "color": "#FF9DA7", "label": "Community 37", "count": 20}, {"cid": 38, "color": "#9C755F", "label": "Community 38", "count": 19}, {"cid": 39, "color": "#BAB0AC", "label": "Community 39", "count": 17}, {"cid": 40, "color": "#4E79A7", "label": "Community 40", "count": 17}, {"cid": 41, "color": "#F28E2B", "label": "Community 41", "count": 16}, {"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": 13}, {"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": 9}, {"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": 8}, {"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": 6}, {"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": 5}, {"cid": 63, "color": "#76B7B2", "label": "Community 63", "count": 5}, {"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": "CommunityLine truncated
const RAW_NODES = [{"id": "app_vue", "label": "App.vue", "color": {"background": "#B07AA1", "border": "#B07AA1", "highlight": {"background": "#ffffff", "border": "#B07AA1"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "App.vue", "community": 56, "community_name": "Community 56", "source_file": "App.vue", "file_type": "code", "degree": 3}, {"id": "src_app_refreshbuttonautoicons", "label": "refreshButtonAutoIcons()", "color": {"background": "#B07AA1", "border": "#B07AA1", "highlight": {"background": "#ffffff", "border": "#B07AA1"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "refreshButtonAutoIcons()", "community": 56, "community_name": "Community 56", "source_file": "App.vue", "file_type": "code", "degree": 1}, {"id": "src_app_refreshpaneltitleicons", "label": "refreshPanelTitleIcons()", "color": {"background": "#B07AA1", "border": "#B07AA1", "highlight": {"background": "#ffffff", "border": "#B07AA1"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "refreshPanelTitleIcons()", "community": 56, "community_name": "Community 56", "source_file": "App.vue", "file_type": "code", "degree": 1}, {"id": "main_ts", "label": "main.ts", "color": {"background": "#B07AA1", "border": "#B07AA1", "highlight": {"background": "#ffffff", "border": "#B07AA1"}}, "size": 10.4, "font": {"size": 0, "color": "#ffffff"}, "title": "main.ts", "community": 56, "community_name": "Community 56", "source_file": "main.ts", "file_type": "code", "degree": 4}, {"id": "src_main_masksecret", "label": "maskSecret()", "color": {"background": "#B07AA1", "border": "#B07AA1", "highlight": {"background": "#ffffff", "border": "#B07AA1"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "maskSecret()", "community": 56, "community_name": "Community 56", "source_file": "main.ts", "file_type": "code", "degree": 2}, {"id": "src_main_logapicryptobootinfo", "label": "logApiCryptoBootInfo()", "color": {"background": "#B07AA1", "border": "#B07AA1", "highlight": {"background": "#ffffff", "border": "#B07AA1"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "logApiCryptoBootInfo()", "community": 56, "community_name": "Community 56", "source_file": "main.ts", "file_type": "code", "degree": 2}, {"id": "env_d_ts", "label": "env.d.ts", "color": {"background": "#E15759", "border": "#E15759", "highlight": {"background": "#ffffff", "border": "#E15759"}}, "size": 10.0, "font": {"size": 0, "color": "#ffffff"}, "title": "env.d.ts", "community": 152, "community_name": "Community 152", "source_file": "env.d.ts", "file_type": "code", "degree": 0}, {"id": "shims_loose_d_ts", "label": "shims-loose.d.ts", "color": {"background": "#76B7B2", "border": "#76B7B2", "highlight": {"background": "#ffffff", "border": "#76B7B2"}}, "size": 10.0, "font": {"size": 0, "color": "#ffffff"}, "title": "shims-loose.d.ts", "community": 153, "community_name": "Community 153", "source_file": "shims-loose.d.ts", "file_type": "code", "degree": 0}, {"id": "directives_index_ts", "label": "index.ts", "color": {"background": "#EDC948", "border": "#EDC948", "highlight": {"background": "#ffffff", "border": "#EDC948"}}, "size": 10.1, "font": {"size": 0, "color": "#ffffff"}, "title": "index.ts", "community": 35, "community_name": "Community 35", "source_file": "directives/index.ts", "file_type": "code", "degree": 1}, {"id": "directives_index_setupglobdirectives", "label": "setupGlobDirectives()", "color": {"background": "#EDC948", "border": "#EDC948", "highlight": {"background": "#ffffff", "border": "#EDC948"}}, "size": 10.5, "font": {"size": 0, "color": "#ffffff"}, "title": "setupGlobDirectives()", "community": 35, "community_name": "Community 35", "source_file": "directives/index.ts", "file_type": "code", "degree": 5}, {"id": "directives_core_roles_ts", "label": "roles.ts", "color": {"background": "#EDC948", "border": "#EDC948", "highlight": {"background": "#ffffff", "border": "#EDC948"}}, "size": 10.3, "font": {"size": 0, "color": "#ffffff"}, "title": "roles.ts", "community": 35, "community_name": "Community 35", "source_file": "directives/core/roles.ts", "file_type": "code", "degree": 3}, {"id": "core_roles_checkrolepermission", "label": "checkRolePermission()", "color": {"background": "#EDC948", "border": "#EDC948", "highlight": {"background": "#ffffff", "border": "#EDC948"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "checkRolePermission()", "community": 35, "community_name": "Community 35", "source_file": "directives/core/roles.ts", "file_type": "code", "degree": 2}, {"id": "core_roles_removeelement", "label": "removeElement()", "color": {"background": "#EDC948", "border": "#EDC948", "highlight": {"background": "#ffffff", "border": "#EDC948"}}, "size": 10.2, "font": {"size": 0, "color": "#ffffff"}, "title": "removeElement()", "community": 35, "community_name": "Community 35", "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": 549}, {"cid": 1, "color": "#F28E2B", "label": "Community 1", "count": 123}, {"cid": 2, "color": "#E15759", "label": "Community 2", "count": 120}, {"cid": 3, "color": "#76B7B2", "label": "Community 3", "count": 111}, {"cid": 4, "color": "#59A14F", "label": "Community 4", "count": 110}, {"cid": 5, "color": "#EDC948", "label": "Community 5", "count": 102}, {"cid": 6, "color": "#B07AA1", "label": "Community 6", "count": 96}, {"cid": 7, "color": "#FF9DA7", "label": "Community 7", "count": 94}, {"cid": 8, "color": "#9C755F", "label": "Community 8", "count": 92}, {"cid": 9, "color": "#BAB0AC", "label": "Community 9", "count": 92}, {"cid": 10, "color": "#4E79A7", "label": "Community 10", "count": 92}, {"cid": 11, "color": "#F28E2B", "label": "Community 11", "count": 84}, {"cid": 12, "color": "#E15759", "label": "Community 12", "count": 82}, {"cid": 13, "color": "#76B7B2", "label": "Community 13", "count": 80}, {"cid": 14, "color": "#59A14F", "label": "Community 14", "count": 78}, {"cid": 15, "color": "#EDC948", "label": "Community 15", "count": 75}, {"cid": 16, "color": "#B07AA1", "label": "Community 16", "count": 74}, {"cid": 17, "color": "#FF9DA7", "label": "Community 17", "count": 72}, {"cid": 18, "color": "#9C755F", "label": "Community 18", "count": 60}, {"cid": 19, "color": "#BAB0AC", "label": "Community 19", "count": 57}, {"cid": 20, "color": "#4E79A7", "label": "Community 20", "count": 47}, {"cid": 21, "color": "#F28E2B", "label": "Community 21", "count": 46}, {"cid": 22, "color": "#E15759", "label": "Community 22", "count": 42}, {"cid": 23, "color": "#76B7B2", "label": "Community 23", "count": 41}, {"cid": 24, "color": "#59A14F", "label": "Community 24", "count": 38}, {"cid": 25, "color": "#EDC948", "label": "Community 25", "count": 37}, {"cid": 26, "color": "#B07AA1", "label": "Community 26", "count": 37}, {"cid": 27, "color": "#FF9DA7", "label": "Community 27", "count": 36}, {"cid": 28, "color": "#9C755F", "label": "Community 28", "count": 35}, {"cid": 29, "color": "#BAB0AC", "label": "Community 29", "count": 35}, {"cid": 30, "color": "#4E79A7", "label": "Community 30", "count": 35}, {"cid": 31, "color": "#F28E2B", "label": "Community 31", "count": 33}, {"cid": 32, "color": "#E15759", "label": "Community 32", "count": 31}, {"cid": 33, "color": "#76B7B2", "label": "Community 33", "count": 25}, {"cid": 34, "color": "#59A14F", "label": "Community 34", "count": 24}, {"cid": 35, "color": "#EDC948", "label": "Community 35", "count": 22}, {"cid": 36, "color": "#B07AA1", "label": "Community 36", "count": 20}, {"cid": 37, "color": "#FF9DA7", "label": "Community 37", "count": 19}, {"cid": 38, "color": "#9C755F", "label": "Community 38", "count": 17}, {"cid": 39, "color": "#BAB0AC", "label": "Community 39", "count": 17}, {"cid": 40, "color": "#4E79A7", "label": "Community 40", "count": 16}, {"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": 13}, {"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": 9}, {"cid": 52, "color": "#E15759", "label": "Community 52", "count": 9}, {"cid": 53, "color": "#76B7B2", "label": "Community 53", "count": 8}, {"cid": 54, "color": "#59A14F", "label": "Community 54", "count": 8}, {"cid": 55, "color": "#EDC948", "label": "Community 55", "count": 8}, {"cid": 56, "color": "#B07AA1", "label": "Community 56", "count": 7}, {"cid": 57, "color": "#FF9DA7", "label": "Community 57", "count": 7}, {"cid": 58, "color": "#9C755F", "label": "Community 58", "count": 7}, {"cid": 59, "color": "#BAB0AC", "label": "Community 59", "count": 6}, {"cid": 60, "color": "#4E79A7", "label": "Community 60", "count": 6}, {"cid": 61, "color": "#F28E2B", "label": "Community 61", "count": 5}, {"cid": 62, "color": "#E15759", "label": "Community 62", "count": 5}, {"cid": 63, "color": "#76B7B2", "label": "Community 63", "count": 5}, {"cid": 64, "color": "#59A14F", "label": "Community 64", "count": 5}, {"cid": 65, "color": "#EDC948", "label": "Community 65", "count": 5}, {"cid": 66, "color": "#B07AA1", "label": "Community 66", "count": 5}, {"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": "CommunityLine truncated
// HTML-escape helper — prevents XSS when injecting graph data into innerHTML
function esc(s) {
File diff suppressed because it is too large. Load diff
+14 -13
View File
@@ -17,10 +17,10 @@
"/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": 1787885606.1539679,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/types/import/auto-imports.d.ts": 1787881878.2320535,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/types/store/index.ts": 1781272556.364766,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/types/router/index.ts": 1782394569.8806834,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/types/import/components.d.ts": 1787900576.2954183,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/types/import/auto-imports.d.ts": 1787900560.6600368,
"/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": 1783921717.4015942,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/composables/useAttachmentDropZone.ts": 1782873161.9839864,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/locales/index.ts": 1781272556.3657222,
@@ -62,7 +62,7 @@
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-overtime-kit.ts": 1785488982.6957128,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-approval-print-related.ts": 1785145511.865531,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/qc-material-ui.ts": 1781525352.6976836,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/sop-print.ts": 1787881631.4311998,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/sop-print.ts": 1787899876.3465168,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/qc-work-order-tabs.ts": 1787193681.0370538,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-overtime-kit-rule.ts": 1786374586.9544816,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/rmb-upper.test.ts": 1785380467.5004647,
@@ -168,6 +168,7 @@
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/protocol-payment-flow-steps.ts": 1782806499.3099828,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-form-create-related-approval.ts": 1785145511.866155,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/production-step-output.test.ts": 1787019495.9619598,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/oa-history-export.ts": 1787892864.869699,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/loginRsa.ts": 1781272556.4129546,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/chinese-datetime-parse.ts": 1782958233.483039,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/production-task-editor-cache.ts": 1782602746.754815,
@@ -195,7 +196,7 @@
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/form/validator.ts": 1781272556.386984,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/constants/links.ts": 1781272556.3907003,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/constants/index.ts": 1781272556.390974,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/navigation/worktab.ts": 1781272556.391687,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/navigation/worktab.ts": 1787887332.2557578,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/navigation/jump.ts": 1781272556.3920226,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/navigation/route.ts": 1781272556.3928444,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/navigation/index.ts": 1781272556.3933916,
@@ -336,7 +337,6 @@
"/Users/wuzilong/work/00code/zkxw/web-admin/src/components/common/decimal-input/index.vue": 1782893851.5090024,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/OaPostSelect.vue": 1785394386.0894492,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/OaFlowPreview.vue": 1785392987.9755206,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/OaAppHistoryDialog.vue": 1787885605.5324888,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/oa-condition-fields.ts": 1786002784.7150648,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/OaPersonSelect.vue": 1785388355.4534001,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/components/oa-approval/OaOvertimeKit.vue": 1786374594.648936,
@@ -412,7 +412,7 @@
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/cell-product.ts": 1785290097.6330564,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/sample-sms-notification.ts": 1781272556.666838,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/production-waste-output.ts": 1787023802.604376,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/oaApproval.ts": 1787885508.363352,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/oaApproval.ts": 1787892852.5955176,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/material-stock-check.ts": 1781427280.4992144,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/research-donation.ts": 1782893816.502791,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/api/qc-task.ts": 1783327864.9737554,
@@ -500,9 +500,10 @@
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/system/leave/index.vue": 1783326448.934463,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/receive-accounts/index.vue": 1785391037.6431305,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/drafts/index.vue": 1785999332.6019115,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/start/index.vue": 1787885694.2328417,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/start/index.vue": 1787887346.920489,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/form-designer-spike/index.vue": 1785145511.870818,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/done/index.vue": 1786416827.7349942,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/history/index.vue": 1787896445.8062387,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/mine/index.vue": 1786416848.7317674,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/designer/index.vue": 1786415778.485927,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/oa-approval/instances/detail.vue": 1785990793.1733682,
@@ -577,7 +578,7 @@
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/consumable/index.vue": 1783326448.950747,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/consumable/ConsumablePackTab.vue": 1783326448.951496,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cleanroom-garment/index.vue": 1783326448.9530618,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-material/index.vue": 1785210206.2032187,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-material/index.vue": 1787901052.2520447,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-material/MaterialConsumptionTab.vue": 1785210280.6240091,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-material/ProductionMaterialConfiguredCatalogDialog.vue": 1785210135.312117,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-material/ProductionMaterialUsageTab.vue": 1785209913.2979107,
@@ -639,7 +640,7 @@
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/lab-test-item/index.vue": 1782893853.832618,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/lab-test-item/ThirdPartyCompanyTab.vue": 1783326448.9753742,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/my-qc-material-usage/index.vue": 1782893853.6503608,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-material/index.vue": 1787115003.8945668,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-material/index.vue": 1787900942.2708254,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-material/QcMaterialStockCheckTab.vue": 1783326448.981454,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-material/QcMaterialUsageTab.vue": 1783429524.2582674,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/views/quality-inspection/qc-material/QcMaterialMonthImportDialog.vue": 1787118965.9649005,
@@ -720,7 +721,7 @@
"/Users/wuzilong/work/00code/zkxw/web-admin/src/assets/svg/loading.ts": 1781272558.486104,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/store/index.ts": 1781272559.227605,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/store/modules/qc-menu-badge.ts": 1782394567.2213001,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/store/modules/worktab.ts": 1781351182.1456184,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/store/modules/worktab.ts": 1787887329.153417,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/store/modules/table.ts": 1781272559.2465377,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/store/modules/oa-menu-badge.ts": 1785990702.1987846,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/store/modules/menu.ts": 1781272559.2476027,
@@ -737,7 +738,7 @@
"/Users/wuzilong/work/00code/zkxw/web-admin/src/router/core/RoutePermissionValidator.ts": 1781272559.4235668,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/router/core/index.ts": 1781272559.424284,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/router/core/IframeRouteManager.ts": 1781272559.425215,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/router/modules/sqxp.ts": 1787112428.2639441,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/router/modules/sqxp.ts": 1787887334.7914455,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/router/modules/index.ts": 1781272559.5419338,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/router/modules/exception.ts": 1781272559.549901,
"/Users/wuzilong/work/00code/zkxw/web-admin/src/router/routes/staticRoutes.ts": 1781272559.596198,
+33
View File
@@ -386,6 +386,39 @@ export function fetchOaInstanceHistory(params: {
})
}
export function fetchOaInstanceHistoryExport(params: {
appId: string
instanceId?: string
instanceIds?: string
instanceStatus?: string
initiatorName?: string
applyTimeFrom?: string
applyTimeTo?: string
finishTimeFrom?: string
finishTimeTo?: string
}) {
return request.get<{
appName?: string
businessColumns?: Array<{
key: string
label: string
kind?: string
subLabel?: string
}>
fixedColumns?: Array<{ key: string; label: string }>
rows?: Array<{
index?: number
id?: string
business?: Record<string, string>
fixed?: Record<string, string>
}>
total?: number
}>({
url: `${BASE}/instances/history/export`,
params
})
}
export function fetchOaPendingTaskCount() {
return request.get<{ count: number }>({ url: `${BASE}/tasks/pending/count` })
}
@@ -1,388 +0,0 @@
<!-- OA 发起审批 · 单流程历史记录弹窗 -->
<template>
<el-dialog
v-model="visible"
class="dialog-form-layout"
:title="`历史记录 · ${appName}`"
width="1080px"
append-to-body
destroy-on-close
align-center
modal-class="protocol-dialog-mask"
@closed="onClosed"
>
<div class="filter-block">
<el-form :model="searchForm" class="filter-form" @submit.prevent>
<div class="filter-grid">
<el-form-item label="流程名称">
<el-input :model-value="appName" readonly placeholder="流程名称" />
</el-form-item>
<el-form-item label="审批状态">
<el-select v-model="searchForm.instanceStatus" placeholder="全部" clearable>
<el-option label="全部" value="" />
<el-option label="进行中" value="running" />
<el-option label="已完成" value="completed" />
<el-option label="已拒绝" value="rejected" />
<el-option label="已打回" value="returned" />
<el-option label="已撤销" value="cancelled" />
</el-select>
</el-form-item>
<el-form-item label="审批 ID">
<el-input
v-model="searchForm.instanceId"
placeholder="请输入审批 ID"
clearable
/>
</el-form-item>
<el-form-item label="发起时间">
<el-date-picker
v-model="applyTimeRange"
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="YYYY-MM-DD"
style="width: 100%"
/>
</el-form-item>
<el-form-item label="完成时间">
<el-date-picker
v-model="finishTimeRange"
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="YYYY-MM-DD"
style="width: 100%"
/>
</el-form-item>
<el-form-item v-if="canViewAll" label="申请人">
<el-input
v-model="searchForm.initiatorName"
placeholder="请输入申请人"
clearable
/>
</el-form-item>
</div>
<div class="filter-actions-row">
<div class="filter-actions-end">
<el-button class="btn-ghost" @click="handleReset">
<el-icon><RefreshLeft /></el-icon>
重置
</el-button>
<el-button class="btn-main" type="primary" @click="handleSearch">
<el-icon><Search /></el-icon>
搜索
</el-button>
</div>
</div>
</el-form>
</div>
<div class="list-body list-wrap">
<el-table
class="list-table"
:data="rows"
v-loading="loading"
stripe
empty-text="暂无历史记录"
>
<el-table-column
type="index"
label="序号"
min-width="68"
align="center"
header-align="center"
:index="indexMethod"
/>
<el-table-column
prop="id"
label="审批 ID"
min-width="160"
align="center"
header-align="center"
show-overflow-tooltip
>
<template #default="{ row }">{{ row.id || '-' }}</template>
</el-table-column>
<el-table-column
prop="appName"
label="流程名称"
min-width="140"
align="center"
header-align="center"
show-overflow-tooltip
>
<template #default="{ row }">{{ row.appName || appName || '-' }}</template>
</el-table-column>
<el-table-column
prop="initiatorUserName"
label="申请人"
min-width="100"
align="center"
header-align="center"
>
<template #default="{ row }">{{ row.initiatorUserName || '-' }}</template>
</el-table-column>
<el-table-column
v-for="label in previewFieldLabels"
:key="label"
:label="label"
min-width="120"
align="center"
header-align="center"
show-overflow-tooltip
>
<template #default="{ row }">{{ previewValue(row, label) }}</template>
</el-table-column>
<el-table-column
prop="applyTime"
label="发起时间"
min-width="170"
align="center"
header-align="center"
>
<template #default="{ row }">{{ row.applyTime || '-' }}</template>
</el-table-column>
<el-table-column
prop="finishTime"
label="完成时间"
min-width="170"
align="center"
header-align="center"
>
<template #default="{ row }">{{ row.finishTime || '-' }}</template>
</el-table-column>
<el-table-column
prop="instanceStatus"
label="审批状态"
min-width="110"
align="center"
header-align="center"
>
<template #default="{ row }">
<el-tag size="small" :type="statusType(row.instanceStatus || row.status)">
{{ statusText(row.instanceStatus || row.status) }}
</el-tag>
</template>
</el-table-column>
<el-table-column
prop="currentNodeName"
label="当前节点"
min-width="140"
align="center"
header-align="center"
show-overflow-tooltip
>
<template #default="{ row }">{{ row.currentNodeName || '-' }}</template>
</el-table-column>
<el-table-column label="操作" min-width="260" fixed="right" align="center">
<template #default="{ row }">
<el-button class="btn-op-item primary" @click="openDetail(row)">
<el-icon><View /></el-icon>
查看
</el-button>
<el-button
class="btn-op-item"
:loading="printingId === row.id"
@click="printRow(row)"
>
<el-icon><Printer /></el-icon>
打印
</el-button>
</template>
</el-table-column>
</el-table>
<div class="pagination list-pager-bar">
<el-pagination
v-model:current-page="page"
v-model:page-size="pageSize"
:total="total"
:page-sizes="[10, 20, 50]"
layout="total, sizes, prev, pager, next"
background
@size-change="load"
@current-change="load"
/>
</div>
</div>
</el-dialog>
</template>
<script setup lang="ts">
import { Printer, RefreshLeft, Search, View } from '@element-plus/icons-vue'
import { fetchOaInstanceDetail, fetchOaInstanceHistory } from '@/api/oaApproval'
import { useMenuPerm } from '@/hooks/core/useMenuPerm'
import { useUserStore } from '@/store/modules/user'
import { exportOaApprovalPdf } from '@/utils/oa-approval-print'
defineOptions({ name: 'OaAppHistoryDialog' })
const OA_START_HISTORY_ALL = 'oa:start:history:all'
const { hasMenuPerm } = useMenuPerm()
const canViewAll = computed(() => hasMenuPerm(OA_START_HISTORY_ALL))
const router = useRouter()
const userStore = useUserStore()
const visible = ref(false)
const appId = ref('')
const appName = ref('')
const loading = ref(false)
const printingId = ref('')
const rows = ref<any[]>([])
const page = ref(1)
const pageSize = ref(20)
const total = ref(0)
const applyTimeRange = ref<string[] | null>(null)
const finishTimeRange = ref<string[] | null>(null)
const searchForm = reactive({
instanceStatus: '',
instanceId: '',
initiatorName: ''
})
const previewFieldLabels = computed(() => {
const labels: string[] = []
for (const row of rows.value) {
for (const f of row.previewFields || []) {
const lb = String(f?.label || '').trim()
if (lb && !labels.includes(lb)) labels.push(lb)
}
}
return labels.slice(0, 6)
})
function indexMethod(index: number) {
return (page.value - 1) * pageSize.value + index + 1
}
function previewValue(row: any, label: string) {
const hit = (row.previewFields || []).find((f: any) => f.label === label)
return hit?.value || '-'
}
function currentPrinterName() {
const info: any = userStore.info || userStore.getUserInfo || {}
return String(
info.realName || info.nickName || info.userName || info.username || ''
).trim()
}
function statusType(s: string) {
if (s === 'pending' || s === 'running') return 'warning'
if (s === 'approved' || s === 'completed' || s === 'done') return 'success'
if (s === 'rejected' || s === 'cancelled' || s === 'returned') return 'danger'
return 'info'
}
function statusText(s: string) {
if (!s) return '-'
const map: Record<string, string> = {
pending: '待处理',
running: '进行中',
approved: '已同意',
rejected: '已拒绝',
completed: '已完成',
cancelled: '已撤销',
done: '已结束',
returned: '已打回',
transferred: '已转交'
}
return map[s] || s
}
function resetFilters() {
searchForm.instanceStatus = ''
searchForm.instanceId = ''
searchForm.initiatorName = ''
applyTimeRange.value = null
finishTimeRange.value = null
page.value = 1
}
function open(app: { id: string; appName?: string }) {
appId.value = String(app?.id || '').trim()
appName.value = String(app?.appName || '').trim()
resetFilters()
visible.value = true
void load()
}
function onClosed() {
rows.value = []
total.value = 0
printingId.value = ''
}
function handleSearch() {
page.value = 1
void load()
}
function handleReset() {
resetFilters()
void load()
}
async function load() {
if (!appId.value) return
loading.value = true
try {
const params: any = {
appId: appId.value,
instanceId: searchForm.instanceId || undefined,
instanceStatus: searchForm.instanceStatus || undefined,
applyTimeFrom: applyTimeRange.value?.[0],
applyTimeTo: applyTimeRange.value?.[1],
finishTimeFrom: finishTimeRange.value?.[0],
finishTimeTo: finishTimeRange.value?.[1],
page: page.value,
pageSize: pageSize.value
}
if (canViewAll.value && searchForm.initiatorName) {
params.initiatorName = searchForm.initiatorName
}
const data = await fetchOaInstanceHistory(params)
rows.value = data?.list || []
total.value = Number(data?.total || 0)
} catch {
rows.value = []
total.value = 0
} finally {
loading.value = false
}
}
function openDetail(row: any) {
const id = row?.id
if (!id) return
visible.value = false
router.push({ path: `/system-manage/oa-approval/instances/${id}` })
}
async function printRow(row: any) {
const id = String(row?.id || '').trim()
if (!id || printingId.value) return
printingId.value = id
let detail: any
try {
detail = await fetchOaInstanceDetail(id)
} catch {
printingId.value = ''
ElMessage.error('加载审批单失败')
return
}
try {
await exportOaApprovalPdf(detail, { printerName: currentPrinterName() })
ElMessage.success('PDF 已下载')
} catch {
ElMessage.error('导出 PDF 失败')
} finally {
printingId.value = ''
}
}
defineExpose({ open })
</script>
+13
View File
@@ -1444,6 +1444,19 @@ export const sqxpAdminRoutes: AppRouteRecord[] = [
menuCode: 'oa:start'
}
},
{
id: 'OA000000000000000000000000000203',
name: 'OaApprovalHistory',
path: 'history/:appId',
component: '/oa-approval/history/index',
meta: {
title: '历史记录',
keepAlive: true,
isHide: true,
worktabMulti: true,
menuCode: 'oa:start'
}
},
{
id: 'OA000000000000000000000000000109',
name: 'OaApprovalDrafts',
+13 -4
View File
@@ -206,9 +206,9 @@ export const useWorktabStore = defineStore(
removeKeepAliveExclude(tab.name)
}
// 先根据路由名称查找(应对动态路由参数导致的多开问题),找不到再根据路径查找
// 默认:先按 name 复用(动态参数同页);worktabMulti 仅按 path 匹配以支持同 name 多开
let existingIndex = -1
if (tab.name) {
if (!tab.worktabMulti && tab.name) {
existingIndex = opened.value.findIndex((t) => t.name === tab.name)
}
if (existingIndex === -1) {
@@ -239,6 +239,7 @@ export const useWorktabStore = defineStore(
title: tab.title || existingTab.title,
fixedTab: tab.fixedTab ?? existingTab.fixedTab,
keepAlive: tab.keepAlive ?? existingTab.keepAlive,
worktabMulti: tab.worktabMulti ?? existingTab.worktabMulti,
name: tab.name || existingTab.name,
icon: tab.icon || existingTab.icon
}
@@ -430,6 +431,8 @@ export const useWorktabStore = defineStore(
*/
const addKeepAliveExclude = (tab: WorkTab): void => {
if (!tab.keepAlive || !tab.name) return
// 同 name 多开:仍有其它同名标签时勿排除,否则会清掉其它实例缓存
if (opened.value.some((t) => t.name === tab.name)) return
if (!keepAliveExclude.value.includes(tab.name)) {
keepAliveExclude.value.push(tab.name)
@@ -449,9 +452,15 @@ export const useWorktabStore = defineStore(
* 将传入的一组选项卡的组件名称标记为排除缓存
*/
const markTabsToRemove = (tabs: WorkTab[]): void => {
const removePaths = new Set(tabs.map((t) => t.path))
tabs.forEach((tab) => {
if (tab.name) {
addKeepAliveExclude(tab)
if (!tab.keepAlive || !tab.name) return
const stillOpen = opened.value.some(
(t) => t.name === tab.name && !removePaths.has(t.path)
)
if (stillOpen) return
if (!keepAliveExclude.value.includes(tab.name)) {
keepAliveExclude.value.push(tab.name)
}
})
}
+5
View File
@@ -60,6 +60,11 @@ export interface RouteMeta extends Record<string | number | symbol, unknown> {
roles?: string[]
/** 是否固定标签页 */
fixedTab?: boolean
/**
* 同路由 name 允许多开(按完整 path 区分)
* 用于如「历史记录/:appId」等需同时保留多份的页面
*/
worktabMulti?: boolean
/** 激活菜单路径 */
activePath?: string
/** 是否为全屏页面 */
+5
View File
@@ -91,6 +91,11 @@ export interface WorkTab {
keepAlive: boolean
/** 是否固定标签 */
fixedTab?: boolean
/**
* 同路由 name 允许多开(按 path 区分,如历史记录按 appId)
* 为 true 时 openTab 不按 name 复用已有标签
*/
worktabMulti?: boolean
/** 路由参数 */
params?: object
/** 路由查询参数 */
+2 -1
View File
@@ -63,7 +63,8 @@ export const setWorktab = (to: RouteLocationNormalized): void => {
keepAlive: meta.keepAlive as boolean,
params,
query,
fixedTab: meta.fixedTab as boolean
fixedTab: meta.fixedTab as boolean,
worktabMulti: Boolean(meta.worktabMulti)
})
}
}
+201
View File
@@ -0,0 +1,201 @@
import ExcelJS from 'exceljs'
import FileSaver from 'file-saver'
export type OaHistoryExportColumn = {
key: string
label: string
kind?: 'business' | 'related'
subLabel?: string
}
export type OaHistoryExportFixedColumn = {
key: string
label: string
}
export type OaHistoryExportRow = {
index?: number
id?: string
business?: Record<string, string>
fixed?: Record<string, string>
}
export type OaHistoryExportPayload = {
appName?: string
businessColumns?: OaHistoryExportColumn[]
fixedColumns?: OaHistoryExportFixedColumn[]
rows?: OaHistoryExportRow[]
}
type SheetColumn = {
key: string
label: string
subLabel?: string
width: number
}
const HEADER_FILL: ExcelJS.Fill = {
type: 'pattern',
pattern: 'solid',
fgColor: { argb: 'FFF0FDF4' }
}
const HEADER_FONT: Partial<ExcelJS.Font> = {
bold: true,
color: { argb: 'FF065F46' },
size: 11
}
const BORDER: Partial<ExcelJS.Borders> = {
top: { style: 'thin', color: { argb: 'FFE2E8F0' } },
left: { style: 'thin', color: { argb: 'FFE2E8F0' } },
bottom: { style: 'thin', color: { argb: 'FFE2E8F0' } },
right: { style: 'thin', color: { argb: 'FFE2E8F0' } }
}
function pad(n: number) {
return String(n).padStart(2, '0')
}
function exportTimestamp() {
const d = new Date()
return (
`${d.getFullYear()}${pad(d.getMonth() + 1)}${pad(d.getDate())}` +
`${pad(d.getHours())}${pad(d.getMinutes())}${pad(d.getSeconds())}`
)
}
function sanitizeFilename(name: string) {
return String(name || '历史记录')
.replace(/[\\/:*?"<>|]/g, '_')
.trim()
}
function styleHeaderCell(cell: ExcelJS.Cell) {
cell.fill = HEADER_FILL
cell.font = HEADER_FONT
cell.alignment = { vertical: 'middle', horizontal: 'center', wrapText: true }
cell.border = BORDER
}
function styleBodyCell(cell: ExcelJS.Cell) {
cell.alignment = { vertical: 'top', horizontal: 'left', wrapText: true }
cell.border = BORDER
}
function buildSheetColumns(payload: OaHistoryExportPayload): SheetColumn[] {
const cols: SheetColumn[] = [
{ key: '__index', label: '序号', width: 8 },
{ key: '__id', label: '数据id', width: 28 }
]
for (const col of payload.businessColumns || []) {
if (col.kind === 'related') {
cols.push({ key: col.key, label: col.label, width: 18 })
cols.push({
key: `${col.key}__titles`,
label: col.label,
subLabel: col.subLabel || '关联标题',
width: 24
})
} else {
cols.push({ key: col.key, label: col.label, width: 20 })
}
}
for (const col of payload.fixedColumns || []) {
cols.push({
key: col.key,
label: col.label,
width: col.key === 'approvalRecord' ? 48 : 18
})
}
return cols
}
function cellValue(row: OaHistoryExportRow, key: string) {
if (key === '__index') return row.index ?? ''
if (key === '__id') return row.id ?? ''
const fixed = row.fixed || {}
const business = row.business || {}
if (key in fixed) return fixed[key] ?? ''
return business[key] ?? ''
}
function writeHeaderRows(worksheet: ExcelJS.Worksheet, sheetColumns: SheetColumn[]) {
const headerRow1 = worksheet.getRow(1)
const headerRow2 = worksheet.getRow(2)
headerRow1.height = 24
headerRow2.height = 20
let colIdx = 1
let i = 0
while (i < sheetColumns.length) {
const col = sheetColumns[i]
const next = sheetColumns[i + 1]
const isRelatedPair = Boolean(next?.subLabel && next.label === col.label && !col.subLabel)
if (isRelatedPair) {
const c1 = headerRow1.getCell(colIdx)
c1.value = col.label
styleHeaderCell(c1)
worksheet.mergeCells(1, colIdx, 1, colIdx + 1)
const c2a = headerRow2.getCell(colIdx)
c2a.value = ''
styleHeaderCell(c2a)
const c2b = headerRow2.getCell(colIdx + 1)
c2b.value = next.subLabel || '关联标题'
styleHeaderCell(c2b)
colIdx += 2
i += 2
continue
}
const c1 = headerRow1.getCell(colIdx)
c1.value = col.label
styleHeaderCell(c1)
const c2 = headerRow2.getCell(colIdx)
c2.value = ''
styleHeaderCell(c2)
worksheet.mergeCells(1, colIdx, 2, colIdx)
colIdx += 1
i += 1
}
}
export async function downloadOaHistoryExcel(
payload: OaHistoryExportPayload,
options?: { filenamePrefix?: string }
) {
const rows = payload.rows || []
if (!rows.length) {
throw new Error('暂无可导出数据')
}
const sheetColumns = buildSheetColumns(payload)
const workbook = new ExcelJS.Workbook()
const sheetName = sanitizeFilename(payload.appName || '历史记录').slice(0, 31)
const worksheet = workbook.addWorksheet(sheetName)
worksheet.columns = sheetColumns.map((c) => ({ width: c.width }))
writeHeaderRows(worksheet, sheetColumns)
rows.forEach((row, rowIndex) => {
const excelRow = worksheet.getRow(rowIndex + 3)
sheetColumns.forEach((col, i) => {
const cell = excelRow.getCell(i + 1)
cell.value = cellValue(row, col.key)
styleBodyCell(cell)
})
})
worksheet.views = [{ state: 'frozen', ySplit: 2 }]
const buffer = await workbook.xlsx.writeBuffer()
const prefix = sanitizeFilename(options?.filenamePrefix || payload.appName || '历史记录')
const blob = new Blob([buffer], {
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
})
FileSaver.saveAs(blob, `${prefix}-${exportTimestamp()}.xlsx`)
}
@@ -74,7 +74,7 @@ export const PRODUCTION_WORK_ORDER_TABS: ProductionWorkOrderTabConfig[] = [
},
{
key: 'temporary',
label: '临时生产',
label: '扩增/传代生产',
group: 'temporary',
workOrderType: 'temporary',
listLayout: 'standalone'
+8
View File
@@ -119,6 +119,14 @@ const SOP_SHARED_CONTENT_STYLE = `
.sop-body-table tbody {
height: 100%;
}
.sop-header-table.sop-row-hidden,
.sop-body-table tr.sop-row-hidden {
display: none !important;
}
.sop-record.sop-a4:has(.sop-row-hidden) {
min-height: auto !important;
height: auto !important;
}
.sop-body-table tr.sop-fill-row {
height: 100%;
}
@@ -0,0 +1,874 @@
<!-- OA 发起审批 · 单流程历史记录(WorkTab 页,按 appId 多开) -->
<template>
<div class="page-container">
<section class="panel">
<div class="panel-top">
<h2 class="title-bar-heading">{{ pageTitle }}</h2>
</div>
<div class="filter-block">
<el-form :model="searchForm" class="filter-form" @submit.prevent>
<div class="filter-grid">
<el-form-item label="流程名称">
<el-input :model-value="appName" readonly placeholder="流程名称" />
</el-form-item>
<el-form-item label="审批状态">
<el-select v-model="searchForm.instanceStatus" placeholder="全部" clearable>
<el-option label="全部" value="" />
<el-option label="进行中" value="running" />
<el-option label="已完成" value="completed" />
<el-option label="已拒绝" value="rejected" />
<el-option label="已打回" value="returned" />
<el-option label="已撤销" value="cancelled" />
</el-select>
</el-form-item>
<el-form-item label="审批 ID">
<el-input
v-model="searchForm.instanceId"
placeholder="请输入审批 ID"
clearable
/>
</el-form-item>
<el-form-item label="发起时间">
<el-date-picker
v-model="applyTimeRange"
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="YYYY-MM-DD"
style="width: 100%"
/>
</el-form-item>
<el-form-item label="完成时间">
<el-date-picker
v-model="finishTimeRange"
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="YYYY-MM-DD"
style="width: 100%"
/>
</el-form-item>
<el-form-item v-if="canViewAll" label="申请人">
<el-input
v-model="searchForm.initiatorName"
placeholder="请输入申请人"
clearable
/>
</el-form-item>
</div>
<div class="filter-actions-row">
<div class="filter-actions-end">
<el-button class="btn-ghost" @click="handleReset">
<el-icon><RefreshLeft /></el-icon>
重置
</el-button>
<el-button class="btn-main" type="primary" @click="handleSearch">
<el-icon><Search /></el-icon>
搜索
</el-button>
</div>
</div>
</el-form>
</div>
<div class="list-toolbar">
<div class="list-toolbar-row">
<div class="list-toolbar-selected">
已选 <span class="sel-num">{{ selectedRows.length }}</span> 项
</div>
<el-button
class="btn-ghost"
:disabled="selectedRows.length === 0 || exporting"
:loading="exporting && exportMode === 'selected'"
@click="handleExportSelected"
>
<el-icon><Download /></el-icon>
导出勾选
</el-button>
<el-button
class="btn-ghost"
:disabled="total <= 0 || exporting"
:loading="exporting && exportMode === 'all'"
@click="handleExportAll"
>
<el-icon><Download /></el-icon>
导出全部
</el-button>
</div>
</div>
<div class="list-body list-wrap">
<el-table
class="list-table"
:data="rows"
v-loading="loading"
stripe
row-key="id"
empty-text="暂无历史记录"
@selection-change="onSelectionChange"
@row-dblclick="openDetail"
>
<el-table-column type="selection" min-width="55" align="center" header-align="center" />
<el-table-column
type="index"
label="序号"
min-width="68"
align="center"
header-align="center"
:index="indexMethod"
/>
<el-table-column
prop="id"
label="审批 ID"
min-width="160"
align="center"
header-align="center"
show-overflow-tooltip
>
<template #default="{ row }">{{ row.id || '-' }}</template>
</el-table-column>
<el-table-column
prop="appName"
label="流程名称"
min-width="140"
align="center"
header-align="center"
show-overflow-tooltip
>
<template #default="{ row }">{{ row.appName || appName || '-' }}</template>
</el-table-column>
<el-table-column
prop="initiatorUserName"
label="申请人"
min-width="100"
align="center"
header-align="center"
>
<template #default="{ row }">{{ row.initiatorUserName || '-' }}</template>
</el-table-column>
<el-table-column
v-for="label in previewFieldLabels"
:key="label"
:label="label"
:min-width="previewColumnMinWidth(label)"
align="center"
header-align="center"
:show-overflow-tooltip="!isUploadPreviewLabel(label)"
>
<template #default="{ row }">
<div
v-if="previewFiles(row, label).length"
class="hist-attach"
:class="{ 'is-multi': previewFiles(row, label).length > 1 }"
>
<div
v-for="(file, idx) in previewFiles(row, label)"
:key="`${file.url}-${idx}`"
class="hist-attach__card"
:title="file.name || '附件'"
>
<div class="hist-attach__preview">
<el-image
v-if="isImageFile(file)"
class="hist-attach__img"
:src="fileFullUrl(file.url)"
:preview-src-list="imagePreviewList(row, label)"
:initial-index="imagePreviewIndex(row, label, file.url)"
fit="cover"
preview-teleported
>
<template #error>
<div class="hist-attach__fallback">
<el-icon :size="18"><Picture /></el-icon>
</div>
</template>
</el-image>
<button
v-else
type="button"
class="hist-attach__doc"
@click="previewFile(file)"
>
<span class="hist-attach__doc-icon">
<el-icon :size="18"><Document /></el-icon>
</span>
<span class="hist-attach__ext">{{ fileExt(file) }}</span>
</button>
<div class="hist-attach__hint" aria-hidden="true">
<el-icon :size="14">
<ZoomIn v-if="isImageFile(file)" />
<View v-else />
</el-icon>
</div>
</div>
<div class="hist-attach__footer">
<span class="hist-attach__name">{{ shortFileLabel(file) }}</span>
<button
type="button"
class="hist-attach__dl"
title="下载"
@click.stop="downloadFile(file)"
>
<el-icon :size="12"><Download /></el-icon>
</button>
</div>
</div>
</div>
<span v-else>{{ previewValue(row, label) }}</span>
</template>
</el-table-column>
<el-table-column
prop="applyTime"
label="发起时间"
min-width="170"
align="center"
header-align="center"
>
<template #default="{ row }">{{ row.applyTime || '-' }}</template>
</el-table-column>
<el-table-column
prop="finishTime"
label="完成时间"
min-width="170"
align="center"
header-align="center"
>
<template #default="{ row }">{{ row.finishTime || '-' }}</template>
</el-table-column>
<el-table-column
prop="instanceStatus"
label="审批状态"
min-width="110"
align="center"
header-align="center"
>
<template #default="{ row }">
<el-tag size="small" :type="statusType(row.instanceStatus || row.status)">
{{ statusText(row.instanceStatus || row.status) }}
</el-tag>
</template>
</el-table-column>
<el-table-column
prop="currentNodeName"
label="当前节点"
min-width="140"
align="center"
header-align="center"
show-overflow-tooltip
>
<template #default="{ row }">{{ row.currentNodeName || '-' }}</template>
</el-table-column>
<el-table-column label="操作" min-width="260" fixed="right" align="center">
<template #default="{ row }">
<el-button class="btn-op-item primary" @click="openDetail(row)">
<el-icon><View /></el-icon>
查看
</el-button>
<el-button
class="btn-op-item"
:loading="printingId === row.id"
@click="printRow(row)"
>
<el-icon><Printer /></el-icon>
打印
</el-button>
</template>
</el-table-column>
</el-table>
<div class="pagination list-pager-bar">
<el-pagination
v-model:current-page="page"
v-model:page-size="pageSize"
:total="total"
:page-sizes="[10, 20, 50]"
layout="total, sizes, prev, pager, next"
background
@size-change="load"
@current-change="load"
/>
</div>
</div>
</section>
</div>
</template>
<script setup lang="ts">
import {
Document,
Download,
Picture,
Printer,
RefreshLeft,
Search,
View,
ZoomIn
} from '@element-plus/icons-vue'
import { fetchOaInstanceDetail, fetchOaInstanceHistory, fetchOaInstanceHistoryExport } from '@/api/oaApproval'
import { attachmentFullUrl } from '@/composables/useAttachmentActions'
import { useMenuPerm } from '@/hooks/core/useMenuPerm'
import { useUserStore } from '@/store/modules/user'
import { useWorktabStore } from '@/store/modules/worktab'
import { downloadAttachmentFile } from '@/utils/download-attachment'
import { downloadOaHistoryExcel } from '@/utils/oa-history-export'
import { exportOaApprovalPdf } from '@/utils/oa-approval-print'
import { isOaUploadImageFile } from '@/utils/oa-upload-file-type'
defineOptions({ name: 'OaApprovalHistory' })
type PreviewFile = { url: string; name: string }
const OA_START_HISTORY_ALL = 'oa:start:history:all'
const { hasMenuPerm } = useMenuPerm()
const canViewAll = computed(() => hasMenuPerm(OA_START_HISTORY_ALL))
const route = useRoute()
const router = useRouter()
const userStore = useUserStore()
const worktabStore = useWorktabStore()
// KeepAlive 多开:setup 时锁定本实例对应的流程,避免全局 route 切走后串数据/标题
const boundAppId = String(route.params.appId || route.query.appId || '').trim()
const boundPath = String(route.path || '')
const boundAppName = ref(String(route.query.appName || '').trim())
const loading = ref(false)
const exporting = ref(false)
const exportMode = ref<'selected' | 'all' | ''>('')
const printingId = ref('')
const selectedRows = ref<any[]>([])
const rows = ref<any[]>([])
const page = ref(1)
const pageSize = ref(20)
const total = ref(0)
const applyTimeRange = ref<string[] | null>(null)
const finishTimeRange = ref<string[] | null>(null)
const searchForm = reactive({
instanceStatus: '',
instanceId: '',
initiatorName: ''
})
const appId = computed(() => boundAppId)
const appName = computed(() => boundAppName.value)
const pageTitle = computed(() =>
appName.value ? `历史记录 · ${appName.value}` : '历史记录'
)
function isActiveHistoryInstance() {
return (
route.name === 'OaApprovalHistory' &&
String(route.params.appId || route.query.appId || '').trim() === boundAppId
)
}
const previewFieldLabels = computed(() => {
const labels: string[] = []
for (const row of rows.value) {
for (const f of row.previewFields || []) {
const lb = String(f?.label || '').trim()
if (lb && !labels.includes(lb)) labels.push(lb)
}
}
return labels.slice(0, 6)
})
const uploadPreviewLabels = computed(() => {
const set = new Set<string>()
for (const row of rows.value) {
for (const f of row.previewFields || []) {
const lb = String(f?.label || '').trim()
if (!lb) continue
const files = Array.isArray(f?.files) ? f.files : []
if (files.length || isUploadFieldType(f?.fieldType)) set.add(lb)
}
}
return set
})
function isUploadFieldType(t: unknown) {
const s = String(t || '')
return s === 'upload' || s === 'fcUpload' || s === 'image' || s === 'oaAttachment'
}
function isUploadPreviewLabel(label: string) {
return uploadPreviewLabels.value.has(label)
}
function previewColumnMinWidth(label: string) {
return isUploadPreviewLabel(label) ? 168 : 120
}
function syncWorktabTitle() {
if (!isActiveHistoryInstance() || !boundPath) return
worktabStore.updateTabTitle(boundPath, pageTitle.value)
}
function indexMethod(index: number) {
return (page.value - 1) * pageSize.value + index + 1
}
function onSelectionChange(selection: any[]) {
selectedRows.value = selection
}
function buildExportParams(instanceIds?: string[]) {
const params: Record<string, string> = { appId: appId.value }
if (searchForm.instanceId) params.instanceId = searchForm.instanceId
if (searchForm.instanceStatus) params.instanceStatus = searchForm.instanceStatus
if (applyTimeRange.value?.[0]) params.applyTimeFrom = applyTimeRange.value[0]
if (applyTimeRange.value?.[1]) params.applyTimeTo = applyTimeRange.value[1]
if (finishTimeRange.value?.[0]) params.finishTimeFrom = finishTimeRange.value[0]
if (finishTimeRange.value?.[1]) params.finishTimeTo = finishTimeRange.value[1]
if (canViewAll.value && searchForm.initiatorName) {
params.initiatorName = searchForm.initiatorName
}
if (instanceIds?.length) {
params.instanceIds = instanceIds.join(',')
}
return params
}
async function runExport(instanceIds?: string[]) {
if (!appId.value) {
ElMessage.warning('缺少流程信息,无法导出')
return
}
exporting.value = true
try {
const data = await fetchOaInstanceHistoryExport(buildExportParams(instanceIds))
if (!data?.rows?.length) {
ElMessage.warning('暂无可导出数据')
return
}
await downloadOaHistoryExcel(data, {
filenamePrefix: appName.value || data.appName || '历史记录'
})
ElMessage.success(`已导出 ${data.rows.length} 条`)
} catch {
ElMessage.error('导出失败')
} finally {
exporting.value = false
exportMode.value = ''
}
}
function handleExportSelected() {
const ids = selectedRows.value.map((r) => String(r?.id || '').trim()).filter(Boolean)
if (!ids.length) {
ElMessage.warning('请先勾选要导出的记录')
return
}
exportMode.value = 'selected'
void runExport(ids)
}
function handleExportAll() {
if (total.value <= 0) {
ElMessage.warning('暂无可导出数据')
return
}
exportMode.value = 'all'
void runExport()
}
function previewField(row: any, label: string) {
return (row.previewFields || []).find((f: any) => f.label === label)
}
function previewValue(row: any, label: string) {
const hit = previewField(row, label)
return hit?.value || '-'
}
function previewFiles(row: any, label: string): PreviewFile[] {
const hit = previewField(row, label)
const files = Array.isArray(hit?.files) ? hit.files : []
return files
.map((f: any) => ({
url: String(f?.url || '').trim(),
name: String(f?.name || '').trim()
}))
.filter((f: PreviewFile) => !!f.url)
}
function fileFullUrl(url: string) {
return attachmentFullUrl(url) || url
}
function isImageFile(file: PreviewFile) {
return isOaUploadImageFile({ url: file.url, name: file.name })
}
function fileExt(file: PreviewFile) {
const name = String(file.name || file.url || '')
const m = name.match(/\.([a-z0-9]+)(?:\?|$)/i)
return (m?.[1] || 'FILE').toUpperCase().slice(0, 4)
}
/** 列表内短名:UUID 文件名改为「图片/文件.ext」,避免一长串哈希 */
function shortFileLabel(file: PreviewFile) {
const raw = String(file.name || '').trim()
if (!raw) return isImageFile(file) ? '图片' : '附件'
const extMatch = raw.match(/\.([a-z0-9]+)$/i)
const ext = extMatch?.[1] || ''
const base = ext ? raw.slice(0, -(ext.length + 1)) : raw
if (/^[a-f0-9_-]{16,}$/i.test(base)) {
if (isImageFile(file)) return ext ? `图片.${ext.toLowerCase()}` : '图片'
return ext ? `文件.${ext.toLowerCase()}` : '文件'
}
if (raw.length <= 14) return raw
if (ext) {
const keep = Math.max(4, 10 - ext.length)
return `${base.slice(0, keep)}….${ext.toLowerCase()}`
}
return `${raw.slice(0, 12)}…`
}
function imagePreviewList(row: any, label: string) {
return previewFiles(row, label)
.filter((f) => isImageFile(f))
.map((f) => fileFullUrl(f.url))
}
function imagePreviewIndex(row: any, label: string, url: string) {
const list = previewFiles(row, label).filter((f) => isImageFile(f))
const idx = list.findIndex((f) => f.url === url)
return idx >= 0 ? idx : 0
}
function previewFile(file: PreviewFile) {
const url = fileFullUrl(file.url)
if (url) window.open(url, '_blank')
}
function downloadFile(file: PreviewFile) {
void downloadAttachmentFile(
{ fileUrl: file.url, fileName: file.name || undefined },
{ fullFileUrl: (u) => attachmentFullUrl(u) }
)
}
function currentPrinterName() {
const info: any = userStore.info || userStore.getUserInfo || {}
return String(
info.realName || info.nickName || info.userName || info.username || ''
).trim()
}
function statusType(s: string) {
if (s === 'pending' || s === 'running') return 'warning'
if (s === 'approved' || s === 'completed' || s === 'done') return 'success'
if (s === 'rejected' || s === 'cancelled' || s === 'returned') return 'danger'
return 'info'
}
function statusText(s: string) {
if (!s) return '-'
const map: Record<string, string> = {
pending: '待处理',
running: '进行中',
approved: '已同意',
rejected: '已拒绝',
completed: '已完成',
cancelled: '已撤销',
done: '已结束',
returned: '已打回',
transferred: '已转交'
}
return map[s] || s
}
function resetFilters() {
searchForm.instanceStatus = ''
searchForm.instanceId = ''
searchForm.initiatorName = ''
applyTimeRange.value = null
finishTimeRange.value = null
page.value = 1
}
function handleSearch() {
page.value = 1
void load()
}
function handleReset() {
resetFilters()
void load()
}
async function load() {
if (!appId.value) {
rows.value = []
total.value = 0
return
}
loading.value = true
try {
const params: any = {
appId: appId.value,
instanceId: searchForm.instanceId || undefined,
instanceStatus: searchForm.instanceStatus || undefined,
applyTimeFrom: applyTimeRange.value?.[0],
applyTimeTo: applyTimeRange.value?.[1],
finishTimeFrom: finishTimeRange.value?.[0],
finishTimeTo: finishTimeRange.value?.[1],
page: page.value,
pageSize: pageSize.value
}
if (canViewAll.value && searchForm.initiatorName) {
params.initiatorName = searchForm.initiatorName
}
const data = await fetchOaInstanceHistory(params)
rows.value = data?.list || []
total.value = Number(data?.total || 0)
} catch {
rows.value = []
total.value = 0
} finally {
loading.value = false
}
}
function openDetail(row: any) {
const id = row?.id
if (!id) return
router.push({ path: `/system-manage/oa-approval/instances/${id}` })
}
async function printRow(row: any) {
const id = String(row?.id || '').trim()
if (!id || printingId.value) return
printingId.value = id
let detail: any
try {
detail = await fetchOaInstanceDetail(id)
} catch {
printingId.value = ''
ElMessage.error('加载审批单失败')
return
}
try {
await exportOaApprovalPdf(detail, { printerName: currentPrinterName() })
ElMessage.success('PDF 已下载')
} catch {
ElMessage.error('导出 PDF 失败')
} finally {
printingId.value = ''
}
}
function bootstrapFromRoute() {
if (!isActiveHistoryInstance()) return
const qName = String(route.query.appName || '').trim()
if (qName) boundAppName.value = qName
resetFilters()
syncWorktabTitle()
void load()
}
watch(
() => [route.name, route.params.appId, route.query.appId, route.query.appName] as const,
() => {
if (!isActiveHistoryInstance()) return
bootstrapFromRoute()
}
)
onMounted(bootstrapFromRoute)
onActivated(() => {
if (!isActiveHistoryInstance()) return
const qName = String(route.query.appName || '').trim()
if (qName) boundAppName.value = qName
syncWorktabTitle()
void load()
})
</script>
<style scoped lang="scss">
.hist-attach {
display: inline-flex;
flex-wrap: wrap;
gap: 8px;
justify-content: center;
max-width: 100%;
padding: 2px 0;
vertical-align: middle;
}
.hist-attach__card {
width: 88px;
overflow: hidden;
background: #fff;
border: 1px solid #e2e8f0;
border-radius: 8px;
transition:
border-color 0.15s ease,
box-shadow 0.15s ease,
transform 0.15s ease;
&:hover {
border-color: #10b981;
box-shadow: 0 4px 12px rgb(16 185 129 / 14%);
transform: translateY(-1px);
.hist-attach__hint {
opacity: 1;
}
}
}
.hist-attach__preview {
position: relative;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 64px;
overflow: hidden;
background: linear-gradient(180deg, #f8fafc 0%, #f1f5f9 100%);
}
.hist-attach__img {
display: block;
width: 100%;
height: 64px;
cursor: zoom-in;
:deep(.el-image__inner) {
width: 100%;
height: 64px;
object-fit: cover;
}
}
.hist-attach__fallback,
.hist-attach__doc {
display: flex;
flex-direction: column;
gap: 4px;
align-items: center;
justify-content: center;
width: 100%;
height: 64px;
padding: 0;
color: #64748b;
cursor: pointer;
background: transparent;
border: none;
}
.hist-attach__doc-icon {
display: flex;
align-items: center;
justify-content: center;
width: 28px;
height: 28px;
color: #0284c7;
background: #e0f2fe;
border-radius: 8px;
}
.hist-attach__ext {
font-size: 10px;
font-weight: 600;
line-height: 1;
color: #475569;
letter-spacing: 0.02em;
}
.hist-attach__hint {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
color: #fff;
pointer-events: none;
background: rgb(15 23 42 / 38%);
opacity: 0;
transition: opacity 0.15s ease;
}
.hist-attach__footer {
display: flex;
gap: 4px;
align-items: center;
min-width: 0;
padding: 5px 6px;
background: #fff;
border-top: 1px solid #f1f5f9;
}
.hist-attach__name {
flex: 1;
min-width: 0;
overflow: hidden;
font-size: 11px;
line-height: 1.3;
color: #334155;
text-align: left;
text-overflow: ellipsis;
white-space: nowrap;
}
.hist-attach__dl {
display: inline-flex;
flex-shrink: 0;
align-items: center;
justify-content: center;
width: 20px;
height: 20px;
padding: 0;
color: #64748b;
cursor: pointer;
background: #f1f5f9;
border: none;
border-radius: 5px;
transition:
background 0.15s ease,
color 0.15s ease;
&:hover {
color: #fff;
background: #10b981;
}
}
.hist-attach.is-multi {
gap: 6px;
.hist-attach__card {
width: 72px;
border-radius: 7px;
}
.hist-attach__preview,
.hist-attach__img,
.hist-attach__fallback,
.hist-attach__doc {
height: 52px;
}
.hist-attach__img :deep(.el-image__inner) {
height: 52px;
}
.hist-attach__footer {
padding: 4px 5px;
}
.hist-attach__name {
font-size: 10px;
}
.hist-attach__dl {
width: 18px;
height: 18px;
}
}
</style>
@@ -93,33 +93,32 @@
@saved="onDialogSaved"
@submitted="onDialogSubmitted"
/>
<OaAppHistoryDialog ref="historyDialogRef" />
</section>
</div>
</template>
<script setup lang="ts">
import { computed, onMounted, ref } from 'vue'
import { computed, onActivated, onMounted, ref } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { Clock, Promotion, Search } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'
import { fetchOaGroupList, fetchOaTemplates } from '@/api/oaApproval'
import OaAppIcon from '@/components/oa-approval/OaAppIcon.vue'
import OaAppHistoryDialog from '@/components/oa-approval/OaAppHistoryDialog.vue'
import OaStartFormDialog from '@/components/oa-approval/OaStartFormDialog.vue'
import { useWorktabStore } from '@/store/modules/worktab'
import { refreshOaMenuBadges } from '@/utils/oa-menu-badge'
defineOptions({ name: 'OaApprovalStart' })
const router = useRouter()
const route = useRoute()
const worktabStore = useWorktabStore()
const loading = ref(false)
const templates = ref<any[]>([])
const groupOptions = ref<Array<{ id: string; groupName: string }>>([])
const searchKeyword = ref('')
const activeGroupId = ref('')
const startDialogRef = ref<InstanceType<typeof OaStartFormDialog> | null>(null)
const historyDialogRef = ref<InstanceType<typeof OaAppHistoryDialog> | null>(null)
const displayGroups = computed(() => {
const kw = (searchKeyword.value || '').trim().toLowerCase()
@@ -168,7 +167,14 @@
}
function openHistory(row: any) {
historyDialogRef.value?.open({ id: row.id, appName: row.appName })
const id = String(row?.id || '').trim()
if (!id) return
router.push({
path: `/system-manage/oa-approval/history/${encodeURIComponent(id)}`,
query: {
appName: String(row?.appName || '').trim()
}
})
}
function onDialogSaved() {
@@ -182,7 +188,16 @@
}
}
function restoreStartTabTitle() {
worktabStore.resetTabTitle('/system-manage/oa-approval/start')
}
onActivated(() => {
restoreStartTabTitle()
})
onMounted(async () => {
restoreStartTabTitle()
loading.value = true
try {
const [tpl, groupsRes] = await Promise.all([fetchOaTemplates(), fetchOaGroupList()])
@@ -2456,16 +2456,98 @@
}
}
function buildBatchStockOutPrefillFromSelection(): {
lines: BatchStockOutLine[]
options: ProductionMaterialBatchOption[]
skippedZero: number
} {
const sel = selectedRows.value || []
const lines: BatchStockOutLine[] = []
const options: ProductionMaterialBatchOption[] = []
const seen = new Set<string>()
let skippedZero = 0
for (const row of sel) {
const rem = Number(row.remainingQty) || 0
if (rem <= 0) {
skippedZero += 1
continue
}
const batchId = row.batchId || row.id
if (!batchId || seen.has(batchId)) continue
seen.add(batchId)
const unit = (row.unit || '').trim()
const mfr = (row.manufacturer || '').trim()
const cat = (row.catalogNo || '').trim()
lines.push({
batchId,
stockInNo: row.stockInNo || '',
materialName: row.materialName || '',
batchNo: row.batchNo || '',
remainingQty: rem,
qty: Math.min(1, rem),
usageUnit: unit,
remark: ''
})
options.push({
id: batchId,
batchId,
stockInNo: row.stockInNo || '',
stockInDate: row.stockInDate,
expireDate: row.expireDate,
productionDate: row.productionDate,
materialId: row.materialId,
materialCode: row.materialCode || '',
materialName: row.materialName || '',
materialType: row.materialType || '',
specModel: row.specModel || '',
unit,
batchNo: row.batchNo || '',
catalogNo: row.catalogNo || '',
manufacturer: row.manufacturer || '',
storageLocation: row.storageLocation,
unitPrice: row.unitPrice,
amount: row.amount,
remainingQty: rem,
label: `${row.stockInNo || ''} / ${row.materialName || ''} / 厂家:${mfr || '—'} / 批号:${
row.batchNo || '—'
} / 货号:${cat || '—'} / 剩:${rem}${unit}`
})
if (unit) ensureUnitOption(unit)
}
return { lines, options, skippedZero }
}
function mergeBatchOptions(extra: ProductionMaterialBatchOption[]) {
if (!extra.length) return
const ids = new Set(batchOptions.value.map((o) => o.id))
const missing = extra.filter((o) => o.id && !ids.has(o.id))
if (missing.length) {
batchOptions.value = [...missing, ...batchOptions.value]
}
}
function handleBatchStockOut() {
batchStockOutLines.value = [newBatchStockOutLine()]
const { lines, options, skippedZero } = buildBatchStockOutPrefillFromSelection()
const selectedCount = (selectedRows.value || []).length
if (selectedCount > 0 && lines.length === 0) {
ElMessage.warning('所选物料剩余数量均为 0,无法出库,请手动选择有库存的批次')
} else if (skippedZero > 0) {
ElMessage.warning(`已跳过 ${skippedZero} 项剩余数量为 0 的物料`)
}
batchStockOutLines.value = lines.length ? lines : [newBatchStockOutLine()]
batchOptions.value = options
batchStockOutForm.stockOutTime = formatNowDatetime()
batchStockOutForm.receiver = ''
batchStockOutForm.purpose = ''
batchStockOutForm.remark = ''
batchStockOutVisible.value = true
void searchReceiverUsers('')
void searchBatchOptions('')
void searchUnitOptions('')
void searchBatchOptions('').then(() => mergeBatchOptions(options))
void searchUnitOptions('').then(() => {
for (const line of batchStockOutLines.value) {
if (line.usageUnit) ensureUnitOption(line.usageUnit)
}
})
batchStockOutFormRef.value?.clearValidate?.()
}
@@ -2434,16 +2434,95 @@
}
}
function buildBatchStockOutPrefillFromSelection(): {
lines: BatchStockOutLine[]
options: QcMaterialBatchOption[]
skippedZero: number
} {
const sel = selectedRows.value || []
const lines: BatchStockOutLine[] = []
const options: QcMaterialBatchOption[] = []
const seen = new Set<string>()
let skippedZero = 0
for (const row of sel) {
const rem = Number(row.remainingQty) || 0
if (rem <= 0) {
skippedZero += 1
continue
}
const batchId = row.batchId || row.id
if (!batchId || seen.has(batchId)) continue
seen.add(batchId)
const unit = (row.unit || '').trim()
const mfr = (row.manufacturer || '').trim()
const cat = (row.catalogNo || '').trim()
lines.push({
batchId,
stockInNo: row.stockInNo || '',
materialName: row.materialName || '',
batchNo: row.batchNo || '',
remainingQty: rem,
qty: Math.min(1, rem),
usageUnit: unit,
remark: ''
})
options.push({
id: batchId,
batchId,
stockInNo: row.stockInNo || '',
stockInDate: row.stockInDate,
expireDate: row.expireDate,
materialId: row.materialId,
materialCode: row.materialCode || '',
materialName: row.materialName || '',
specModel: row.specModel || '',
unit,
batchNo: row.batchNo || '',
catalogNo: row.catalogNo || '',
manufacturer: row.manufacturer || '',
unitPrice: row.unitPrice,
amount: row.amount,
remainingQty: rem,
label: `${row.stockInNo || ''} / ${row.materialName || ''} / 厂家:${mfr || '—'} / 批号:${
row.batchNo || '—'
} / 货号:${cat || '—'} / 剩:${rem}${unit}`
})
if (unit) ensureUnitOption(unit)
}
return { lines, options, skippedZero }
}
function mergeBatchOptions(extra: QcMaterialBatchOption[]) {
if (!extra.length) return
const ids = new Set(batchOptions.value.map((o) => o.id))
const missing = extra.filter((o) => o.id && !ids.has(o.id))
if (missing.length) {
batchOptions.value = [...missing, ...batchOptions.value]
}
}
function handleBatchStockOut() {
batchStockOutLines.value = [newBatchStockOutLine()]
const { lines, options, skippedZero } = buildBatchStockOutPrefillFromSelection()
const selectedCount = (selectedRows.value || []).length
if (selectedCount > 0 && lines.length === 0) {
ElMessage.warning('所选物料剩余数量均为 0,无法出库,请手动选择有库存的批次')
} else if (skippedZero > 0) {
ElMessage.warning(`已跳过 ${skippedZero} 项剩余数量为 0 的物料`)
}
batchStockOutLines.value = lines.length ? lines : [newBatchStockOutLine()]
batchOptions.value = options
batchStockOutForm.stockOutTime = formatNowDatetime()
batchStockOutForm.receiver = ''
batchStockOutForm.purpose = ''
batchStockOutForm.remark = ''
batchStockOutVisible.value = true
void searchReceiverUsers('')
void searchBatchOptions('')
void searchUnitOptions('')
void searchBatchOptions('').then(() => mergeBatchOptions(options))
void searchUnitOptions('').then(() => {
for (const line of batchStockOutLines.value) {
if (line.usageUnit) ensureUnitOption(line.usageUnit)
}
})
batchStockOutFormRef.value?.clearValidate?.()
}