smart-admin-web 10.15.0 → 10.20.1

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.
Files changed (432) hide show
  1. package/README.md +1 -1
  2. package/dist/api/index.d.ts +4 -2
  3. package/dist/api/index.js +1 -1
  4. package/dist/api/index.js.map +1 -1
  5. package/dist/api/schema.d.ts +39 -5
  6. package/dist/assets/icons/ph-subset.json.js +5 -5
  7. package/dist/components/AppIcon.vue.js +9 -9
  8. package/dist/components/AppIcon.vue.js.map +1 -1
  9. package/dist/components/AppWatermark.vue.d.ts +14 -0
  10. package/dist/components/AppWatermark.vue.js +38 -0
  11. package/dist/components/AppWatermark.vue.js.map +1 -0
  12. package/dist/components/AppWatermark2.vue.js +5 -0
  13. package/dist/components/AppWatermark2.vue.js.map +1 -0
  14. package/dist/components/Chart/PieChart.vue.d.ts +1 -1
  15. package/dist/components/Chart/echarts.js +15 -20
  16. package/dist/components/Chart/echarts.js.map +1 -1
  17. package/dist/components/CronEditor/index.vue.js +1 -1
  18. package/dist/components/CronEditor/index2.vue.js +2 -1
  19. package/dist/components/CronEditor/index2.vue.js.map +1 -1
  20. package/dist/components/DetailPage/index.vue.js +2 -2
  21. package/dist/components/DetailPage/index2.vue.js.map +1 -1
  22. package/dist/components/DictTag/index.vue.js.map +1 -1
  23. package/dist/components/ErrorBoundary/index.vue.js +2 -2
  24. package/dist/components/ErrorBoundary/index2.vue.js +1 -1
  25. package/dist/components/ErrorBoundary/index2.vue.js.map +1 -1
  26. package/dist/components/FormContainer/index.vue.js +91 -56
  27. package/dist/components/FormContainer/index.vue.js.map +1 -1
  28. package/dist/components/ImportWizard/index.vue.js +1 -1
  29. package/dist/components/ImportWizard/index2.vue.js +44 -41
  30. package/dist/components/ImportWizard/index2.vue.js.map +1 -1
  31. package/dist/components/MenuSearch.vue.js +2 -2
  32. package/dist/components/MenuSearch2.vue.js +19 -18
  33. package/dist/components/MenuSearch2.vue.js.map +1 -1
  34. package/dist/components/PasswordStrength/index.vue.js +2 -2
  35. package/dist/components/PasswordStrength/index2.vue.js +20 -18
  36. package/dist/components/PasswordStrength/index2.vue.js.map +1 -1
  37. package/dist/components/TableTotal/index.vue.d.ts +6 -0
  38. package/dist/components/{SelectTable → TableTotal}/index.vue.js +1 -1
  39. package/dist/components/TableTotal/index2.vue.js +16 -0
  40. package/dist/components/TableTotal/index2.vue.js.map +1 -0
  41. package/dist/components/TableZoomButton/index.vue.js.map +1 -1
  42. package/dist/components/UserPicker/index.vue.js +2 -2
  43. package/dist/components/UserPicker/index2.vue.js +176 -117
  44. package/dist/components/UserPicker/index2.vue.js.map +1 -1
  45. package/dist/composables/useBatchDelete.js.map +1 -1
  46. package/dist/composables/useLayoutMenu.js +17 -16
  47. package/dist/composables/useLayoutMenu.js.map +1 -1
  48. package/dist/composables/useModule.js +39 -29
  49. package/dist/composables/useModule.js.map +1 -1
  50. package/dist/composables/useShellBreakpoint.d.ts +19 -0
  51. package/dist/composables/useShellBreakpoint.js +37 -0
  52. package/dist/composables/useShellBreakpoint.js.map +1 -0
  53. package/dist/composables/useSite.d.ts +15 -0
  54. package/dist/composables/useSite.js +16 -14
  55. package/dist/composables/useSite.js.map +1 -1
  56. package/dist/composables/useTabTitle.js.map +1 -1
  57. package/dist/composables/useTableTitle.d.ts +6 -0
  58. package/dist/composables/useTableTitle.js +11 -0
  59. package/dist/composables/useTableTitle.js.map +1 -0
  60. package/dist/composables/useTableZoom.d.ts +5 -0
  61. package/dist/composables/useTableZoom.js.map +1 -1
  62. package/dist/composables/useTheme.d.ts +2 -2
  63. package/dist/composables/useTheme.js +23 -20
  64. package/dist/composables/useTheme.js.map +1 -1
  65. package/dist/createSmartAdmin.d.ts +12 -2
  66. package/dist/createSmartAdmin.js +72 -60
  67. package/dist/createSmartAdmin.js.map +1 -1
  68. package/dist/index.d.ts +5 -2
  69. package/dist/index.js +219 -205
  70. package/dist/index.js.map +1 -1
  71. package/dist/layouts/AccentPicker.vue.js +8 -0
  72. package/dist/layouts/AccentPicker.vue.js.map +1 -0
  73. package/dist/layouts/AccentPicker2.vue.js +131 -0
  74. package/dist/layouts/AccentPicker2.vue.js.map +1 -0
  75. package/dist/layouts/AppHeader.vue.d.ts +8 -1
  76. package/dist/layouts/AppHeader.vue.js +2 -2
  77. package/dist/layouts/AppHeader2.vue.js +317 -235
  78. package/dist/layouts/AppHeader2.vue.js.map +1 -1
  79. package/dist/layouts/NoticeBell.vue.js +2 -2
  80. package/dist/layouts/NoticeBell2.vue.js +19 -18
  81. package/dist/layouts/NoticeBell2.vue.js.map +1 -1
  82. package/dist/layouts/PersonalLayout.vue.js +2 -2
  83. package/dist/layouts/PersonalLayout2.vue.js +69 -47
  84. package/dist/layouts/PersonalLayout2.vue.js.map +1 -1
  85. package/dist/layouts/SettingsDrawer.vue.js +3 -3
  86. package/dist/layouts/SettingsDrawer2.vue.js +261 -325
  87. package/dist/layouts/SettingsDrawer2.vue.js.map +1 -1
  88. package/dist/layouts/TabsBar.vue.js +2 -2
  89. package/dist/layouts/TabsBar2.vue.js +97 -69
  90. package/dist/layouts/TabsBar2.vue.js.map +1 -1
  91. package/dist/layouts/components/SideNav.vue.d.ts +3 -0
  92. package/dist/layouts/components/SideNav.vue.js +1 -1
  93. package/dist/layouts/components/SideNav2.vue.js +54 -26
  94. package/dist/layouts/components/SideNav2.vue.js.map +1 -1
  95. package/dist/layouts/default.vue.js +1 -1
  96. package/dist/layouts/default2.vue.js +170 -140
  97. package/dist/layouts/default2.vue.js.map +1 -1
  98. package/dist/lib/loginHero.d.ts +2 -2
  99. package/dist/lib/loginHero.js.map +1 -1
  100. package/dist/lib/runtime.js +1 -1
  101. package/dist/lib/watermark.d.ts +110 -0
  102. package/dist/lib/watermark.js +151 -0
  103. package/dist/lib/watermark.js.map +1 -0
  104. package/dist/locales/en-US.d.ts +221 -15
  105. package/dist/locales/en-US.js +230 -21
  106. package/dist/locales/en-US.js.map +1 -1
  107. package/dist/locales/kernelMenuTitles.d.ts +1 -0
  108. package/dist/locales/kernelMenuTitles.js +128 -0
  109. package/dist/locales/kernelMenuTitles.js.map +1 -0
  110. package/dist/locales/menuTitle.d.ts +3 -0
  111. package/dist/locales/menuTitle.js +14 -12
  112. package/dist/locales/menuTitle.js.map +1 -1
  113. package/dist/locales/zh-CN.d.ts +221 -15
  114. package/dist/locales/zh-CN.js +238 -28
  115. package/dist/locales/zh-CN.js.map +1 -1
  116. package/dist/router/index.js +41 -32
  117. package/dist/router/index.js.map +1 -1
  118. package/dist/router/namedPage.d.ts +4 -0
  119. package/dist/router/namedPage.js +7 -7
  120. package/dist/router/namedPage.js.map +1 -1
  121. package/dist/router/viewRegistry.js +8 -8
  122. package/dist/router/viewRegistry.js.map +1 -1
  123. package/dist/stores/app.d.ts +0 -12
  124. package/dist/stores/app.js +11 -12
  125. package/dist/stores/app.js.map +1 -1
  126. package/dist/stores/tabs.js.map +1 -1
  127. package/dist/stores/user.d.ts +10 -0
  128. package/dist/stores/user.js.map +1 -1
  129. package/dist/style.css +1 -1
  130. package/dist/theme/accentTokens.d.ts +27 -0
  131. package/dist/theme/accentTokens.js +54 -0
  132. package/dist/theme/accentTokens.js.map +1 -0
  133. package/dist/theme/accents.d.ts +21 -1
  134. package/dist/theme/accents.js +11 -2
  135. package/dist/theme/accents.js.map +1 -1
  136. package/dist/theme/mix.d.ts +58 -7
  137. package/dist/theme/mix.js +115 -30
  138. package/dist/theme/mix.js.map +1 -1
  139. package/dist/theme/naive-theme.d.ts +5 -2
  140. package/dist/theme/naive-theme.js +407 -75
  141. package/dist/theme/naive-theme.js.map +1 -1
  142. package/dist/utils/jwt.d.ts +8 -0
  143. package/dist/utils/jwt.js +14 -0
  144. package/dist/utils/jwt.js.map +1 -0
  145. package/dist/utils/menuIcon.d.ts +2 -0
  146. package/dist/utils/menuIcon.js +8 -0
  147. package/dist/utils/menuIcon.js.map +1 -0
  148. package/dist/utils/oauthBrand.js.map +1 -1
  149. package/dist/utils/tableFilter.d.ts +88 -0
  150. package/dist/utils/tableFilter.js +116 -0
  151. package/dist/utils/tableFilter.js.map +1 -0
  152. package/dist/utils/tableToolbar.d.ts +18 -0
  153. package/dist/utils/tableToolbar.js +11 -0
  154. package/dist/utils/tableToolbar.js.map +1 -0
  155. package/dist/utils/treeFilter.d.ts +20 -0
  156. package/dist/utils/treeFilter.js +24 -0
  157. package/dist/utils/treeFilter.js.map +1 -0
  158. package/dist/views/dashboard/ShortcutPicker.vue.js +1 -1
  159. package/dist/views/dashboard/ShortcutPicker2.vue.js +73 -48
  160. package/dist/views/dashboard/ShortcutPicker2.vue.js.map +1 -1
  161. package/dist/views/dashboard/biz.vue.js +1 -1
  162. package/dist/views/dashboard/biz2.vue.js +310 -257
  163. package/dist/views/dashboard/biz2.vue.js.map +1 -1
  164. package/dist/views/dashboard/workbench.vue.js +2 -2
  165. package/dist/views/dashboard/workbench2.vue.js +141 -155
  166. package/dist/views/dashboard/workbench2.vue.js.map +1 -1
  167. package/dist/views/embed/iframe.vue.js +2 -2
  168. package/dist/views/embed/iframe2.vue.js +22 -15
  169. package/dist/views/embed/iframe2.vue.js.map +1 -1
  170. package/dist/views/error/404.vue.js +2 -2
  171. package/dist/views/error/4042.vue.js +33 -24
  172. package/dist/views/error/4042.vue.js.map +1 -1
  173. package/dist/views/error/BootError.vue.js +1 -1
  174. package/dist/views/error/BootError2.vue.js +59 -48
  175. package/dist/views/error/BootError2.vue.js.map +1 -1
  176. package/dist/views/error/MissingRoute.vue.js +2 -2
  177. package/dist/views/error/MissingRoute2.vue.js +34 -15
  178. package/dist/views/error/MissingRoute2.vue.js.map +1 -1
  179. package/dist/views/login/LoginForm.vue.d.ts +7 -1
  180. package/dist/views/login/LoginForm.vue.js +2 -2
  181. package/dist/views/login/LoginForm2.vue.js +580 -488
  182. package/dist/views/login/LoginForm2.vue.js.map +1 -1
  183. package/dist/views/login/components/LoginDesk.vue.d.ts +36 -0
  184. package/dist/views/login/components/LoginDesk.vue.js +9 -0
  185. package/dist/views/login/components/LoginDesk.vue.js.map +1 -0
  186. package/dist/views/login/components/LoginDesk2.vue.js +100 -0
  187. package/dist/views/login/components/LoginDesk2.vue.js.map +1 -0
  188. package/dist/views/login/components/LoginHeroPanel.vue.js +3 -3
  189. package/dist/views/login/components/LoginHeroPanel2.vue.js +34 -39
  190. package/dist/views/login/components/LoginHeroPanel2.vue.js.map +1 -1
  191. package/dist/views/login/index.vue.js +1 -1
  192. package/dist/views/login/index2.vue.js +141 -71
  193. package/dist/views/login/index2.vue.js.map +1 -1
  194. package/dist/views/login/layout.d.ts +11 -0
  195. package/dist/views/login/layout.js +27 -0
  196. package/dist/views/login/layout.js.map +1 -0
  197. package/dist/views/mfa/index.vue.js +2 -2
  198. package/dist/views/mfa/index2.vue.js +367 -321
  199. package/dist/views/mfa/index2.vue.js.map +1 -1
  200. package/dist/views/module/index.vue.js +2 -2
  201. package/dist/views/module/index2.vue.js +132 -99
  202. package/dist/views/module/index2.vue.js.map +1 -1
  203. package/dist/views/oauth/callback.vue.js +2 -2
  204. package/dist/views/oauth/callback2.vue.js +65 -51
  205. package/dist/views/oauth/callback2.vue.js.map +1 -1
  206. package/dist/views/personal/bindings.vue.js +2 -2
  207. package/dist/views/personal/bindings2.vue.js +98 -94
  208. package/dist/views/personal/bindings2.vue.js.map +1 -1
  209. package/dist/views/personal/notice2.vue.js +103 -76
  210. package/dist/views/personal/notice2.vue.js.map +1 -1
  211. package/dist/views/personal/password2.vue.js +47 -40
  212. package/dist/views/personal/password2.vue.js.map +1 -1
  213. package/dist/views/personal/profile.vue.js +3 -3
  214. package/dist/views/personal/profile2.vue.js +24 -18
  215. package/dist/views/personal/profile2.vue.js.map +1 -1
  216. package/dist/views/personal/security.vue.js +2 -2
  217. package/dist/views/personal/security2.vue.js +65 -53
  218. package/dist/views/personal/security2.vue.js.map +1 -1
  219. package/dist/views/personal/sessions.vue.js +2 -2
  220. package/dist/views/personal/sessions2.vue.js +67 -62
  221. package/dist/views/personal/sessions2.vue.js.map +1 -1
  222. package/dist/views/system/ai-model/components/ProviderCard.vue.js +2 -2
  223. package/dist/views/system/ai-model/components/ProviderCard2.vue.js +142 -130
  224. package/dist/views/system/ai-model/components/ProviderCard2.vue.js.map +1 -1
  225. package/dist/views/system/ai-model/components/ProviderForm.vue.js +2 -2
  226. package/dist/views/system/ai-model/components/ProviderForm2.vue.js +71 -70
  227. package/dist/views/system/ai-model/components/ProviderForm2.vue.js.map +1 -1
  228. package/dist/views/system/ai-model/index.vue.js +2 -2
  229. package/dist/views/system/ai-model/index2.vue.js +99 -99
  230. package/dist/views/system/ai-model/index2.vue.js.map +1 -1
  231. package/dist/views/system/ai-model/presets.d.ts +1 -1
  232. package/dist/views/system/ai-model/presets.js +18 -18
  233. package/dist/views/system/ai-model/presets.js.map +1 -1
  234. package/dist/views/system/ai-usage/index.vue.js +2 -2
  235. package/dist/views/system/ai-usage/index2.vue.js +356 -258
  236. package/dist/views/system/ai-usage/index2.vue.js.map +1 -1
  237. package/dist/views/system/api-docs/index.vue.js +5 -2
  238. package/dist/views/system/api-docs/index.vue.js.map +1 -1
  239. package/dist/views/system/api-docs/index2.vue.js +92 -42
  240. package/dist/views/system/api-docs/index2.vue.js.map +1 -1
  241. package/dist/views/system/cache/index.vue.js +2 -2
  242. package/dist/views/system/cache/index2.vue.js +74 -80
  243. package/dist/views/system/cache/index2.vue.js.map +1 -1
  244. package/dist/views/system/config/components/AdminMock.vue.js +2 -2
  245. package/dist/views/system/config/components/AdminMock2.vue.js +60 -43
  246. package/dist/views/system/config/components/AdminMock2.vue.js.map +1 -1
  247. package/dist/views/system/config/components/AdvancedSection.vue.js +5 -2
  248. package/dist/views/system/config/components/AdvancedSection.vue.js.map +1 -1
  249. package/dist/views/system/config/components/AdvancedSection2.vue.js +98 -70
  250. package/dist/views/system/config/components/AdvancedSection2.vue.js.map +1 -1
  251. package/dist/views/system/config/components/BrandSection.vue.js +2 -2
  252. package/dist/views/system/config/components/BrandSection2.vue.js +121 -119
  253. package/dist/views/system/config/components/BrandSection2.vue.js.map +1 -1
  254. package/dist/views/system/config/components/CfgGroup.vue.js +3 -3
  255. package/dist/views/system/config/components/CfgGroup2.vue.js.map +1 -1
  256. package/dist/views/system/config/components/CfgRow.vue.js +1 -1
  257. package/dist/views/system/config/components/CfgRow2.vue.js +24 -23
  258. package/dist/views/system/config/components/CfgRow2.vue.js.map +1 -1
  259. package/dist/views/system/config/components/CfgSegment.vue.js +1 -1
  260. package/dist/views/system/config/components/CfgSegment2.vue.js +16 -15
  261. package/dist/views/system/config/components/CfgSegment2.vue.js.map +1 -1
  262. package/dist/views/system/config/components/ConfigFormModal.vue.js +2 -2
  263. package/dist/views/system/config/components/ConfigFormModal2.vue.js +35 -33
  264. package/dist/views/system/config/components/ConfigFormModal2.vue.js.map +1 -1
  265. package/dist/views/system/config/components/JobSection.vue.js +2 -2
  266. package/dist/views/system/config/components/JobSection2.vue.js +46 -44
  267. package/dist/views/system/config/components/JobSection2.vue.js.map +1 -1
  268. package/dist/views/system/config/components/LoginMock.vue.js +3 -3
  269. package/dist/views/system/config/components/LoginMock2.vue.js +83 -72
  270. package/dist/views/system/config/components/LoginMock2.vue.js.map +1 -1
  271. package/dist/views/system/config/components/LogoCropper.vue.js +1 -1
  272. package/dist/views/system/config/components/LogoCropper2.vue.js.map +1 -1
  273. package/dist/views/system/config/components/LogoEditor.vue.js +2 -2
  274. package/dist/views/system/config/components/LogoEditor2.vue.js +11 -13
  275. package/dist/views/system/config/components/LogoEditor2.vue.js.map +1 -1
  276. package/dist/views/system/config/components/ProviderSheet.vue.js +3 -3
  277. package/dist/views/system/config/components/ProviderSheet2.vue.js.map +1 -1
  278. package/dist/views/system/config/components/SectionLayout.vue.d.ts +4 -2
  279. package/dist/views/system/config/components/SectionLayout.vue.js +2 -2
  280. package/dist/views/system/config/components/SectionLayout2.vue.js +51 -27
  281. package/dist/views/system/config/components/SectionLayout2.vue.js.map +1 -1
  282. package/dist/views/system/config/components/SecuritySection.vue.js +2 -2
  283. package/dist/views/system/config/components/SecuritySection2.vue.js +207 -206
  284. package/dist/views/system/config/components/SecuritySection2.vue.js.map +1 -1
  285. package/dist/views/system/config/components/SensitiveSection.vue.js +2 -2
  286. package/dist/views/system/config/components/SensitiveSection2.vue.js +107 -102
  287. package/dist/views/system/config/components/SensitiveSection2.vue.js.map +1 -1
  288. package/dist/views/system/config/components/UploadSection.vue.js +2 -2
  289. package/dist/views/system/config/components/UploadSection2.vue.js +86 -77
  290. package/dist/views/system/config/components/UploadSection2.vue.js.map +1 -1
  291. package/dist/views/system/config/components/WatermarkSection.vue.js +8 -0
  292. package/dist/views/system/config/components/WatermarkSection.vue.js.map +1 -0
  293. package/dist/views/system/config/components/WatermarkSection2.vue.js +284 -0
  294. package/dist/views/system/config/components/WatermarkSection2.vue.js.map +1 -0
  295. package/dist/views/system/config/draft.d.ts +2 -2
  296. package/dist/views/system/config/draft.js.map +1 -1
  297. package/dist/views/system/config/groups.d.ts +4 -1
  298. package/dist/views/system/config/groups.js +54 -49
  299. package/dist/views/system/config/groups.js.map +1 -1
  300. package/dist/views/system/config/index.vue.js +3 -2
  301. package/dist/views/system/config/index.vue.js.map +1 -1
  302. package/dist/views/system/config/index2.vue.js +173 -148
  303. package/dist/views/system/config/index2.vue.js.map +1 -1
  304. package/dist/views/system/config/layoutMode.d.ts +23 -0
  305. package/dist/views/system/config/layoutMode.js +28 -0
  306. package/dist/views/system/config/layoutMode.js.map +1 -0
  307. package/dist/views/system/dict/index.vue.js +2 -2
  308. package/dist/views/system/dict/index2.vue.js +471 -366
  309. package/dist/views/system/dict/index2.vue.js.map +1 -1
  310. package/dist/views/system/file/index2.vue.js +91 -76
  311. package/dist/views/system/file/index2.vue.js.map +1 -1
  312. package/dist/views/system/job/index.vue.js +3 -3
  313. package/dist/views/system/job/index2.vue.js +897 -828
  314. package/dist/views/system/job/index2.vue.js.map +1 -1
  315. package/dist/views/system/job-log/components/AttemptTable.vue.d.ts +8 -0
  316. package/dist/views/system/job-log/components/AttemptTable.vue.js +5 -0
  317. package/dist/views/system/job-log/components/AttemptTable.vue.js.map +1 -0
  318. package/dist/views/system/job-log/components/AttemptTable2.vue.js +54 -0
  319. package/dist/views/system/job-log/components/AttemptTable2.vue.js.map +1 -0
  320. package/dist/views/system/job-log/index.vue.js +2 -2
  321. package/dist/views/system/job-log/index2.vue.js +193 -207
  322. package/dist/views/system/job-log/index2.vue.js.map +1 -1
  323. package/dist/views/system/job-log/runStatus.d.ts +13 -0
  324. package/dist/views/system/job-log/runStatus.js +26 -0
  325. package/dist/views/system/job-log/runStatus.js.map +1 -0
  326. package/dist/views/system/job-monitor/index.vue.js +2 -2
  327. package/dist/views/system/job-monitor/index2.vue.js +172 -180
  328. package/dist/views/system/job-monitor/index2.vue.js.map +1 -1
  329. package/dist/views/system/log/exception/index.vue.js +2 -2
  330. package/dist/views/system/log/exception/index2.vue.js +135 -96
  331. package/dist/views/system/log/exception/index2.vue.js.map +1 -1
  332. package/dist/views/system/log/login/index2.vue.js +62 -41
  333. package/dist/views/system/log/login/index2.vue.js.map +1 -1
  334. package/dist/views/system/log/op/index.vue.js +2 -2
  335. package/dist/views/system/log/op/index2.vue.js +200 -162
  336. package/dist/views/system/log/op/index2.vue.js.map +1 -1
  337. package/dist/views/system/menu/components/ButtonManager.vue.js +2 -2
  338. package/dist/views/system/menu/components/ButtonManager2.vue.js +206 -190
  339. package/dist/views/system/menu/components/ButtonManager2.vue.js.map +1 -1
  340. package/dist/views/system/menu/components/MenuFormModal.vue.js +2 -2
  341. package/dist/views/system/menu/components/MenuFormModal2.vue.js +127 -118
  342. package/dist/views/system/menu/components/MenuFormModal2.vue.js.map +1 -1
  343. package/dist/views/system/menu/index.vue.js +1 -1
  344. package/dist/views/system/menu/index2.vue.js +216 -183
  345. package/dist/views/system/menu/index2.vue.js.map +1 -1
  346. package/dist/views/system/module/index.vue.js +1 -1
  347. package/dist/views/system/module/index2.vue.js +177 -144
  348. package/dist/views/system/module/index2.vue.js.map +1 -1
  349. package/dist/views/system/monitor/index.vue.js +2 -2
  350. package/dist/views/system/monitor/index2.vue.js +134 -149
  351. package/dist/views/system/monitor/index2.vue.js.map +1 -1
  352. package/dist/views/system/notice/index.vue.js +1 -1
  353. package/dist/views/system/notice/index2.vue.js +209 -181
  354. package/dist/views/system/notice/index2.vue.js.map +1 -1
  355. package/dist/views/system/org/index.vue.js +1 -1
  356. package/dist/views/system/org/index2.vue.js +278 -248
  357. package/dist/views/system/org/index2.vue.js.map +1 -1
  358. package/dist/views/system/position/index.vue.js +5 -2
  359. package/dist/views/system/position/index.vue.js.map +1 -1
  360. package/dist/views/system/position/index2.vue.js +128 -92
  361. package/dist/views/system/position/index2.vue.js.map +1 -1
  362. package/dist/views/system/recycle/index.vue.js +2 -2
  363. package/dist/views/system/recycle/index2.vue.js +90 -67
  364. package/dist/views/system/recycle/index2.vue.js.map +1 -1
  365. package/dist/views/system/role/components/GrantMenuSheet.vue.d.ts +20 -0
  366. package/dist/views/system/role/components/GrantMenuSheet.vue.js +8 -0
  367. package/dist/views/system/role/components/GrantMenuSheet.vue.js.map +1 -0
  368. package/dist/views/system/role/components/GrantMenuSheet2.vue.js +117 -0
  369. package/dist/views/system/role/components/GrantMenuSheet2.vue.js.map +1 -0
  370. package/dist/views/system/role/components/GrantMenuTable.vue.d.ts +6 -4
  371. package/dist/views/system/role/components/GrantMenuTable.vue.js +2 -2
  372. package/dist/views/system/role/components/GrantMenuTable2.vue.js +279 -177
  373. package/dist/views/system/role/components/GrantMenuTable2.vue.js.map +1 -1
  374. package/dist/views/system/role/components/MatchText.vue.d.ts +7 -0
  375. package/dist/views/system/role/components/MatchText.vue.js +8 -0
  376. package/dist/views/system/role/components/MatchText.vue.js.map +1 -0
  377. package/dist/views/system/role/components/MatchText2.vue.js +29 -0
  378. package/dist/views/system/role/components/MatchText2.vue.js.map +1 -0
  379. package/dist/views/system/role/components/grantMenuGroups.d.ts +36 -0
  380. package/dist/views/system/role/components/grantMenuGroups.js +110 -48
  381. package/dist/views/system/role/components/grantMenuGroups.js.map +1 -1
  382. package/dist/views/system/role/index.vue.js +5 -2
  383. package/dist/views/system/role/index.vue.js.map +1 -1
  384. package/dist/views/system/role/index2.vue.js +181 -165
  385. package/dist/views/system/role/index2.vue.js.map +1 -1
  386. package/dist/views/system/session/index2.vue.js +75 -49
  387. package/dist/views/system/session/index2.vue.js.map +1 -1
  388. package/dist/views/system/user/components/ResetPasswordModal.vue.js +2 -2
  389. package/dist/views/system/user/components/ResetPasswordModal2.vue.js +2 -0
  390. package/dist/views/system/user/components/ResetPasswordModal2.vue.js.map +1 -1
  391. package/dist/views/system/user/components/UserFormModal.vue.js +2 -2
  392. package/dist/views/system/user/components/UserFormModal2.vue.js +77 -76
  393. package/dist/views/system/user/components/UserFormModal2.vue.js.map +1 -1
  394. package/dist/views/system/user/index.vue.js +2 -2
  395. package/dist/views/system/user/index2.vue.js +362 -275
  396. package/dist/views/system/user/index2.vue.js.map +1 -1
  397. package/package.json +3 -5
  398. package/dist/components/SelectTable/index.vue.d.ts +0 -76
  399. package/dist/components/SelectTable/index2.vue.js +0 -256
  400. package/dist/components/SelectTable/index2.vue.js.map +0 -1
  401. package/dist/composables/useTableRowSort.d.ts +0 -20
  402. package/dist/composables/useTableRowSort.js +0 -59
  403. package/dist/composables/useTableRowSort.js.map +0 -1
  404. package/dist/layouts/LayoutModeCards.vue.js +0 -8
  405. package/dist/layouts/LayoutModeCards.vue.js.map +0 -1
  406. package/dist/layouts/LayoutModeCards2.vue.js +0 -67
  407. package/dist/layouts/LayoutModeCards2.vue.js.map +0 -1
  408. package/dist/layouts/SettingRow.vue.d.ts +0 -16
  409. package/dist/layouts/SettingRow.vue.js +0 -8
  410. package/dist/layouts/SettingRow.vue.js.map +0 -1
  411. package/dist/layouts/SettingRow2.vue.js +0 -23
  412. package/dist/layouts/SettingRow2.vue.js.map +0 -1
  413. package/dist/views/login/skins/AuroraGlass.vue.js +0 -8
  414. package/dist/views/login/skins/AuroraGlass.vue.js.map +0 -1
  415. package/dist/views/login/skins/AuroraGlass2.vue.js +0 -80
  416. package/dist/views/login/skins/AuroraGlass2.vue.js.map +0 -1
  417. package/dist/views/login/skins/SplitPanel.vue.d.ts +0 -3
  418. package/dist/views/login/skins/SplitPanel.vue.js +0 -8
  419. package/dist/views/login/skins/SplitPanel.vue.js.map +0 -1
  420. package/dist/views/login/skins/SplitPanel2.vue.js +0 -65
  421. package/dist/views/login/skins/SplitPanel2.vue.js.map +0 -1
  422. package/dist/views/login/skins/Spotlight.vue.d.ts +0 -3
  423. package/dist/views/login/skins/Spotlight.vue.js +0 -8
  424. package/dist/views/login/skins/Spotlight.vue.js.map +0 -1
  425. package/dist/views/login/skins/Spotlight2.vue.js +0 -36
  426. package/dist/views/login/skins/Spotlight2.vue.js.map +0 -1
  427. package/dist/views/login/skins.d.ts +0 -8
  428. package/dist/views/login/skins.js +0 -13
  429. package/dist/views/login/skins.js.map +0 -1
  430. /package/dist/components/{SelectTable → TableTotal}/index.vue.js.map +0 -0
  431. /package/dist/layouts/{LayoutModeCards.vue.d.ts → AccentPicker.vue.d.ts} +0 -0
  432. /package/dist/views/{login/skins/AuroraGlass.vue.d.ts → system/config/components/WatermarkSection.vue.d.ts} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"biz2.vue.js","sources":["../../../src/views/dashboard/biz.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// 业务系统的工作台。每个应用一个首页组件——这里和 dashboard/workbench.vue 是两个独立页面,\n// 由各自应用的「工作台」菜单(component 字段)指向,切应用即换首页。\n// 全部真数据拼装:欢迎横幅(user store + sessions + last-login)+ 待办事项(工作台待办扩展点,\n// 内核默认空)+ 快捷方式(手动置顶 + 高频自动补位)+ 我的通知(notice/mine)。\n// 应用要换成自己的业务统计,在自己的 views/ 下放同 key(dashboard/biz)的页面覆盖本页;别造写死的假数字。\nimport { computed, onMounted, onUnmounted, ref } from 'vue'\nimport { NCard, NButton, NList, NListItem, NEmpty, NTag } from 'naive-ui'\nimport { Icon } from '@iconify/vue'\nimport { useI18n } from 'vue-i18n'\nimport { useRoute, useRouter } from 'vue-router'\nimport { useUserStore } from '#/stores/user'\nimport { useAppStore } from '#/stores/app'\nimport { btnGrad } from '#/theme/mix'\nimport { noticeApi, personalApi } from '#/api'\nimport type {\n NoticeMineItem,\n LastLoginInfo,\n WorkbenchTodoSummary,\n UserShortcutItem,\n} from '#/types/api'\nimport { useMenuFlat } from '#/composables/useMenuFlat'\nimport { translateMenuTitle } from '#/locales/menuTitle'\nimport { onlineDurationParts } from './onlineDuration'\nimport { buildShortcutGroups } from './shortcutGroups'\nimport ShortcutPicker from './ShortcutPicker.vue'\nimport AppIcon from '#/components/AppIcon.vue'\nimport { fmtDateTime } from '#/utils/format'\nimport { uaSummary } from '#/utils/ua'\n\nconst { t } = useI18n()\nconst user = useUserStore()\nconst app = useAppStore()\nconst route = useRoute()\nconst router = useRouter()\nconst leaves = useMenuFlat()\n\nconst avatarStyle = computed(() => ({ background: btnGrad(app.accent) }))\n\n// ── 在线时长 + 上次登录 ─────────────────────────────────────\nconst currentLoginTime = ref<string | null>(null)\nconst lastLogin = ref<LastLoginInfo | null>(null)\nconst now = ref(new Date())\nlet tickTimer: ReturnType<typeof setInterval> | undefined\n\nconst onlineText = computed(() => {\n if (!currentLoginTime.value) return ''\n const { hours, minutes } = onlineDurationParts(currentLoginTime.value, now.value)\n return hours > 0\n ? t('biz.onlineDuration', { hours, minutes })\n : t('biz.onlineDurationShort', { minutes })\n})\nconst lastLoginText = computed(() => {\n if (!lastLogin.value) return t('biz.firstLogin')\n const device = uaSummary(lastLogin.value.userAgent)\n const ip = lastLogin.value.ip ? ` · ${lastLogin.value.ip}` : ''\n const base = t('biz.lastLogin', { time: fmtDateTime(lastLogin.value.time, { seconds: false }) })\n return `${base}${ip}${device ? ` · ${device}` : ''}`\n})\n\n// ── 待办事项:内核默认空,消费方接入真实审批/工单系统后有内容 ──────────\nconst todo = ref<WorkbenchTodoSummary | null>(null)\n\n// ── 快捷方式 ─────────────────────────────────────────────\nconst shortcuts = ref<UserShortcutItem[]>([])\nconst pickerShow = ref(false)\n// 排除本页自身:工作台自己也是菜单树里的一条,不该出现在\"去哪儿\"的快捷方式里\nconst groups = computed(() =>\n buildShortcutGroups(\n shortcuts.value.filter(s => s.menuPath !== route.path),\n leaves.value,\n ),\n)\nconst pinnedPaths = computed(() => shortcuts.value.filter(s => s.pinned).map(s => s.menuPath))\n\nasync function loadShortcuts() {\n try {\n shortcuts.value = await personalApi.shortcuts()\n } catch {\n shortcuts.value = []\n }\n}\nasync function pin(path: string) {\n await personalApi.pinShortcut(path)\n await loadShortcuts()\n}\nasync function unpin(path: string) {\n await personalApi.unpinShortcut(path)\n await loadShortcuts()\n}\n\n// ── 通知 ────────────────────────────────────────────────\nconst notices = ref<NoticeMineItem[]>([])\n\nonMounted(async () => {\n tickTimer = setInterval(() => {\n now.value = new Date()\n }, 60_000)\n\n try {\n const sessions = await personalApi.sessions()\n currentLoginTime.value = sessions.find(s => s.isCurrent)?.loginTime ?? null\n } catch {\n // 在线时长拿不到就不显示这一段,不影响页面其余部分\n }\n try {\n lastLogin.value = await personalApi.lastLogin()\n } catch {\n lastLogin.value = null\n }\n try {\n todo.value = await personalApi.workbenchTodo()\n } catch {\n todo.value = null\n }\n await loadShortcuts()\n try {\n notices.value = (await noticeApi.mine({ page: 1, pageSize: 5 })).items\n } catch {\n // 首页不因一张卡挂了糊用户一脸红:通知取不到就空态,其余照常可用。\n }\n})\nonUnmounted(() => {\n if (tickTimer) clearInterval(tickTimer)\n})\n</script>\n\n<template>\n <div class=\"view\">\n <!-- 欢迎横幅:身份 + 在线状态,一行说完 -->\n <div class=\"banner\">\n <div class=\"avatar\" :style=\"avatarStyle\">\n <Icon icon=\"ph:user\" :width=\"26\" color=\"#fff\" />\n </div>\n <div class=\"banner-body\">\n <div class=\"hi\">\n {{ t('biz.welcome', { name: user.userInfo?.name ?? user.userInfo?.account ?? '' }) }}\n </div>\n <div class=\"tip\">{{ t('biz.subtitle') }}</div>\n <div v-if=\"onlineText || lastLoginText\" class=\"meta-row\">\n <span v-if=\"onlineText\">{{ onlineText }}</span>\n <span v-if=\"onlineText && lastLoginText\" class=\"meta-dot\" />\n <span>{{ lastLoginText }}</span>\n </div>\n </div>\n </div>\n\n <div class=\"row\">\n <!-- 待办事项:内核默认空,消费方接入真实审批/工单系统后有内容 -->\n <n-card :title=\"t('biz.todo')\" :bordered=\"true\">\n <template v-if=\"todo && todo.totalCount > 0\" #header-extra>\n <n-tag type=\"error\" round size=\"small\">{{ todo.totalCount }}</n-tag>\n </template>\n <div v-if=\"todo && todo.items.length\" class=\"todo-list\">\n <div\n v-for=\"i in todo.items\"\n :key=\"i.id\"\n class=\"todo-row\"\n @click=\"i.url && router.push(i.url)\"\n >\n <div class=\"todo-main\">\n <div class=\"todo-title\">{{ i.title }}</div>\n <div v-if=\"i.description\" class=\"todo-sub\">{{ i.description }}</div>\n </div>\n <span class=\"todo-time\">{{ fmtDateTime(i.createTime, { seconds: false }) }}</span>\n </div>\n </div>\n <n-empty v-else :description=\"t('biz.todoEmpty')\" />\n </n-card>\n\n <!-- 快捷方式:实心星=手动置顶(可移除),虚线框+空心星=高频访问自动推荐(点固定即置顶) -->\n <n-card :title=\"t('biz.quick')\" :bordered=\"true\">\n <template #header-extra>\n <n-button size=\"small\" quaternary circle @click=\"pickerShow = true\">\n <template #icon><Icon icon=\"ph:plus\" :width=\"16\" /></template>\n </n-button>\n </template>\n <div v-if=\"groups.pinned.length || groups.suggested.length\">\n <div v-if=\"groups.pinned.length\" class=\"quick-group-label\">\n {{ t('biz.quickPinned') }}\n </div>\n <div v-if=\"groups.pinned.length\" class=\"quick-grid\">\n <div v-for=\"s in groups.pinned\" :key=\"s.path\" class=\"quick-item\">\n <button\n class=\"quick-star active\"\n type=\"button\"\n :aria-label=\"t('biz.quickUnpin')\"\n @click.stop=\"unpin(s.path)\"\n >\n <Icon icon=\"ph:star-fill\" :width=\"12\" />\n </button>\n <div class=\"quick-body\" @click=\"router.push(s.path)\">\n <AppIcon :icon=\"s.icon\" :size=\"17\" />\n <span class=\"quick-name\">{{ translateMenuTitle(s.title) }}</span>\n </div>\n </div>\n </div>\n <div v-if=\"groups.suggested.length\" class=\"quick-group-label\">\n {{ t('biz.quickSuggested') }}\n </div>\n <div v-if=\"groups.suggested.length\" class=\"quick-grid\">\n <div v-for=\"s in groups.suggested\" :key=\"s.path\" class=\"quick-item suggested\">\n <button\n class=\"quick-star\"\n type=\"button\"\n :aria-label=\"t('biz.quickPin')\"\n @click.stop=\"pin(s.path)\"\n >\n <Icon icon=\"ph:star\" :width=\"12\" />\n </button>\n <div class=\"quick-body\" @click=\"router.push(s.path)\">\n <AppIcon :icon=\"s.icon\" :size=\"17\" />\n <span class=\"quick-name\">{{ translateMenuTitle(s.title) }}</span>\n </div>\n </div>\n </div>\n </div>\n <n-empty v-else :description=\"t('biz.noMenus')\" />\n </n-card>\n </div>\n\n <!-- 通知:没有\"查看全部\"——卡片本身就是完整内容 -->\n <n-card :title=\"t('biz.notices')\" :bordered=\"true\">\n <n-list v-if=\"notices.length\" :show-divider=\"false\">\n <n-list-item v-for=\"n in notices\" :key=\"n.id\">\n <div class=\"notice-row\" @click=\"router.push('/personal/notice')\">\n <span class=\"notice-title\">\n <span v-if=\"!n.isRead\" class=\"dot\" />\n {{ n.title }}\n </span>\n <span class=\"notice-time\">{{ fmtDateTime(n.publishTime, { seconds: false }) }}</span>\n </div>\n </n-list-item>\n </n-list>\n <n-empty v-else :description=\"t('biz.noticesEmpty')\" />\n </n-card>\n\n <ShortcutPicker\n v-model:show=\"pickerShow\"\n :exclude-paths=\"[...pinnedPaths, route.path]\"\n @pick=\"pin\"\n />\n </div>\n</template>\n\n<style scoped>\n.view {\n display: flex;\n flex-direction: column;\n gap: var(--gap-card);\n}\n.banner {\n display: flex;\n align-items: center;\n gap: 16px;\n padding: 24px;\n border-radius: var(--radius-lg);\n background: var(--color-primary-light);\n}\n.avatar {\n flex-shrink: 0;\n width: 52px;\n height: 52px;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.banner-body {\n min-width: 0;\n}\n.hi {\n font-size: var(--font-size-lg);\n font-weight: 600;\n color: var(--color-text-primary);\n}\n.tip {\n color: var(--color-text-secondary);\n margin-top: 4px;\n}\n.meta-row {\n margin-top: 8px;\n display: flex;\n align-items: center;\n gap: 10px;\n font-size: 13px;\n color: var(--color-text-tertiary);\n font-variant-numeric: tabular-nums;\n}\n.meta-dot {\n width: 3px;\n height: 3px;\n border-radius: 50%;\n background: var(--color-text-disabled);\n flex-shrink: 0;\n}\n.row {\n display: grid;\n grid-template-columns: 1.35fr 1fr;\n gap: var(--gap-card);\n align-items: start;\n}\n@media (max-width: 760px) {\n .row {\n grid-template-columns: 1fr;\n }\n}\n.todo-list {\n display: flex;\n flex-direction: column;\n}\n.todo-row {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n gap: 12px;\n padding: 10px 0;\n border-bottom: 1px solid var(--color-border);\n cursor: pointer;\n}\n.todo-row:last-child {\n border-bottom: none;\n}\n.todo-title {\n color: var(--color-text-primary);\n font-weight: 500;\n}\n.todo-sub {\n margin-top: 2px;\n font-size: 12px;\n color: var(--color-text-tertiary);\n}\n.todo-time {\n flex-shrink: 0;\n font-size: 12px;\n color: var(--color-text-tertiary);\n}\n.quick-group-label {\n font-size: 12px;\n color: var(--color-text-tertiary);\n margin: 4px 0 8px;\n}\n.quick-grid {\n display: flex;\n flex-wrap: wrap;\n gap: 10px;\n margin-bottom: 4px;\n}\n.quick-item {\n position: relative;\n border: 1px solid var(--color-border);\n border-radius: var(--radius-md);\n}\n.quick-item.suggested {\n border-style: dashed;\n}\n.quick-body {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 8px 14px 8px 10px;\n cursor: pointer;\n}\n.quick-name {\n font-size: 13px;\n color: var(--color-text-secondary);\n}\n.quick-star {\n position: absolute;\n top: -6px;\n right: -6px;\n width: 18px;\n height: 18px;\n border-radius: 50%;\n border: 1px solid var(--color-border);\n background: var(--color-bg-elevated);\n color: var(--color-text-disabled);\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n}\n.quick-star.active {\n color: var(--color-warning);\n}\n.notice-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n cursor: pointer;\n}\n.notice-title {\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--color-text-primary);\n}\n.dot {\n flex-shrink: 0;\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: var(--color-primary);\n}\n.notice-time {\n flex-shrink: 0;\n color: var(--color-text-secondary);\n font-size: 12px;\n}\n</style>\n"],"names":["t","useI18n","user","useUserStore","app","useAppStore","route","useRoute","router","useRouter","leaves","useMenuFlat","avatarStyle","computed","btnGrad","currentLoginTime","ref","lastLogin","now","tickTimer","onlineText","hours","minutes","onlineDurationParts","lastLoginText","device","uaSummary","ip","fmtDateTime","todo","shortcuts","pickerShow","groups","buildShortcutGroups","s","pinnedPaths","loadShortcuts","personalApi","pin","path","unpin","notices","onMounted","sessions","_a","noticeApi","onUnmounted","_openBlock","_createElementBlock","_hoisted_1","_createElementVNode","_hoisted_2","_createVNode","_unref","Icon","_hoisted_3","_hoisted_4","_toDisplayString","_hoisted_5","_hoisted_6","_hoisted_8","_hoisted_9","NCard","_hoisted_10","_Fragment","_renderList","i","$event","_hoisted_12","_hoisted_13","_hoisted_14","_hoisted_15","_createBlock","NEmpty","NTag","_createTextVNode","NButton","_hoisted_16","_hoisted_17","_hoisted_18","_withModifiers","AppIcon","_hoisted_21","_hoisted_22","_hoisted_23","_hoisted_26","NList","n","NListItem","_cache","_hoisted_27","_hoisted_28","_hoisted_29","ShortcutPicker"],"mappings":"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"}
