zlwu 5 月之前
父节点
当前提交
93f5801aa9

+ 1 - 1
backend/app.pid

@@ -1 +1 @@
-15653
+56686

+ 4 - 1
backend/app/api/operations.py

@@ -329,7 +329,10 @@ async def list_storage_facilities(
     if keyword:
         query = query.filter(BizStorageFacility.node_name.like(f"%{keyword}%"))
     query = apply_data_scope(query, BizStorageFacility, user, db, tenant_no)
-    items = query.order_by(BizStorageFacility.create_time.desc()).all()
+    items = query.order_by(
+        BizStorageFacility.order_num.asc(),
+        BizStorageFacility.create_time.asc(),
+    ).all()
     result_list = [storage_facility_svc._row_to_dict(r) for r in items]
     return success_response(result_list)
 

文件差异内容过多而无法显示
+ 443 - 460
web-admin/graphify-out/.graphify_analysis.json


+ 233 - 3
web-admin/graphify-out/.graphify_extract.json

@@ -19,7 +19,7 @@
       "label": "refreshPanelTitleIcons()",
       "file_type": "code",
       "source_file": "App.vue",
-      "source_location": "L112"
+      "source_location": "L113"
     },
     {
       "id": "main_ts",
@@ -462,6 +462,69 @@
       "source_file": "utils/patch-el-select-filterable.ts",
       "source_location": "L1"
     },
+    {
+      "id": "utils_storage_slot_options_ts",
+      "label": "storage-slot-options.ts",
+      "file_type": "code",
+      "source_file": "utils/storage-slot-options.ts",
+      "source_location": "L1"
+    },
+    {
+      "id": "utils_storage_slot_options_getstoragefacilityordernum",
+      "label": "getStorageFacilityOrderNum()",
+      "file_type": "code",
+      "source_file": "utils/storage-slot-options.ts",
+      "source_location": "L8"
+    },
+    {
+      "id": "utils_storage_slot_options_getstorageslotordernum",
+      "label": "getStorageSlotOrderNum()",
+      "file_type": "code",
+      "source_file": "utils/storage-slot-options.ts",
+      "source_location": "L15"
+    },
+    {
+      "id": "utils_storage_slot_options_parsestorageslotcode",
+      "label": "parseStorageSlotCode()",
+      "file_type": "code",
+      "source_file": "utils/storage-slot-options.ts",
+      "source_location": "L22"
+    },
+    {
+      "id": "utils_storage_slot_options_comparestoragefacilityslots",
+      "label": "compareStorageFacilitySlots()",
+      "file_type": "code",
+      "source_file": "utils/storage-slot-options.ts",
+      "source_location": "L31"
+    },
+    {
+      "id": "utils_storage_slot_options_sortstoragefacilityslots",
+      "label": "sortStorageFacilitySlots()",
+      "file_type": "code",
+      "source_file": "utils/storage-slot-options.ts",
+      "source_location": "L51"
+    },
+    {
+      "id": "utils_storage_slot_options_collectleaffacilitynodesintreeorder",
+      "label": "collectLeafFacilityNodesInTreeOrder()",
+      "file_type": "code",
+      "source_file": "utils/storage-slot-options.ts",
+      "source_location": "L60"
+    },
+    {
+      "id": "utils_storage_slot_options_mapslotstoselectoptions",
+      "label": "mapSlotsToSelectOptions()",
+      "file_type": "code",
+      "source_file": "utils/storage-slot-options.ts",
+      "source_location": "L112"
+    },
+    {
+      "id": "utils_storage_slot_options_loadstorageslotselectoptions",
+      "label": "loadStorageSlotSelectOptions()",
+      "file_type": "code",
+      "source_file": "utils/storage-slot-options.ts",
+      "source_location": "L128"
+    },
     {
       "id": "utils_user_avatar_ts",
       "label": "user-avatar.ts",
@@ -10694,7 +10757,7 @@
       "relation": "contains",
       "confidence": "EXTRACTED",
       "source_file": "App.vue",
-      "source_location": "L112",
+      "source_location": "L113",
       "weight": 1.0
     },
     {
@@ -11768,6 +11831,123 @@
       "source_location": "L6",
       "weight": 1.0
     },
+    {
+      "source": "utils_storage_slot_options_ts",
+      "target": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_tree_path",
+      "relation": "imports_from",
+      "confidence": "EXTRACTED",
+      "source_file": "utils/storage-slot-options.ts",
+      "source_location": "L4",
+      "weight": 1.0
+    },
+    {
+      "source": "utils_storage_slot_options_ts",
+      "target": "utils_storage_slot_options_getstoragefacilityordernum",
+      "relation": "contains",
+      "confidence": "EXTRACTED",
+      "source_file": "utils/storage-slot-options.ts",
+      "source_location": "L8",
+      "weight": 1.0
+    },
+    {
+      "source": "utils_storage_slot_options_ts",
+      "target": "utils_storage_slot_options_getstorageslotordernum",
+      "relation": "contains",
+      "confidence": "EXTRACTED",
+      "source_file": "utils/storage-slot-options.ts",
+      "source_location": "L15",
+      "weight": 1.0
+    },
+    {
+      "source": "utils_storage_slot_options_ts",
+      "target": "utils_storage_slot_options_parsestorageslotcode",
+      "relation": "contains",
+      "confidence": "EXTRACTED",
+      "source_file": "utils/storage-slot-options.ts",
+      "source_location": "L22",
+      "weight": 1.0
+    },
+    {
+      "source": "utils_storage_slot_options_ts",
+      "target": "utils_storage_slot_options_comparestoragefacilityslots",
+      "relation": "contains",
+      "confidence": "EXTRACTED",
+      "source_file": "utils/storage-slot-options.ts",
+      "source_location": "L31",
+      "weight": 1.0
+    },
+    {
+      "source": "utils_storage_slot_options_ts",
+      "target": "utils_storage_slot_options_sortstoragefacilityslots",
+      "relation": "contains",
+      "confidence": "EXTRACTED",
+      "source_file": "utils/storage-slot-options.ts",
+      "source_location": "L51",
+      "weight": 1.0
+    },
+    {
+      "source": "utils_storage_slot_options_ts",
+      "target": "utils_storage_slot_options_collectleaffacilitynodesintreeorder",
+      "relation": "contains",
+      "confidence": "EXTRACTED",
+      "source_file": "utils/storage-slot-options.ts",
+      "source_location": "L60",
+      "weight": 1.0
+    },
+    {
+      "source": "utils_storage_slot_options_ts",
+      "target": "utils_storage_slot_options_mapslotstoselectoptions",
+      "relation": "contains",
+      "confidence": "EXTRACTED",
+      "source_file": "utils/storage-slot-options.ts",
+      "source_location": "L112",
+      "weight": 1.0
+    },
+    {
+      "source": "utils_storage_slot_options_ts",
+      "target": "utils_storage_slot_options_loadstorageslotselectoptions",
+      "relation": "contains",
+      "confidence": "EXTRACTED",
+      "source_file": "utils/storage-slot-options.ts",
+      "source_location": "L128",
+      "weight": 1.0
+    },
+    {
+      "source": "utils_storage_slot_options_comparestoragefacilityslots",
+      "target": "utils_storage_slot_options_getstorageslotordernum",
+      "relation": "calls",
+      "confidence": "EXTRACTED",
+      "source_file": "utils/storage-slot-options.ts",
+      "source_location": "L35",
+      "weight": 1.0
+    },
+    {
+      "source": "utils_storage_slot_options_comparestoragefacilityslots",
+      "target": "utils_storage_slot_options_parsestorageslotcode",
+      "relation": "calls",
+      "confidence": "EXTRACTED",
+      "source_file": "utils/storage-slot-options.ts",
+      "source_location": "L39",
+      "weight": 1.0
+    },
+    {
+      "source": "utils_storage_slot_options_mapslotstoselectoptions",
+      "target": "utils_storage_slot_options_sortstoragefacilityslots",
+      "relation": "calls",
+      "confidence": "EXTRACTED",
+      "source_file": "utils/storage-slot-options.ts",
+      "source_location": "L120",
+      "weight": 1.0
+    },
+    {
+      "source": "utils_storage_slot_options_loadstorageslotselectoptions",
+      "target": "utils_storage_slot_options_collectleaffacilitynodesintreeorder",
+      "relation": "calls",
+      "confidence": "EXTRACTED",
+      "source_file": "utils/storage-slot-options.ts",
+      "source_location": "L132",
+      "weight": 1.0
+    },
     {
       "source": "utils_user_avatar_ts",
       "target": "utils_user_avatar_defaultavatarpathbyrole",
@@ -25405,7 +25585,7 @@
     },
     {
       "source": "views_production_production_work_order_usetaskstepeditor_ts",
-      "target": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_tree_path",
+      "target": "users_wuzilong_work_00code_zkxw_web_admin_src_utils_storage_slot_options",
       "relation": "imports_from",
       "confidence": "EXTRACTED",
       "source_file": "views/production/production-work-order/useTaskStepEditor.ts",
@@ -29144,6 +29324,56 @@
       "source_location": "L78",
       "weight": 1.0
     },
