smart-admin-web 10.15.0 → 10.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/api/index.d.ts +4 -2
- package/dist/api/index.js +1 -1
- package/dist/api/index.js.map +1 -1
- package/dist/api/schema.d.ts +39 -5
- package/dist/assets/icons/ph-subset.json.js +5 -5
- package/dist/components/AppIcon.vue.js +9 -9
- package/dist/components/AppIcon.vue.js.map +1 -1
- package/dist/components/AppWatermark.vue.d.ts +14 -0
- package/dist/components/AppWatermark.vue.js +38 -0
- package/dist/components/AppWatermark.vue.js.map +1 -0
- package/dist/components/AppWatermark2.vue.js +5 -0
- package/dist/components/AppWatermark2.vue.js.map +1 -0
- package/dist/components/Chart/PieChart.vue.d.ts +1 -1
- package/dist/components/Chart/echarts.js +15 -20
- package/dist/components/Chart/echarts.js.map +1 -1
- package/dist/components/CronEditor/index.vue.js +1 -1
- package/dist/components/CronEditor/index2.vue.js +2 -1
- package/dist/components/CronEditor/index2.vue.js.map +1 -1
- package/dist/components/DetailPage/index.vue.js +2 -2
- package/dist/components/DetailPage/index2.vue.js.map +1 -1
- package/dist/components/DictTag/index.vue.js.map +1 -1
- package/dist/components/ErrorBoundary/index.vue.js +2 -2
- package/dist/components/ErrorBoundary/index2.vue.js +1 -1
- package/dist/components/ErrorBoundary/index2.vue.js.map +1 -1
- package/dist/components/FormContainer/index.vue.js +91 -56
- package/dist/components/FormContainer/index.vue.js.map +1 -1
- package/dist/components/ImportWizard/index.vue.js +1 -1
- package/dist/components/ImportWizard/index2.vue.js +44 -41
- package/dist/components/ImportWizard/index2.vue.js.map +1 -1
- package/dist/components/MenuSearch.vue.js +2 -2
- package/dist/components/MenuSearch2.vue.js +19 -18
- package/dist/components/MenuSearch2.vue.js.map +1 -1
- package/dist/components/PasswordStrength/index.vue.js +2 -2
- package/dist/components/PasswordStrength/index2.vue.js +20 -18
- package/dist/components/PasswordStrength/index2.vue.js.map +1 -1
- package/dist/components/TableTotal/index.vue.d.ts +6 -0
- package/dist/components/{SelectTable → TableTotal}/index.vue.js +1 -1
- package/dist/components/TableTotal/index2.vue.js +16 -0
- package/dist/components/TableTotal/index2.vue.js.map +1 -0
- package/dist/components/TableZoomButton/index.vue.js.map +1 -1
- package/dist/components/UserPicker/index.vue.js +2 -2
- package/dist/components/UserPicker/index2.vue.js +176 -117
- package/dist/components/UserPicker/index2.vue.js.map +1 -1
- package/dist/composables/useBatchDelete.js.map +1 -1
- package/dist/composables/useLayoutMenu.js +17 -16
- package/dist/composables/useLayoutMenu.js.map +1 -1
- package/dist/composables/useModule.js +39 -29
- package/dist/composables/useModule.js.map +1 -1
- package/dist/composables/useShellBreakpoint.d.ts +19 -0
- package/dist/composables/useShellBreakpoint.js +37 -0
- package/dist/composables/useShellBreakpoint.js.map +1 -0
- package/dist/composables/useSite.d.ts +15 -0
- package/dist/composables/useSite.js +16 -14
- package/dist/composables/useSite.js.map +1 -1
- package/dist/composables/useTabTitle.js.map +1 -1
- package/dist/composables/useTableTitle.d.ts +6 -0
- package/dist/composables/useTableTitle.js +11 -0
- package/dist/composables/useTableTitle.js.map +1 -0
- package/dist/composables/useTableZoom.d.ts +5 -0
- package/dist/composables/useTableZoom.js.map +1 -1
- package/dist/composables/useTheme.d.ts +2 -2
- package/dist/composables/useTheme.js +23 -20
- package/dist/composables/useTheme.js.map +1 -1
- package/dist/createSmartAdmin.d.ts +12 -2
- package/dist/createSmartAdmin.js +72 -60
- package/dist/createSmartAdmin.js.map +1 -1
- package/dist/index.d.ts +5 -2
- package/dist/index.js +219 -205
- package/dist/index.js.map +1 -1
- package/dist/layouts/AccentPicker.vue.js +8 -0
- package/dist/layouts/AccentPicker.vue.js.map +1 -0
- package/dist/layouts/AccentPicker2.vue.js +131 -0
- package/dist/layouts/AccentPicker2.vue.js.map +1 -0
- package/dist/layouts/AppHeader.vue.d.ts +8 -1
- package/dist/layouts/AppHeader.vue.js +2 -2
- package/dist/layouts/AppHeader2.vue.js +317 -235
- package/dist/layouts/AppHeader2.vue.js.map +1 -1
- package/dist/layouts/NoticeBell.vue.js +2 -2
- package/dist/layouts/NoticeBell2.vue.js +1 -1
- package/dist/layouts/NoticeBell2.vue.js.map +1 -1
- package/dist/layouts/PersonalLayout.vue.js +2 -2
- package/dist/layouts/PersonalLayout2.vue.js +69 -47
- package/dist/layouts/PersonalLayout2.vue.js.map +1 -1
- package/dist/layouts/SettingsDrawer.vue.js +3 -3
- package/dist/layouts/SettingsDrawer2.vue.js +261 -325
- package/dist/layouts/SettingsDrawer2.vue.js.map +1 -1
- package/dist/layouts/TabsBar.vue.js +2 -2
- package/dist/layouts/TabsBar2.vue.js +97 -69
- package/dist/layouts/TabsBar2.vue.js.map +1 -1
- package/dist/layouts/components/SideNav.vue.d.ts +3 -0
- package/dist/layouts/components/SideNav.vue.js +1 -1
- package/dist/layouts/components/SideNav2.vue.js +54 -26
- package/dist/layouts/components/SideNav2.vue.js.map +1 -1
- package/dist/layouts/default.vue.js +1 -1
- package/dist/layouts/default2.vue.js +170 -140
- package/dist/layouts/default2.vue.js.map +1 -1
- package/dist/lib/loginHero.d.ts +2 -2
- package/dist/lib/loginHero.js.map +1 -1
- package/dist/lib/runtime.js +1 -1
- package/dist/lib/watermark.d.ts +110 -0
- package/dist/lib/watermark.js +151 -0
- package/dist/lib/watermark.js.map +1 -0
- package/dist/locales/en-US.d.ts +221 -15
- package/dist/locales/en-US.js +230 -21
- package/dist/locales/en-US.js.map +1 -1
- package/dist/locales/kernelMenuTitles.d.ts +1 -0
- package/dist/locales/kernelMenuTitles.js +128 -0
- package/dist/locales/kernelMenuTitles.js.map +1 -0
- package/dist/locales/menuTitle.d.ts +3 -0
- package/dist/locales/menuTitle.js +14 -12
- package/dist/locales/menuTitle.js.map +1 -1
- package/dist/locales/zh-CN.d.ts +221 -15
- package/dist/locales/zh-CN.js +238 -28
- package/dist/locales/zh-CN.js.map +1 -1
- package/dist/router/index.js +41 -32
- package/dist/router/index.js.map +1 -1
- package/dist/router/namedPage.d.ts +4 -0
- package/dist/router/namedPage.js +7 -7
- package/dist/router/namedPage.js.map +1 -1
- package/dist/router/viewRegistry.js +8 -8
- package/dist/router/viewRegistry.js.map +1 -1
- package/dist/stores/app.d.ts +0 -12
- package/dist/stores/app.js +11 -12
- package/dist/stores/app.js.map +1 -1
- package/dist/stores/tabs.js.map +1 -1
- package/dist/stores/user.d.ts +10 -0
- package/dist/stores/user.js.map +1 -1
- package/dist/style.css +1 -1
- package/dist/theme/accentTokens.d.ts +27 -0
- package/dist/theme/accentTokens.js +54 -0
- package/dist/theme/accentTokens.js.map +1 -0
- package/dist/theme/accents.d.ts +21 -1
- package/dist/theme/accents.js +11 -2
- package/dist/theme/accents.js.map +1 -1
- package/dist/theme/mix.d.ts +58 -7
- package/dist/theme/mix.js +115 -30
- package/dist/theme/mix.js.map +1 -1
- package/dist/theme/naive-theme.d.ts +5 -2
- package/dist/theme/naive-theme.js +405 -75
- package/dist/theme/naive-theme.js.map +1 -1
- package/dist/utils/jwt.d.ts +8 -0
- package/dist/utils/jwt.js +14 -0
- package/dist/utils/jwt.js.map +1 -0
- package/dist/utils/menuIcon.d.ts +2 -0
- package/dist/utils/menuIcon.js +8 -0
- package/dist/utils/menuIcon.js.map +1 -0
- package/dist/utils/oauthBrand.js.map +1 -1
- package/dist/utils/tableFilter.d.ts +88 -0
- package/dist/utils/tableFilter.js +116 -0
- package/dist/utils/tableFilter.js.map +1 -0
- package/dist/utils/tableToolbar.d.ts +18 -0
- package/dist/utils/tableToolbar.js +11 -0
- package/dist/utils/tableToolbar.js.map +1 -0
- package/dist/utils/treeFilter.d.ts +20 -0
- package/dist/utils/treeFilter.js +24 -0
- package/dist/utils/treeFilter.js.map +1 -0
- package/dist/views/dashboard/ShortcutPicker.vue.js +1 -1
- package/dist/views/dashboard/ShortcutPicker2.vue.js +73 -48
- package/dist/views/dashboard/ShortcutPicker2.vue.js.map +1 -1
- package/dist/views/dashboard/biz.vue.js +1 -1
- package/dist/views/dashboard/biz2.vue.js +310 -257
- package/dist/views/dashboard/biz2.vue.js.map +1 -1
- package/dist/views/dashboard/workbench.vue.js +2 -2
- package/dist/views/dashboard/workbench2.vue.js +141 -155
- package/dist/views/dashboard/workbench2.vue.js.map +1 -1
- package/dist/views/embed/iframe.vue.js +2 -2
- package/dist/views/embed/iframe2.vue.js +22 -15
- package/dist/views/embed/iframe2.vue.js.map +1 -1
- package/dist/views/error/404.vue.js +2 -2
- package/dist/views/error/4042.vue.js +33 -24
- package/dist/views/error/4042.vue.js.map +1 -1
- package/dist/views/error/BootError.vue.js +1 -1
- package/dist/views/error/BootError2.vue.js +59 -48
- package/dist/views/error/BootError2.vue.js.map +1 -1
- package/dist/views/error/MissingRoute.vue.js +2 -2
- package/dist/views/error/MissingRoute2.vue.js +34 -15
- package/dist/views/error/MissingRoute2.vue.js.map +1 -1
- package/dist/views/login/LoginForm.vue.d.ts +7 -1
- package/dist/views/login/LoginForm.vue.js +2 -2
- package/dist/views/login/LoginForm2.vue.js +580 -488
- package/dist/views/login/LoginForm2.vue.js.map +1 -1
- package/dist/views/login/components/LoginDesk.vue.d.ts +36 -0
- package/dist/views/login/components/LoginDesk.vue.js +9 -0
- package/dist/views/login/components/LoginDesk.vue.js.map +1 -0
- package/dist/views/login/components/LoginDesk2.vue.js +100 -0
- package/dist/views/login/components/LoginDesk2.vue.js.map +1 -0
- package/dist/views/login/components/LoginHeroPanel.vue.js +3 -3
- package/dist/views/login/components/LoginHeroPanel2.vue.js +34 -39
- package/dist/views/login/components/LoginHeroPanel2.vue.js.map +1 -1
- package/dist/views/login/index.vue.js +1 -1
- package/dist/views/login/index2.vue.js +141 -71
- package/dist/views/login/index2.vue.js.map +1 -1
- package/dist/views/login/layout.d.ts +11 -0
- package/dist/views/login/layout.js +27 -0
- package/dist/views/login/layout.js.map +1 -0
- package/dist/views/mfa/index.vue.js +2 -2
- package/dist/views/mfa/index2.vue.js +367 -321
- package/dist/views/mfa/index2.vue.js.map +1 -1
- package/dist/views/module/index.vue.js +2 -2
- package/dist/views/module/index2.vue.js +132 -99
- package/dist/views/module/index2.vue.js.map +1 -1
- package/dist/views/oauth/callback.vue.js +2 -2
- package/dist/views/oauth/callback2.vue.js +65 -51
- package/dist/views/oauth/callback2.vue.js.map +1 -1
- package/dist/views/personal/bindings.vue.js +2 -2
- package/dist/views/personal/bindings2.vue.js +98 -94
- package/dist/views/personal/bindings2.vue.js.map +1 -1
- package/dist/views/personal/notice2.vue.js +103 -76
- package/dist/views/personal/notice2.vue.js.map +1 -1
- package/dist/views/personal/password2.vue.js +47 -40
- package/dist/views/personal/password2.vue.js.map +1 -1
- package/dist/views/personal/profile.vue.js +3 -3
- package/dist/views/personal/profile2.vue.js +24 -18
- package/dist/views/personal/profile2.vue.js.map +1 -1
- package/dist/views/personal/security.vue.js +2 -2
- package/dist/views/personal/security2.vue.js +65 -53
- package/dist/views/personal/security2.vue.js.map +1 -1
- package/dist/views/personal/sessions.vue.js +2 -2
- package/dist/views/personal/sessions2.vue.js +67 -62
- package/dist/views/personal/sessions2.vue.js.map +1 -1
- package/dist/views/system/ai-model/components/ProviderCard.vue.js +2 -2
- package/dist/views/system/ai-model/components/ProviderCard2.vue.js +142 -130
- package/dist/views/system/ai-model/components/ProviderCard2.vue.js.map +1 -1
- package/dist/views/system/ai-model/components/ProviderForm.vue.js +2 -2
- package/dist/views/system/ai-model/components/ProviderForm2.vue.js +71 -70
- package/dist/views/system/ai-model/components/ProviderForm2.vue.js.map +1 -1
- package/dist/views/system/ai-model/index.vue.js +2 -2
- package/dist/views/system/ai-model/index2.vue.js +99 -99
- package/dist/views/system/ai-model/index2.vue.js.map +1 -1
- package/dist/views/system/ai-model/presets.d.ts +1 -1
- package/dist/views/system/ai-model/presets.js +18 -18
- package/dist/views/system/ai-model/presets.js.map +1 -1
- package/dist/views/system/ai-usage/index.vue.js +2 -2
- package/dist/views/system/ai-usage/index2.vue.js +356 -258
- package/dist/views/system/ai-usage/index2.vue.js.map +1 -1
- package/dist/views/system/api-docs/index.vue.js +5 -2
- package/dist/views/system/api-docs/index.vue.js.map +1 -1
- package/dist/views/system/api-docs/index2.vue.js +92 -42
- package/dist/views/system/api-docs/index2.vue.js.map +1 -1
- package/dist/views/system/cache/index.vue.js +2 -2
- package/dist/views/system/cache/index2.vue.js +74 -80
- package/dist/views/system/cache/index2.vue.js.map +1 -1
- package/dist/views/system/config/components/AdminMock.vue.js +2 -2
- package/dist/views/system/config/components/AdminMock2.vue.js +60 -43
- package/dist/views/system/config/components/AdminMock2.vue.js.map +1 -1
- package/dist/views/system/config/components/AdvancedSection.vue.js +5 -2
- package/dist/views/system/config/components/AdvancedSection.vue.js.map +1 -1
- package/dist/views/system/config/components/AdvancedSection2.vue.js +98 -70
- package/dist/views/system/config/components/AdvancedSection2.vue.js.map +1 -1
- package/dist/views/system/config/components/BrandSection.vue.js +2 -2
- package/dist/views/system/config/components/BrandSection2.vue.js +121 -119
- package/dist/views/system/config/components/BrandSection2.vue.js.map +1 -1
- package/dist/views/system/config/components/CfgGroup.vue.js +3 -3
- package/dist/views/system/config/components/CfgGroup2.vue.js.map +1 -1
- package/dist/views/system/config/components/CfgRow.vue.js +1 -1
- package/dist/views/system/config/components/CfgRow2.vue.js +24 -23
- package/dist/views/system/config/components/CfgRow2.vue.js.map +1 -1
- package/dist/views/system/config/components/CfgSegment.vue.js +1 -1
- package/dist/views/system/config/components/CfgSegment2.vue.js +16 -15
- package/dist/views/system/config/components/CfgSegment2.vue.js.map +1 -1
- package/dist/views/system/config/components/ConfigFormModal.vue.js +2 -2
- package/dist/views/system/config/components/ConfigFormModal2.vue.js +35 -33
- package/dist/views/system/config/components/ConfigFormModal2.vue.js.map +1 -1
- package/dist/views/system/config/components/JobSection.vue.js +2 -2
- package/dist/views/system/config/components/JobSection2.vue.js +46 -44
- package/dist/views/system/config/components/JobSection2.vue.js.map +1 -1
- package/dist/views/system/config/components/LoginMock.vue.js +3 -3
- package/dist/views/system/config/components/LoginMock2.vue.js +83 -72
- package/dist/views/system/config/components/LoginMock2.vue.js.map +1 -1
- package/dist/views/system/config/components/LogoCropper.vue.js +1 -1
- package/dist/views/system/config/components/LogoCropper2.vue.js.map +1 -1
- package/dist/views/system/config/components/LogoEditor.vue.js +2 -2
- package/dist/views/system/config/components/LogoEditor2.vue.js +11 -13
- package/dist/views/system/config/components/LogoEditor2.vue.js.map +1 -1
- package/dist/views/system/config/components/ProviderSheet.vue.js +3 -3
- package/dist/views/system/config/components/ProviderSheet2.vue.js.map +1 -1
- package/dist/views/system/config/components/SectionLayout.vue.d.ts +4 -2
- package/dist/views/system/config/components/SectionLayout.vue.js +2 -2
- package/dist/views/system/config/components/SectionLayout2.vue.js +51 -27
- package/dist/views/system/config/components/SectionLayout2.vue.js.map +1 -1
- package/dist/views/system/config/components/SecuritySection.vue.js +2 -2
- package/dist/views/system/config/components/SecuritySection2.vue.js +207 -206
- package/dist/views/system/config/components/SecuritySection2.vue.js.map +1 -1
- package/dist/views/system/config/components/SensitiveSection.vue.js +2 -2
- package/dist/views/system/config/components/SensitiveSection2.vue.js +107 -102
- package/dist/views/system/config/components/SensitiveSection2.vue.js.map +1 -1
- package/dist/views/system/config/components/UploadSection.vue.js +2 -2
- package/dist/views/system/config/components/UploadSection2.vue.js +86 -77
- package/dist/views/system/config/components/UploadSection2.vue.js.map +1 -1
- package/dist/views/system/config/components/WatermarkSection.vue.js +8 -0
- package/dist/views/system/config/components/WatermarkSection.vue.js.map +1 -0
- package/dist/views/system/config/components/WatermarkSection2.vue.js +284 -0
- package/dist/views/system/config/components/WatermarkSection2.vue.js.map +1 -0
- package/dist/views/system/config/draft.d.ts +2 -2
- package/dist/views/system/config/draft.js.map +1 -1
- package/dist/views/system/config/groups.d.ts +4 -1
- package/dist/views/system/config/groups.js +54 -49
- package/dist/views/system/config/groups.js.map +1 -1
- package/dist/views/system/config/index.vue.js +3 -2
- package/dist/views/system/config/index.vue.js.map +1 -1
- package/dist/views/system/config/index2.vue.js +173 -148
- package/dist/views/system/config/index2.vue.js.map +1 -1
- package/dist/views/system/config/layoutMode.d.ts +23 -0
- package/dist/views/system/config/layoutMode.js +28 -0
- package/dist/views/system/config/layoutMode.js.map +1 -0
- package/dist/views/system/dict/index.vue.js +2 -2
- package/dist/views/system/dict/index2.vue.js +471 -366
- package/dist/views/system/dict/index2.vue.js.map +1 -1
- package/dist/views/system/file/index2.vue.js +91 -76
- package/dist/views/system/file/index2.vue.js.map +1 -1
- package/dist/views/system/job/index.vue.js +3 -3
- package/dist/views/system/job/index2.vue.js +897 -828
- package/dist/views/system/job/index2.vue.js.map +1 -1
- package/dist/views/system/job-log/components/AttemptTable.vue.d.ts +8 -0
- package/dist/views/system/job-log/components/AttemptTable.vue.js +5 -0
- package/dist/views/system/job-log/components/AttemptTable.vue.js.map +1 -0
- package/dist/views/system/job-log/components/AttemptTable2.vue.js +54 -0
- package/dist/views/system/job-log/components/AttemptTable2.vue.js.map +1 -0
- package/dist/views/system/job-log/index.vue.js +2 -2
- package/dist/views/system/job-log/index2.vue.js +193 -207
- package/dist/views/system/job-log/index2.vue.js.map +1 -1
- package/dist/views/system/job-log/runStatus.d.ts +13 -0
- package/dist/views/system/job-log/runStatus.js +26 -0
- package/dist/views/system/job-log/runStatus.js.map +1 -0
- package/dist/views/system/job-monitor/index.vue.js +2 -2
- package/dist/views/system/job-monitor/index2.vue.js +172 -180
- package/dist/views/system/job-monitor/index2.vue.js.map +1 -1
- package/dist/views/system/log/exception/index.vue.js +2 -2
- package/dist/views/system/log/exception/index2.vue.js +135 -96
- package/dist/views/system/log/exception/index2.vue.js.map +1 -1
- package/dist/views/system/log/login/index2.vue.js +62 -41
- package/dist/views/system/log/login/index2.vue.js.map +1 -1
- package/dist/views/system/log/op/index.vue.js +2 -2
- package/dist/views/system/log/op/index2.vue.js +200 -162
- package/dist/views/system/log/op/index2.vue.js.map +1 -1
- package/dist/views/system/menu/components/ButtonManager.vue.js +2 -2
- package/dist/views/system/menu/components/ButtonManager2.vue.js +206 -190
- package/dist/views/system/menu/components/ButtonManager2.vue.js.map +1 -1
- package/dist/views/system/menu/components/MenuFormModal.vue.js +2 -2
- package/dist/views/system/menu/components/MenuFormModal2.vue.js +127 -118
- package/dist/views/system/menu/components/MenuFormModal2.vue.js.map +1 -1
- package/dist/views/system/menu/index.vue.js +1 -1
- package/dist/views/system/menu/index2.vue.js +216 -183
- package/dist/views/system/menu/index2.vue.js.map +1 -1
- package/dist/views/system/module/index.vue.js +1 -1
- package/dist/views/system/module/index2.vue.js +177 -144
- package/dist/views/system/module/index2.vue.js.map +1 -1
- package/dist/views/system/monitor/index.vue.js +2 -2
- package/dist/views/system/monitor/index2.vue.js +134 -149
- package/dist/views/system/monitor/index2.vue.js.map +1 -1
- package/dist/views/system/notice/index.vue.js +1 -1
- package/dist/views/system/notice/index2.vue.js +209 -181
- package/dist/views/system/notice/index2.vue.js.map +1 -1
- package/dist/views/system/org/index.vue.js +1 -1
- package/dist/views/system/org/index2.vue.js +278 -248
- package/dist/views/system/org/index2.vue.js.map +1 -1
- package/dist/views/system/position/index.vue.js +5 -2
- package/dist/views/system/position/index.vue.js.map +1 -1
- package/dist/views/system/position/index2.vue.js +128 -92
- package/dist/views/system/position/index2.vue.js.map +1 -1
- package/dist/views/system/recycle/index.vue.js +2 -2
- package/dist/views/system/recycle/index2.vue.js +90 -67
- package/dist/views/system/recycle/index2.vue.js.map +1 -1
- package/dist/views/system/role/components/GrantMenuSheet.vue.d.ts +20 -0
- package/dist/views/system/role/components/GrantMenuSheet.vue.js +8 -0
- package/dist/views/system/role/components/GrantMenuSheet.vue.js.map +1 -0
- package/dist/views/system/role/components/GrantMenuSheet2.vue.js +117 -0
- package/dist/views/system/role/components/GrantMenuSheet2.vue.js.map +1 -0
- package/dist/views/system/role/components/GrantMenuTable.vue.d.ts +6 -4
- package/dist/views/system/role/components/GrantMenuTable.vue.js +2 -2
- package/dist/views/system/role/components/GrantMenuTable2.vue.js +279 -177
- package/dist/views/system/role/components/GrantMenuTable2.vue.js.map +1 -1
- package/dist/views/system/role/components/MatchText.vue.d.ts +7 -0
- package/dist/views/system/role/components/MatchText.vue.js +8 -0
- package/dist/views/system/role/components/MatchText.vue.js.map +1 -0
- package/dist/views/system/role/components/MatchText2.vue.js +29 -0
- package/dist/views/system/role/components/MatchText2.vue.js.map +1 -0
- package/dist/views/system/role/components/grantMenuGroups.d.ts +36 -0
- package/dist/views/system/role/components/grantMenuGroups.js +110 -48
- package/dist/views/system/role/components/grantMenuGroups.js.map +1 -1
- package/dist/views/system/role/index.vue.js +5 -2
- package/dist/views/system/role/index.vue.js.map +1 -1
- package/dist/views/system/role/index2.vue.js +181 -165
- package/dist/views/system/role/index2.vue.js.map +1 -1
- package/dist/views/system/session/index2.vue.js +75 -49
- package/dist/views/system/session/index2.vue.js.map +1 -1
- package/dist/views/system/user/components/ResetPasswordModal.vue.js +2 -2
- package/dist/views/system/user/components/ResetPasswordModal2.vue.js +2 -0
- package/dist/views/system/user/components/ResetPasswordModal2.vue.js.map +1 -1
- package/dist/views/system/user/components/UserFormModal.vue.js +2 -2
- package/dist/views/system/user/components/UserFormModal2.vue.js +77 -76
- package/dist/views/system/user/components/UserFormModal2.vue.js.map +1 -1
- package/dist/views/system/user/index.vue.js +2 -2
- package/dist/views/system/user/index2.vue.js +362 -275
- package/dist/views/system/user/index2.vue.js.map +1 -1
- package/package.json +3 -5
- package/dist/components/SelectTable/index.vue.d.ts +0 -76
- package/dist/components/SelectTable/index2.vue.js +0 -256
- package/dist/components/SelectTable/index2.vue.js.map +0 -1
- package/dist/composables/useTableRowSort.d.ts +0 -20
- package/dist/composables/useTableRowSort.js +0 -59
- package/dist/composables/useTableRowSort.js.map +0 -1
- package/dist/layouts/LayoutModeCards.vue.js +0 -8
- package/dist/layouts/LayoutModeCards.vue.js.map +0 -1
- package/dist/layouts/LayoutModeCards2.vue.js +0 -67
- package/dist/layouts/LayoutModeCards2.vue.js.map +0 -1
- package/dist/layouts/SettingRow.vue.d.ts +0 -16
- package/dist/layouts/SettingRow.vue.js +0 -8
- package/dist/layouts/SettingRow.vue.js.map +0 -1
- package/dist/layouts/SettingRow2.vue.js +0 -23
- package/dist/layouts/SettingRow2.vue.js.map +0 -1
- package/dist/views/login/skins/AuroraGlass.vue.js +0 -8
- package/dist/views/login/skins/AuroraGlass.vue.js.map +0 -1
- package/dist/views/login/skins/AuroraGlass2.vue.js +0 -80
- package/dist/views/login/skins/AuroraGlass2.vue.js.map +0 -1
- package/dist/views/login/skins/SplitPanel.vue.d.ts +0 -3
- package/dist/views/login/skins/SplitPanel.vue.js +0 -8
- package/dist/views/login/skins/SplitPanel.vue.js.map +0 -1
- package/dist/views/login/skins/SplitPanel2.vue.js +0 -65
- package/dist/views/login/skins/SplitPanel2.vue.js.map +0 -1
- package/dist/views/login/skins/Spotlight.vue.d.ts +0 -3
- package/dist/views/login/skins/Spotlight.vue.js +0 -8
- package/dist/views/login/skins/Spotlight.vue.js.map +0 -1
- package/dist/views/login/skins/Spotlight2.vue.js +0 -36
- package/dist/views/login/skins/Spotlight2.vue.js.map +0 -1
- package/dist/views/login/skins.d.ts +0 -8
- package/dist/views/login/skins.js +0 -13
- package/dist/views/login/skins.js.map +0 -1
- /package/dist/components/{SelectTable → TableTotal}/index.vue.js.map +0 -0
- /package/dist/layouts/{LayoutModeCards.vue.d.ts → AccentPicker.vue.d.ts} +0 -0
- /package/dist/views/{login/skins/AuroraGlass.vue.d.ts → system/config/components/WatermarkSection.vue.d.ts} +0 -0
package/dist/router/index.js
CHANGED
|
@@ -1,63 +1,72 @@
|
|
|
1
|
-
import { createRouter as c, createWebHistory as
|
|
2
|
-
import { staticRoutes as
|
|
1
|
+
import { createRouter as c, createWebHistory as m } from "vue-router";
|
|
2
|
+
import { staticRoutes as f } from "./routes.js";
|
|
3
3
|
import { useUserStore as p } from "../stores/user.js";
|
|
4
4
|
import { useAuthStore as l } from "../stores/auth.js";
|
|
5
5
|
import { useTabsStore as h } from "../stores/tabs.js";
|
|
6
|
-
import { loadingBar as
|
|
6
|
+
import { loadingBar as s } from "../lib/loadingBar.js";
|
|
7
7
|
import { reloadOnChunkError as d } from "../lib/chunkReload.js";
|
|
8
8
|
import { ensureAccessToken as g } from "../api/client.js";
|
|
9
9
|
import { isSessionDead as y } from "./bootFailure.js";
|
|
10
|
-
import { personalApi as
|
|
11
|
-
const
|
|
12
|
-
history:
|
|
13
|
-
routes:
|
|
10
|
+
import { personalApi as b } from "../api/index.js";
|
|
11
|
+
const o = c({
|
|
12
|
+
history: m(),
|
|
13
|
+
routes: f
|
|
14
14
|
});
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
o.beforeEach(() => {
|
|
16
|
+
s.start();
|
|
17
17
|
});
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
o.afterEach(() => {
|
|
19
|
+
s.finish();
|
|
20
20
|
});
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
o.beforeResolve(async (e) => {
|
|
22
|
+
const r = e.matched.map(
|
|
23
|
+
(t) => {
|
|
24
|
+
var n, a;
|
|
25
|
+
return (a = (n = t.components) == null ? void 0 : n.default) == null ? void 0 : a.preload;
|
|
26
|
+
}
|
|
27
|
+
);
|
|
28
|
+
await Promise.all(r.map((t) => t == null ? void 0 : t()));
|
|
29
|
+
});
|
|
30
|
+
o.onError((e) => {
|
|
31
|
+
s.error(), d(e);
|
|
23
32
|
});
|
|
24
|
-
let
|
|
33
|
+
let u = [];
|
|
25
34
|
function L(e) {
|
|
26
|
-
|
|
35
|
+
u.push(e);
|
|
27
36
|
}
|
|
28
|
-
function
|
|
29
|
-
for (const e of
|
|
30
|
-
|
|
37
|
+
function i() {
|
|
38
|
+
for (const e of u) o.hasRoute(e) && o.removeRoute(e);
|
|
39
|
+
u = [];
|
|
31
40
|
}
|
|
32
|
-
|
|
33
|
-
var
|
|
34
|
-
const r = p(),
|
|
41
|
+
o.beforeEach(async (e) => {
|
|
42
|
+
var n;
|
|
43
|
+
const r = p(), t = l();
|
|
35
44
|
if (!r.accessToken && (r.cookieSession || r.refreshToken) && (await g() || r.clear()), e.name === "login")
|
|
36
|
-
return e.query.pendingLink || e.query.totpChallenge ? ((r.accessToken || r.refreshToken || r.cookieSession) && (
|
|
45
|
+
return e.query.pendingLink || e.query.totpChallenge ? ((r.accessToken || r.refreshToken || r.cookieSession) && (i(), t.reset(), r.clear()), !0) : r.isLoggedIn ? { path: "/", replace: !0 } : !0;
|
|
37
46
|
if (e.meta.public) return !0;
|
|
38
47
|
if (!r.isLoggedIn) return { path: "/login", replace: !0 };
|
|
39
|
-
if ((
|
|
48
|
+
if ((n = r.userInfo) != null && n.mustChangePassword)
|
|
40
49
|
return e.path === "/personal/password" ? !0 : { path: "/personal/password", replace: !0 };
|
|
41
50
|
if (e.name === "boot-error") return !0;
|
|
42
|
-
if (!
|
|
51
|
+
if (!t.routesReady)
|
|
43
52
|
try {
|
|
44
53
|
const { useModule: a } = await import("../composables/useModule.js");
|
|
45
|
-
return (await a().enterInitial()).chooser ? e.name === "module" ? !0 : { path: "/module", replace: !0 } : e.name === "module" ? !0 : e.path === "/" ? { path:
|
|
54
|
+
return (await a().enterInitial()).chooser ? e.name === "module" ? !0 : { path: "/module", replace: !0 } : e.name === "module" ? !0 : e.path === "/" ? { path: t.homePath, replace: !0 } : e.fullPath;
|
|
46
55
|
} catch (a) {
|
|
47
|
-
return y(a) ? (
|
|
56
|
+
return y(a) ? (i(), t.reset(), r.clear(), { path: "/login", replace: !0 }) : { path: "/boot-error", query: { redirect: e.fullPath }, replace: !0 };
|
|
48
57
|
}
|
|
49
|
-
return e.path === "/" ? { path:
|
|
58
|
+
return e.path === "/" ? { path: t.homePath, replace: !0 } : !0;
|
|
50
59
|
});
|
|
51
|
-
|
|
60
|
+
o.afterEach((e) => {
|
|
52
61
|
e.meta.public || ["login", "module", "not-found", "personal"].includes(e.name) || e.matched.some((r) => r.name === "layout") && h().addTab(e);
|
|
53
62
|
});
|
|
54
|
-
|
|
55
|
-
e.meta.public || ["login", "module", "not-found", "personal"].includes(e.name) || e.matched.some((r) => r.name === "layout") &&
|
|
63
|
+
o.afterEach((e) => {
|
|
64
|
+
e.meta.public || ["login", "module", "not-found", "personal"].includes(e.name) || e.matched.some((r) => r.name === "layout") && b.recordShortcutVisit(e.path).catch(() => {
|
|
56
65
|
});
|
|
57
66
|
});
|
|
58
67
|
export {
|
|
59
68
|
L as registerDynamic,
|
|
60
|
-
|
|
61
|
-
|
|
69
|
+
i as resetRouter,
|
|
70
|
+
o as router
|
|
62
71
|
};
|
|
63
72
|
//# sourceMappingURL=index.js.map
|
package/dist/router/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../src/router/index.ts"],"sourcesContent":["import { createRouter, createWebHistory } from 'vue-router'\nimport { staticRoutes } from './routes'\nimport { useUserStore } from '#/stores/user'\nimport { useAuthStore } from '#/stores/auth'\nimport { useTabsStore } from '#/stores/tabs'\nimport { loadingBar } from '#/lib/loadingBar'\nimport { reloadOnChunkError } from '#/lib/chunkReload'\nimport { ensureAccessToken } from '#/api/client'\nimport { isSessionDead } from './bootFailure'\nimport { personalApi } from '#/api'\n\nexport const router = createRouter({\n history: createWebHistory(),\n routes: staticRoutes,\n})\n\n// 路由加载进度条:懒加载 chunk 与 F5 重建菜单(enterInitial)期间给出反馈。\nrouter.beforeEach(() => {\n loadingBar.start()\n})\nrouter.afterEach(() => {\n loadingBar.finish()\n})\n// 路由懒加载失败大多是发版后旧 chunk 404 —— 自动重载一次拿新 index.html(每标签页仅一次)。\nrouter.onError(err => {\n loadingBar.error()\n reloadOnChunkError(err)\n})\n\n// 动态路由名登记,用于登出/切应用时精确移除。\nlet dynamicNames: Array<string | symbol> = []\nexport function registerDynamic(name: string | symbol) {\n dynamicNames.push(name)\n}\nexport function resetRouter() {\n for (const n of dynamicNames) if (router.hasRoute(n)) router.removeRoute(n)\n dynamicNames = []\n}\n\nrouter.beforeEach(async to => {\n const user = useUserStore()\n const auth = useAuthStore()\n\n // Cookie 会话:access 只在内存,F5 后靠 cookieSession 标记 + HttpOnly refresh 静默换发。\n // 默认模式令牌已 localStorage 水合,ensureAccessToken 立即 true。\n if (!user.accessToken && (user.cookieSession || user.refreshToken)) {\n const ok = await ensureAccessToken()\n if (!ok) user.clear()\n }\n\n // 登录页是唯一免认证页;已登录再访问则回首页。\n // 例外:SSO 未绑定 pendingLink / SSO 后 TOTP 挑战——必须停在登录页完成账密或二次验证。\n // 若仍带着残留会话进 /login,会误弹回首页,看起来像「解绑后 GitHub 仍直接登录」。\n if (to.name === 'login') {\n const needReauth = !!(to.query.pendingLink || to.query.totpChallenge)\n if (needReauth) {\n if (user.accessToken || user.refreshToken || user.cookieSession) {\n resetRouter()\n auth.reset()\n user.clear()\n }\n return true\n }\n return user.isLoggedIn ? { path: '/', replace: true } : true\n }\n\n // 公开的 OAuth 回调和 MFA 绑定/恢复页不能被登录守卫送回登录页。\n if (to.meta.public) return true\n\n if (!user.isLoggedIn) return { path: '/login', replace: true }\n\n // 强制改密守卫:管理员建号/重置后首登,未改密前只允许停留在改密页,阻断其它一切导航\n // (含应用选择/门户重建)。改密页是静态路由,无需动态路由就绪即可渲染,故放在 routesReady 重建之前,\n // 直接放行改密页避免\"重建→选应用→又被弹回\"的循环。改密成功后现有流程强制登出重登,标志由后端清零。\n if (user.userInfo?.mustChangePassword) {\n return to.path === '/personal/password' ? true : { path: '/personal/password', replace: true }\n }\n\n // 重建失败页本身就是重建失败的落点,放行,否则下面的重建守卫会在它身上再试一次,变成死循环。\n if (to.name === 'boot-error') return true\n\n // 刷新白屏守卫:动态路由只活在内存,F5/深链时 routesReady=false → 重建后重解析。\n // 注意:不能用 to.meta.public 短路——未注册的动态路由会先命中 catch-all(404),\n // 若按 public 放行就会错显 404 而非重建。\n if (!auth.routesReady) {\n try {\n const { useModule } = await import('#/composables/useModule')\n const res = await useModule().enterInitial()\n if (res.chooser) return to.name === 'module' ? true : { path: '/module', replace: true }\n // 选应用页放行:enterInitial 已填好 auth.modules,渲染所需数据齐备。\n // 不能弹回 '/' —— 那样默认应用一旦设定就再无入口改它(右上角九宫格正是导航到这里)。\n if (to.name === 'module') return true\n // 目标是 '/' 时不能 return to.fullPath——那是重定向到自身,'/' 没有静态 redirect,会被判成无限重定向。\n // 此刻菜单树已就绪,直接给出首页。\n if (to.path === '/') return { path: auth.homePath, replace: true }\n return to.fullPath // 重解析当前 URL(此时动态路由已就绪)\n } catch (e) {\n // 只有会话确实失效才清会话;网络抖动/5xx/限流留在原地给可重试的错误页(见 bootFailure.ts)。\n if (isSessionDead(e)) {\n resetRouter()\n auth.reset()\n user.clear()\n return { path: '/login', replace: true }\n }\n return { path: '/boot-error', query: { redirect: to.fullPath }, replace: true }\n }\n }\n\n // '/' 落到当前应用自己的首页。放在守卫里(而非 layout 的 redirect)——redirect 在 resolve 阶段求值,\n // 早于本守卫,那时 menuTree 还空、动态路由未建,算出的首页必然是错的。\n if (to.path === '/') return { path: auth.homePath, replace: true }\n\n return true\n})\n\n// 记录已访问页为标签(动态路由就绪后触发,F5 重解析也会命中)。\nrouter.afterEach(to => {\n if (to.meta.public) return\n if (['login', 'module', 'not-found', 'personal'].includes(to.name as string)) return\n if (!to.matched.some(r => r.name === 'layout')) return\n useTabsStore().addTab(to)\n})\n\n// 记一次工作台快捷方式访问(高频自动补位用)。守卫条件与上面记标签页的那个一致,\n// 失败静默——这不是用户能感知的操作,不值得为它弹错误提示。\nrouter.afterEach(to => {\n if (to.meta.public) return\n if (['login', 'module', 'not-found', 'personal'].includes(to.name as string)) return\n if (!to.matched.some(r => r.name === 'layout')) return\n personalApi.recordShortcutVisit(to.path).catch(() => {})\n})\n"],"names":["router","createRouter","createWebHistory","staticRoutes","loadingBar","err","reloadOnChunkError","dynamicNames","registerDynamic","name","resetRouter","n","
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../src/router/index.ts"],"sourcesContent":["import { createRouter, createWebHistory } from 'vue-router'\nimport { staticRoutes } from './routes'\nimport { useUserStore } from '#/stores/user'\nimport { useAuthStore } from '#/stores/auth'\nimport { useTabsStore } from '#/stores/tabs'\nimport { loadingBar } from '#/lib/loadingBar'\nimport { reloadOnChunkError } from '#/lib/chunkReload'\nimport { ensureAccessToken } from '#/api/client'\nimport { isSessionDead } from './bootFailure'\nimport type { PreloadablePage } from './namedPage'\nimport { personalApi } from '#/api'\n\nexport const router = createRouter({\n history: createWebHistory(),\n routes: staticRoutes,\n})\n\n// 路由加载进度条:懒加载 chunk 与 F5 重建菜单(enterInitial)期间给出反馈。\nrouter.beforeEach(() => {\n loadingBar.start()\n})\nrouter.afterEach(() => {\n loadingBar.finish()\n})\n// 导航落定前把目标页的 chunk 取回来:页面组件是 namedPage 包的异步组件,vue-router 看不见里面的 import,\n// 不预取的话旧页会先被卸掉、露出一段空白再出新页。chunk 已缓存时这一步是瞬时的;\n// 失败交给 onError(发版后旧 chunk 404 → 自动重载)。\nrouter.beforeResolve(async to => {\n const loaders = to.matched.map(\n r => (r.components?.default as PreloadablePage | undefined)?.preload,\n )\n await Promise.all(loaders.map(load => load?.()))\n})\n// 路由懒加载失败大多是发版后旧 chunk 404 —— 自动重载一次拿新 index.html(每标签页仅一次)。\nrouter.onError(err => {\n loadingBar.error()\n reloadOnChunkError(err)\n})\n\n// 动态路由名登记,用于登出/切应用时精确移除。\nlet dynamicNames: Array<string | symbol> = []\nexport function registerDynamic(name: string | symbol) {\n dynamicNames.push(name)\n}\nexport function resetRouter() {\n for (const n of dynamicNames) if (router.hasRoute(n)) router.removeRoute(n)\n dynamicNames = []\n}\n\nrouter.beforeEach(async to => {\n const user = useUserStore()\n const auth = useAuthStore()\n\n // Cookie 会话:access 只在内存,F5 后靠 cookieSession 标记 + HttpOnly refresh 静默换发。\n // 默认模式令牌已 localStorage 水合,ensureAccessToken 立即 true。\n if (!user.accessToken && (user.cookieSession || user.refreshToken)) {\n const ok = await ensureAccessToken()\n if (!ok) user.clear()\n }\n\n // 登录页是唯一免认证页;已登录再访问则回首页。\n // 例外:SSO 未绑定 pendingLink / SSO 后 TOTP 挑战——必须停在登录页完成账密或二次验证。\n // 若仍带着残留会话进 /login,会误弹回首页,看起来像「解绑后 GitHub 仍直接登录」。\n if (to.name === 'login') {\n const needReauth = !!(to.query.pendingLink || to.query.totpChallenge)\n if (needReauth) {\n if (user.accessToken || user.refreshToken || user.cookieSession) {\n resetRouter()\n auth.reset()\n user.clear()\n }\n return true\n }\n return user.isLoggedIn ? { path: '/', replace: true } : true\n }\n\n // 公开的 OAuth 回调和 MFA 绑定/恢复页不能被登录守卫送回登录页。\n if (to.meta.public) return true\n\n if (!user.isLoggedIn) return { path: '/login', replace: true }\n\n // 强制改密守卫:管理员建号/重置后首登,未改密前只允许停留在改密页,阻断其它一切导航\n // (含应用选择/门户重建)。改密页是静态路由,无需动态路由就绪即可渲染,故放在 routesReady 重建之前,\n // 直接放行改密页避免\"重建→选应用→又被弹回\"的循环。改密成功后现有流程强制登出重登,标志由后端清零。\n if (user.userInfo?.mustChangePassword) {\n return to.path === '/personal/password' ? true : { path: '/personal/password', replace: true }\n }\n\n // 重建失败页本身就是重建失败的落点,放行,否则下面的重建守卫会在它身上再试一次,变成死循环。\n if (to.name === 'boot-error') return true\n\n // 刷新白屏守卫:动态路由只活在内存,F5/深链时 routesReady=false → 重建后重解析。\n // 注意:不能用 to.meta.public 短路——未注册的动态路由会先命中 catch-all(404),\n // 若按 public 放行就会错显 404 而非重建。\n if (!auth.routesReady) {\n try {\n const { useModule } = await import('#/composables/useModule')\n const res = await useModule().enterInitial()\n if (res.chooser) return to.name === 'module' ? true : { path: '/module', replace: true }\n // 选应用页放行:enterInitial 已填好 auth.modules,渲染所需数据齐备。\n // 不能弹回 '/' —— 那样默认应用一旦设定就再无入口改它(右上角九宫格正是导航到这里)。\n if (to.name === 'module') return true\n // 目标是 '/' 时不能 return to.fullPath——那是重定向到自身,'/' 没有静态 redirect,会被判成无限重定向。\n // 此刻菜单树已就绪,直接给出首页。\n if (to.path === '/') return { path: auth.homePath, replace: true }\n return to.fullPath // 重解析当前 URL(此时动态路由已就绪)\n } catch (e) {\n // 只有会话确实失效才清会话;网络抖动/5xx/限流留在原地给可重试的错误页(见 bootFailure.ts)。\n if (isSessionDead(e)) {\n resetRouter()\n auth.reset()\n user.clear()\n return { path: '/login', replace: true }\n }\n return { path: '/boot-error', query: { redirect: to.fullPath }, replace: true }\n }\n }\n\n // '/' 落到当前应用自己的首页。放在守卫里(而非 layout 的 redirect)——redirect 在 resolve 阶段求值,\n // 早于本守卫,那时 menuTree 还空、动态路由未建,算出的首页必然是错的。\n if (to.path === '/') return { path: auth.homePath, replace: true }\n\n return true\n})\n\n// 记录已访问页为标签(动态路由就绪后触发,F5 重解析也会命中)。\nrouter.afterEach(to => {\n if (to.meta.public) return\n if (['login', 'module', 'not-found', 'personal'].includes(to.name as string)) return\n if (!to.matched.some(r => r.name === 'layout')) return\n useTabsStore().addTab(to)\n})\n\n// 记一次工作台快捷方式访问(高频自动补位用)。守卫条件与上面记标签页的那个一致,\n// 失败静默——这不是用户能感知的操作,不值得为它弹错误提示。\nrouter.afterEach(to => {\n if (to.meta.public) return\n if (['login', 'module', 'not-found', 'personal'].includes(to.name as string)) return\n if (!to.matched.some(r => r.name === 'layout')) return\n personalApi.recordShortcutVisit(to.path).catch(() => {})\n})\n"],"names":["router","createRouter","createWebHistory","staticRoutes","loadingBar","to","loaders","r","_b","_a","load","err","reloadOnChunkError","dynamicNames","registerDynamic","name","resetRouter","n","user","useUserStore","auth","useAuthStore","ensureAccessToken","useModule","e","isSessionDead","useTabsStore","personalApi"],"mappings":"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"}
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import { Component, AsyncComponentLoader } from 'vue';
|
|
2
|
+
/** namedPage 产出的组件带着自己的 loader,供路由守卫预加载。 */
|
|
3
|
+
export type PreloadablePage = Component & {
|
|
4
|
+
preload?: AsyncComponentLoader;
|
|
5
|
+
};
|
|
2
6
|
/**
|
|
3
7
|
* 包装懒加载页面,使「组件名 === 路由名」。
|
|
4
8
|
* keep-alive 的 :include 按组件 name 匹配,而 <script setup> 的 __name 取自文件名
|
package/dist/router/namedPage.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { defineAsyncComponent as s, defineComponent as
|
|
2
|
-
const d =
|
|
3
|
-
function a(
|
|
4
|
-
const
|
|
5
|
-
if ((
|
|
6
|
-
const
|
|
7
|
-
return r.set(
|
|
1
|
+
import { defineAsyncComponent as s, defineComponent as p, h as c } from "vue";
|
|
2
|
+
const d = p({ render: () => c("div") }), r = /* @__PURE__ */ new Map();
|
|
3
|
+
function a(o, n) {
|
|
4
|
+
const e = r.get(o);
|
|
5
|
+
if ((e == null ? void 0 : e.loader) === n) return e.comp;
|
|
6
|
+
const i = s({ loader: n, loadingComponent: d, delay: 0 }), t = p({ name: o, render: () => c("div", { class: "page-view" }, c(i)) });
|
|
7
|
+
return t.preload = n, r.set(o, { loader: n, comp: t }), t;
|
|
8
8
|
}
|
|
9
9
|
export {
|
|
10
10
|
a as namedPage
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"namedPage.js","sources":["../../src/router/namedPage.ts"],"sourcesContent":["import {\n defineAsyncComponent,\n defineComponent,\n h,\n type Component,\n type AsyncComponentLoader,\n} from 'vue'\n\n// 加载占位:必须是真实元素——defineAsyncComponent 默认 pending 态渲染 null(注释节点),\n// out-in Transition 遇到会判成\"非元素根节点\",连续快切页面时可能卡死整条过渡序列、之后每页永久空白。\n// delay:0 让占位立即生效,不留 pending-无占位的窗口期。\nconst LOADING = defineComponent({ render: () => h('div') })\n\n// 按路由名记忆化:改一次菜单就会重建全部动态路由(见 useAuthMenu.buildRoutesForModule),\n// 若每次都新建组件对象,已开标签页的路由记录会换上新身份 → keep-alive 缓存全部 miss、切回时重挂、状态清空。\n// 失效条件用 loader 引用:import.meta.glob 的 loader 每个文件一个稳定函数,\n// 组件路径没改 → 同一引用 → 复用(缓存保住);管理员改了组件路径 → 引用变 → 重建(正确失效)。\nconst cache = new Map<string, { loader: AsyncComponentLoader; comp: Component }>()\n\n/**\n * 包装懒加载页面,使「组件名 === 路由名」。\n * keep-alive 的 :include 按组件 name 匹配,而 <script setup> 的 __name 取自文件名\n * (众多 index.vue 会跨页冲突、且与路由名 menu-${id} 不符)。\n * inner 只建一次 → 身份稳定,keep-alive 缓存其子树;onActivated/onDeactivated 照常透传。\n *\n * 外面再套一层原生 <div.page-view>:default.vue 的 <transition mode=\"out-in\"> 硬性要求子节点是\n * 单个根元素,而不少页面模板是「主体 + 并排若干弹窗组件」的多根 Fragment(关着时渲染成注释节点)。\n * out-in 遇到非元素/多根会走进\"non-element root node\"分支瞬时卡死。统一套一层 div,交给 transition\n * 的永远是单元素根,任何页面(单根/多根/异步加载中)都能瞬时过渡。\n */\nexport function namedPage(name: string, loader: AsyncComponentLoader) {\n const hit = cache.get(name)\n if (hit?.loader === loader) return hit.comp\n\n const inner = defineAsyncComponent({ loader, loadingComponent: LOADING, delay: 0 })\n const comp = defineComponent({ name, render: () => h('div', { class: 'page-view' }, h(inner)) })\n cache.set(name, { loader, comp })\n return comp\n}\n"],"names":["LOADING","defineComponent","h","cache","namedPage","name","loader","hit","inner","defineAsyncComponent","comp"],"mappings":";AAWA,MAAMA,IAAUC,EAAgB,EAAE,QAAQ,MAAMC,EAAE,KAAK,GAAG,
|
|
1
|
+
{"version":3,"file":"namedPage.js","sources":["../../src/router/namedPage.ts"],"sourcesContent":["import {\n defineAsyncComponent,\n defineComponent,\n h,\n type Component,\n type AsyncComponentLoader,\n} from 'vue'\n\n// 加载占位:必须是真实元素——defineAsyncComponent 默认 pending 态渲染 null(注释节点),\n// out-in Transition 遇到会判成\"非元素根节点\",连续快切页面时可能卡死整条过渡序列、之后每页永久空白。\n// delay:0 让占位立即生效,不留 pending-无占位的窗口期。\nconst LOADING = defineComponent({ render: () => h('div') })\n\n/** namedPage 产出的组件带着自己的 loader,供路由守卫预加载。 */\nexport type PreloadablePage = Component & { preload?: AsyncComponentLoader }\n\n// 按路由名记忆化:改一次菜单就会重建全部动态路由(见 useAuthMenu.buildRoutesForModule),\n// 若每次都新建组件对象,已开标签页的路由记录会换上新身份 → keep-alive 缓存全部 miss、切回时重挂、状态清空。\n// 失效条件用 loader 引用:import.meta.glob 的 loader 每个文件一个稳定函数,\n// 组件路径没改 → 同一引用 → 复用(缓存保住);管理员改了组件路径 → 引用变 → 重建(正确失效)。\nconst cache = new Map<string, { loader: AsyncComponentLoader; comp: Component }>()\n\n/**\n * 包装懒加载页面,使「组件名 === 路由名」。\n * keep-alive 的 :include 按组件 name 匹配,而 <script setup> 的 __name 取自文件名\n * (众多 index.vue 会跨页冲突、且与路由名 menu-${id} 不符)。\n * inner 只建一次 → 身份稳定,keep-alive 缓存其子树;onActivated/onDeactivated 照常透传。\n *\n * 外面再套一层原生 <div.page-view>:default.vue 的 <transition mode=\"out-in\"> 硬性要求子节点是\n * 单个根元素,而不少页面模板是「主体 + 并排若干弹窗组件」的多根 Fragment(关着时渲染成注释节点)。\n * out-in 遇到非元素/多根会走进\"non-element root node\"分支瞬时卡死。统一套一层 div,交给 transition\n * 的永远是单元素根,任何页面(单根/多根/异步加载中)都能瞬时过渡。\n */\nexport function namedPage(name: string, loader: AsyncComponentLoader) {\n const hit = cache.get(name)\n if (hit?.loader === loader) return hit.comp\n\n const inner = defineAsyncComponent({ loader, loadingComponent: LOADING, delay: 0 })\n const comp = defineComponent({ name, render: () => h('div', { class: 'page-view' }, h(inner)) })\n // 路由守卫在导航落定前调它(见 router/index.ts 的 beforeResolve):chunk 先到位,旧页再换成新页,\n // 否则旧页卸掉后到 chunk 回来之间是一段空白,切菜单就是一次闪。\n ;(comp as PreloadablePage).preload = loader\n cache.set(name, { loader, comp })\n return comp\n}\n"],"names":["LOADING","defineComponent","h","cache","namedPage","name","loader","hit","inner","defineAsyncComponent","comp"],"mappings":";AAWA,MAAMA,IAAUC,EAAgB,EAAE,QAAQ,MAAMC,EAAE,KAAK,GAAG,GASpDC,wBAAY,IAAA;AAaX,SAASC,EAAUC,GAAcC,GAA8B;AACpE,QAAMC,IAAMJ,EAAM,IAAIE,CAAI;AAC1B,OAAIE,KAAA,gBAAAA,EAAK,YAAWD,EAAQ,QAAOC,EAAI;AAEvC,QAAMC,IAAQC,EAAqB,EAAE,QAAAH,GAAQ,kBAAkBN,GAAS,OAAO,GAAG,GAC5EU,IAAOT,EAAgB,EAAE,MAAAI,GAAM,QAAQ,MAAMH,EAAE,OAAO,EAAE,OAAO,eAAeA,EAAEM,CAAK,CAAC,GAAG;AAG7F,SAAAE,EAAyB,UAAUJ,GACrCH,EAAM,IAAIE,GAAM,EAAE,QAAAC,GAAQ,MAAAI,GAAM,GACzBA;AACT;"}
|
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
const
|
|
1
|
+
const i = {};
|
|
2
2
|
function t(e) {
|
|
3
|
-
const
|
|
4
|
-
return (
|
|
3
|
+
const o = e.lastIndexOf("/views/");
|
|
4
|
+
return (o >= 0 ? e.slice(o + 7) : e.replace(/^\.?\/+/, "")).replace(/\.vue$/, "");
|
|
5
5
|
}
|
|
6
6
|
function n(e) {
|
|
7
|
-
for (const [
|
|
7
|
+
for (const [o, s] of Object.entries(e)) i[t(o)] = s;
|
|
8
8
|
}
|
|
9
9
|
function m(e) {
|
|
10
|
-
return
|
|
10
|
+
return i[e];
|
|
11
11
|
}
|
|
12
12
|
function r() {
|
|
13
|
-
return Object.keys(
|
|
13
|
+
return Object.keys(i).toSorted();
|
|
14
14
|
}
|
|
15
15
|
function v() {
|
|
16
|
-
return Object.entries(
|
|
16
|
+
return Object.entries(i).filter(([e]) => e.endsWith("/detail"));
|
|
17
17
|
}
|
|
18
|
-
n(/* @__PURE__ */ Object.assign({ "../views/dashboard/ShortcutPicker.vue": () => import("../views/dashboard/ShortcutPicker.vue.js"), "../views/dashboard/biz.vue": () => import("../views/dashboard/biz.vue.js"), "../views/dashboard/workbench.vue": () => import("../views/dashboard/workbench.vue.js"), "../views/embed/iframe.vue": () => import("../views/embed/iframe.vue.js"), "../views/error/404.vue": () => import("../views/error/404.vue.js"), "../views/error/BootError.vue": () => import("../views/error/BootError.vue.js"), "../views/error/MissingRoute.vue": () => import("../views/error/MissingRoute.vue.js"), "../views/login/LoginForm.vue": () => import("../views/login/LoginForm.vue.js"), "../views/login/components/
|
|
18
|
+
n(/* @__PURE__ */ Object.assign({ "../views/dashboard/ShortcutPicker.vue": () => import("../views/dashboard/ShortcutPicker.vue.js"), "../views/dashboard/biz.vue": () => import("../views/dashboard/biz.vue.js"), "../views/dashboard/workbench.vue": () => import("../views/dashboard/workbench.vue.js"), "../views/embed/iframe.vue": () => import("../views/embed/iframe.vue.js"), "../views/error/404.vue": () => import("../views/error/404.vue.js"), "../views/error/BootError.vue": () => import("../views/error/BootError.vue.js"), "../views/error/MissingRoute.vue": () => import("../views/error/MissingRoute.vue.js"), "../views/login/LoginForm.vue": () => import("../views/login/LoginForm.vue.js"), "../views/login/components/LoginDesk.vue": () => import("../views/login/components/LoginDesk.vue.js"), "../views/login/components/LoginHeroPanel.vue": () => import("../views/login/components/LoginHeroPanel.vue.js"), "../views/login/index.vue": () => import("../views/login/index.vue.js"), "../views/mfa/index.vue": () => import("../views/mfa/index.vue.js"), "../views/module/index.vue": () => import("../views/module/index.vue.js"), "../views/oauth/callback.vue": () => import("../views/oauth/callback.vue.js"), "../views/personal/bindings.vue": () => import("../views/personal/bindings.vue.js"), "../views/personal/notice.vue": () => import("../views/personal/notice.vue.js"), "../views/personal/password.vue": () => import("../views/personal/password.vue.js"), "../views/personal/profile.vue": () => import("../views/personal/profile.vue.js"), "../views/personal/security.vue": () => import("../views/personal/security.vue.js"), "../views/personal/sessions.vue": () => import("../views/personal/sessions.vue.js"), "../views/system/ai-model/components/ProviderCard.vue": () => import("../views/system/ai-model/components/ProviderCard.vue.js"), "../views/system/ai-model/components/ProviderForm.vue": () => import("../views/system/ai-model/components/ProviderForm.vue.js"), "../views/system/ai-model/index.vue": () => import("../views/system/ai-model/index.vue.js"), "../views/system/ai-usage/index.vue": () => import("../views/system/ai-usage/index.vue.js"), "../views/system/api-docs/index.vue": () => import("../views/system/api-docs/index.vue.js"), "../views/system/cache/index.vue": () => import("../views/system/cache/index.vue.js"), "../views/system/config/components/AdminMock.vue": () => import("../views/system/config/components/AdminMock.vue.js"), "../views/system/config/components/AdvancedSection.vue": () => import("../views/system/config/components/AdvancedSection.vue.js"), "../views/system/config/components/BrandSection.vue": () => import("../views/system/config/components/BrandSection.vue.js"), "../views/system/config/components/CfgGroup.vue": () => import("../views/system/config/components/CfgGroup.vue.js"), "../views/system/config/components/CfgRow.vue": () => import("../views/system/config/components/CfgRow.vue.js"), "../views/system/config/components/CfgSegment.vue": () => import("../views/system/config/components/CfgSegment.vue.js"), "../views/system/config/components/ConfigFormModal.vue": () => import("../views/system/config/components/ConfigFormModal.vue.js"), "../views/system/config/components/JobSection.vue": () => import("../views/system/config/components/JobSection.vue.js"), "../views/system/config/components/LoginMock.vue": () => import("../views/system/config/components/LoginMock.vue.js"), "../views/system/config/components/LogoCropper.vue": () => import("../views/system/config/components/LogoCropper.vue.js"), "../views/system/config/components/LogoEditor.vue": () => import("../views/system/config/components/LogoEditor.vue.js"), "../views/system/config/components/ProviderSheet.vue": () => import("../views/system/config/components/ProviderSheet.vue.js"), "../views/system/config/components/ScaleToFit.vue": () => import("../views/system/config/components/ScaleToFit.vue.js"), "../views/system/config/components/SectionLayout.vue": () => import("../views/system/config/components/SectionLayout.vue.js"), "../views/system/config/components/SecuritySection.vue": () => import("../views/system/config/components/SecuritySection.vue.js"), "../views/system/config/components/SensitiveSection.vue": () => import("../views/system/config/components/SensitiveSection.vue.js"), "../views/system/config/components/SigninSection.vue": () => import("../views/system/config/components/SigninSection.vue.js"), "../views/system/config/components/UploadSection.vue": () => import("../views/system/config/components/UploadSection.vue.js"), "../views/system/config/components/WatermarkSection.vue": () => import("../views/system/config/components/WatermarkSection.vue.js"), "../views/system/config/index.vue": () => import("../views/system/config/index.vue.js"), "../views/system/dict/index.vue": () => import("../views/system/dict/index.vue.js"), "../views/system/file/index.vue": () => import("../views/system/file/index.vue.js"), "../views/system/job-log/components/AttemptTable.vue": () => import("../views/system/job-log/components/AttemptTable.vue.js"), "../views/system/job-log/index.vue": () => import("../views/system/job-log/index.vue.js"), "../views/system/job-monitor/index.vue": () => import("../views/system/job-monitor/index.vue.js"), "../views/system/job/index.vue": () => import("../views/system/job/index.vue.js"), "../views/system/log/exception/index.vue": () => import("../views/system/log/exception/index.vue.js"), "../views/system/log/login/index.vue": () => import("../views/system/log/login/index.vue.js"), "../views/system/log/op/index.vue": () => import("../views/system/log/op/index.vue.js"), "../views/system/menu/components/ButtonManager.vue": () => import("../views/system/menu/components/ButtonManager.vue.js"), "../views/system/menu/components/MenuFormModal.vue": () => import("../views/system/menu/components/MenuFormModal.vue.js"), "../views/system/menu/index.vue": () => import("../views/system/menu/index.vue.js"), "../views/system/module/index.vue": () => import("../views/system/module/index.vue.js"), "../views/system/monitor/index.vue": () => import("../views/system/monitor/index.vue.js"), "../views/system/notice/index.vue": () => import("../views/system/notice/index.vue.js"), "../views/system/org/index.vue": () => import("../views/system/org/index.vue.js"), "../views/system/position/index.vue": () => import("../views/system/position/index.vue.js"), "../views/system/recycle/index.vue": () => import("../views/system/recycle/index.vue.js"), "../views/system/role/components/GrantMenuSheet.vue": () => import("../views/system/role/components/GrantMenuSheet.vue.js"), "../views/system/role/components/GrantMenuTable.vue": () => import("../views/system/role/components/GrantMenuTable.vue.js"), "../views/system/role/components/MatchText.vue": () => import("../views/system/role/components/MatchText.vue.js"), "../views/system/role/index.vue": () => import("../views/system/role/index.vue.js"), "../views/system/session/index.vue": () => import("../views/system/session/index.vue.js"), "../views/system/user/components/ResetPasswordModal.vue": () => import("../views/system/user/components/ResetPasswordModal.vue.js"), "../views/system/user/components/UserFormModal.vue": () => import("../views/system/user/components/UserFormModal.vue.js"), "../views/system/user/index.vue": () => import("../views/system/user/index.vue.js") }));
|
|
19
19
|
export {
|
|
20
20
|
v as detailViews,
|
|
21
21
|
m as getView,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"viewRegistry.js","sources":["../../src/router/viewRegistry.ts"],"sourcesContent":["import type { Component } from 'vue'\n\n/** 页面懒加载器:import.meta.glob 的每个值就是一个。 */\nexport type ViewLoader = () => Promise<Component | { default: Component }>\n\n// 页面表:key 即菜单 component 字段的取值(如 system/user/index)。内核内置页在本模块加载时登记,\n// 消费方与插件经 registerViews 并入;同名覆盖,谁后注册谁生效(createSmartAdmin 里插件在前、应用最后)。\n// 每个 loader 引用稳定(glob 每文件一个函数),namedPage 靠它判断 keep-alive 缓存要不要失效。\nconst views: Record<string, ViewLoader> = {}\n\n/** glob 键 → 页面 key:取最后一个 `/views/` 之后、去掉 .vue(`./views/system/user/index.vue` → `system/user/index`)。 */\nexport function normalizeViewKey(path: string): string {\n const i = path.lastIndexOf('/views/')\n const rel = i >= 0 ? path.slice(i + '/views/'.length) : path.replace(/^\\.?\\/+/, '')\n return rel.replace(/\\.vue$/, '')\n}\n\n/** 并入一批页面(键可以是 glob 原始路径,也可以是已规范化的 key)。 */\nexport function registerViews(map: Record<string, ViewLoader>): void {\n for (const [key, loader] of Object.entries(map)) views[normalizeViewKey(key)] = loader\n}\n\nexport function getView(key: string): ViewLoader | undefined {\n return views[key]\n}\n\nexport function hasView(key: string): boolean {\n return key in views\n}\n\n/**\n * 菜单 component 字段的全部合法取值,供菜单管理表单的「组件路径」下拉:\n * 手敲错一个字符时 buildRoutesForModule 会保留路径并落到 MissingRoute 诊断页;下拉仍是第一道防线。\n */\nexport function viewComponentPaths(): string[] {\n return Object.keys(views).toSorted()\n}\n\n/** 约定式详情页:key 以 `/detail` 结尾的页面(views/<模块>/detail.vue)。 */\nexport function detailViews(): Array<[key: string, loader: ViewLoader]> {\n return Object.entries(views).filter(([k]) => k.endsWith('/detail'))\n}\n\n// 内核内置页\nregisterViews(import.meta.glob('../views/**/*.vue') as Record<string, ViewLoader>)\n"],"names":["views","normalizeViewKey","path","registerViews","map","key","loader","getView","viewComponentPaths","detailViews","k"],"mappings":"AAQA,MAAMA,IAAoC,CAAA;AAGnC,SAASC,EAAiBC,GAAsB;AACrD,
|
|
1
|
+
{"version":3,"file":"viewRegistry.js","sources":["../../src/router/viewRegistry.ts"],"sourcesContent":["import type { Component } from 'vue'\n\n/** 页面懒加载器:import.meta.glob 的每个值就是一个。 */\nexport type ViewLoader = () => Promise<Component | { default: Component }>\n\n// 页面表:key 即菜单 component 字段的取值(如 system/user/index)。内核内置页在本模块加载时登记,\n// 消费方与插件经 registerViews 并入;同名覆盖,谁后注册谁生效(createSmartAdmin 里插件在前、应用最后)。\n// 每个 loader 引用稳定(glob 每文件一个函数),namedPage 靠它判断 keep-alive 缓存要不要失效。\nconst views: Record<string, ViewLoader> = {}\n\n/** glob 键 → 页面 key:取最后一个 `/views/` 之后、去掉 .vue(`./views/system/user/index.vue` → `system/user/index`)。 */\nexport function normalizeViewKey(path: string): string {\n const i = path.lastIndexOf('/views/')\n const rel = i >= 0 ? path.slice(i + '/views/'.length) : path.replace(/^\\.?\\/+/, '')\n return rel.replace(/\\.vue$/, '')\n}\n\n/** 并入一批页面(键可以是 glob 原始路径,也可以是已规范化的 key)。 */\nexport function registerViews(map: Record<string, ViewLoader>): void {\n for (const [key, loader] of Object.entries(map)) views[normalizeViewKey(key)] = loader\n}\n\nexport function getView(key: string): ViewLoader | undefined {\n return views[key]\n}\n\nexport function hasView(key: string): boolean {\n return key in views\n}\n\n/**\n * 菜单 component 字段的全部合法取值,供菜单管理表单的「组件路径」下拉:\n * 手敲错一个字符时 buildRoutesForModule 会保留路径并落到 MissingRoute 诊断页;下拉仍是第一道防线。\n */\nexport function viewComponentPaths(): string[] {\n return Object.keys(views).toSorted()\n}\n\n/** 约定式详情页:key 以 `/detail` 结尾的页面(views/<模块>/detail.vue)。 */\nexport function detailViews(): Array<[key: string, loader: ViewLoader]> {\n return Object.entries(views).filter(([k]) => k.endsWith('/detail'))\n}\n\n// 内核内置页\nregisterViews(import.meta.glob('../views/**/*.vue') as Record<string, ViewLoader>)\n"],"names":["views","normalizeViewKey","path","i","registerViews","map","key","loader","getView","viewComponentPaths","detailViews","k"],"mappings":"AAQA,MAAMA,IAAoC,CAAA;AAGnC,SAASC,EAAiBC,GAAsB;AACrD,QAAMC,IAAID,EAAK,YAAY,SAAS;AAEpC,UADYC,KAAK,IAAID,EAAK,MAAMC,IAAI,CAAgB,IAAID,EAAK,QAAQ,WAAW,EAAE,GACvE,QAAQ,UAAU,EAAE;AACjC;AAGO,SAASE,EAAcC,GAAuC;AACnE,aAAW,CAACC,GAAKC,CAAM,KAAK,OAAO,QAAQF,CAAG,EAAG,CAAAL,EAAMC,EAAiBK,CAAG,CAAC,IAAIC;AAClF;AAEO,SAASC,EAAQF,GAAqC;AAC3D,SAAON,EAAMM,CAAG;AAClB;AAUO,SAASG,IAA+B;AAC7C,SAAO,OAAO,KAAKT,CAAK,EAAE,SAAA;AAC5B;AAGO,SAASU,IAAwD;AACtE,SAAO,OAAO,QAAQV,CAAK,EAAE,OAAO,CAAC,CAACW,CAAC,MAAMA,EAAE,SAAS,SAAS,CAAC;AACpE;AAGAP,muOAAiF;"}
|
package/dist/stores/app.d.ts
CHANGED
|
@@ -16,9 +16,6 @@ declare const DEFAULTS: {
|
|
|
16
16
|
showTabs: boolean;
|
|
17
17
|
fixedHeader: boolean;
|
|
18
18
|
pageTransition: PageTransition;
|
|
19
|
-
grayscale: boolean;
|
|
20
|
-
watermark: boolean;
|
|
21
|
-
watermarkText: string;
|
|
22
19
|
formStyle: FormStyle;
|
|
23
20
|
};
|
|
24
21
|
/** UI 偏好:主题模式 / 主色 / 密度 / 布局 / 界面开关 / 折叠 / 语言。持久化(localStorage key "app")。 */
|
|
@@ -33,9 +30,6 @@ export declare const useAppStore: import('pinia').StoreDefinition<"app", {
|
|
|
33
30
|
showTabs: boolean;
|
|
34
31
|
fixedHeader: boolean;
|
|
35
32
|
pageTransition: PageTransition;
|
|
36
|
-
grayscale: boolean;
|
|
37
|
-
watermark: boolean;
|
|
38
|
-
watermarkText: string;
|
|
39
33
|
formStyle: FormStyle;
|
|
40
34
|
}, {
|
|
41
35
|
isDark(state: {
|
|
@@ -49,9 +43,6 @@ export declare const useAppStore: import('pinia').StoreDefinition<"app", {
|
|
|
49
43
|
showTabs: boolean;
|
|
50
44
|
fixedHeader: boolean;
|
|
51
45
|
pageTransition: PageTransition;
|
|
52
|
-
grayscale: boolean;
|
|
53
|
-
watermark: boolean;
|
|
54
|
-
watermarkText: string;
|
|
55
46
|
formStyle: FormStyle;
|
|
56
47
|
} & import('pinia').PiniaCustomStateProperties<{
|
|
57
48
|
collapsed: boolean;
|
|
@@ -64,9 +55,6 @@ export declare const useAppStore: import('pinia').StoreDefinition<"app", {
|
|
|
64
55
|
showTabs: boolean;
|
|
65
56
|
fixedHeader: boolean;
|
|
66
57
|
pageTransition: PageTransition;
|
|
67
|
-
grayscale: boolean;
|
|
68
|
-
watermark: boolean;
|
|
69
|
-
watermarkText: string;
|
|
70
58
|
formStyle: FormStyle;
|
|
71
59
|
}>): boolean;
|
|
72
60
|
}, {
|
package/dist/stores/app.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { defineStore as
|
|
1
|
+
import { defineStore as a } from "pinia";
|
|
2
2
|
import { usePreferredDark as i } from "@vueuse/core";
|
|
3
|
-
import { ACCENTS as
|
|
3
|
+
import { ACCENTS as s } from "../theme/accents.js";
|
|
4
4
|
const o = i(), c = [
|
|
5
5
|
"vertical",
|
|
6
6
|
"vertical-mix",
|
|
@@ -10,20 +10,18 @@ const o = i(), c = [
|
|
|
10
10
|
"top-hybrid-header-first"
|
|
11
11
|
], t = {
|
|
12
12
|
themeScheme: "auto",
|
|
13
|
-
accent:
|
|
13
|
+
accent: s[0],
|
|
14
14
|
density: "compact",
|
|
15
15
|
// 系统设置密度默认使用紧凑档,提升后台列表与表单的信息密度。
|
|
16
16
|
layoutMode: "vertical",
|
|
17
17
|
showBreadcrumb: !0,
|
|
18
18
|
showTabs: !0,
|
|
19
19
|
fixedHeader: !0,
|
|
20
|
-
pageTransition: "
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
watermarkText: "",
|
|
24
|
-
// FormContainer 的全局形态偏好(弹窗/抽屉);组件可 per-instance 覆盖。
|
|
20
|
+
pageTransition: "none",
|
|
21
|
+
// 切页直接换,不加动画(macOS 手感);要柔化的在外观设置里选
|
|
22
|
+
// FormContainer 的全局形态偏好(弹窗 / 抽屉);组件可按实例用 variant 覆盖。默认弹窗。
|
|
25
23
|
formStyle: "modal"
|
|
26
|
-
},
|
|
24
|
+
}, n = a("app", {
|
|
27
25
|
state: () => ({
|
|
28
26
|
...t,
|
|
29
27
|
collapsed: !1,
|
|
@@ -69,14 +67,15 @@ const o = i(), c = [
|
|
|
69
67
|
}
|
|
70
68
|
},
|
|
71
69
|
persist: {
|
|
72
|
-
// localStorage 里的值不受代码约束:布局模式不在 LAYOUT_MODES
|
|
70
|
+
// localStorage 里的值不受代码约束:布局模式不在 LAYOUT_MODES、主色不是合法的 #RRGGBB 的,回落默认。
|
|
71
|
+
// 主色允许自定义(外观抽屉的彩虹圆点),所以只校验格式,不要求在 ACCENTS 里。
|
|
73
72
|
afterHydrate: ({ store: e }) => {
|
|
74
|
-
c.includes(e.layoutMode) || (e.layoutMode = "vertical"),
|
|
73
|
+
c.includes(e.layoutMode) || (e.layoutMode = "vertical"), /^#[0-9a-f]{6}$/i.test(e.accent) || (e.accent = s[0]);
|
|
75
74
|
}
|
|
76
75
|
}
|
|
77
76
|
});
|
|
78
77
|
export {
|
|
79
78
|
c as LAYOUT_MODES,
|
|
80
|
-
|
|
79
|
+
n as useAppStore
|
|
81
80
|
};
|
|
82
81
|
//# sourceMappingURL=app.js.map
|
package/dist/stores/app.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app.js","sources":["../../src/stores/app.ts"],"sourcesContent":["import { defineStore } from 'pinia'\nimport { usePreferredDark } from '@vueuse/core'\nimport { ACCENTS } from '#/theme/accents'\n\n// 模块级:建一次 matchMedia 监听;isDark getter 内响应式读取 → auto 下随系统实时翻。\nconst prefersDark = usePreferredDark()\n\nexport type Density = 'comfortable' | 'compact'\nexport type FormStyle = 'modal' | 'drawer'\nexport type Locale = 'zh-CN' | 'en-US'\nexport type ThemeScheme = 'light' | 'dark' | 'auto'\nexport type PageTransition = 'fade' | 'fade-slide' | 'none'\nexport type LayoutMode =\n | 'vertical'\n | 'vertical-mix'\n | 'vertical-hybrid-header-first'\n | 'horizontal'\n | 'top-hybrid-sidebar-first'\n | 'top-hybrid-header-first'\n\n/** 布局模式全集(单一来源:抽屉卡片、布局 shell、持久化值校验共用)。 */\nexport const LAYOUT_MODES: LayoutMode[] = [\n 'vertical',\n 'vertical-mix',\n 'vertical-hybrid-header-first',\n 'horizontal',\n 'top-hybrid-sidebar-first',\n 'top-hybrid-header-first',\n]\n\n/** 可被\"恢复默认\"重置的外观项(不含 locale / collapsed,那两项按会话保留)。 */\nconst DEFAULTS = {\n themeScheme: 'auto' as ThemeScheme,\n accent: ACCENTS[0] as string,\n density: 'compact' as Density, // 系统设置密度默认使用紧凑档,提升后台列表与表单的信息密度。\n layoutMode: 'vertical' as LayoutMode,\n showBreadcrumb: true,\n showTabs: true,\n fixedHeader: true,\n pageTransition: '
|
|
1
|
+
{"version":3,"file":"app.js","sources":["../../src/stores/app.ts"],"sourcesContent":["import { defineStore } from 'pinia'\nimport { usePreferredDark } from '@vueuse/core'\nimport { ACCENTS } from '#/theme/accents'\n\n// 模块级:建一次 matchMedia 监听;isDark getter 内响应式读取 → auto 下随系统实时翻。\nconst prefersDark = usePreferredDark()\n\nexport type Density = 'comfortable' | 'compact'\nexport type FormStyle = 'modal' | 'drawer'\nexport type Locale = 'zh-CN' | 'en-US'\nexport type ThemeScheme = 'light' | 'dark' | 'auto'\nexport type PageTransition = 'fade' | 'fade-slide' | 'none'\nexport type LayoutMode =\n | 'vertical'\n | 'vertical-mix'\n | 'vertical-hybrid-header-first'\n | 'horizontal'\n | 'top-hybrid-sidebar-first'\n | 'top-hybrid-header-first'\n\n/** 布局模式全集(单一来源:抽屉卡片、布局 shell、持久化值校验共用)。 */\nexport const LAYOUT_MODES: LayoutMode[] = [\n 'vertical',\n 'vertical-mix',\n 'vertical-hybrid-header-first',\n 'horizontal',\n 'top-hybrid-sidebar-first',\n 'top-hybrid-header-first',\n]\n\n/** 可被\"恢复默认\"重置的外观项(不含 locale / collapsed,那两项按会话保留)。 */\nconst DEFAULTS = {\n themeScheme: 'auto' as ThemeScheme,\n accent: ACCENTS[0] as string,\n density: 'compact' as Density, // 系统设置密度默认使用紧凑档,提升后台列表与表单的信息密度。\n layoutMode: 'vertical' as LayoutMode,\n showBreadcrumb: true,\n showTabs: true,\n fixedHeader: true,\n pageTransition: 'none' as PageTransition, // 切页直接换,不加动画(macOS 手感);要柔化的在外观设置里选\n // FormContainer 的全局形态偏好(弹窗 / 抽屉);组件可按实例用 variant 覆盖。默认弹窗。\n formStyle: 'modal' as FormStyle,\n}\n\n/** UI 偏好:主题模式 / 主色 / 密度 / 布局 / 界面开关 / 折叠 / 语言。持久化(localStorage key \"app\")。 */\nexport const useAppStore = defineStore('app', {\n state: () => ({\n ...DEFAULTS,\n collapsed: false,\n locale: 'zh-CN' as Locale,\n }),\n getters: {\n // auto 时按系统深浅色实时解析(prefersDark 是响应式 ref,getter 是 computed → 随之更新)。\n isDark(state): boolean {\n return state.themeScheme === 'auto' ? prefersDark.value : state.themeScheme === 'dark'\n },\n },\n actions: {\n setThemeScheme(s: ThemeScheme) {\n this.themeScheme = s\n },\n // 顶栏快捷切换:在当前生效的深浅色基础上翻到明确的一侧。\n toggleDark() {\n this.themeScheme = this.isDark ? 'light' : 'dark'\n },\n setAccent(hex: string) {\n this.accent = hex\n },\n setDensity(d: Density) {\n this.density = d\n },\n setLocale(l: Locale) {\n this.locale = l\n },\n toggleCollapsed() {\n this.collapsed = !this.collapsed\n },\n setLayoutMode(m: LayoutMode) {\n this.layoutMode = m\n },\n // 抽屉\"恢复默认\":还原外观项,保留 locale / collapsed。其余布尔项由抽屉 v-model 直接改。\n resetSettings() {\n Object.assign(this, DEFAULTS)\n },\n // 导出当前外观配置(DEFAULTS 同名键的现值);抽屉「复制配置」用,粘回 app.ts DEFAULTS 即为新默认。\n exportSettings(): Record<keyof typeof DEFAULTS, unknown> {\n const keys = Object.keys(DEFAULTS) as (keyof typeof DEFAULTS)[]\n return Object.fromEntries(keys.map(k => [k, this[k]])) as Record<\n keyof typeof DEFAULTS,\n unknown\n >\n },\n },\n persist: {\n // localStorage 里的值不受代码约束:布局模式不在 LAYOUT_MODES、主色不是合法的 #RRGGBB 的,回落默认。\n // 主色允许自定义(外观抽屉的彩虹圆点),所以只校验格式,不要求在 ACCENTS 里。\n afterHydrate: ({ store }) => {\n if (!LAYOUT_MODES.includes(store.layoutMode)) store.layoutMode = 'vertical'\n if (!/^#[0-9a-f]{6}$/i.test(store.accent)) store.accent = ACCENTS[0]\n },\n },\n})\n"],"names":["prefersDark","usePreferredDark","LAYOUT_MODES","DEFAULTS","ACCENTS","useAppStore","defineStore","state","s","hex","d","l","m","keys","k","store"],"mappings":";;;AAKA,MAAMA,IAAcC,EAAA,GAgBPC,IAA6B;AAAA,EACxC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAGMC,IAAW;AAAA,EACf,aAAa;AAAA,EACb,QAAQC,EAAQ,CAAC;AAAA,EACjB,SAAS;AAAA;AAAA,EACT,YAAY;AAAA,EACZ,gBAAgB;AAAA,EAChB,UAAU;AAAA,EACV,aAAa;AAAA,EACb,gBAAgB;AAAA;AAAA;AAAA,EAEhB,WAAW;AACb,GAGaC,IAAcC,EAAY,OAAO;AAAA,EAC5C,OAAO,OAAO;AAAA,IACZ,GAAGH;AAAA,IACH,WAAW;AAAA,IACX,QAAQ;AAAA,EAAA;AAAA,EAEV,SAAS;AAAA;AAAA,IAEP,OAAOI,GAAgB;AACrB,aAAOA,EAAM,gBAAgB,SAASP,EAAY,QAAQO,EAAM,gBAAgB;AAAA,IAClF;AAAA,EAAA;AAAA,EAEF,SAAS;AAAA,IACP,eAAeC,GAAgB;AAC7B,WAAK,cAAcA;AAAA,IACrB;AAAA;AAAA,IAEA,aAAa;AACX,WAAK,cAAc,KAAK,SAAS,UAAU;AAAA,IAC7C;AAAA,IACA,UAAUC,GAAa;AACrB,WAAK,SAASA;AAAA,IAChB;AAAA,IACA,WAAWC,GAAY;AACrB,WAAK,UAAUA;AAAA,IACjB;AAAA,IACA,UAAUC,GAAW;AACnB,WAAK,SAASA;AAAA,IAChB;AAAA,IACA,kBAAkB;AAChB,WAAK,YAAY,CAAC,KAAK;AAAA,IACzB;AAAA,IACA,cAAcC,GAAe;AAC3B,WAAK,aAAaA;AAAA,IACpB;AAAA;AAAA,IAEA,gBAAgB;AACd,aAAO,OAAO,MAAMT,CAAQ;AAAA,IAC9B;AAAA;AAAA,IAEA,iBAAyD;AACvD,YAAMU,IAAO,OAAO,KAAKV,CAAQ;AACjC,aAAO,OAAO,YAAYU,EAAK,IAAI,CAAAC,MAAK,CAACA,GAAG,KAAKA,CAAC,CAAC,CAAC,CAAC;AAAA,IAIvD;AAAA,EAAA;AAAA,EAEF,SAAS;AAAA;AAAA;AAAA,IAGP,cAAc,CAAC,EAAE,OAAAC,QAAY;AAC3B,MAAKb,EAAa,SAASa,EAAM,UAAU,QAAS,aAAa,aAC5D,kBAAkB,KAAKA,EAAM,MAAM,MAAGA,EAAM,SAASX,EAAQ,CAAC;AAAA,IACrE;AAAA,EAAA;AAEJ,CAAC;"}
|
package/dist/stores/tabs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tabs.js","sources":["../../src/stores/tabs.ts"],"sourcesContent":["import { defineStore } from 'pinia'\nimport type { RouteLocationNormalized } from 'vue-router'\nimport { router } from '#/router'\nimport { useAuthStore } from '#/stores/auth'\n\nexport interface TabItem {\n path: string // 主键(与 keep-alive 单实例一致)\n fullPath: string // 最后一次访问的完整 URL(含 query),点击标签时导航到此\n title: string // 原始 meta.title(可能是 i18n key)\n name: string // 路由名 → keep-alive include\n icon?: string\n affix?: boolean // 固定标签(= 当前应用的首页),不可关闭\n pinned?: boolean // 用户手动固定(右键「固定」);与 affix 同样不可关闭,但可取消固定\n titleFixed?: boolean // setTitle 置真:动态标题(如记录名),addTab
|
|
1
|
+
{"version":3,"file":"tabs.js","sources":["../../src/stores/tabs.ts"],"sourcesContent":["import { defineStore } from 'pinia'\nimport type { RouteLocationNormalized } from 'vue-router'\nimport { router } from '#/router'\nimport { useAuthStore } from '#/stores/auth'\n\nexport interface TabItem {\n path: string // 主键(与 keep-alive 单实例一致)\n fullPath: string // 最后一次访问的完整 URL(含 query),点击标签时导航到此\n title: string // 原始 meta.title(可能是 i18n key)\n name: string // 路由名 → keep-alive include\n icon?: string\n affix?: boolean // 固定标签(= 当前应用的首页),不可关闭\n pinned?: boolean // 用户手动固定(右键「固定」);与 affix 同样不可关闭,但可取消固定\n titleFixed?: boolean // setTitle 置真:动态标题(如记录名),addTab 复访时不会用 meta.title 覆盖\n noCache?: boolean // meta.noCache:排除出 keep-alive(详情等瞬时页,复访本就该拉新数据)\n}\n\n/**\n * 多标签页会话:标签列表 + keep-alive 缓存名。sessionStorage 持久化(F5 恢复,新标签页从净态开始)。\n * 首页标签不写死:每个应用首页不同(homePath()),故 affix 在 addTab 时按当前应用判定。\n */\nexport const useTabsStore = defineStore('tabs', {\n state: () => ({\n tabs: [] as TabItem[],\n reloadKey: 0, // 变更 → 强制页面重挂(refreshTab)\n excludeName: '', // 临时逐出 keep-alive 实例(refreshTab)\n }),\n getters: {\n // 供 keep-alive :include。noCache 标签(详情等瞬时页)排除出缓存;再剪掉 F5 重建期失效的名。\n cachedNames(state): string[] {\n return state.tabs\n .filter(t => !t.noCache)\n .map(t => t.name)\n .filter(n => router.hasRoute(n))\n },\n },\n actions: {\n addTab(route: RouteLocationNormalized) {\n const name = String(route.name ?? '')\n if (!name) return\n const path = route.path\n const title = (route.meta.title as string) || name || path\n const icon = route.meta.icon as string | undefined\n const existing = this.tabs.find(t => t.path === path)\n if (existing) {\n existing.fullPath = route.fullPath\n if (!existing.titleFixed) existing.title = title // 动态标题(setTitle 设过)不被 meta.title 复访覆盖\n if (icon) existing.icon = icon\n } else {\n // 当前应用的首页 → 固定标签,不可关闭(每个应用各有一个)\n this.tabs.push({\n path,\n fullPath: route.fullPath,\n title,\n name,\n icon,\n affix: path === useAuthStore().homePath,\n noCache: route.meta.noCache === true, // 详情等瞬时页不进 keep-alive\n })\n }\n },\n removeTab(path: string) {\n const idx = this.tabs.findIndex(t => t.path === path)\n if (idx === -1 || this.tabs[idx]!.affix || this.tabs[idx]!.pinned) return\n const wasActive = router.currentRoute.value.path === path\n this.tabs.splice(idx, 1)\n if (wasActive) {\n const next = this.tabs[idx] ?? this.tabs[idx - 1] ?? this.tabs[0]!\n router.push(next.fullPath)\n }\n },\n closeOthers(path: string) {\n this.tabs = this.tabs.filter(t => t.affix || t.pinned || t.path === path)\n this._ensureActive(path)\n },\n closeAll() {\n this.tabs = this.tabs.filter(t => t.affix || t.pinned)\n this._ensureActive(useAuthStore().homePath)\n },\n closeLeft(path: string) {\n const idx = this.tabs.findIndex(t => t.path === path)\n if (idx <= 0) return\n this.tabs = this.tabs.filter((t, i) => t.affix || t.pinned || i >= idx)\n this._ensureActive(path)\n },\n closeRight(path: string) {\n const idx = this.tabs.findIndex(t => t.path === path)\n if (idx === -1) return\n this.tabs = this.tabs.filter((t, i) => t.affix || t.pinned || i <= idx)\n this._ensureActive(path)\n },\n // 用户手动固定/取消固定(右键菜单);应用首页 affix 恒固定,不受此影响。\n togglePin(path: string) {\n const tab = this.tabs.find(t => t.path === path)\n if (tab && !tab.affix) tab.pinned = !tab.pinned\n },\n // 当前激活标签被批量关闭后,导航到 preferPath(通常是右键的那个)或末尾标签。\n _ensureActive(preferPath: string) {\n const cur = router.currentRoute.value.path\n if (this.tabs.some(t => t.path === cur)) return\n const target = this.tabs.find(t => t.path === preferPath) ?? this.tabs[this.tabs.length - 1]\n if (target) router.push(target.fullPath)\n },\n // 逐出缓存实例并发信号;default.vue 监听 reloadKey 做 v-if 重挂,重挂后清 excludeName。\n refreshTab(name: string) {\n this.excludeName = name\n this.reloadKey++\n },\n // 详情页数据加载后设置动态标签标题(如记录名);titleFixed 防 addTab 复访用 meta.title 覆盖回去。\n setTitle(path: string, title: string) {\n const tab = this.tabs.find(t => t.path === path)\n if (!tab) return\n tab.title = title\n tab.titleFixed = true\n },\n // 切应用/登出:标签清空。新应用首页由 router.afterEach 的 addTab 自然补成第一个(affix)标签。\n clearTabs() {\n this.tabs = []\n },\n },\n persist: { storage: sessionStorage, pick: ['tabs'] },\n})\n"],"names":["useTabsStore","defineStore","state","router","n","route","name","path","title","icon","existing","t","useAuthStore","idx","wasActive","next","tab","preferPath","cur","target"],"mappings":"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"}
|
package/dist/stores/user.d.ts
CHANGED
|
@@ -5,6 +5,10 @@ interface UserInfo {
|
|
|
5
5
|
name: string;
|
|
6
6
|
/** 头像 ViewUrl;登录出参不含,由 useModule.enterInitial 经 /personal/profile 回填,profile 页保存时同步。 */
|
|
7
7
|
avatar?: string | null;
|
|
8
|
+
/** 机构名称;同 avatar 由 useModule.enterInitial 经 /personal/profile 回填,水印用。 */
|
|
9
|
+
orgName?: string | null;
|
|
10
|
+
/** 手机号后四位(只存尾号,整号不进浏览器存储);回填来源同 orgName,水印用。 */
|
|
11
|
+
phoneTail?: string | null;
|
|
8
12
|
/** 是否需强制改密(管理员建号/重置后首登为 true);路由守卫据此强制跳改密页。 */
|
|
9
13
|
mustChangePassword: boolean;
|
|
10
14
|
/** 登录时快照的超管标记;profile 故障时 v-auth 用此值 fail-open。 */
|
|
@@ -41,6 +45,12 @@ export declare const useUserStore: import('pinia').StoreDefinition<"user", {
|
|
|
41
45
|
account: string;
|
|
42
46
|
name: string;
|
|
43
47
|
avatar?: string | null
|
|
48
|
+
/** 机构名称;同 avatar 由 useModule.enterInitial 经 /personal/profile 回填,水印用。 */
|
|
49
|
+
| undefined;
|
|
50
|
+
orgName?: string | null
|
|
51
|
+
/** 手机号后四位(只存尾号,整号不进浏览器存储);回填来源同 orgName,水印用。 */
|
|
52
|
+
| undefined;
|
|
53
|
+
phoneTail?: string | null
|
|
44
54
|
/** 是否需强制改密(管理员建号/重置后首登为 true);路由守卫据此强制跳改密页。 */
|
|
45
55
|
| undefined;
|
|
46
56
|
mustChangePassword: boolean;
|
package/dist/stores/user.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"user.js","sources":["../../src/stores/user.ts"],"sourcesContent":["import { defineStore } from 'pinia'\nimport type { LoginOutput } from '#/types/api'\n\ninterface UserInfo {\n userId: number\n account: string\n name: string\n /** 头像 ViewUrl;登录出参不含,由 useModule.enterInitial 经 /personal/profile 回填,profile 页保存时同步。 */\n avatar?: string | null\n /** 是否需强制改密(管理员建号/重置后首登为 true);路由守卫据此强制跳改密页。 */\n mustChangePassword: boolean\n /** 登录时快照的超管标记;profile 故障时 v-auth 用此值 fail-open。 */\n isSuperAdmin?: boolean\n}\n\n/**\n * 判定是否为 Cookie 会话:\n * - sessionMode === 'cookie' / csrfRequired === true(后端 AuthCookieService 显式信号)\n * - 两个显式信号都缺席时兜底:body 下发了 access 但 refresh 为空\n */\nexport function isCookieSession(\n data: Pick<LoginOutput, 'sessionMode' | 'csrfRequired' | 'accessToken' | 'refreshToken'>,\n): boolean {\n if (data.sessionMode === 'cookie' || data.csrfRequired === true) return true\n if (data.sessionMode === 'body' || data.csrfRequired === false) return false\n return !!data.accessToken && !data.refreshToken\n}\n\n/**\n * 令牌 + 用户信息。\n * - 默认模式:持久化 access/refresh 到 localStorage。\n * - Cookie 会话:access 仅内存;refresh 在 HttpOnly Cookie;storage 只记 cookieSession 标记,\n * 绝不以 localStorage/sessionStorage 存放 access/refresh。\n */\nexport const useUserStore = defineStore('user', {\n state: () => ({\n accessToken: '',\n refreshToken: '',\n /**\n * Cookie 会话标记(可持久化,不含任何令牌)。\n * F5 后 access 已丢,靠此标记 + HttpOnly refresh Cookie 触发静默刷新。\n */\n cookieSession: false,\n userInfo: null as UserInfo | null,\n }),\n getters: {\n isLoggedIn: (s): boolean => !!s.accessToken,\n },\n actions: {\n /** 用登录/刷新出参落地会话。 */\n setSession(data: LoginOutput) {\n const cookie = isCookieSession(data)\n this.cookieSession = cookie\n this.accessToken = data.accessToken\n // Cookie 模式 body 的 refresh 为空串,不进内存也不进 storage\n this.refreshToken = cookie ? '' : (data.refreshToken ?? '')\n this.userInfo = {\n userId: Number(data.userId),\n account: data.account,\n name: data.name,\n mustChangePassword: data.mustChangePassword ?? false,\n isSuperAdmin: data.isSuperAdmin ?? false,\n }\n },\n clear() {\n this.accessToken = ''\n this.refreshToken = ''\n this.cookieSession = false\n this.userInfo = null\n },\n },\n persist: {\n // 序列化时按会话模式分流:Cookie 会话只落 cookieSession,令牌字段强制空串。\n serializer: {\n serialize(state) {\n if (state.cookieSession) {\n return JSON.stringify({\n accessToken: '',\n refreshToken: '',\n cookieSession: true,\n userInfo: null,\n })\n }\n return JSON.stringify({\n accessToken: state.accessToken ?? '',\n refreshToken: state.refreshToken ?? '',\n cookieSession: false,\n userInfo: state.userInfo ?? null,\n })\n },\n deserialize(raw) {\n return JSON.parse(raw) as {\n accessToken: string\n refreshToken: string\n cookieSession: boolean\n userInfo: UserInfo | null\n }\n },\n },\n afterHydrate: ({ store }) => {\n // 防御:Cookie 会话下 storage 里不该有令牌,残留的一律抹掉\n if (store.cookieSession) {\n store.accessToken = ''\n store.refreshToken = ''\n }\n },\n },\n})\n"],"names":["isCookieSession","data","useUserStore","defineStore","s","cookie","state","raw","store"],"mappings":";
|
|
1
|
+
{"version":3,"file":"user.js","sources":["../../src/stores/user.ts"],"sourcesContent":["import { defineStore } from 'pinia'\nimport type { LoginOutput } from '#/types/api'\n\ninterface UserInfo {\n userId: number\n account: string\n name: string\n /** 头像 ViewUrl;登录出参不含,由 useModule.enterInitial 经 /personal/profile 回填,profile 页保存时同步。 */\n avatar?: string | null\n /** 机构名称;同 avatar 由 useModule.enterInitial 经 /personal/profile 回填,水印用。 */\n orgName?: string | null\n /** 手机号后四位(只存尾号,整号不进浏览器存储);回填来源同 orgName,水印用。 */\n phoneTail?: string | null\n /** 是否需强制改密(管理员建号/重置后首登为 true);路由守卫据此强制跳改密页。 */\n mustChangePassword: boolean\n /** 登录时快照的超管标记;profile 故障时 v-auth 用此值 fail-open。 */\n isSuperAdmin?: boolean\n}\n\n/**\n * 判定是否为 Cookie 会话:\n * - sessionMode === 'cookie' / csrfRequired === true(后端 AuthCookieService 显式信号)\n * - 两个显式信号都缺席时兜底:body 下发了 access 但 refresh 为空\n */\nexport function isCookieSession(\n data: Pick<LoginOutput, 'sessionMode' | 'csrfRequired' | 'accessToken' | 'refreshToken'>,\n): boolean {\n if (data.sessionMode === 'cookie' || data.csrfRequired === true) return true\n if (data.sessionMode === 'body' || data.csrfRequired === false) return false\n return !!data.accessToken && !data.refreshToken\n}\n\n/**\n * 令牌 + 用户信息。\n * - 默认模式:持久化 access/refresh 到 localStorage。\n * - Cookie 会话:access 仅内存;refresh 在 HttpOnly Cookie;storage 只记 cookieSession 标记,\n * 绝不以 localStorage/sessionStorage 存放 access/refresh。\n */\nexport const useUserStore = defineStore('user', {\n state: () => ({\n accessToken: '',\n refreshToken: '',\n /**\n * Cookie 会话标记(可持久化,不含任何令牌)。\n * F5 后 access 已丢,靠此标记 + HttpOnly refresh Cookie 触发静默刷新。\n */\n cookieSession: false,\n userInfo: null as UserInfo | null,\n }),\n getters: {\n isLoggedIn: (s): boolean => !!s.accessToken,\n },\n actions: {\n /** 用登录/刷新出参落地会话。 */\n setSession(data: LoginOutput) {\n const cookie = isCookieSession(data)\n this.cookieSession = cookie\n this.accessToken = data.accessToken\n // Cookie 模式 body 的 refresh 为空串,不进内存也不进 storage\n this.refreshToken = cookie ? '' : (data.refreshToken ?? '')\n this.userInfo = {\n userId: Number(data.userId),\n account: data.account,\n name: data.name,\n mustChangePassword: data.mustChangePassword ?? false,\n isSuperAdmin: data.isSuperAdmin ?? false,\n }\n },\n clear() {\n this.accessToken = ''\n this.refreshToken = ''\n this.cookieSession = false\n this.userInfo = null\n },\n },\n persist: {\n // 序列化时按会话模式分流:Cookie 会话只落 cookieSession,令牌字段强制空串。\n serializer: {\n serialize(state) {\n if (state.cookieSession) {\n return JSON.stringify({\n accessToken: '',\n refreshToken: '',\n cookieSession: true,\n userInfo: null,\n })\n }\n return JSON.stringify({\n accessToken: state.accessToken ?? '',\n refreshToken: state.refreshToken ?? '',\n cookieSession: false,\n userInfo: state.userInfo ?? null,\n })\n },\n deserialize(raw) {\n return JSON.parse(raw) as {\n accessToken: string\n refreshToken: string\n cookieSession: boolean\n userInfo: UserInfo | null\n }\n },\n },\n afterHydrate: ({ store }) => {\n // 防御:Cookie 会话下 storage 里不该有令牌,残留的一律抹掉\n if (store.cookieSession) {\n store.accessToken = ''\n store.refreshToken = ''\n }\n },\n },\n})\n"],"names":["isCookieSession","data","useUserStore","defineStore","s","cookie","state","raw","store"],"mappings":";AAwBO,SAASA,EACdC,GACS;AACT,SAAIA,EAAK,gBAAgB,YAAYA,EAAK,iBAAiB,KAAa,KACpEA,EAAK,gBAAgB,UAAUA,EAAK,iBAAiB,KAAc,KAChE,CAAC,CAACA,EAAK,eAAe,CAACA,EAAK;AACrC;AAQO,MAAMC,IAAeC,EAAY,QAAQ;AAAA,EAC9C,OAAO,OAAO;AAAA,IACZ,aAAa;AAAA,IACb,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA,IAKd,eAAe;AAAA,IACf,UAAU;AAAA,EAAA;AAAA,EAEZ,SAAS;AAAA,IACP,YAAY,CAACC,MAAe,CAAC,CAACA,EAAE;AAAA,EAAA;AAAA,EAElC,SAAS;AAAA;AAAA,IAEP,WAAWH,GAAmB;AAC5B,YAAMI,IAASL,EAAgBC,CAAI;AACnC,WAAK,gBAAgBI,GACrB,KAAK,cAAcJ,EAAK,aAExB,KAAK,eAAeI,IAAS,KAAMJ,EAAK,gBAAgB,IACxD,KAAK,WAAW;AAAA,QACd,QAAQ,OAAOA,EAAK,MAAM;AAAA,QAC1B,SAASA,EAAK;AAAA,QACd,MAAMA,EAAK;AAAA,QACX,oBAAoBA,EAAK,sBAAsB;AAAA,QAC/C,cAAcA,EAAK,gBAAgB;AAAA,MAAA;AAAA,IAEvC;AAAA,IACA,QAAQ;AACN,WAAK,cAAc,IACnB,KAAK,eAAe,IACpB,KAAK,gBAAgB,IACrB,KAAK,WAAW;AAAA,IAClB;AAAA,EAAA;AAAA,EAEF,SAAS;AAAA;AAAA,IAEP,YAAY;AAAA,MACV,UAAUK,GAAO;AACf,eAAIA,EAAM,gBACD,KAAK,UAAU;AAAA,UACpB,aAAa;AAAA,UACb,cAAc;AAAA,UACd,eAAe;AAAA,UACf,UAAU;AAAA,QAAA,CACX,IAEI,KAAK,UAAU;AAAA,UACpB,aAAaA,EAAM,eAAe;AAAA,UAClC,cAAcA,EAAM,gBAAgB;AAAA,UACpC,eAAe;AAAA,UACf,UAAUA,EAAM,YAAY;AAAA,QAAA,CAC7B;AAAA,MACH;AAAA,MACA,YAAYC,GAAK;AACf,eAAO,KAAK,MAAMA,CAAG;AAAA,MAMvB;AAAA,IAAA;AAAA,IAEF,cAAc,CAAC,EAAE,OAAAC,QAAY;AAE3B,MAAIA,EAAM,kBACRA,EAAM,cAAc,IACpBA,EAAM,eAAe;AAAA,IAEzB;AAAA,EAAA;AAEJ,CAAC;"}
|