1
+ {"version":3,"file":"biz2.vue.js","sources":["../../../src/views/dashboard/biz.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// 业务系统的工作台。每个应用一个首页组件——这里和 dashboard/workbench.vue 是两个独立页面,\n// 由各自应用的「工作台」菜单(component 字段)指向,切应用即换首页。\n// 全部真数据拼装:欢迎横幅(user store + sessions + last-login)+ 待办事项(工作台待办扩展点,\n// 内核默认空)+ 快捷方式(手动置顶 + 高频自动补位)+ 我的通知(notice/mine)。\n// 应用要换成自己的业务统计,在自己的 views/ 下放同 key(dashboard/biz)的页面覆盖本页;别造写死的假数字。\nimport { computed, onMounted, onUnmounted, ref } from 'vue'\nimport { NCard, NButton, NList, NListItem, NEmpty, NTag } from 'naive-ui'\nimport { useElementSize } from '@vueuse/core'\nimport { Icon } from '@iconify/vue'\nimport { useI18n } from 'vue-i18n'\nimport { useRoute, useRouter } from 'vue-router'\nimport { useUserStore } from '#/stores/user'\nimport { noticeApi, personalApi } from '#/api'\nimport type {\n NoticeMineItem,\n LastLoginInfo,\n WorkbenchTodoSummary,\n UserShortcutItem,\n} from '#/types/api'\nimport { useMenuFlat } from '#/composables/useMenuFlat'\nimport { translateMenuTitle } from '#/locales/menuTitle'\nimport { onlineDurationParts } from './onlineDuration'\nimport { buildShortcutGroups } from './shortcutGroups'\nimport ShortcutPicker from './ShortcutPicker.vue'\nimport AppIcon from '#/components/AppIcon.vue'\nimport { fmtDateTime } from '#/utils/format'\nimport { uaSummary } from '#/utils/ua'\n\nconst { t } = useI18n()\nconst user = useUserStore()\nconst route = useRoute()\nconst router = useRouter()\nconst leaves = useMenuFlat()\n\n// 内容区宽度(不是视口):窄档元信息的小圆点隐藏、通知时间换到标题下一行\nconst viewRef = ref<HTMLElement | null>(null)\nconst { width: pw } = useElementSize(viewRef)\nconst twoCols = computed(() => pw.value === 0 || pw.value >= 760)\nconst wideRow = computed(() => pw.value === 0 || pw.value >= 600)\n\n// ── 在线时长 + 上次登录 ─────────────────────────────────────\nconst currentLoginTime = ref<string | null>(null)\nconst lastLogin = ref<LastLoginInfo | null>(null)\nconst now = ref(new Date())\nlet tickTimer: ReturnType<typeof setInterval> | undefined\n\nconst onlineText = computed(() => {\n if (!currentLoginTime.value) return ''\n const { hours, minutes } = onlineDurationParts(currentLoginTime.value, now.value)\n return hours > 0\n ? t('biz.onlineDuration', { hours, minutes })\n : t('biz.onlineDurationShort', { minutes })\n})\nconst lastLoginText = computed(() => {\n if (!lastLogin.value) return t('biz.firstLogin')\n const device = uaSummary(lastLogin.value.userAgent)\n const ip = lastLogin.value.ip ? ` · ${lastLogin.value.ip}` : ''\n const base = t('biz.lastLogin', { time: fmtDateTime(lastLogin.value.time, { seconds: false }) })\n return `${base}${ip}${device ? ` · ${device}` : ''}`\n})\n\n// ── 待办事项:内核默认空,消费方接入真实审批/工单系统后有内容 ──────────\nconst todo = ref<WorkbenchTodoSummary | null>(null)\n\n// ── 快捷方式 ─────────────────────────────────────────────\nconst shortcuts = ref<UserShortcutItem[]>([])\nconst pickerShow = ref(false)\n// 排除本页自身:工作台自己也是菜单树里的一条,不该出现在\"去哪儿\"的快捷方式里\nconst groups = computed(() =>\n buildShortcutGroups(\n shortcuts.value.filter(s => s.menuPath !== route.path),\n leaves.value,\n ),\n)\nconst pinnedPaths = computed(() => shortcuts.value.filter(s => s.pinned).map(s => s.menuPath))\n\nasync function loadShortcuts() {\n try {\n shortcuts.value = await personalApi.shortcuts()\n } catch {\n shortcuts.value = []\n }\n}\nasync function pin(path: string) {\n await personalApi.pinShortcut(path)\n await loadShortcuts()\n}\nasync function unpin(path: string) {\n await personalApi.unpinShortcut(path)\n await loadShortcuts()\n}\n\n// ── 通知 ────────────────────────────────────────────────\nconst notices = ref<NoticeMineItem[]>([])\n\nonMounted(async () => {\n tickTimer = setInterval(() => {\n now.value = new Date()\n }, 60_000)\n\n try {\n const sessions = await personalApi.sessions()\n currentLoginTime.value = sessions.find(s => s.isCurrent)?.loginTime ?? null\n } catch {\n // 在线时长拿不到就不显示这一段,不影响页面其余部分\n }\n try {\n lastLogin.value = await personalApi.lastLogin()\n } catch {\n lastLogin.value = null\n }\n try {\n todo.value = await personalApi.workbenchTodo()\n } catch {\n todo.value = null\n }\n await loadShortcuts()\n try {\n notices.value = (await noticeApi.mine({ page: 1, pageSize: 5 })).items\n } catch {\n // 首页不因一张卡挂了糊用户一脸红:通知取不到就空态,其余照常可用。\n }\n})\nonUnmounted(() => {\n if (tickTimer) clearInterval(tickTimer)\n})\n</script>\n\n<template>\n <div ref=\"viewRef\" class=\"view\">\n <!-- 欢迎横幅:身份 + 在线状态,一行说完 -->\n <n-card class=\"a-card banner-card\" :bordered=\"true\" content-style=\"padding: 18px 20px\">\n <div class=\"banner\">\n <div class=\"avatar\">\n <Icon icon=\"ph:user\" :width=\"26\" />\n </div>\n <div class=\"banner-body\">\n <div class=\"hi\">\n {{ t('biz.welcome', { name: user.userInfo?.name ?? user.userInfo?.account ?? '' }) }}\n </div>\n <div class=\"tip\">{{ t('biz.subtitle') }}</div>\n <div v-if=\"onlineText || lastLoginText\" class=\"meta-row\">\n <span v-if=\"onlineText\">{{ onlineText }}</span>\n <span\n v-if=\"onlineText && lastLoginText && wideRow\"\n class=\"meta-dot\"\n aria-hidden=\"true\"\n />\n <span>{{ lastLoginText }}</span>\n </div>\n </div>\n </div>\n </n-card>\n\n <div\n class=\"row\"\n :style=\"{\n gridTemplateColumns: twoCols ? 'minmax(0, 1.35fr) minmax(0, 1fr)' : 'minmax(0, 1fr)',\n }\"\n >\n <!-- 待办事项:内核默认空,消费方接入真实审批/工单系统后有内容 -->\n <n-card\n class=\"a-card\"\n :title=\"t('biz.todo')\"\n :bordered=\"true\"\n content-style=\"padding: 2px 8px 8px\"\n >\n <template v-if=\"todo && todo.totalCount > 0\" #header-extra>\n <n-tag type=\"error\" round size=\"small\" :bordered=\"false\">{{ todo.totalCount }}</n-tag>\n </template>\n <n-list v-if=\"todo && todo.items.length\" hoverable :show-divider=\"false\">\n <n-list-item\n v-for=\"i in todo.items\"\n :key=\"i.id\"\n class=\"list-item\"\n :style=\"{ cursor: i.url ? 'pointer' : 'default' }\"\n @click=\"i.url && router.push(i.url)\"\n >\n <div class=\"todo-row\">\n <div class=\"todo-main\">\n <div class=\"todo-title\">{{ i.title }}</div>\n <div v-if=\"i.description\" class=\"todo-sub\">{{ i.description }}</div>\n </div>\n <span class=\"todo-time\">{{ fmtDateTime(i.createTime, { seconds: false }) }}</span>\n </div>\n </n-list-item>\n </n-list>\n <n-empty v-else :description=\"t('biz.todoEmpty')\" class=\"empty\" />\n </n-card>\n\n <!-- 快捷方式:实心星 + 实线框=手动置顶(可移除),空心星 + 虚线框=高频访问自动推荐(点星即置顶) -->\n <n-card\n class=\"a-card\"\n :title=\"t('biz.quick')\"\n :bordered=\"true\"\n content-style=\"padding: 4px 16px 16px\"\n >\n <template #header-extra>\n <n-button quaternary circle :aria-label=\"t('biz.quickAdd')\" @click=\"pickerShow = true\">\n <template #icon><Icon icon=\"ph:plus\" :width=\"16\" /></template>\n </n-button>\n </template>\n <div v-if=\"groups.pinned.length || groups.suggested.length\">\n <template v-if=\"groups.pinned.length\">\n <div class=\"quick-group-label\">{{ t('biz.quickPinned') }}</div>\n <div class=\"quick-grid\">\n <div v-for=\"s in groups.pinned\" :key=\"s.path\" class=\"quick-item pinned\">\n <n-button quaternary class=\"quick-body\" @click=\"router.push(s.path)\">\n <template #icon><AppIcon :icon=\"s.icon\" :size=\"17\" /></template>\n <span class=\"quick-name\">{{ translateMenuTitle(s.title) }}</span>\n </n-button>\n <n-button\n quaternary\n circle\n class=\"quick-star\"\n :aria-label=\"t('biz.quickUnpin')\"\n @click.stop=\"unpin(s.path)\"\n >\n <template #icon>\n <Icon icon=\"ph:star-fill\" :width=\"14\" class=\"star-on\" />\n </template>\n </n-button>\n </div>\n </div>\n </template>\n <template v-if=\"groups.suggested.length\">\n <div class=\"quick-group-label\" :class=\"{ 'after-pinned': groups.pinned.length }\">\n {{ t('biz.quickSuggested') }}\n </div>\n <div class=\"quick-grid\">\n <div v-for=\"s in groups.suggested\" :key=\"s.path\" class=\"quick-item suggested\">\n <n-button quaternary class=\"quick-body\" @click=\"router.push(s.path)\">\n <template #icon><AppIcon :icon=\"s.icon\" :size=\"17\" /></template>\n <span class=\"quick-name\">{{ translateMenuTitle(s.title) }}</span>\n </n-button>\n <n-button\n quaternary\n circle\n class=\"quick-star\"\n :aria-label=\"t('biz.quickPin')\"\n @click.stop=\"pin(s.path)\"\n >\n <template #icon><Icon icon=\"ph:star\" :width=\"14\" class=\"star-off\" /></template>\n </n-button>\n </div>\n </div>\n </template>\n </div>\n <n-empty v-else :description=\"t('biz.noMenus')\" class=\"empty\" />\n </n-card>\n </div>\n\n <!-- 通知:没有\"查看全部\"——卡片本身就是完整内容;整行点击进「我的通知」 -->\n <n-card\n class=\"a-card\"\n :title=\"t('biz.notices')\"\n :bordered=\"true\"\n content-style=\"padding: 2px 8px 8px\"\n >\n <n-list v-if=\"notices.length\" hoverable clickable :show-divider=\"false\">\n <n-list-item\n v-for=\"n in notices\"\n :key=\"n.id\"\n class=\"list-item\"\n @click=\"router.push('/personal/notice')\"\n >\n <!-- 用 grid 而不是 flex:标题单行省略要靠 minmax(0, 1fr) 才收得住;窄屏时间换到标题下一行。\n 已读的圆点位置留空占位,标题与未读对齐 -->\n <div class=\"notice-row\" :class=\"{ stacked: !wideRow }\">\n <span class=\"dot\" :class=\"{ unread: !n.isRead }\" />\n <span class=\"notice-title\" :class=\"{ unread: !n.isRead }\" :title=\"n.title\">\n {{ n.title }}\n </span>\n <span class=\"notice-time\">{{ fmtDateTime(n.publishTime, { seconds: false }) }}</span>\n </div>\n </n-list-item>\n </n-list>\n <n-empty v-else :description=\"t('biz.noticesEmpty')\" class=\"empty\" />\n </n-card>\n\n <ShortcutPicker\n v-model:show=\"pickerShow\"\n :exclude-paths=\"[...pinnedPaths, route.path]\"\n @pick=\"pin\"\n />\n </div>\n</template>\n\n<style scoped>\n.view {\n display: grid;\n grid-template-columns: minmax(0, 1fr);\n gap: var(--gap-card);\n align-content: start;\n}\n/* 横幅卡底色取选中态令牌(主色 6% / 暗色 14%),与管理工作台同一套 */\n.banner-card {\n background-image: linear-gradient(var(--sel-bg), var(--sel-bg));\n}\n.banner {\n display: flex;\n align-items: center;\n gap: 16px;\n}\n.avatar {\n flex: none;\n width: 52px;\n height: 52px;\n border-radius: 50%;\n display: grid;\n place-items: center;\n color: var(--on-acc);\n background-image: linear-gradient(135deg, var(--signal), var(--login-accent-2));\n box-shadow: 0 8px 20px -8px var(--signal-glow);\n}\n.banner-body {\n min-width: 0;\n flex: 1;\n}\n.hi {\n font-size: 18px;\n font-weight: 600;\n letter-spacing: -0.02em;\n color: var(--text-1);\n}\n.tip {\n margin-top: 2px;\n font-size: 14px;\n color: var(--text-2);\n}\n.meta-row {\n margin-top: 8px;\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 2px 8px;\n font-size: 13px;\n color: var(--text-3);\n font-variant-numeric: tabular-nums;\n}\n.meta-dot {\n width: 3px;\n height: 3px;\n border-radius: 50%;\n background: currentColor;\n opacity: 0.7;\n flex-shrink: 0;\n}\n.row {\n display: grid;\n align-items: start;\n gap: var(--gap-card);\n}\n/* 列表行:圆角 10px,悬停底色由 NList 自带 */\n.list-item {\n border-radius: var(--radius-md);\n padding: 8px 10px;\n}\n.empty {\n padding: 26px 0;\n}\n.todo-row {\n display: flex;\n flex-wrap: wrap;\n justify-content: space-between;\n align-items: flex-start;\n gap: 2px 16px;\n}\n.todo-main {\n flex: 1 1 220px;\n min-width: 0;\n}\n.todo-title {\n font-weight: 500;\n color: var(--text-1);\n}\n.todo-sub {\n margin-top: 2px;\n font-size: 13px;\n color: var(--text-3);\n}\n.todo-time {\n font-size: 13px;\n white-space: nowrap;\n color: var(--text-3);\n font-variant-numeric: tabular-nums;\n}\n.quick-group-label {\n margin: 0 0 8px;\n font-size: 13px;\n color: var(--text-3);\n}\n.quick-group-label.after-pinned {\n margin-top: 16px;\n}\n.quick-grid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));\n gap: 10px;\n}\n.quick-item {\n display: flex;\n align-items: center;\n min-width: 0;\n border-radius: var(--radius-md);\n}\n.quick-item.pinned {\n border: 1px solid var(--hairline-strong);\n background: var(--fill);\n}\n.quick-item.suggested {\n border: 1px dashed var(--hairline-strong);\n}\n.quick-body {\n flex: 1 1 auto;\n min-width: 0;\n height: 40px;\n justify-content: flex-start;\n}\n.quick-name {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.quick-star {\n flex: none;\n margin-right: 3px;\n}\n.star-on {\n color: var(--warn);\n}\n.star-off {\n color: var(--text-3);\n}\n.notice-row {\n display: grid;\n grid-template-columns: 6px minmax(0, 1fr) auto;\n align-items: center;\n column-gap: 10px;\n row-gap: 2px;\n overflow: hidden;\n}\n.notice-row.stacked {\n grid-template-columns: 6px minmax(0, 1fr);\n}\n.notice-row.stacked .notice-time {\n grid-column: 2;\n}\n.dot {\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: transparent;\n}\n.dot.unread {\n background: var(--signal);\n}\n.notice-title {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n color: var(--text-1);\n}\n.notice-title.unread {\n font-weight: 500;\n}\n.notice-time {\n font-size: 13px;\n white-space: nowrap;\n color: var(--text-3);\n font-variant-numeric: tabular-nums;\n}\n</style>\n"],"names":["t","useI18n","user","useUserStore","route","useRoute","router","useRouter","leaves","useMenuFlat","viewRef","ref","pw","useElementSize","twoCols","computed","wideRow","currentLoginTime","lastLogin","now","tickTimer","onlineText","hours","minutes","onlineDurationParts","lastLoginText","device","uaSummary","ip","fmtDateTime","todo","shortcuts","pickerShow","groups","buildShortcutGroups","pinnedPaths","loadShortcuts","personalApi","pin","path","unpin","notices","onMounted","sessions","_a","s","noticeApi","onUnmounted","_createElementBlock","_createVNode","_unref","NCard","_createElementVNode","_hoisted_1","_hoisted_2","Icon","_hoisted_3","_hoisted_4","_toDisplayString","_hoisted_5","_openBlock","_hoisted_6","_hoisted_8","_normalizeStyle","_createBlock","NList","_Fragment","_renderList","i","NListItem","$event","_hoisted_9","_hoisted_10","_hoisted_11","_hoisted_12","_hoisted_13","NEmpty","NTag","_createTextVNode","NButton","_hoisted_14","_hoisted_15","_hoisted_16","AppIcon","_hoisted_17","_withModifiers","_hoisted_18","_hoisted_19","n","_cache","_normalizeClass","_hoisted_20","_hoisted_21","ShortcutPicker"],"mappings":"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"}
@@ -1,8 +1,8 @@
1
1
  import o from "./workbench2.vue.js";