+    {
+      "source": "utils_storage_slot_options_collectleaffacilitynodesintreeorder",
+      "target": "process_route_index_set",
+      "relation": "calls",
+      "confidence": "INFERRED",
+      "confidence_score": 0.8,
+      "source_file": "utils/storage-slot-options.ts",
+      "source_location": "L69",
+      "weight": 1.0
+    },
+    {
+      "source": "utils_storage_slot_options_collectleaffacilitynodesintreeorder",
+      "target": "process_route_index_get",
+      "relation": "calls",
+      "confidence": "INFERRED",
+      "confidence_score": 0.8,
+      "source_file": "utils/storage-slot-options.ts",
+      "source_location": "L73",
+      "weight": 1.0
+    },
+    {
+      "source": "utils_storage_slot_options_collectleaffacilitynodesintreeorder",
+      "target": "storage_facility_index_push",
+      "relation": "calls",
+      "confidence": "INFERRED",
+      "confidence_score": 0.8,
+      "source_file": "utils/storage-slot-options.ts",
+      "source_location": "L77",
+      "weight": 1.0
+    },
+    {
+      "source": "utils_storage_slot_options_collectleaffacilitynodesintreeorder",
+      "target": "role_index_walk",
+      "relation": "calls",
+      "confidence": "INFERRED",
+      "confidence_score": 0.8,
+      "source_file": "utils/storage-slot-options.ts",
+      "source_location": "L108",
+      "weight": 1.0
+    },
+    {
+      "source": "utils_storage_slot_options_mapslotstoselectoptions",
+      "target": "utils_tree_path_buildtreepathlabelfromflat",
+      "relation": "calls",
+      "confidence": "INFERRED",
+      "confidence_score": 0.8,
+      "source_file": "utils/storage-slot-options.ts",
+      "source_location": "L117",
+      "weight": 1.0
+    },
     {
       "source": "utils_fullscreen_loading_withfullscreenloading",
       "target": "socket_index_websocketclient_close",

+ 135 - 79
web-admin/graphify-out/GRAPH_REPORT.md

@@ -1,11 +1,11 @@
 # Graph Report - src  (2026-05-24)
 
 ## Corpus Check
-- Large corpus: 595 files · ~325,295 words. Semantic extraction will be expensive (many Claude tokens). Consider running on a subfolder, or use --no-semantic to run AST-only.
+- Large corpus: 596 files · ~326,544 words. Semantic extraction will be expensive (many Claude tokens). Consider running on a subfolder, or use --no-semantic to run AST-only.
 
 ## Summary
-- 1515 nodes · 1895 edges · 34 communities detected
-- Extraction: 78% EXTRACTED · 22% INFERRED · 0% AMBIGUOUS · INFERRED: 412 edges (avg confidence: 0.8)
+- 1524 nodes · 1912 edges · 42 communities detected
+- Extraction: 78% EXTRACTED · 22% INFERRED · 0% AMBIGUOUS · INFERRED: 417 edges (avg confidence: 0.8)
 - Token cost: 0 input · 0 output
 
 ## Community Hubs (Navigation)
@@ -32,22 +32,30 @@
 - [[_COMMUNITY_Community 20|Community 20]]
 - [[_COMMUNITY_Community 21|Community 21]]
 - [[_COMMUNITY_Community 22|Community 22]]
+- [[_COMMUNITY_Community 23|Community 23]]
 - [[_COMMUNITY_Community 24|Community 24]]
 - [[_COMMUNITY_Community 26|Community 26]]
-- [[_COMMUNITY_Community 27|Community 27]]
 - [[_COMMUNITY_Community 28|Community 28]]
 - [[_COMMUNITY_Community 29|Community 29]]
+- [[_COMMUNITY_Community 30|Community 30]]
 - [[_COMMUNITY_Community 31|Community 31]]
 - [[_COMMUNITY_Community 32|Community 32]]
 - [[_COMMUNITY_Community 33|Community 33]]
 - [[_COMMUNITY_Community 34|Community 34]]
 - [[_COMMUNITY_Community 35|Community 35]]
-- [[_COMMUNITY_Community 37|Community 37]]
+- [[_COMMUNITY_Community 36|Community 36]]
+- [[_COMMUNITY_Community 38|Community 38]]
+- [[_COMMUNITY_Community 39|Community 39]]
+- [[_COMMUNITY_Community 40|Community 40]]
+- [[_COMMUNITY_Community 41|Community 41]]
+- [[_COMMUNITY_Community 42|Community 42]]
+- [[_COMMUNITY_Community 43|Community 43]]
+- [[_COMMUNITY_Community 45|Community 45]]
 
 ## God Nodes (most connected - your core abstractions)
-1. `get()` - 163 edges
+1. `get()` - 164 edges
 2. `WebSocketClient` - 26 edges
-3. `push()` - 19 edges
+3. `push()` - 20 edges
 4. `withFullscreenLoading()` - 17 edges
 5. `MenuProcessor` - 16 edges
 6. `VersionManager` - 15 edges
@@ -57,186 +65,234 @@
 10. `StorageConfig` - 10 edges
 
 ## Surprising Connections (you probably didn't know these)
+- `handleBatchDelete()` --calls--> `withFullscreenLoading()`  [INFERRED]
+  views/basic-info/customer/index.vue → utils/fullscreen-loading.ts
 - `handleUnauthorizedResponse()` --calls--> `fetchRefreshToken()`  [INFERRED]
   utils/http/index.ts → api/auth.ts
-- `fetchStorageReleaseReviewList()` --calls--> `get()`  [INFERRED]
-  api/storage-release-review.ts → views/production/process-route/index.vue
-- `fetchStorageReleaseReviewDetail()` --calls--> `get()`  [INFERRED]
-  api/storage-release-review.ts → views/production/process-route/index.vue
-- `fetchProcessDefList()` --calls--> `get()`  [INFERRED]
-  api/workflow.ts → views/production/process-route/index.vue
-- `fetchVersionList()` --calls--> `get()`  [INFERRED]
-  api/workflow.ts → views/production/process-route/index.vue
+- `fetchLeaveList()` --calls--> `get()`  [INFERRED]
+  api/leave.ts → views/production/process-route/index.vue
+- `fetchLeaveDetail()` --calls--> `get()`  [INFERRED]
+  api/leave.ts → views/production/process-route/index.vue
+- `fetchSampleReceptionCheckItemList()` --calls--> `get()`  [INFERRED]
+  api/sample-reception-check-item.ts → views/production/process-route/index.vue
 
 ## Communities
 
 ### Community 0 - "Community 0"
 Cohesion: 0.01
-Nodes (115): fetchActiveRegions(), fetchCategoryList(), fetchCategoryParameters(), fetchCellProductPriceList(), fetchCellProductSpecList(), fetchCellProductTypeList(), fetchCellSampleTypeList(), fetchChannelAgreementPrices() (+107 more)
+Nodes (85): fetchActiveRegions(), fetchCategoryList(), fetchCategoryParameters(), fetchCellProductPriceList(), fetchCellProductSpecList(), fetchCellProductTypeList(), fetchCellSampleTypeList(), fetchChannelAgreementPrices() (+77 more)
 
 ### Community 1 - "Community 1"
-Cohesion: 0.01
-Nodes (24): fetchCollectionRegionList(), fetchCreateCollectionRegion(), fetchCreateHospital(), fetchDeleteCollectionRegion(), fetchDeleteHospital(), fetchDeleteProjectSystemItem(), fetchGetRoleList(), fetchHospitalList() (+16 more)
-
-### Community 2 - "Community 2"
 Cohesion: 0.03
-Nodes (62): fetchBatchGenerateProtocolNos(), fetchBatchGenerateSampleCodes(), fetchBatchIssueProtocolNos(), fetchBatchIssueSampleCodes(), fetchCollectionProtocolNoList(), fetchCreateCollectionProtocolNo(), fetchCreateSampleCode(), fetchDeleteCollectionProtocolNo() (+54 more)
+Nodes (60): fetchBatchGenerateProtocolNos(), fetchBatchGenerateSampleCodes(), fetchBatchIssueProtocolNos(), fetchBatchIssueSampleCodes(), fetchCollectionProtocolNoList(), fetchCreateCollectionProtocolNo(), fetchCreateSampleCode(), fetchDeleteCollectionProtocolNo() (+52 more)
 
-### Community 3 - "Community 3"
+### Community 2 - "Community 2"
 Cohesion: 0.04
 Nodes (31): fetchGetUserInfo(), clickTab(), handleTouchEnd(), setTransition(), IframeRouteManager, RouteRegistry, useCommon(), setupAfterEachGuard() (+23 more)
 
+### Community 3 - "Community 3"
+Cohesion: 0.03
+Nodes (22): fetchAllConsumablePacks(), fetchAllConsumables(), fetchAllConsumableStockLogs(), fetchAllOutputTypes(), fetchAllProcessCategories(), fetchAllProcesses(), fetchAllReagents(), fetchAllReagentStockLogs() (+14 more)
+
 ### Community 4 - "Community 4"
-Cohesion: 0.05
-Nodes (33): fetchDeptTree(), fetchPostBoundUserIds(), FireworkSystem, reload(), formatUserLabel(), loadDeptData(), onPersonSelectChange(), subscribeTokenRefresh() (+25 more)
+Cohesion: 0.04
+Nodes (40): fetchDeptTree(), fetchPostBoundUserIds(), FireworkSystem, reload(), formatUserLabel(), loadDeptData(), onPersonSelectChange(), subscribeTokenRefresh() (+32 more)
 
 ### Community 5 - "Community 5"
-Cohesion: 0.05
-Nodes (41): fetchAccessLogList(), fetchCleanRoomList(), fetchCreateAccessLog(), fetchCreateCleanRoom(), fetchCreateSite(), fetchDeleteAccessLog(), fetchDeleteCleanRoom(), fetchDeleteSite() (+33 more)
+Cohesion: 0.04
+Nodes (33): fetchCollectionRegionList(), fetchCreateCollectionRegion(), fetchCreateHospital(), fetchDeleteCollectionRegion(), fetchDeleteHospital(), fetchHospitalList(), fetchUpdateCollectionRegion(), fetchUpdateHospital() (+25 more)
 
 ### Community 6 - "Community 6"
 Cohesion: 0.04
 Nodes (23): fetchAttachmentDownloadUrl(), fetchOrderAdjusts(), fetchOrderDetail(), fetchOrderItems(), fetchOrderList(), fetchPriceVersionDetail(), fetchSystemConfig(), handleReceptionAttachmentDownload() (+15 more)
 
 ### Community 7 - "Community 7"
-Cohesion: 0.09
-Nodes (5): handleReset(), handleSearch(), WebSocketClient, TableCache, emit()
+Cohesion: 0.05
+Nodes (39): fetchAccessLogList(), fetchCleanRoomList(), fetchCreateAccessLog(), fetchCreateCleanRoom(), fetchCreateSite(), fetchDeleteAccessLog(), fetchDeleteCleanRoom(), fetchDeleteSite() (+31 more)
 
 ### Community 8 - "Community 8"
 Cohesion: 0.06
 Nodes (21): auditorDisplay(), dash(), expressName(), formatYm(), formatYmd(), sampleTypeName(), siteName(), unitName() (+13 more)
 
 ### Community 9 - "Community 9"
-Cohesion: 0.07
-Nodes (11): useSettingsHandlers(), useSettingsPanel(), useSettingsState(), ComponentLoader, RoutePermissionValidator, RouteTransformer, useCeremony(), useTheme() (+3 more)
+Cohesion: 0.06
+Nodes (11): collectIds(), useSettingsHandlers(), useSettingsPanel(), useSettingsState(), RoutePermissionValidator, useCeremony(), useTheme(), TableCache (+3 more)
 
 ### Community 10 - "Community 10"
 Cohesion: 0.09
-Nodes (31): toLogin(), base64ToBytes(), bytesToBase64(), decryptJson(), deriveKey(), encryptJson(), fromBase64Url(), hexToBytes() (+23 more)
+Nodes (8): getDefaultLanguage(), checkStorageCompatibility(), StorageConfig, getSystemStorage(), getSysVersion(), StorageKeyManager, StorageCompatibilityManager, validateStorageData()
 
 ### Community 11 - "Community 11"
 Cohesion: 0.09
-Nodes (8): getDefaultLanguage(), checkStorageCompatibility(), StorageConfig, getSystemStorage(), getSysVersion(), StorageKeyManager, StorageCompatibilityManager, validateStorageData()
+Nodes (29): base64ToBytes(), bytesToBase64(), decryptJson(), deriveKey(), encryptJson(), fromBase64Url(), hexToBytes(), sha256Hex() (+21 more)
 
 ### Community 12 - "Community 12"
-Cohesion: 0.07
-Nodes (15): fetchDeleteProductionTask(), fetchProductionTaskDetail(), fetchProductionTaskList(), fetchUpdateProductionTask(), fetchCompleteProductionWorkOrder(), fetchProductionWorkOrderDetail(), fetchProductionWorkOrderList(), handleClose() (+7 more)
+Cohesion: 0.06
+Nodes (8): fetchMaterialList(), fetchMaterialOptions(), fetchMaterialStockLogList(), fetchQcThirdPartyCompanyList(), fetchQcThirdPartyCompanyOptions(), fetchResearchDonationAuditList(), fetchResearchDonationDetail(), fetchResearchDonationList()
 
 ### Community 13 - "Community 13"
-Cohesion: 0.08
-Nodes (17): fetchCreateMenu(), fetchDeleteMenu(), fetchMenuTree(), fetchUpdateMenu(), collectIds(), postorder(), preorder(), applyTreeExpand() (+9 more)
+Cohesion: 0.11
+Nodes (8): disableDevTools(), handleLock(), handleUnlock(), isMobile(), toLogin(), logOut(), systemUpgrade(), VersionManager
 
 ### Community 14 - "Community 14"
-Cohesion: 0.1
-Nodes (8): fetchGetMenuList(), fetchGetMenuCodes(), fetchLogin(), fetchRefreshToken(), MenuProcessor, useAppMode(), useAuth(), buildWebEncryptedLoginBody()
+Cohesion: 0.18
+Nodes (1): WebSocketClient
 
 ### Community 15 - "Community 15"
 Cohesion: 0.1
-Nodes (13): fetchEthnicList(), addSample(), applyDonationBundleToForm(), confirmBatchTransportApply(), createEmptyTransport(), ensureDonationProtocolNoInOptions(), ensureEthnicOptionInList(), handleOpenForAdd() (+5 more)
+Nodes (16): fetchCreateMenu(), fetchDeleteMenu(), fetchMenuTree(), fetchUpdateMenu(), postorder(), preorder(), applyTreeExpand(), handleAdd() (+8 more)
 
 ### Community 16 - "Community 16"
-Cohesion: 0.12
-Nodes (15): addCopyButton(), highlightCode(), insertLineNumbers(), isBlockProcessed(), markBlockAsProcessed(), processBlock(), setupHighlightDirective(), setupRippleDirective() (+7 more)
+Cohesion: 0.1
+Nodes (8): fetchGetMenuList(), fetchGetMenuCodes(), fetchLogin(), fetchRefreshToken(), MenuProcessor, useAppMode(), useAuth(), buildWebEncryptedLoginBody()
 
 ### Community 17 - "Community 17"
-Cohesion: 0.12
-Nodes (19): fetchCreateUser(), fetchDeleteUser(), fetchResetPassword(), fetchRoleOptions(), fetchUpdateUser(), fetchUserDetail(), formatUserDeptDisplay(), handleAdd() (+11 more)
+Cohesion: 0.1
+Nodes (13): fetchEthnicList(), addSample(), applyDonationBundleToForm(), confirmBatchTransportApply(), createEmptyTransport(), ensureDonationProtocolNoInOptions(), ensureEthnicOptionInList(), handleOpenForAdd() (+5 more)
 
 ### Community 18 - "Community 18"
-Cohesion: 0.19
-Nodes (3): fetchGetLatestUpgradeLog(), systemUpgrade(), VersionManager
+Cohesion: 0.12
+Nodes (15): addCopyButton(), highlightCode(), insertLineNumbers(), isBlockProcessed(), markBlockAsProcessed(), processBlock(), setupHighlightDirective(), setupRippleDirective() (+7 more)
 
 ### Community 19 - "Community 19"
+Cohesion: 0.14
+Nodes (17): fetchCreateUser(), fetchDeleteUser(), fetchResetPassword(), fetchUpdateUser(), fetchUserDetail(), formatUserDeptDisplay(), handleAdd(), handleDelete() (+9 more)
+
+### Community 20 - "Community 20"
 Cohesion: 0.12
 Nodes (12): fetchApproveTask(), fetchBusinessAllTasks(), fetchCompletedTasks(), fetchDesignerData(), fetchInstanceDetail(), fetchMyInstances(), fetchPendingTasks(), fetchProcessDefList() (+4 more)
 
-### Community 20 - "Community 20"
+### Community 21 - "Community 21"
 Cohesion: 0.16
 Nodes (10): useTable(), useTableImpl(), getColumnChecks(), useTableColumns(), createErrorHandler(), createSmartDebounce(), defaultResponseAdapter(), extractPagination() (+2 more)
 
-### Community 21 - "Community 21"
+### Community 22 - "Community 22"
+Cohesion: 0.2
+Nodes (2): ComponentLoader, RouteTransformer
+
+### Community 23 - "Community 23"
 Cohesion: 0.27
 Nodes (14): useChart(), useChartComponent(), useChartOps(), colourBlend(), getCssVar(), getDarkColor(), getLightColor(), handleElementThemeColor() (+6 more)
 
-### Community 22 - "Community 22"
-Cohesion: 0.18
-Nodes (11): fetchCreateCustomer(), fetchCustomerList(), fetchDeleteCustomer(), fetchUpdateCustomer(), handleAdd(), handleDelete(), handleReset(), handleSearch() (+3 more)
-
 ### Community 24 - "Community 24"
+Cohesion: 0.17
+Nodes (12): fetchCreateCustomer(), fetchCustomerList(), fetchDeleteCustomer(), fetchUpdateCustomer(), handleAdd(), handleBatchDelete(), handleDelete(), handleReset() (+4 more)
+
+### Community 26 - "Community 26"
 Cohesion: 0.2
 Nodes (2): fetchQcMaterialList(), fetchQcMaterialOptions()
 
-### Community 26 - "Community 26"
+### Community 28 - "Community 28"
 Cohesion: 0.39
 Nodes (6): isIgnorableScriptError(), normalizeErrorMessage(), registerPromiseErrorHandler(), registerResourceErrorHandler(), scriptErrorHandler(), setupErrorHandle()
 
-### Community 27 - "Community 27"
+### Community 29 - "Community 29"
 Cohesion: 0.36
 Nodes (1): TableHeightCalculator
 
-### Community 28 - "Community 28"
+### Community 30 - "Community 30"
 Cohesion: 0.33
 Nodes (2): logApiCryptoBootInfo(), maskSecret()
 
-### Community 29 - "Community 29"
+### Community 31 - "Community 31"
+Cohesion: 0.29
+Nodes (2): fetchLeaveDetail(), fetchLeaveList()
+
+### Community 32 - "Community 32"
 Cohesion: 0.47
 Nodes (3): isPaymentDueWithinWarnWindow(), parsePaymentDueYmd(), startOfLocalDay()
 
-### Community 31 - "Community 31"
+### Community 33 - "Community 33"
+Cohesion: 0.33
+Nodes (2): fetchSampleReceptionCheckItemList(), fetchSampleReceptionCheckItemsActive()
+
+### Community 34 - "Community 34"
+Cohesion: 0.33
+Nodes (2): fetchQcThirdPartyItemList(), fetchQcThirdPartyItemsActive()
+
+### Community 35 - "Community 35"
+Cohesion: 0.33
+Nodes (2): fetchQcLabTestItemList(), fetchQcLabTestItemsActive()
+
+### Community 36 - "Community 36"
+Cohesion: 0.33
+Nodes (2): fetchQcTaskDetail(), fetchQcTaskList()
+
+### Community 38 - "Community 38"
 Cohesion: 0.53
 Nodes (4): isEtaTodayOrEarlier(), parseEtaLocalDate(), sampleReceptionRowClassName(), startOfLocalDay()
 
-### Community 32 - "Community 32"
+### Community 39 - "Community 39"
 Cohesion: 0.5
 Nodes (2): focusInput(), handleKeydown()
 
-### Community 33 - "Community 33"
+### Community 40 - "Community 40"
 Cohesion: 0.67
 Nodes (2): if(), logSidebarMenu()
 
-### Community 34 - "Community 34"
+### Community 41 - "Community 41"
 Cohesion: 0.5
 Nodes (1): fetchStorageEntrySmsList()
 
-### Community 35 - "Community 35"
+### Community 42 - "Community 42"
+Cohesion: 0.5
+Nodes (1): fetchSampleSmsNotificationList()
+
+### Community 43 - "Community 43"
 Cohesion: 1.0
 Nodes (2): getSettingDefaults(), resetToDefaults()
 
-### Community 37 - "Community 37"
+### Community 45 - "Community 45"
 Cohesion: 1.0
 Nodes (2): defaultAvatarPathByRole(), resolveUserAvatarUrl()
 
 ## Knowledge Gaps
-- **Thin community `Community 24`** (10 nodes): `fetchBatchStockInQcMaterial()`, `fetchBatchStockOutQcMaterial()`, `fetchCreateQcMaterial()`, `fetchDeleteQcMaterial()`, `fetchQcMaterialList()`, `fetchQcMaterialOptions()`, `fetchStockInQcMaterial()`, `fetchStockOutQcMaterial()`, `fetchUpdateQcMaterial()`, `qc-material.ts`
+- **Thin community `Community 14`** (28 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()`, `.log()`, `index.ts`
+  Too small to be a meaningful cluster - may be noise or needs more connections extracted.
+- **Thin community `Community 22`** (17 nodes): `ComponentLoader`, `.constructor()`, `.createEmptyComponent()`, `.createErrorComponent()`, `.load()`, `.loadIframe()`, `.loadLayout()`, `.load()`, `RouteTransformer`, `.extractFirstSegment()`, `.handleFirstLevelRoute()`, `.handleIframeRoute()`, `.handleNormalRoute()`, `.isFirstLevelRoute()`, `.transform()`, `ComponentLoader.ts`, `RouteTransformer.ts`
+  Too small to be a meaningful cluster - may be noise or needs more connections extracted.
+- **Thin community `Community 26`** (10 nodes): `fetchBatchStockInQcMaterial()`, `fetchBatchStockOutQcMaterial()`, `fetchCreateQcMaterial()`, `fetchDeleteQcMaterial()`, `fetchQcMaterialList()`, `fetchQcMaterialOptions()`, `fetchStockInQcMaterial()`, `fetchStockOutQcMaterial()`, `fetchUpdateQcMaterial()`, `qc-material.ts`
+  Too small to be a meaningful cluster - may be noise or needs more connections extracted.
+- **Thin community `Community 29`** (8 nodes): `TableHeightCalculator`, `.calculate()`, `.calculateOffset()`, `.calculatePaginationOffset()`, `.constructor()`, `.getHeaderHeight()`, `useTableHeight()`, `useTableHeight.ts`
+  Too small to be a meaningful cluster - may be noise or needs more connections extracted.
+- **Thin community `Community 30`** (7 nodes): `App.vue`, `main.ts`, `refreshButtonAutoIcons()`, `refreshPanelTitleIcons()`, `logApiCryptoBootInfo()`, `maskSecret()`, `console.ts`
+  Too small to be a meaningful cluster - may be noise or needs more connections extracted.
+- **Thin community `Community 31`** (7 nodes): `fetchCreateLeave()`, `fetchDeleteLeave()`, `fetchLeaveDetail()`, `fetchLeaveList()`, `fetchSubmitLeave()`, `fetchUpdateLeave()`, `leave.ts`
+  Too small to be a meaningful cluster - may be noise or needs more connections extracted.
+- **Thin community `Community 33`** (6 nodes): `fetchCreateSampleReceptionCheckItem()`, `fetchDeleteSampleReceptionCheckItem()`, `fetchSampleReceptionCheckItemList()`, `fetchSampleReceptionCheckItemsActive()`, `fetchUpdateSampleReceptionCheckItem()`, `sample-reception-check-item.ts`
+  Too small to be a meaningful cluster - may be noise or needs more connections extracted.
+- **Thin community `Community 34`** (6 nodes): `fetchCreateQcThirdPartyItem()`, `fetchDeleteQcThirdPartyItem()`, `fetchQcThirdPartyItemList()`, `fetchQcThirdPartyItemsActive()`, `fetchUpdateQcThirdPartyItem()`, `qc-third-party-item.ts`
+  Too small to be a meaningful cluster - may be noise or needs more connections extracted.
+- **Thin community `Community 35`** (6 nodes): `fetchCreateQcLabTestItem()`, `fetchDeleteQcLabTestItem()`, `fetchQcLabTestItemList()`, `fetchQcLabTestItemsActive()`, `fetchUpdateQcLabTestItem()`, `qc-lab-test-item.ts`
   Too small to be a meaningful cluster - may be noise or needs more connections extracted.
-- **Thin community `Community 27`** (8 nodes): `TableHeightCalculator`, `.calculate()`, `.calculateOffset()`, `.calculatePaginationOffset()`, `.constructor()`, `.getHeaderHeight()`, `useTableHeight()`, `useTableHeight.ts`
+- **Thin community `Community 36`** (6 nodes): `fetchCompleteQcTask()`, `fetchQcTaskDetail()`, `fetchQcTaskList()`, `fetchStartQcTask()`, `fetchUpdateQcTaskAttachments()`, `qc-task.ts`
   Too small to be a meaningful cluster - may be noise or needs more connections extracted.
-- **Thin community `Community 28`** (7 nodes): `App.vue`, `main.ts`, `refreshButtonAutoIcons()`, `refreshPanelTitleIcons()`, `logApiCryptoBootInfo()`, `maskSecret()`, `console.ts`
+- **Thin community `Community 39`** (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 32`** (5 nodes): `focusInput()`, `handleKeydown()`, `if()`, `search()`, `index.vue`
+- **Thin community `Community 40`** (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 33`** (4 nodes): `if()`, `logSidebarMenu()`, `index.vue`, `SidebarSubmenu.vue`
+- **Thin community `Community 41`** (4 nodes): `fetchGenerateStorageEntrySms()`, `fetchStorageEntrySmsList()`, `fetchToggleStorageEntrySmsNotified()`, `storage-entry-sms-notification.ts`
   Too small to be a meaningful cluster - may be noise or needs more connections extracted.
-- **Thin community `Community 34`** (4 nodes): `fetchGenerateStorageEntrySms()`, `fetchStorageEntrySmsList()`, `fetchToggleStorageEntrySmsNotified()`, `storage-entry-sms-notification.ts`
+- **Thin community `Community 42`** (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 35`** (3 nodes): `getSettingDefaults()`, `resetToDefaults()`, `setting.ts`
+- **Thin community `Community 43`** (3 nodes): `getSettingDefaults()`, `resetToDefaults()`, `setting.ts`
   Too small to be a meaningful cluster - may be noise or needs more connections extracted.
-- **Thin community `Community 37`** (3 nodes): `defaultAvatarPathByRole()`, `resolveUserAvatarUrl()`, `user-avatar.ts`
+- **Thin community `Community 45`** (3 nodes): `defaultAvatarPathByRole()`, `resolveUserAvatarUrl()`, `user-avatar.ts`
   Too small to be a meaningful cluster - may be noise or needs more connections extracted.
 
 ## Suggested Questions
 _Questions this graph is uniquely positioned to answer:_
 
-- **Why does `get()` connect `Community 0` to `Community 1`, `Community 2`, `Community 34`, `Community 4`, `Community 5`, `Community 6`, `Community 3`, `Community 8`, `Community 12`, `Community 13`, `Community 14`, `Community 15`, `Community 17`, `Community 18`, `Community 19`, `Community 22`, `Community 24`?**
-  _High betweenness centrality (0.288) - this node is a cross-community bridge._
-- **Why does `push()` connect `Community 4` to `Community 1`, `Community 6`, `Community 7`, `Community 9`, `Community 15`, `Community 18`?**
-  _High betweenness centrality (0.081) - this node is a cross-community bridge._
-- **Why does `fetchGetLatestUpgradeLog()` connect `Community 18` to `Community 0`?**
-  _High betweenness centrality (0.043) - this node is a cross-community bridge._
-- **Are the 162 inferred relationships involving `get()` (e.g. with `buildTreePathLabelFromFlat()` and `alignFqPaymentDetailsForDisplay()`) actually correct?**
-  _`get()` has 162 INFERRED edges - model-reasoned connections that need verification._
-- **Are the 18 inferred relationships involving `push()` (e.g. with `fetchAllPagedRecords()` and `calcInstallmentDueAmounts()`) actually correct?**
-  _`push()` has 18 INFERRED edges - model-reasoned connections that need verification._
+- **Why does `get()` connect `Community 0` to `Community 1`, `Community 2`, `Community 3`, `Community 4`, `Community 5`, `Community 6`, `Community 7`, `Community 8`, `Community 12`, `Community 15`, `Community 16`, `Community 17`, `Community 19`, `Community 20`, `Community 24`, `Community 26`, `Community 31`, `Community 33`, `Community 34`, `Community 35`, `Community 36`, `Community 41`, `Community 42`?**
+  _High betweenness centrality (0.287) - this node is a cross-community bridge._
+- **Why does `push()` connect `Community 4` to `Community 0`, `Community 6`, `Community 9`, `Community 13`, `Community 14`, `Community 17`?**
+  _High betweenness centrality (0.121) - this node is a cross-community bridge._
+- **Why does `fetchGetLatestUpgradeLog()` connect `Community 0` to `Community 13`?**
+  _High betweenness centrality (0.041) - this node is a cross-community bridge._
+- **Are the 163 inferred relationships involving `get()` (e.g. with `collectLeafFacilityNodesInTreeOrder()` and `buildTreePathLabelFromFlat()`) actually correct?**
+  _`get()` has 163 INFERRED edges - model-reasoned connections that need verification._
+- **Are the 19 inferred relationships involving `push()` (e.g. with `collectLeafFacilityNodesInTreeOrder()` and `fetchAllPagedRecords()`) actually correct?**
+  _`push()` has 19 INFERRED edges - model-reasoned connections that need verification._
 - **Are the 16 inferred relationships involving `withFullscreenLoading()` (e.g. with `.close()` and `handleSubmit()`) actually correct?**
   _`withFullscreenLoading()` has 16 INFERRED edges - model-reasoned connections that need verification._
 - **Should `Community 0` be split into smaller, more focused modules?**

文件差异内容过多而无法显示
+ 1 - 1
web-admin/graphify-out/graph.html


文件差异内容过多而无法显示
+ 184 - 103
web-admin/graphify-out/graph.json


+ 7 - 6
web-admin/graphify-out/manifest.json

@@ -1,5 +1,5 @@
 {
-  "/Users/wuzilong/work/00code/zkxw/web-admin/src/App.vue": 1779525781.5731733,
+  "/Users/wuzilong/work/00code/zkxw/web-admin/src/App.vue": 1779588353.6246555,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/main.ts": 1779258114.8468678,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/env.d.ts": 1778582067.998984,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/shims-loose.d.ts": 1778582068.0215242,
@@ -17,7 +17,7 @@
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/types/common/index.ts": 1778582068.0254738,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/types/directive/directive.d.ts": 1778582068.026978,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/types/api/api.d.ts": 1778582068.0246184,
-  "/Users/wuzilong/work/00code/zkxw/web-admin/src/types/import/components.d.ts": 1779587829.0283062,
+  "/Users/wuzilong/work/00code/zkxw/web-admin/src/types/import/components.d.ts": 1779589500.1938324,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/types/import/auto-imports.d.ts": 1779587821.900029,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/types/store/index.ts": 1778582068.0293276,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/types/router/index.ts": 1778775532.895603,
@@ -39,6 +39,7 @@
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/enums/formEnum.ts": 1778582067.9986193,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/enums/appEnum.ts": 1778582067.9982593,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/patch-el-select-filterable.ts": 1778582068.0385695,
+  "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/storage-slot-options.ts": 1779590044.2530277,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/user-avatar.ts": 1778775532.8966901,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/fullscreen-loading.ts": 1779117454.818312,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/utils/router.ts": 1778582068.0393815,
@@ -276,13 +277,13 @@
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/system/dict/index.vue": 1779543540.7390752,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/system/leave/index.vue": 1779543540.7368186,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/output-type/index.vue": 1779543540.722031,
-  "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/index.vue": 1779543540.7214005,
+  "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/index.vue": 1779590060.1180878,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/process-route/index.vue": 1779543540.7289982,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/sop/index.vue": 1779543540.726837,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-task/index.vue": 1779586846.3205786,
-  "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/reagent/index.vue": 1779543540.724915,
+  "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/reagent/index.vue": 1779589143.1296964,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/index.vue": 1779586813.5815248,
-  "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts": 1779587781.963615,
+  "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/useTaskStepEditor.ts": 1779590059.4362776,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/StepDetailPanel.vue": 1779525781.678735,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/TaskInputEnhancedTable.vue": 1779525781.679505,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/TaskExecutionDialog.vue": 1779525781.680895,
@@ -291,7 +292,7 @@
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/DispatchTaskDialog.vue": 1779525781.6835842,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/production-work-order/TaskOutputProductDialog.vue": 1779525781.6850414,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/consumable-pack/index.vue": 1779543540.719702,
-  "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/consumable/index.vue": 1779543540.7187445,
+  "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/consumable/index.vue": 1779588932.4529731,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/process/index.vue": 1779543540.717012,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/process-category/index.vue": 1779543540.7154598,
   "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/index/index.vue": 1779525781.6949234,

+ 1 - 0
web-admin/src/graphify-out/cache/ast/0e0efc77cd9c4f492cbf08cac4bf8f46518256ba4da7d8b59f54287dbfed73cc.json

@@ -0,0 +1 @@
+{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_types_import_components_d_ts", "label": "components.d.ts", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/types/import/components.d.ts", "source_location": "L1"}], "edges": [], "raw_calls": []}

文件差异内容过多而无法显示
+ 0 - 0
web-admin/src/graphify-out/cache/ast/19c05771ec9d5f1451b1faac67c49af2f807b4e0ef7a1214825732e980f99407.json


+ 1 - 0
web-admin/src/graphify-out/cache/ast/1dc9035246be964d79d3960a200763dbf18ca7283fd4b5e3f5dd637457b7c1ff.json

@@ -0,0 +1 @@
+{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_consumable_index_vue", "label": "index.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/consumable/index.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}

文件差异内容过多而无法显示
+ 0 - 0
web-admin/src/graphify-out/cache/ast/242161bd5d6f75274753cc76423dfd30f3b61a5a0d57eebf361a6785a994d5d5.json


+ 1 - 0
web-admin/src/graphify-out/cache/ast/4542430d0a8343ae4700623f0d58677a2a36b633ffd09dd05b6c69229eea1fb0.json

@@ -0,0 +1 @@
+{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_reagent_index_vue", "label": "index.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/reagent/index.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}

+ 1 - 0
web-admin/src/graphify-out/cache/ast/967745e99562216a39745b4e0c7f31e4c039d67857f26da334209d4b8b5e5f54.json

@@ -0,0 +1 @@
+{"nodes": [{"id": "users_wuzilong_work_00code_zkxw_web_admin_src_views_production_cell_product_index_vue", "label": "index.vue", "file_type": "code", "source_file": "/Users/wuzilong/work/00code/zkxw/web-admin/src/views/production/cell-product/index.vue", "source_location": "L1"}], "edges": [], "raw_calls": []}

文件差异内容过多而无法显示
+ 0 - 0
web-admin/src/graphify-out/cache/ast/ba457df7cd47562d32b0cc9f432a4898ff332ffe8796c014f06a76049c12a2f1.json


+ 149 - 0
web-admin/src/utils/storage-slot-options.ts

@@ -0,0 +1,149 @@
+/**
+ * 储物格下拉选项:设施树 DFS(order_num)+ 盒内格位按行/列升序
+ */
+import { buildTreePathLabelFromFlat } from '@/utils/tree-path'
+
+export type StorageSlotSelectOption = { id: string; name: string }
+
+export function getStorageFacilityOrderNum(item: Record<string, unknown>): number {
+  const raw =
+    item?.orderNum ?? item?.order_num ?? item?.sortOrder ?? item?.sort_order ?? 0
+  const parsed = Number(raw)
+  return Number.isFinite(parsed) ? parsed : 0
+}
+
+export function getStorageSlotOrderNum(slot: Record<string, unknown>): number {
+  const raw = slot?.orderNum ?? slot?.order_num ?? 0
+  const parsed = Number(raw)
+  return Number.isFinite(parsed) ? parsed : 0
+}
+
+/** 解析 slotCode「{prefix}{row}-{col}」 */
+export function parseStorageSlotCode(
+  code: string
+): { row: number; col: number } | null {
+  const match = (code || '').trim().match(/^(.*?)(\d+)-(\d+)$/)
+  if (!match) return null
+  return { row: parseInt(match[2], 10), col: parseInt(match[3], 10) }
+}
+
+/** 盒内格位:order_num → 行 → 列 → 编码 */
+export function compareStorageFacilitySlots(
+  a: Record<string, unknown>,
+  b: Record<string, unknown>
+): number {
+  const orderDiff = getStorageSlotOrderNum(a) - getStorageSlotOrderNum(b)
+  if (orderDiff !== 0) return orderDiff
+  const codeA = String(a.slotCode ?? a.slot_code ?? '')
+  const codeB = String(b.slotCode ?? b.slot_code ?? '')
+  const pa = parseStorageSlotCode(codeA)
+  const pb = parseStorageSlotCode(codeB)
+  if (pa && pb) {
+    if (pa.row !== pb.row) return pa.row - pb.row
+    if (pa.col !== pb.col) return pa.col - pb.col
+  } else if (pa && !pb) return -1
+  else if (!pa && pb) return 1
+  const codeCmp = codeA.localeCompare(codeB, 'zh-Hans-CN', { numeric: true })
+  if (codeCmp !== 0) return codeCmp
+  return String(a.id ?? '').localeCompare(String(b.id ?? ''))
+}
+
+export function sortStorageFacilitySlots<T extends Record<string, unknown>>(
+  slots: T[]
+): T[] {
+  return [...slots].sort(compareStorageFacilitySlots)
+}
+
+/**
+ * 按设施树顺序收集叶子节点(罐 → 层 → 盒…),同级按 order_num、名称排序。
+ */
+export function collectLeafFacilityNodesInTreeOrder(
+  flatList: Record<string, unknown>[]
+): Record<string, unknown>[] {
+  const map = new Map<string, Record<string, unknown> & { children: unknown[] }>()
+  const roots: (Record<string, unknown> & { children: unknown[] })[] = []
+
+  for (const item of flatList || []) {
+    const id = String(item?.id ?? '').trim()
+    if (!id) continue
+    map.set(id, { ...item, children: [] })
+  }
+  for (const item of flatList || []) {
+    const id = String(item?.id ?? '').trim()
+    const node = map.get(id)
+    if (!node) continue
+    const parentId = String(item?.parentId ?? item?.parent_id ?? '').trim()
+    if (parentId && parentId !== '0' && map.has(parentId)) {
+      ;(map.get(parentId)!.children as typeof roots).push(node)
+    } else {
+      roots.push(node)
+    }
+  }
+
+  const sortNodes = (nodes: (typeof roots)[number][]) => {
+    nodes.sort((a, b) => {
+      const orderDiff = getStorageFacilityOrderNum(a) - getStorageFacilityOrderNum(b)
+      if (orderDiff !== 0) return orderDiff
+      return String(a.nodeName ?? '').localeCompare(String(b.nodeName ?? ''), 'zh-Hans-CN')
+    })
+    nodes.forEach((node) => {
+      const ch = node.children
+      if (Array.isArray(ch) && ch.length) sortNodes(ch as typeof roots)
+    })
+  }
+  sortNodes(roots)
+
+  const leaves: Record<string, unknown>[] = []
+  const walk = (nodes: typeof roots) => {
+    for (const n of nodes) {
+      const isLeaf = n.isLeaf === 1 || n.is_leaf === 1
+      const ch = n.children
+      if (isLeaf) {
+        leaves.push(n)
+      } else if (Array.isArray(ch) && ch.length) {
+        walk(ch as typeof roots)
+      }
+    }
+  }
+  walk(roots)
+  return leaves
+}
+
+export function mapSlotsToSelectOptions(
+  facilityNodeId: string,
+  facilities: Record<string, unknown>[],
+  slots: Record<string, unknown>[]
+): StorageSlotSelectOption[] {
+  const nodePath = buildTreePathLabelFromFlat(facilityNodeId, facilities, {
+    nameKey: 'nodeName',
+  })
+  return sortStorageFacilitySlots(slots).map((slot) => {
+    const id = String(slot.id ?? '').trim()
+    const code = String(slot.slotCode ?? slot.slot_code ?? '')
+    const name = nodePath && code ? `${nodePath} / ${code}` : code || nodePath
+    return { id, name }
+  })
+}
+
+export async function loadStorageSlotSelectOptions(
+  facilities: Record<string, unknown>[],
+  fetchStorageSlotList: (params: { facilityNodeId: string }) => Promise<unknown>
+): Promise<StorageSlotSelectOption[]> {
+  const leafNodes = collectLeafFacilityNodesInTreeOrder(facilities)
+  if (!leafNodes.length) return []
+
+  const results = await Promise.allSettled(
+    leafNodes.map(async (node) => {
+      const nodeId = String(node.id ?? '').trim()
+      const res: any = await fetchStorageSlotList({ facilityNodeId: nodeId })
+      const slots = (res?.list || res || []) as Record<string, unknown>[]
+      return mapSlotsToSelectOptions(nodeId, facilities, slots)
+    })
+  )
+
+  const options: StorageSlotSelectOption[] = []
+  results.forEach((r) => {
+    if (r.status === 'fulfilled') options.push(...r.value)
+  })
+  return options
+}

+ 4 - 24
web-admin/src/views/production/cell-product/index.vue

@@ -650,7 +650,7 @@
     fetchStorageSlotList,
     fetchItemUnitList,
   } from '@/api/admin'
-  import { buildTreePathLabelFromFlat } from '@/utils/tree-path'
+  import { loadStorageSlotSelectOptions } from '@/utils/storage-slot-options'
   import { fetchUploadAttachment } from '@/api/business'
   import { downloadAttachmentFile } from '@/utils/download-attachment'
 
@@ -956,30 +956,10 @@
   }
 
   async function loadStorageSlotOptions(facilities: any[]) {
-    const leafNodes = facilities.filter((n) => n.isLeaf === 1)
-    if (!leafNodes.length) {
-      storageSlotOptions.value = []
-      return
-    }
-    const results = await Promise.allSettled(
-      leafNodes.map(async (node) => {
-        const res: any = await fetchStorageSlotList({ facilityNodeId: node.id })
-        const slots = res?.list || res || []
-        const nodePath = buildTreePathLabelFromFlat(node.id, facilities, {
-          nameKey: 'nodeName',
-        })
-        return slots.map((slot: any) => {
-          const code = slot.slotCode || ''
-          const name = nodePath && code ? `${nodePath} / ${code}` : code || nodePath
-          return { id: slot.id, name }
-        })
-      })
+    storageSlotOptions.value = await loadStorageSlotSelectOptions(
+      facilities,
+      fetchStorageSlotList
     )
-    const options: Array<{ id: string; name: string }> = []
-    results.forEach((r) => {
-      if (r.status === 'fulfilled') options.push(...r.value)
-    })
-    storageSlotOptions.value = options
   }
 
   async function loadDropdownData() {

+ 4 - 22
web-admin/src/views/production/production-work-order/useTaskStepEditor.ts

@@ -29,7 +29,7 @@ import {
   fetchStorageFacilityList,
   fetchStorageSlotList
 } from '@/api/admin'
-import { buildTreePathLabelFromFlat } from '@/utils/tree-path'
+import { loadStorageSlotSelectOptions } from '@/utils/storage-slot-options'
 
 // ── helpers ──────────────────────────────────────────────────────────
 function toApiFlag(val: boolean | number | string | undefined): string {
@@ -511,28 +511,10 @@ export function useTaskStepEditor() {
     try {
       const facilityRes = await fetchStorageFacilityList()
       const facilities = facilityRes?.list || facilityRes || []
-      const leafNodes = facilities.filter((n: any) => n.isLeaf === 1)
-      if (!leafNodes.length) {
-        storageSlotOptions.value = []
-        return
-      }
-      const results = await Promise.allSettled(
-        leafNodes.map(async (node: any) => {
-          const res: any = await fetchStorageSlotList({ facilityNodeId: node.id })
-          const slots = res?.list || res || []
-          const nodePath = buildTreePathLabelFromFlat(node.id, facilities, { nameKey: 'nodeName' })
-          return slots.map((slot: any) => {
-            const code = slot.slotCode || ''
-            const name = nodePath && code ? `${nodePath} / ${code}` : code || nodePath
-            return { id: slot.id, name }
-          })
-        })
+      storageSlotOptions.value = await loadStorageSlotSelectOptions(
+        facilities,
+        fetchStorageSlotList
       )
-      const options: Array<{ id: string; name: string }> = []
-      results.forEach((r) => {
-        if (r.status === 'fulfilled') options.push(...r.value)
-      })
-      storageSlotOptions.value = options
     } catch {
       storageSlotOptions.value = []
     }

部分文件因为文件数量过多而无法显示