From 13e4aa56ec8cc8b682748746808440b424be9461 Mon Sep 17 00:00:00 2001 From: ouyangxq <775153912@qq.com> Date: Tue, 20 Oct 2026 23:34:11 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AGENTS.md | 13 +- src/app/components/AdminSidebarMenu.test.ts | 73 +- src/app/components/AdminSidebarMenuNode.vue | 2 +- src/app/components/WorkspaceTabs.test.ts | 11 + src/app/components/WorkspaceTabs.vue | 26 +- src/app/layouts/AppLayout.test.ts | 24 +- src/app/layouts/AppLayout.vue | 39 +- src/app/pages/ForbiddenView.vue | 3 +- src/core/navigation/adminNavigation.test.ts | 11 +- src/core/navigation/adminNavigation.ts | 1 + .../AppointmentBatchForm.test.ts | 4 +- .../AppointmentBatchForm.vue | 7 +- .../AppointmentCalendarDialogs.native.test.ts | 20 +- .../AppointmentCalendarPanel.vue | 45 +- .../AppointmentCalendarView.test.ts | 4 +- .../AppointmentCalendarView.vue | 15 +- .../AppointmentCreatePanel.vue | 5 +- .../appointment-calendar/PROTOTYPE_MATRIX.md | 42 + .../appointment-calendar/ReceivingScope.vue | 3 +- .../SourceAppointmentPanel.vue | 3 +- .../TripAppointmentPanel.vue | 5 +- .../WorkCommandForm.test.ts | 8 +- .../appointment-calendar/WorkCommandForm.vue | 4 +- .../appointment-calendar/WorkDetailPanel.vue | 11 +- .../WorkReceivingPanel.test.ts | 2 + .../WorkReceivingPanel.vue | 13 +- .../appointment-calendar/scheduleApi.test.ts | 71 ++ .../appointment-calendar/scheduleApi.ts | 22 +- .../temporal-picker.test-support.ts | 8 + .../temporalControls.test.ts | 36 + .../components/CustomerAuditLogsPanel.vue | 21 +- src/modules/auth/operation-matrix.md | 14 + src/modules/auth/pages/LoginView.test.ts | 14 +- src/modules/auth/pages/LoginView.vue | 64 +- .../components/ContainerCustomsPanel.vue | 13 +- .../components/ContainerLastLegFeesPanel.vue | 11 +- .../components/ContainerOverviewPanel.vue | 19 +- .../ContainerSimulationCreate.test.ts | 1 + .../components/ContainerSimulationCreate.vue | 5 +- .../components/OceanBookingLinkDialog.vue | 7 +- .../components/SmartLoadingDialog.test.ts | 5 +- .../components/SmartLoadingDialog.vue | 11 +- .../pages/ContainerDetailView.test.ts | 4 +- .../pages/ContainerDetailView.vue | 58 +- .../pages/ContainerWorkbenchView.vue | 3 +- .../pages/ContainersView.test.ts | 5 +- .../pages/ContainersView.vue | 36 +- .../pages/GlobalSmartLoadingView.test.ts | 66 +- .../pages/GlobalSmartLoadingView.vue | 139 ++-- .../pages/SmartLoadingWorkbenchView.vue | 47 +- .../CustomerOverseasStorageFeePanel.vue | 15 +- .../CustomerBillingRulesPanel.test.ts | 8 +- .../components/CustomerBillingRulesPanel.vue | 42 +- src/modules/customers/customerDensity.css | 15 +- .../customers/customerFeeDialogs.test.ts | 2 +- .../customers/pages/CustomerDetailView.vue | 41 +- .../customers/pages/CustomersView.test.ts | 4 +- src/modules/customers/pages/CustomersView.vue | 76 +- .../pages/OverseasStorageFeesView.vue | 17 +- .../customs/pages/CustomsCasesView.test.ts | 6 +- .../customs/pages/CustomsCasesView.vue | 8 +- src/modules/dashboard/operation-matrix.md | 13 + .../dashboard/pages/DashboardView.test.ts | 25 +- src/modules/dashboard/pages/DashboardView.vue | 80 +- .../DomesticContainerInventoryDetailView.vue | 37 +- .../pages/DomesticContainersView.test.ts | 15 +- .../pages/DomesticContainersView.vue | 19 +- .../downloads/pages/DownloadCenterView.vue | 11 +- .../pages/CarrierRateDetailView.vue | 29 +- .../carrier-rates/pages/CarrierRatesView.vue | 21 +- src/modules/fee-items/pages/FeeItemsView.vue | 19 +- src/modules/finance/financeDensity.css | 2 +- .../pages/FinanceArapStatementDialogs.test.ts | 2 +- .../pages/FinanceCustomerAccountsView.test.ts | 6 +- .../pages/FinanceCustomerAccountsView.vue | 43 +- .../finance/pages/FinanceCustomerArapView.vue | 33 +- .../pages/FinanceCustomerStatementsView.vue | 29 +- .../FinanceFormalSettlementLayout.test.ts | 6 +- .../pages/FinanceFormalSettlementPage.vue | 31 +- .../finance/pages/FinancePresentation.test.ts | 18 +- .../pages/FinanceReceivableStatisticsView.vue | 16 +- .../pages/FinanceSettlementDialogs.test.ts | 2 +- src/modules/iam/AGENTS.md | 1 + src/modules/iam/index.ts | 1 + src/modules/iam/pages/InternalUsersView.vue | 15 +- src/modules/iam/pages/PermissionsView.vue | 17 +- src/modules/iam/pages/RolesView.vue | 13 +- .../iam/useActiveCustomerOptions.test.ts | 118 +++ src/modules/iam/useActiveCustomerOptions.ts | 70 ++ .../components/InboundTaskList.test.ts | 12 + .../inbounds/components/InboundTaskList.vue | 14 +- .../core/DropshipPalletPrintPanel.vue | 7 +- .../inbounds/core/InboundHistoryPanel.vue | 36 +- src/modules/inbounds/fee/InboundFeePanel.vue | 64 +- .../InboundMeasurementDialog.test.ts | 4 +- .../measurement/InboundMeasurementDialog.vue | 5 +- .../measurement/InboundMeasurementPanel.vue | 49 +- .../MeasurementEvidenceThumbnail.vue | 12 +- .../review/MeasurementReviewPanel.vue | 27 +- .../weight/components/WeightOcrPanel.vue | 41 +- .../components/ContainerFeesPanel.test.ts | 2 +- .../components/ContainerFeesPanel.vue | 33 +- .../components/LoadingListDetailDrawer.vue | 40 +- .../components/LoadingListsView.vue | 9 +- .../components/PalletLabelPrintDialog.vue | 5 +- .../pages/ConfirmedLoadingListDetailView.vue | 5 +- .../pages/PreloadPlanDetailView.test.ts | 2 +- .../pages/PreloadPlanDetailView.vue | 21 +- .../counterparties/pages/PartnersView.vue | 17 +- .../pages/ExpressCompaniesView.vue | 19 +- .../notifications/NotificationDialogs.test.ts | 4 +- .../components/MessageComposerDialog.vue | 7 +- .../components/TemplateEditorDialog.vue | 5 +- .../pages/MessageManagementView.vue | 13 +- .../pages/MessageTemplatesView.vue | 5 +- .../pages/PlatformNotificationsView.vue | 7 +- .../components/OceanBookingDocumentsPanel.vue | 7 +- .../components/OceanBookingPrintDialog.vue | 11 +- .../OceanBookingDetailView.release.test.ts | 29 +- .../pages/OceanBookingDetailView.vue | 36 +- .../pages/OceanBookingsView.test.ts | 3 +- .../pages/OceanBookingsView.vue | 7 +- .../pages/OutboundDispatchesView.test.ts | 6 +- .../pages/OutboundDispatchesView.vue | 25 +- .../overseas-business/PROTOTYPE_MATRIX.md | 31 + .../components/ProcurementNodeActions.vue | 3 +- .../components/TransportDemandForm.vue | 9 +- .../components/TruckOrderActions.vue | 5 +- .../overseasBusinessDensity.css | 2 +- .../pages/PurchaseOrderDetailView.vue | 34 +- .../pages/PurchaseOrderEditView.vue | 5 +- .../pages/PurchaseOrdersView.vue | 7 +- .../pages/TransportOrderFormView.vue | 3 +- .../pages/TransportOrdersView.vue | 9 +- .../pages/TruckOrderDetailView.vue | 7 +- src/modules/overseas-master-data/AGENTS.md | 3 +- .../overseas-master-data/PROTOTYPE_MATRIX.md | 143 +++- .../api/outsourcedBusiness.test.ts | 87 ++ .../api/outsourcedBusiness.ts | 74 ++ .../components/CapacityInquiryDialog.vue | 3 +- .../components/CapacityInquiryFulfillment.vue | 3 +- .../components/CapacityInquiryTable.vue | 7 +- .../CapacityOfferSettingsDialog.vue | 5 +- .../components/DriverEditorDialog.vue | 3 +- .../components/DriverLicensePreview.vue | 3 +- .../components/FleetQuoteEditor.vue | 3 +- .../components/FleetQuoteImport.vue | 3 +- .../OutsourcedBusinessCommandRecovery.test.ts | 72 ++ .../OutsourcedBusinessCommandRecovery.ts | 89 ++ .../OutsourcedBusinessDetailLayout.vue | 37 + .../components/OutsourcedBusinessFixtures.ts | 20 + .../OutsourcedBusinessLayouts.test.ts | 48 ++ .../OutsourcedBusinessListLayout.vue | 17 + .../OutsourcedBusinessOperationsDialog.vue | 36 + ...OutsourcedBusinessOperationsEditor.test.ts | 59 ++ .../OutsourcedBusinessOperationsEditor.vue | 92 +++ .../OutsourcedBusinessPhotosDialog.vue | 38 + .../OutsourcedBusinessPhotosEditor.test.ts | 64 ++ .../OutsourcedBusinessPhotosEditor.vue | 128 +++ .../components/OwnedBusinessDetailLayout.vue | 5 +- .../components/OwnedBusinessListLayout.vue | 3 +- .../OwnedBusinessOperationsDialog.vue | 14 +- .../OwnedBusinessOperationsEditor.vue | 3 +- .../components/OwnedBusinessPhotosDialog.vue | 14 +- .../components/OwnedBusinessPhotosEditor.vue | 3 +- .../components/PickupDemandPanel.vue | 7 +- .../components/TransportRouteDialog.vue | 9 +- .../TripBookingFulfillmentDialog.vue | 7 +- .../components/TripBookingPanel.vue | 9 +- .../components/TripCostPanel.vue | 19 +- .../components/TripHandoverPanel.vue | 5 +- .../components/TripLoadingPanel.vue | 5 +- .../components/TripOperationsCharts.test.ts | 7 +- .../components/TripOperationsCharts.vue | 26 +- .../components/TripOperationsRecordDialog.vue | 5 +- .../components/TripPickupPanel.vue | 9 +- .../components/TripPlanDialog.vue | 3 +- .../components/TripPreparationDialog.vue | 3 +- .../components/VehicleCareEditor.vue | 5 +- .../components/VehicleCareFinanceLedger.vue | 9 +- .../components/VehicleCareTable.vue | 7 +- .../components/VehicleFulfillmentTable.vue | 10 +- .../outsourcedBusinessTypes.test.ts | 21 + .../outsourcedBusinessTypes.ts | 45 + .../pages/CapacityOfferDetailView.vue | 5 +- .../pages/CapacityOffersView.vue | 15 +- .../pages/DriverDetailView.vue | 13 +- .../pages/DriversView.vue | 19 +- .../pages/ExchangeRatesView.vue | 11 +- .../pages/FleetQuotesView.vue | 13 +- .../pages/FleetReportingViews.test.ts | 8 +- .../pages/OutsourcedBusinessDetailView.vue | 83 ++ .../pages/OutsourcedBusinessView.vue | 130 +++ .../pages/OutsourcedBusinessViews.test.ts | 96 +++ .../pages/OverseasMasterDataViews.test.ts | 2 +- .../pages/OverseasQuotesView.vue | 13 +- .../pages/OwnedBusinessDetailView.vue | 7 +- .../pages/OwnedBusinessView.vue | 18 +- .../pages/TripDetailView.vue | 19 +- .../pages/TripOperationsView.vue | 15 +- .../overseas-master-data/pages/TripsView.vue | 7 +- .../pages/VehicleDetailView.vue | 3 +- .../pages/VehiclesQueryRace.test.ts | 3 +- .../pages/VehiclesView.vue | 13 +- .../overseas-master-data/permissions.ts | 3 + .../overseas-master-data/routes.test.ts | 13 + src/modules/overseas-master-data/routes.ts | 12 + .../overseas-warehouse/PROTOTYPE_MATRIX.md | 128 +++ .../components/DeliveryDocumentsDialog.vue | 5 +- .../components/DispatchEvidenceFiles.vue | 3 +- .../components/DispatchWorkflowDialog.vue | 3 +- .../components/ExceptionProcessingPanel.vue | 2 +- .../components/OverseasDetailShell.vue | 10 +- .../components/OverseasReadOnlyDetail.vue | 2 + .../SmartDispatchDialog.layout.test.ts | 104 ++- .../components/SmartDispatchDialog.test.ts | 10 +- .../components/SmartDispatchDialog.vue | 103 ++- .../WarehouseTransferFulfillmentPanel.vue | 11 +- .../WarehouseTransferReceiptPanel.vue | 21 +- .../WarehouseTransferReviewDialog.vue | 3 +- .../layoutAcceptance.test.ts | 2 +- .../pages/CargoDiscardsView.vue | 7 +- .../pages/CustomerVisitsView.vue | 17 +- .../pages/DeliveryOrderDetailView.vue | 11 +- .../pages/DeliveryOrdersView.vue | 9 +- .../pages/DispatchDetailView.vue | 5 +- .../pages/DispatchesView.test.ts | 3 +- .../pages/DispatchesView.vue | 11 +- .../pages/ExceptionOrdersView.vue | 11 +- .../pages/InboundOrderDetailView.vue | 29 +- .../pages/InboundOrdersView.vue | 11 +- .../pages/InventoryDetailView.vue | 11 +- .../pages/InventoryTransactionsView.vue | 9 +- .../pages/InventoryView.vue | 15 +- .../pages/LastMileOrderDetailView.vue | 19 +- .../pages/LastMileOrdersView.behavior.test.ts | 13 +- .../pages/LastMileOrdersView.vue | 91 +- .../pages/LocationsView.vue | 13 +- .../pages/MojiaSkuSyncView.vue | 19 +- .../pages/OutboundDetailView.vue | 15 +- .../pages/OutboundsView.vue | 11 +- .../pages/PalletDetailView.vue | 3 +- .../overseas-warehouse/pages/PalletsView.vue | 17 +- .../pages/RelabelOrderDetailView.vue | 25 +- .../pages/RelabelOrdersView.vue | 15 +- .../ReturnInventoryManagementView.test.ts | 3 +- .../pages/ReturnInventoryManagementView.vue | 62 +- .../pages/prototypeContract.test.ts | 4 +- .../pages/PdaReleasesView.test.ts | 8 +- .../pda-releases/pages/PdaReleasesView.vue | 20 +- ...CarrierScheduleQueryPanel.behavior.test.ts | 27 + .../components/CarrierScheduleQueryPanel.vue | 31 +- .../components/ContainerPortSchedulePanel.vue | 17 +- .../pages/PortSchedulesView.test.ts | 5 +- .../pages/PortSchedulesView.vue | 14 +- .../pages/SailingCalendarView.test.ts | 41 + .../pages/SailingCalendarView.vue | 79 +- .../collectionPresentation.test.ts | 21 +- .../self-operated/collectionPresentation.ts | 22 +- .../components/AnalyticsView.vue | 27 +- .../components/ChartDetailsDialog.vue | 5 +- .../CollectionAccountMonitor.test.ts | 79 +- .../components/CollectionAccountMonitor.vue | 222 +++-- .../components/CollectionProgressGauge.vue | 34 +- .../components/CollectionTaskProgress.test.ts | 76 ++ .../components/CollectionTaskProgress.vue | 57 +- .../components/DashboardBars.vue | 16 +- .../components/DashboardChartHeading.vue | 13 +- .../components/DashboardCharts.test.ts | 7 + .../components/DashboardTrend.vue | 11 +- .../components/InventoryTurnoverView.test.ts | 60 +- .../components/InventoryTurnoverView.vue | 146 ++-- .../self-operated/components/SkuTrend.test.ts | 31 + .../self-operated/components/SkuTrend.vue | 31 +- .../dashboardChartOptions.test.ts | 94 ++- .../self-operated/dashboardChartOptions.ts | 43 +- src/modules/self-operated/operation-matrix.md | 11 +- .../self-operated/pages/CollectionView.vue | 3 +- .../self-operated/pages/InventoryView.vue | 8 +- .../self-operated/pages/OverviewView.test.ts | 30 + .../self-operated/pages/OverviewView.vue | 106 +-- .../self-operated/pages/workbench.test.ts | 11 + .../self-operated/skuTrendChart.test.ts | 29 +- src/modules/self-operated/skuTrendChart.ts | 38 +- src/modules/self-operated/state.test.ts | 19 +- src/modules/self-operated/state.ts | 3 + .../turnoverPresentation.test.ts | 51 +- .../self-operated/turnoverPresentation.ts | 27 +- .../components/SupplierLicenseDialog.vue | 5 +- .../suppliers/pages/SupplierDetailView.vue | 5 +- .../suppliers/pages/SupplierFormView.vue | 9 +- .../suppliers/pages/SuppliersView.test.ts | 8 +- src/modules/suppliers/pages/SuppliersView.vue | 16 +- .../components/TruckAppointmentForm.vue | 11 +- .../components/TruckAttachmentDialog.vue | 7 +- .../pages/TruckAppointmentCreateView.test.ts | 2 +- .../pages/TruckAppointmentCreateView.vue | 9 +- .../pages/TruckAppointmentDetailView.test.ts | 6 +- .../pages/TruckAppointmentDetailView.vue | 17 +- .../trucking/pages/TruckAppointmentsView.vue | 7 +- .../components/InboundFeeDetailManager.vue | 9 +- .../OrderDeclarationEditorDialog.vue | 9 +- .../components/OrderFulfillmentTreePanel.vue | 14 +- .../pages/UnifiedOrdersView.coLoad.test.ts | 3 +- .../UnifiedOrdersView.fulfillment.test.ts | 3 +- .../pages/UnifiedOrdersView.requests.test.ts | 6 +- .../pages/UnifiedOrdersView.test.ts | 17 +- .../pages/UnifiedOrdersView.vue | 185 +++-- .../locations/pages/LocationsView.vue | 17 +- .../pallets/pages/PalletsView.test.ts | 2 +- .../pallets/pages/PalletsView.vue | 24 +- .../warehouses/pages/WarehousesView.vue | 31 +- src/shared/components/DataTable.vue | 12 +- src/styles/adminDensity.css | 4 +- src/styles/adminDensity.test.ts | 174 +++- src/styles/adminWorkbench.css | 775 ++++++++++++++++++ src/styles/adminWorkbench.test.ts | 318 +++++++ src/styles/adminWorkbenchChartTheme.ts | 43 + src/styles/adminWorkbenchTokens.css | 74 ++ src/styles/index.css | 21 +- src/styles/shell.css | 69 +- 321 files changed, 6756 insertions(+), 2110 deletions(-) create mode 100644 src/modules/appointment-calendar/scheduleApi.test.ts create mode 100644 src/modules/appointment-calendar/temporal-picker.test-support.ts create mode 100644 src/modules/appointment-calendar/temporalControls.test.ts create mode 100644 src/modules/auth/operation-matrix.md create mode 100644 src/modules/dashboard/operation-matrix.md create mode 100644 src/modules/iam/useActiveCustomerOptions.test.ts create mode 100644 src/modules/iam/useActiveCustomerOptions.ts create mode 100644 src/modules/overseas-master-data/api/outsourcedBusiness.test.ts create mode 100644 src/modules/overseas-master-data/api/outsourcedBusiness.ts create mode 100644 src/modules/overseas-master-data/components/OutsourcedBusinessCommandRecovery.test.ts create mode 100644 src/modules/overseas-master-data/components/OutsourcedBusinessCommandRecovery.ts create mode 100644 src/modules/overseas-master-data/components/OutsourcedBusinessDetailLayout.vue create mode 100644 src/modules/overseas-master-data/components/OutsourcedBusinessFixtures.ts create mode 100644 src/modules/overseas-master-data/components/OutsourcedBusinessLayouts.test.ts create mode 100644 src/modules/overseas-master-data/components/OutsourcedBusinessListLayout.vue create mode 100644 src/modules/overseas-master-data/components/OutsourcedBusinessOperationsDialog.vue create mode 100644 src/modules/overseas-master-data/components/OutsourcedBusinessOperationsEditor.test.ts create mode 100644 src/modules/overseas-master-data/components/OutsourcedBusinessOperationsEditor.vue create mode 100644 src/modules/overseas-master-data/components/OutsourcedBusinessPhotosDialog.vue create mode 100644 src/modules/overseas-master-data/components/OutsourcedBusinessPhotosEditor.test.ts create mode 100644 src/modules/overseas-master-data/components/OutsourcedBusinessPhotosEditor.vue create mode 100644 src/modules/overseas-master-data/outsourcedBusinessTypes.test.ts create mode 100644 src/modules/overseas-master-data/outsourcedBusinessTypes.ts create mode 100644 src/modules/overseas-master-data/pages/OutsourcedBusinessDetailView.vue create mode 100644 src/modules/overseas-master-data/pages/OutsourcedBusinessView.vue create mode 100644 src/modules/overseas-master-data/pages/OutsourcedBusinessViews.test.ts create mode 100644 src/styles/adminWorkbench.css create mode 100644 src/styles/adminWorkbench.test.ts create mode 100644 src/styles/adminWorkbenchChartTheme.ts create mode 100644 src/styles/adminWorkbenchTokens.css diff --git a/AGENTS.md b/AGENTS.md index 414358d1..3fad531f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2,13 +2,14 @@ ## 快速读取顺序 -1. 用“模块快速路由”选择最小业务模块,进入后读取该目录最近的 `AGENTS.md`;按 `routes.ts → pages/ → api/types/stores/composables` 下钻,不先扫描全部 `src/`。 -2. 视觉还原、布局/交互承载方式变更或真实页面验收时读取 `../../docs/Admin-Client前端原型还原验收规则.md`;需要原型依据才读取 `../../docs/悦/货代SAAS平台后台/AGENTS.md` 并定位目标片段。纯文案、逻辑或单元测试任务不自动读取。 - Admin 样式优化还须读取 `../../docs/Admin高密度界面规范.md` 的“样式维护边界”和“新模块接入规则”;以已确认密度与彩色页签为视觉基线,逐操作保留业务语义和承载方式。国内仓、客户管理是样板;新增菜单按本轮范围显式接入,货柜管理入口见 `../../docs/Admin货柜管理样式核对记录.md`。 -3. 标准列表或公共组件任务读取 `src/shared/components/AGENTS.md`;国内/海外 HTTP、Token 或刷新任务读取 `src/shared/api/AGENTS.md`;Finance 任务读取 `src/modules/finance/AGENTS.md`;海外仓全流程任务先读 `../../docs/海外仓业务/README.md`。 -4. 平台/客户层级与权限公共语义读取 `../../docs/平台客户层级与权限契约.md`;统一 API、Token、会话撤销或可靠事件任务按需读取 `../../docs/统一认证与服务通信契约.md` 对应章节。 +1. 由“模块快速路由”选最小模块并读最近 `AGENTS.md`,按 `routes.ts → pages/ → api/types/stores/composables` 下钻,不扫描全部 `src/`。 +2. 视觉、布局/交互承载变更或真实页面验收先读 `../../docs/Admin-Client前端原型还原验收规则.md`;需原型依据再读 `../../docs/悦/货代SAAS平台后台/AGENTS.md` 并定位片段。纯文案、逻辑或单元测试不触发。 + 样式优化另读 `../../docs/Admin高密度界面规范.md` 的“样式维护边界”“新模块接入规则”,保留已确认密度、彩色页签、业务语义及承载。国内仓、客户管理为样板;新增菜单按本轮范围显式接入,货柜入口见 `../../docs/Admin货柜管理样式核对记录.md`。 + 蓝白样式接入见 [样板指南](../../docs/界面参考/蓝白卡片式工作台风格参考.md)。 +3. 标准列表/公共组件读 `src/shared/components/AGENTS.md`;HTTP、Token/刷新读 `src/shared/api/AGENTS.md`;Finance 读 `src/modules/finance/AGENTS.md`;海外仓全流程先读 `../../docs/海外仓业务/README.md`。 +4. 平台/客户层级及权限读 `../../docs/平台客户层级与权限契约.md`;统一 API、Token、会话撤销或可靠事件按需读 `../../docs/统一认证与服务通信契约.md` 对应章节。 -普通单端任务的最小读取集是本文件、目标模块最近的 `AGENTS.md` 和目标代码命中段;只有跨服务状态、权限或接口边界无法判断时才增加后端契约。读取预算遵循根指引的行数与字符数标准,先读适用规则,再定向读取业务表,不全文加载无关专题。 +单端仅读本指引、最近模块指引及命中代码;跨服务状态、权限或接口边界不明才加后端契约。预算遵循根指引,先读适用规则、定向查业务表,跳过无关专题。 ## 项目定位与技术基线 diff --git a/src/app/components/AdminSidebarMenu.test.ts b/src/app/components/AdminSidebarMenu.test.ts index ba96e2ff..e2e7e696 100644 --- a/src/app/components/AdminSidebarMenu.test.ts +++ b/src/app/components/AdminSidebarMenu.test.ts @@ -1,7 +1,10 @@ import { flushPromises, mount } from '@vue/test-utils' -import { defineComponent } from 'vue' +import { defineComponent, markRaw } from 'vue' +import { readFileSync } from 'node:fs' +import { resolve } from 'node:path' import { createMemoryHistory, createRouter } from 'vue-router' -import { describe, expect, it } from 'vitest' +import { ElMenu, ElMenuItem, ElSubMenu } from 'element-plus' +import { describe, expect, it, vi } from 'vitest' import { adminNavigation, filterAdminNavigation, type AdminNavigationNode } from '@/core/navigation/adminNavigation' import AdminSidebarMenu from './AdminSidebarMenu.vue' @@ -85,6 +88,72 @@ describe('AdminSidebarMenu', () => { expect(wrapper.get('nav').attributes('data-collapsed')).toBe('true') }) + it('fits collapsed icons inside the scrolling rail and keeps hover submenus outside it', async () => { + const host = document.createElement('div') + host.className = 'app-shell is-collapsed' + host.innerHTML = '' + document.body.append(host) + const style = document.createElement('style') + style.textContent = readFileSync(resolve(process.cwd(), 'src/styles/shell.css'), 'utf8') + document.head.append(style) + const rail = host.querySelector('.side-nav')! + const router = routerPlugin() + await router.push('/') + const icon = markRaw(adminNavigation[0].icon) + const items: AdminNavigationNode[] = [ + { key: 'home', title: '首页', icon, path: '/' }, + { + key: 'resources', title: '资源管理', icon, + children: [{ key: 'warehouses', title: '仓库管理', icon, path: '/warehouses' }], + }, + ] + const wrapper = mount(AdminSidebarMenu, { + attachTo: rail, + props: { items, activePath: '/', collapsed: true }, + global: { plugins: [router], components: { ElMenu, ElMenuItem, ElSubMenu }, stubs: { transition: false } }, + }) + try { + await flushPromises() + const menu = wrapper.get('.side-nav-menu.el-menu--collapse') + const group = wrapper.get('.side-nav-menu > .el-sub-menu') + const leafTrigger = wrapper.get('.el-menu-tooltip__trigger') + expect(getComputedStyle(host.querySelector('.app-sidebar')!).width).toBe('76px') + expect(getComputedStyle(rail).overflowX).toBe('hidden') + expect(getComputedStyle(rail).overflowY).toBe('auto') + expect(getComputedStyle(menu.element).width).toBe('100%') + for (const trigger of [leafTrigger, group.get('.el-sub-menu__title')]) { + expect(getComputedStyle(trigger.element).paddingLeft).toBe('0px') + expect(getComputedStyle(trigger.element).paddingRight).toBe('0px') + expect(getComputedStyle(trigger.element).justifyContent).toBe('center') + expect(getComputedStyle(trigger.get('.menu-icon').element).marginRight).toBe('0px') + } + + await group.trigger('mouseenter') + await vi.waitFor(() => expect(group.attributes('aria-expanded')).toBe('true')) + const popup = document.body.querySelector('.shell-nav-popper .el-menu--popup') + expect(popup).not.toBeNull() + expect(popup?.closest('.side-nav')).toBeNull() + expect(popup?.textContent).toContain('仓库管理') + + const destination = popup!.querySelector('.el-menu-item')! + destination.focus() + expect(document.activeElement).toBe(destination) + expect(destination.getAttribute('role')).toBe('menuitem') + destination.click() + await flushPromises() + expect(router.currentRoute.value.path).toBe('/warehouses') + + await wrapper.setProps({ collapsed: false }) + host.classList.remove('is-collapsed') + expect(getComputedStyle(host.querySelector('.app-sidebar')!).width).toBe('240px') + expect(wrapper.find('.el-menu--collapse').exists()).toBe(false) + } finally { + wrapper.unmount() + style.remove() + host.remove() + } + }) + it('renders only entries included in the filtered navigation input', () => { const items = filterAdminNavigation(adminNavigation, new Set(['platform:permission:list'])) const wrapper = mount(AdminSidebarMenu, { diff --git a/src/app/components/AdminSidebarMenuNode.vue b/src/app/components/AdminSidebarMenuNode.vue index ab50c0da..c7e6f07c 100644 --- a/src/app/components/AdminSidebarMenuNode.vue +++ b/src/app/components/AdminSidebarMenuNode.vue @@ -10,7 +10,7 @@ defineProps<{