2
2
  /* empty css */
3
3
  import r from "../../_virtual/_plugin-vue_export-helper.js";
4
- const p = /* @__PURE__ */ r(o, [["__scopeId", "data-v-a20971bd"]]);
4
+ const m = /* @__PURE__ */ r(o, [["__scopeId", "data-v-4b676ea4"]]);
5
5
  export {
6
- p as default
6
+ m as default
7
7
  };
8
8
  //# sourceMappingURL=workbench.vue.js.map
@@ -1,195 +1,181 @@
1
- import { defineComponent as I, computed as v, ref as b, onMounted as L, openBlock as s, createElementBlock as _, createElementVNode as n, normalizeStyle as w, createVNode as l, unref as e, toDisplayString as h, withCtx as u, Fragment as $, renderList as E, createBlock as d } from "vue";
2
- import { NGrid as g, NGi as f, NCard as k, NSkeleton as y } from "naive-ui";
1
+ import { defineComponent as D, ref as _, onMounted as E, computed as i, openBlock as n, createElementBlock as y, createVNode as u, unref as t, withCtx as p, createElementVNode as o, toDisplayString as h, normalizeStyle as k, Fragment as I, renderList as L, createBlock as c } from "vue";
2
+ import { NCard as f, NSkeleton as b } from "naive-ui";
3
+ import { useElementSize as z } from "@vueuse/core";
3
4
  import { Icon as x } from "@iconify/vue";
4
- import { useI18n as T } from "vue-i18n";
5
+ import { useI18n as R } from "vue-i18n";
5
6
  import { useUserStore as U } from "../../stores/user.js";
6
- import { useAppStore as V } from "../../stores/app.js";
7
- import { btnGrad as z } from "../../theme/mix.js";
8
- import { dashboardApi as F } from "../../api/index.js";
9
- import M from "../../components/Chart/LineChart.vue.js";
10
- import j from "../../components/Chart/PieChart.vue.js";
11
- const q = { class: "view" }, H = { class: "banner" }, J = { class: "hi" }, K = { class: "tip" }, O = { class: "stat" }, P = { class: "stat-body" }, Q = {
7
+ import { dashboardApi as V } from "../../api/index.js";
8
+ import F from "../../components/Chart/LineChart.vue.js";
9
+ import M from "../../components/Chart/PieChart.vue.js";
10
+ const j = { class: "banner" }, q = { class: "avatar" }, G = { class: "banner-body" }, H = { class: "hi" }, J = { class: "tip" }, K = { class: "stat-body" }, O = {
12
11
  key: 1,
13
12
  class: "stat-val tabular"
14
- }, R = { class: "stat-label" }, le = /* @__PURE__ */ I({
13
+ }, P = { class: "stat-label" }, oe = /* @__PURE__ */ D({
15
14
  __name: "workbench",
16
- setup(W) {
17
- const { t: r } = T(), S = U(), N = V(), A = v(() => ({ background: z(N.accent) })), o = b(null), m = b(!0);
18
- L(async () => {
15
+ setup(Q) {
16
+ const { t: s } = R(), C = U(), r = _(null), v = _(!0);
17
+ E(async () => {
19
18
  try {
20
- o.value = await F.summary();
19
+ r.value = await V.summary();
21
20
  } catch {
22
21
  } finally {
23
- m.value = !1;
22
+ v.value = !1;
24
23
  }
25
24
  });
26
- function p(t) {
27
- return t === void 0 ? "—" : t;
25
+ function m(e) {
26
+ return e === void 0 ? "—" : e;
28
27
  }
29
- const B = v(() => {
30
- var t, a, c, i;
28
+ const S = i(() => {
29
+ var e, l, a, g;
31
30
  return [
32
31
  {
33
32
  key: "roles",
34
- icon: "ph:shield-duotone",
35
- value: p((t = o.value) == null ? void 0 : t.roles),
36
- color: "var(--color-primary)"
33
+ icon: "ph:shield",
34
+ value: m((e = r.value) == null ? void 0 : e.roles),
35
+ color: "var(--chart-1)"
37
36
  },
38
37
  {
39
38
  key: "users",
40
- icon: "ph:users-duotone",
41
- value: p((a = o.value) == null ? void 0 : a.users),
42
- color: "var(--color-success)"
39
+ icon: "ph:users",
40
+ value: m((l = r.value) == null ? void 0 : l.users),
41
+ color: "var(--chart-2)"
43
42
  },
44
43
  {
45
44
  key: "perms",
46
- icon: "ph:key-duotone",
47
- value: p((c = o.value) == null ? void 0 : c.perms),
48
- color: "var(--color-warning)"
45
+ icon: "ph:key",
46
+ value: m((a = r.value) == null ? void 0 : a.perms),
47
+ color: "var(--chart-3)"
49
48
  },
50
49
  {
51
50
  key: "online",
52
- icon: "ph:broadcast-duotone",
53
- value: p((i = o.value) == null ? void 0 : i.onlineSessions),
54
- color: "var(--color-danger)"
51
+ icon: "ph:broadcast",
52
+ value: m((g = r.value) == null ? void 0 : g.onlineSessions),
53
+ color: "var(--chart-4)"
55
54
  }
56
55
  ];
57
- }), C = v(() => {
58
- var t;
59
- return ((t = o.value) == null ? void 0 : t.trendDays) ?? [];
60
- }), D = v(() => {
61
- var t, a;
56
+ }), $ = i(() => {
57
+ var e;
58
+ return ((e = r.value) == null ? void 0 : e.trendDays) ?? [];
59
+ }), N = i(() => {
60
+ var e, l;
62
61
  return [
63
- { name: r("workbench.trendLogins"), data: ((t = o.value) == null ? void 0 : t.trendLogins) ?? [] },
64
- { name: r("workbench.trendActive"), data: ((a = o.value) == null ? void 0 : a.trendActiveUsers) ?? [] }
62
+ { name: s("workbench.trendLogins"), data: ((e = r.value) == null ? void 0 : e.trendLogins) ?? [] },
63
+ { name: s("workbench.trendActive"), data: ((l = r.value) == null ? void 0 : l.trendActiveUsers) ?? [] }
65
64
  ];
66
- }), G = v(() => {
67
- var t, a, c;
65
+ }), T = i(() => {
66
+ var e, l, a;
68
67
  return [
69
- { name: r("workbench.roles"), value: ((t = o.value) == null ? void 0 : t.roles) ?? 0 },
70
- { name: r("workbench.users"), value: ((a = o.value) == null ? void 0 : a.users) ?? 0 },
71
- { name: r("workbench.perms"), value: ((c = o.value) == null ? void 0 : c.perms) ?? 0 }
68
+ { name: s("workbench.roles"), value: ((e = r.value) == null ? void 0 : e.roles) ?? 0 },
69
+ { name: s("workbench.users"), value: ((l = r.value) == null ? void 0 : l.users) ?? 0 },
70
+ { name: s("workbench.perms"), value: ((a = r.value) == null ? void 0 : a.perms) ?? 0 }
72
71
  ];
73
- });
74
- return (t, a) => {
75
- var c;
76
- return s(), _("div", q, [
77
- n("div", H, [
78
- n("div", {
79
- class: "avatar",
80
- style: w(A.value)
81
- }, [
82
- l(e(x), {
83
- icon: "ph:user",
84
- width: 26,
85
- color: "#fff"
86
- })
87
- ], 4),
88
- n("div", null, [
89
- n("div", J, h(e(r)("workbench.welcome", { name: ((c = e(S).userInfo) == null ? void 0 : c.name) ?? "" })), 1),
90
- n("div", K, h(e(r)("workbench.subtitle")), 1)
91
- ])
92
- ]),
93
- l(e(g), {
94
- cols: "1 s:2 l:4",
95
- responsive: "screen",
96
- "x-gap": 16,
97
- "y-gap": 16
98
- }, {
99
- default: u(() => [
100
- (s(!0), _($, null, E(B.value, (i) => (s(), d(e(f), {
101
- key: i.key
102
- }, {
103
- default: u(() => [
104
- l(e(k), { bordered: !0 }, {
105
- default: u(() => [
106
- n("div", O, [
107
- n("div", {
108
- class: "stat-ico",
109
- style: w({ color: i.color })
110
- }, [
111
- l(e(x), {
112
- icon: i.icon,
113
- width: 28
114
- }, null, 8, ["icon"])
115
- ], 4),
116
- n("div", P, [
117
- m.value ? (s(), d(e(y), {
118
- key: 0,
119
- text: "",
120
- width: "72px",
121
- height: "34px"
122
- })) : (s(), _("div", Q, h(i.value), 1)),
123
- n("div", R, h(e(r)(`workbench.${i.key}`)), 1)
124
- ])
125
- ])
126
- ]),
127
- _: 2
128
- }, 1024)
72
+ }), w = _(null), { width: d } = z(w), A = i(() => d.value === 0 ? 4 : d.value < 520 ? 1 : d.value < 1e3 ? 2 : 4), B = i(() => d.value === 0 || d.value >= 1e3 ? 2 : 1);
73
+ return (e, l) => (n(), y("div", {
74
+ ref_key: "viewRef",
75
+ ref: w,
76
+ class: "view"
77
+ }, [
78
+ u(t(f), {
79
+ class: "a-card banner-card",
80
+ bordered: !0,
81
+ "content-style": "padding: 18px 20px"
82
+ }, {
83
+ default: p(() => {
84
+ var a;
85
+ return [
86
+ o("div", j, [
87
+ o("div", q, [
88
+ u(t(x), {
89
+ icon: "ph:user",
90
+ width: 26
91
+ })
129
92
  ]),
130
- _: 2
131
- }, 1024))), 128))
93
+ o("div", G, [
94
+ o("div", H, h(t(s)("workbench.welcome", { name: ((a = t(C).userInfo) == null ? void 0 : a.name) ?? "" })), 1),
95
+ o("div", J, h(t(s)("workbench.subtitle")), 1)
96
+ ])
97
+ ])
98
+ ];
99
+ }),
100
+ _: 1
101
+ }),
102
+ o("div", {
103
+ class: "grid",
104
+ style: k({ gridTemplateColumns: `repeat(${A.value}, minmax(0, 1fr))` })
105
+ }, [
106
+ (n(!0), y(I, null, L(S.value, (a) => (n(), c(t(f), {
107
+ key: a.key,
108
+ class: "a-card",
109
+ bordered: !0,
110
+ "content-style": "display: flex; align-items: center; gap: 16px; padding: 14px 16px"
111
+ }, {
112
+ default: p(() => [
113
+ o("div", {
114
+ class: "stat-ico",
115
+ style: k({ color: a.color })
116
+ }, [
117
+ u(t(x), {
118
+ icon: a.icon,
119
+ width: 28
120
+ }, null, 8, ["icon"])
121
+ ], 4),
122
+ o("div", K, [
123
+ v.value ? (n(), c(t(b), {
124
+ key: 0,
125
+ text: "",
126
+ width: "72px",
127
+ height: "34px"
128
+ })) : (n(), y("div", O, h(a.value), 1)),
129
+ o("div", P, h(t(s)(`workbench.${a.key}`)), 1)
130
+ ])
131
+ ]),
132
+ _: 2
133
+ }, 1024))), 128))
134
+ ], 4),
135
+ o("div", {
136
+ class: "grid",
137
+ style: k({ gridTemplateColumns: `repeat(${B.value}, minmax(0, 1fr))` })
138
+ }, [
139
+ u(t(f), {
140
+ class: "a-card",
141
+ title: t(s)("workbench.trendTitle"),
142
+ bordered: !0
143
+ }, {
144
+ default: p(() => [
145
+ v.value ? (n(), c(t(b), {
146
+ key: 0,
147
+ height: "320px",
148
+ sharp: !1
149
+ })) : (n(), c(F, {
150
+ key: 1,
151
+ categories: $.value,
152
+ series: N.value
153
+ }, null, 8, ["categories", "series"]))
132
154
  ]),
133
155
  _: 1
134
- }),
135
- l(e(g), {
136
- cols: "1 l:2",
137
- responsive: "screen",
138
- "x-gap": 16,
139
- "y-gap": 16
156
+ }, 8, ["title"]),
157
+ u(t(f), {
158
+ class: "a-card",
159
+ title: t(s)("workbench.distributionTitle"),
160
+ bordered: !0
140
161
  }, {
141
- default: u(() => [
142
- l(e(f), null, {
143
- default: u(() => [
144
- l(e(k), {
145
- title: e(r)("workbench.trendTitle"),
146
- bordered: !0
147
- }, {
148
- default: u(() => [
149
- m.value ? (s(), d(e(y), {
150
- key: 0,
151
- height: "320px",
152
- sharp: !1
153
- })) : (s(), d(M, {
154
- key: 1,
155
- categories: C.value,
156
- series: D.value
157
- }, null, 8, ["categories", "series"]))
158
- ]),
159
- _: 1
160
- }, 8, ["title"])
161
- ]),
162
- _: 1
163
- }),
164
- l(e(f), null, {
165
- default: u(() => [
166
- l(e(k), {
167
- title: e(r)("workbench.distributionTitle"),
168
- bordered: !0
169
- }, {
170
- default: u(() => [
171
- m.value ? (s(), d(e(y), {
172
- key: 0,
173
- height: "320px",
174
- sharp: !1
175
- })) : (s(), d(j, {
176
- key: 1,
177
- data: G.value
178
- }, null, 8, ["data"]))
179
- ]),
180
- _: 1
181
- }, 8, ["title"])
182
- ]),
183
- _: 1
184
- })
162
+ default: p(() => [
163
+ v.value ? (n(), c(t(b), {
164
+ key: 0,
165
+ height: "320px",
166
+ sharp: !1
167
+ })) : (n(), c(M, {
168
+ key: 1,
169
+ data: T.value
170
+ }, null, 8, ["data"]))
185
171
  ]),
186
172
  _: 1
187
- })
188
- ]);
189
- };
173
+ }, 8, ["title"])
174
+ ], 4)
175
+ ], 512));
190
176
  }
191
177
  });
192
178
  export {
193
- le as default
179
+ oe as default
194
180
  };
195
181
  //# sourceMappingURL=workbench2.vue.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"workbench2.vue.js","sources":["../../../src/views/dashboard/workbench.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, onMounted, ref } from 'vue'\nimport { NGrid, NGi, NCard, NSkeleton } from 'naive-ui'\nimport { Icon } from '@iconify/vue'\nimport { useI18n } from 'vue-i18n'\nimport { useUserStore } from '#/stores/user'\nimport { useAppStore } from '#/stores/app'\nimport { btnGrad } from '#/theme/mix'\nimport { dashboardApi } from '#/api'\nimport type { DashboardSummary } from '#/types/api'\nimport LineChart from '#/components/Chart/LineChart.vue'\nimport PieChart from '#/components/Chart/PieChart.vue'\n\nconst { t } = useI18n()\nconst user = useUserStore()\nconst app = useAppStore()\n\nconst avatarStyle = computed(() => ({ background: btnGrad(app.accent) }))\n\nconst summary = ref<DashboardSummary | null>(null)\nconst loading = ref(true)\n\nonMounted(async () => {\n try {\n summary.value = await dashboardApi.summary()\n } catch {\n // 首页不该因为一张统计图挂了就糊用户一脸红:统计取不到就显示 —,页面其余部分照常可用。\n } finally {\n loading.value = false\n }\n})\n\n/** 计数未到位时显示 —,而不是先闪个 0 再跳到真值。 */\nfunction num(v: number | undefined) {\n return v === undefined ? '—' : v\n}\n\nconst stats = computed(() => [\n {\n key: 'roles',\n icon: 'ph:shield-duotone',\n value: num(summary.value?.roles),\n color: 'var(--color-primary)',\n },\n {\n key: 'users',\n icon: 'ph:users-duotone',\n value: num(summary.value?.users),\n color: 'var(--color-success)',\n },\n {\n key: 'perms',\n icon: 'ph:key-duotone',\n value: num(summary.value?.perms),\n color: 'var(--color-warning)',\n },\n {\n key: 'online',\n icon: 'ph:broadcast-duotone',\n value: num(summary.value?.onlineSessions),\n color: 'var(--color-danger)',\n },\n])\n\nconst trendDays = computed(() => summary.value?.trendDays ?? [])\nconst trendSeries = computed(() => [\n { name: t('workbench.trendLogins'), data: summary.value?.trendLogins ?? [] },\n { name: t('workbench.trendActive'), data: summary.value?.trendActiveUsers ?? [] },\n])\n// 资源分布就是前三个计数,不必让后端再返一份\nconst distribution = computed(() => [\n { name: t('workbench.roles'), value: summary.value?.roles ?? 0 },\n { name: t('workbench.users'), value: summary.value?.users ?? 0 },\n { name: t('workbench.perms'), value: summary.value?.perms ?? 0 },\n])\n</script>\n\n<template>\n <div class=\"view\">\n <!-- 欢迎横幅(英雄区:btnGrad 头像)-->\n <div class=\"banner\">\n <div class=\"avatar\" :style=\"avatarStyle\">\n <Icon icon=\"ph:user\" :width=\"26\" color=\"#fff\" />\n </div>\n <div>\n <div class=\"hi\">{{ t('workbench.welcome', { name: user.userInfo?.name ?? '' }) }}</div>\n <div class=\"tip\">{{ t('workbench.subtitle') }}</div>\n </div>\n </div>\n\n <n-grid :cols=\"'1 s:2 l:4'\" responsive=\"screen\" :x-gap=\"16\" :y-gap=\"16\">\n <n-gi v-for=\"s in stats\" :key=\"s.key\">\n <n-card :bordered=\"true\">\n <div class=\"stat\">\n <div class=\"stat-ico\" :style=\"{ color: s.color }\">\n <Icon :icon=\"s.icon\" :width=\"28\" />\n </div>\n <div class=\"stat-body\">\n <!-- 骨架而非先闪 0 再跳真值:数字位宽固定,到数时不抖 -->\n <n-skeleton v-if=\"loading\" text width=\"72px\" height=\"34px\" />\n <div v-else class=\"stat-val tabular\">{{ s.value }}</div>\n <div class=\"stat-label\">{{ t(`workbench.${s.key}`) }}</div>\n </div>\n </div>\n </n-card>\n </n-gi>\n </n-grid>\n\n <n-grid :cols=\"'1 l:2'\" responsive=\"screen\" :x-gap=\"16\" :y-gap=\"16\">\n <n-gi>\n <n-card :title=\"t('workbench.trendTitle')\" :bordered=\"true\">\n <n-skeleton v-if=\"loading\" height=\"320px\" :sharp=\"false\" />\n <LineChart v-else :categories=\"trendDays\" :series=\"trendSeries\" />\n </n-card>\n </n-gi>\n <n-gi>\n <n-card :title=\"t('workbench.distributionTitle')\" :bordered=\"true\">\n <n-skeleton v-if=\"loading\" height=\"320px\" :sharp=\"false\" />\n <PieChart v-else :data=\"distribution\" />\n </n-card>\n </n-gi>\n </n-grid>\n </div>\n</template>\n\n<style scoped>\n.view {\n display: flex;\n flex-direction: column;\n gap: var(--gap-card);\n}\n.banner {\n display: flex;\n align-items: center;\n gap: 16px;\n padding: 24px;\n border-radius: var(--radius-lg);\n background: var(--color-primary-light);\n}\n.avatar {\n width: 52px;\n height: 52px;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.hi {\n font-size: var(--font-size-lg);\n font-weight: 600;\n color: var(--color-text-primary);\n}\n.tip {\n color: var(--color-text-secondary);\n margin-top: 4px;\n}\n.stat {\n display: flex;\n align-items: center;\n gap: 16px;\n}\n/* 骨架与真值换位时高度一致,卡片不跳 */\n.stat-body {\n min-width: 0;\n}\n/* 图标底盘:取当前语义色 12% 作浅底圆角,呼应 banner 头像,避免图标\"裸浮\" */\n.stat-ico {\n flex-shrink: 0;\n width: 48px;\n height: 48px;\n border-radius: var(--radius-md);\n display: flex;\n align-items: center;\n justify-content: center;\n background: color-mix(in srgb, currentColor 12%, transparent);\n}\n.stat-val {\n font-size: 28px;\n font-weight: 700;\n color: var(--color-text-primary);\n line-height: 1.1;\n}\n.stat-label {\n color: var(--color-text-secondary);\n margin-top: 2px;\n}\n</style>\n"],"names":["t","useI18n","user","useUserStore","app","useAppStore","avatarStyle","computed","btnGrad","summary","ref","loading","onMounted","dashboardApi","num","v","stats","_a","_b","_c","_d","trendDays","trendSeries","distribution","_openBlock","_createElementBlock","_hoisted_1","_createElementVNode","_hoisted_2","_createVNode","_unref","Icon","_hoisted_3","_toDisplayString","_hoisted_4","NGrid","_Fragment","_renderList","s","_createBlock","NGi","NCard","_hoisted_5","_normalizeStyle","_hoisted_6","NSkeleton","_hoisted_7","_hoisted_8","LineChart","PieChart"],"mappings":"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"}
1
+ {"version":3,"file":"workbench2.vue.js","sources":["../../../src/views/dashboard/workbench.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, onMounted, ref } from 'vue'\nimport { NCard, NSkeleton } from 'naive-ui'\nimport { useElementSize } from '@vueuse/core'\nimport { Icon } from '@iconify/vue'\nimport { useI18n } from 'vue-i18n'\nimport { useUserStore } from '#/stores/user'\nimport { dashboardApi } from '#/api'\nimport type { DashboardSummary } from '#/types/api'\nimport LineChart from '#/components/Chart/LineChart.vue'\nimport PieChart from '#/components/Chart/PieChart.vue'\n\nconst { t } = useI18n()\nconst user = useUserStore()\n\nconst summary = ref<DashboardSummary | null>(null)\nconst loading = ref(true)\n\nonMounted(async () => {\n try {\n summary.value = await dashboardApi.summary()\n } catch {\n // 首页不该因为一张统计图挂了就糊用户一脸红:统计取不到就显示 —,页面其余部分照常可用。\n } finally {\n loading.value = false\n }\n})\n\n/** 计数未到位时显示 —,而不是先闪个 0 再跳到真值。 */\nfunction num(v: number | undefined) {\n return v === undefined ? '—' : v\n}\n\nconst stats = computed(() => [\n {\n key: 'roles',\n icon: 'ph:shield',\n value: num(summary.value?.roles),\n color: 'var(--chart-1)',\n },\n {\n key: 'users',\n icon: 'ph:users',\n value: num(summary.value?.users),\n color: 'var(--chart-2)',\n },\n {\n key: 'perms',\n icon: 'ph:key',\n value: num(summary.value?.perms),\n color: 'var(--chart-3)',\n },\n {\n key: 'online',\n icon: 'ph:broadcast',\n value: num(summary.value?.onlineSessions),\n color: 'var(--chart-4)',\n },\n])\n\nconst trendDays = computed(() => summary.value?.trendDays ?? [])\nconst trendSeries = computed(() => [\n { name: t('workbench.trendLogins'), data: summary.value?.trendLogins ?? [] },\n { name: t('workbench.trendActive'), data: summary.value?.trendActiveUsers ?? [] },\n])\n// 资源分布就是前三个计数,不必让后端再返一份\nconst distribution = computed(() => [\n { name: t('workbench.roles'), value: summary.value?.roles ?? 0 },\n { name: t('workbench.users'), value: summary.value?.users ?? 0 },\n { name: t('workbench.perms'), value: summary.value?.perms ?? 0 },\n])\n\n// 栅格按内容区宽度分档(不是视口:侧栏展开 / 收起会改变可用宽度)。\n// 统计卡 <520 一列 / <1000 两列 / 否则四列;图表卡 <1000 一列 / 否则并排。宽度还没量到(0)时按宽档,免得首帧闪成单列。\nconst viewRef = ref<HTMLElement | null>(null)\nconst { width: pw } = useElementSize(viewRef)\nconst statCols = computed(() => (pw.value === 0 ? 4 : pw.value < 520 ? 1 : pw.value < 1000 ? 2 : 4))\nconst chartCols = computed(() => (pw.value === 0 || pw.value >= 1000 ? 2 : 1))\n</script>\n\n<template>\n <div ref=\"viewRef\" class=\"view\">\n <!-- 欢迎横幅:浅主题色底 + 渐变头像,不受接口失败影响 -->\n <n-card class=\"a-card banner-card\" :bordered=\"true\" content-style=\"padding: 18px 20px\">\n <div class=\"banner\">\n <div class=\"avatar\">\n <Icon icon=\"ph:user\" :width=\"26\" />\n </div>\n <div class=\"banner-body\">\n <div class=\"hi\">{{ t('workbench.welcome', { name: user.userInfo?.name ?? '' }) }}</div>\n <div class=\"tip\">{{ t('workbench.subtitle') }}</div>\n </div>\n </div>\n </n-card>\n\n <div class=\"grid\" :style=\"{ gridTemplateColumns: `repeat(${statCols}, minmax(0, 1fr))` }\">\n <n-card\n v-for=\"s in stats\"\n :key=\"s.key\"\n class=\"a-card\"\n :bordered=\"true\"\n content-style=\"display: flex; align-items: center; gap: 16px; padding: 14px 16px\"\n >\n <div class=\"stat-ico\" :style=\"{ color: s.color }\">\n <Icon :icon=\"s.icon\" :width=\"28\" />\n </div>\n <div class=\"stat-body\">\n <!-- 骨架而非先闪 0 再跳真值:数字位宽固定,到数时不抖 -->\n <n-skeleton v-if=\"loading\" text width=\"72px\" height=\"34px\" />\n <div v-else class=\"stat-val tabular\">{{ s.value }}</div>\n <div class=\"stat-label\">{{ t(`workbench.${s.key}`) }}</div>\n </div>\n </n-card>\n </div>\n\n <div class=\"grid\" :style=\"{ gridTemplateColumns: `repeat(${chartCols}, minmax(0, 1fr))` }\">\n <n-card class=\"a-card\" :title=\"t('workbench.trendTitle')\" :bordered=\"true\">\n <n-skeleton v-if=\"loading\" height=\"320px\" :sharp=\"false\" />\n <LineChart v-else :categories=\"trendDays\" :series=\"trendSeries\" />\n </n-card>\n <n-card class=\"a-card\" :title=\"t('workbench.distributionTitle')\" :bordered=\"true\">\n <n-skeleton v-if=\"loading\" height=\"320px\" :sharp=\"false\" />\n <PieChart v-else :data=\"distribution\" />\n </n-card>\n </div>\n </div>\n</template>\n\n<style scoped>\n.view {\n display: grid;\n grid-template-columns: minmax(0, 1fr);\n gap: var(--gap-card);\n align-content: start;\n}\n.grid {\n display: grid;\n gap: var(--gap-card);\n}\n/* 横幅卡底色取选中态令牌(主色 6% / 暗色 14%),与业务工作台同一套 */\n.banner-card {\n background-image: linear-gradient(var(--sel-bg), var(--sel-bg));\n}\n.banner {\n display: flex;\n align-items: center;\n gap: 16px;\n}\n.avatar {\n flex: none;\n width: 52px;\n height: 52px;\n border-radius: 50%;\n display: grid;\n place-items: center;\n color: var(--on-acc);\n background-image: linear-gradient(135deg, var(--signal), var(--login-accent-2));\n box-shadow: 0 8px 20px -8px var(--signal-glow);\n}\n.banner-body {\n min-width: 0;\n flex: 1;\n}\n.hi {\n font-size: 18px;\n font-weight: 600;\n letter-spacing: -0.02em;\n color: var(--text-1);\n}\n.tip {\n margin-top: 2px;\n font-size: 14px;\n color: var(--text-2);\n}\n/* 图标底盘:取当前语义色 12% 作浅底圆角 */\n.stat-ico {\n flex-shrink: 0;\n width: 48px;\n height: 48px;\n border-radius: var(--radius-lg);\n display: grid;\n place-items: center;\n background: color-mix(in srgb, currentColor 12%, transparent);\n}\n/* 骨架与真值换位时高度一致(34px),卡片不跳 */\n.stat-body {\n min-width: 0;\n}\n.stat-val {\n font-size: 28px;\n line-height: 34px;\n font-weight: 600;\n letter-spacing: -0.04em;\n color: var(--text-1);\n}\n.stat-label {\n font-size: 14px;\n color: var(--text-2);\n}\n</style>\n"],"names":["t","useI18n","user","useUserStore","summary","ref","loading","onMounted","dashboardApi","num","v","stats","computed","_a","_b","_c","_d","trendDays","trendSeries","distribution","viewRef","pw","useElementSize","statCols","chartCols","_createElementBlock","_createVNode","_unref","NCard","_createElementVNode","_hoisted_1","_hoisted_2","Icon","_hoisted_3","_hoisted_4","_toDisplayString","_hoisted_5","_Fragment","_renderList","s","_createBlock","_normalizeStyle","_hoisted_6","NSkeleton","_openBlock","_hoisted_7","_hoisted_8","LineChart","PieChart"],"mappings":"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"}
@@ -1,8 +1,8 @@
1
1
  import o from "./iframe2.vue.js";
2
2
  /* empty css */
3
3
  import r from "../../_virtual/_plugin-vue_export-helper.js";
4
- const c = /* @__PURE__ */ r(o, [["__scopeId", "data-v-dcc7858a"]]);
4
+ const m = /* @__PURE__ */ r(o, [["__scopeId", "data-v-f642de1e"]]);
5
5
  export {
6
- c as default
6
+ m as default
7
7
  };
8
8
  //# sourceMappingURL=iframe.vue.js.map
@@ -1,21 +1,28 @@
1
- import { defineComponent as t, openBlock as r, createElementBlock as o, unref as s, createCommentVNode as a } from "vue";
2
- import { useRoute as c } from "vue-router";
3
- const n = { class: "embed-wrap" }, m = ["src"], u = /* @__PURE__ */ t({
1
+ import { defineComponent as t, openBlock as o, createBlock as a, unref as e, withCtx as s, createElementBlock as c, createCommentVNode as n } from "vue";
2
+ import { useRoute as l } from "vue-router";
3
+ import { NCard as m } from "naive-ui";
4
+ const p = ["src"], k = /* @__PURE__ */ t({
4
5
  __name: "iframe",
5
- setup(l) {
6
- const e = c().meta.iframeSrc;
7
- return (i, p) => (r(), o("div", n, [
8
- s(e) ? (r(), o("iframe", {
9
- key: 0,
10
- src: s(e),
11
- class: "embed",
12
- referrerpolicy: "no-referrer",
13
- sandbox: "allow-same-origin allow-scripts allow-forms allow-popups"
14
- }, null, 8, m)) : a("", !0)
15
- ]));
6
+ setup(i) {
7
+ const r = l().meta.iframeSrc;
8
+ return (f, d) => (o(), a(e(m), {
9
+ class: "embed-wrap",
10
+ "content-style": "padding: 0"
11
+ }, {
12
+ default: s(() => [
13
+ e(r) ? (o(), c("iframe", {
14
+ key: 0,
15
+ src: e(r),
16
+ class: "embed",
17
+ referrerpolicy: "no-referrer",
18
+ sandbox: "allow-same-origin allow-scripts allow-forms allow-popups"
19
+ }, null, 8, p)) : n("", !0)
20
+ ]),
21
+ _: 1
22
+ }));
16
23
  }
17
24
  });
18
25
  export {
19
- u as default
26
+ k as default
20
27
  };
21
28
  //# sourceMappingURL=iframe2.vue.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"iframe2.vue.js","sources":["../../../src/views/embed/iframe.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// 内嵌外部页面:URL 由菜单约定放进 route.meta.iframeSrc(component 字段为 URL 时,见 useAuthMenu)。\n// 每个内嵌菜单经 namedPage 有独立组件身份、meta 恒定 → src 取一次快照即可,**不能**跟全局当前路由响应式:\n// 否则被 keep-alive 缓存的实例会在切到别的路由时把 src 重算成 undefined(卸载 iframe → 回访白重载)\n// 或另一内嵌页的 URL(后台悄悄加载对方站点)。setup 只跑一次,快照天然正确。\nimport { useRoute } from 'vue-router'\n\nconst src = useRoute().meta.iframeSrc as string | undefined\n</script>\n\n<template>\n <div class=\"embed-wrap\">\n <iframe\n v-if=\"src\"\n :src=\"src\"\n class=\"embed\"\n referrerpolicy=\"no-referrer\"\n sandbox=\"allow-same-origin allow-scripts allow-forms allow-popups\"\n />\n </div>\n</template>\n\n<style scoped>\n.embed-wrap {\n height: 100%;\n min-height: calc(100dvh - 160px);\n}\n.embed {\n display: block;\n width: 100%;\n height: 100%;\n min-height: calc(100dvh - 160px);\n border: 0;\n}\n</style>\n"],"names":["src","useRoute","_openBlock","_createElementBlock","_hoisted_1","_unref"],"mappings":";;;;;AAOA,UAAMA,IAAMC,IAAW,KAAK;sBAI1BC,EAAA,GAAAC,EAQM,OARNC,GAQM;AAAA,MANIC,EAAAL,CAAA,UADRG,EAME,UAAA;AAAA;QAJC,KAAKE,EAAAL,CAAA;AAAA,QACN,OAAM;AAAA,QACN,gBAAe;AAAA,QACf,SAAQ;AAAA,MAAA;;;;"}
1
+ {"version":3,"file":"iframe2.vue.js","sources":["../../../src/views/embed/iframe.vue"],"sourcesContent":["<script setup lang=\"ts\">\n// 内嵌外部页面:URL 由菜单约定放进 route.meta.iframeSrc(component 字段为 URL 时,见 useAuthMenu)。\n// 每个内嵌菜单经 namedPage 有独立组件身份、meta 恒定 → src 取一次快照即可,**不能**跟全局当前路由响应式:\n// 否则被 keep-alive 缓存的实例会在切到别的路由时把 src 重算成 undefined(卸载 iframe → 回访白重载)\n// 或另一内嵌页的 URL(后台悄悄加载对方站点)。setup 只跑一次,快照天然正确。\nimport { useRoute } from 'vue-router'\nimport { NCard } from 'naive-ui'\n\nconst src = useRoute().meta.iframeSrc as string | undefined\n</script>\n\n<template>\n <!-- 无边框 iframe 放进卡片:圆角由卡片裁出,内容区高度撑满 -->\n <n-card class=\"embed-wrap\" content-style=\"padding: 0\">\n <iframe\n v-if=\"src\"\n :src=\"src\"\n class=\"embed\"\n referrerpolicy=\"no-referrer\"\n sandbox=\"allow-same-origin allow-scripts allow-forms allow-popups\"\n />\n </n-card>\n</template>\n\n<style scoped>\n.embed-wrap {\n height: 100%;\n min-height: calc(100dvh - 160px);\n overflow: hidden;\n}\n.embed-wrap :deep(.n-card__content) {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: calc(100dvh - 160px);\n}\n.embed {\n display: block;\n flex: 1 1 0;\n width: 100%;\n min-height: calc(100dvh - 160px);\n border: 0;\n}\n</style>\n"],"names":["src","useRoute","_createBlock","_unref","NCard","_createElementBlock"],"mappings":";;;;;;AAQA,UAAMA,IAAMC,IAAW,KAAK;2BAK1BC,EAQSC,EAAAC,CAAA,GAAA;AAAA,MARD,OAAM;AAAA,MAAa,iBAAc;AAAA,IAAA;iBACvC,MAME;AAAA,QALMD,EAAAH,CAAA,UADRK,EAME,UAAA;AAAA;UAJC,KAAKF,EAAAH,CAAA;AAAA,UACN,OAAM;AAAA,UACN,gBAAe;AAAA,UACf,SAAQ;AAAA,QAAA;;;;;;"}
@@ -1,8 +1,8 @@
1
1
  import o from "./4042.vue.js";
2
2
  /* empty css */
3
3
  import t from "../../_virtual/_plugin-vue_export-helper.js";
4
- const p = /* @__PURE__ */ t(o, [["__scopeId", "data-v-6b886879"]]);
4
+ const f = /* @__PURE__ */ t(o, [["__scopeId", "data-v-67a3298f"]]);
5
5
  export {
6
- p as default
6
+ f as default
7
7
  };
8
8
  //# sourceMappingURL=404.vue.js.map