smart-admin-web 10.14.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.
Files changed (538) hide show
  1. package/README.md +6 -6
  2. package/dist/api/index.d.ts +41 -2
  3. package/dist/api/index.js +36 -15
  4. package/dist/api/index.js.map +1 -1
  5. package/dist/api/schema.d.ts +418 -6
  6. package/dist/assets/icons/ph-subset.json.js +7 -7
  7. package/dist/assets/smart-logo.svg.js +5 -0
  8. package/dist/assets/smart-logo.svg.js.map +1 -0
  9. package/dist/components/AppIcon.vue.js +9 -9
  10. package/dist/components/AppIcon.vue.js.map +1 -1
  11. package/dist/components/AppWatermark.vue.d.ts +14 -0
  12. package/dist/components/AppWatermark.vue.js +38 -0
  13. package/dist/components/AppWatermark.vue.js.map +1 -0
  14. package/dist/components/AppWatermark2.vue.js +5 -0
  15. package/dist/components/AppWatermark2.vue.js.map +1 -0
  16. package/dist/components/Chart/PieChart.vue.d.ts +1 -1
  17. package/dist/components/Chart/echarts.js +15 -20
  18. package/dist/components/Chart/echarts.js.map +1 -1
  19. package/dist/components/CronEditor/index.vue.js +1 -1
  20. package/dist/components/CronEditor/index2.vue.js +2 -1
  21. package/dist/components/CronEditor/index2.vue.js.map +1 -1
  22. package/dist/components/DetailPage/index.vue.js +2 -2
  23. package/dist/components/DetailPage/index2.vue.js.map +1 -1
  24. package/dist/components/DictTag/index.vue.js.map +1 -1
  25. package/dist/components/ErrorBoundary/index.vue.js +2 -2
  26. package/dist/components/ErrorBoundary/index2.vue.js +1 -1
  27. package/dist/components/ErrorBoundary/index2.vue.js.map +1 -1
  28. package/dist/components/FormContainer/index.vue.js +91 -56
  29. package/dist/components/FormContainer/index.vue.js.map +1 -1
  30. package/dist/components/ImportWizard/index.vue.js +1 -1
  31. package/dist/components/ImportWizard/index2.vue.js +44 -41
  32. package/dist/components/ImportWizard/index2.vue.js.map +1 -1
  33. package/dist/components/MenuSearch.vue.js +2 -2
  34. package/dist/components/MenuSearch2.vue.js +19 -18
  35. package/dist/components/MenuSearch2.vue.js.map +1 -1
  36. package/dist/components/PasswordStrength/index.vue.js +2 -2
  37. package/dist/components/PasswordStrength/index2.vue.js +20 -18
  38. package/dist/components/PasswordStrength/index2.vue.js.map +1 -1
  39. package/dist/components/SmartLogo.vue.d.ts +3 -0
  40. package/dist/components/SmartLogo.vue.js +1 -1
  41. package/dist/components/SmartLogo2.vue.js +22 -64
  42. package/dist/components/SmartLogo2.vue.js.map +1 -1
  43. package/dist/{views/system/config/components/GroupExtraConfig.vue.d.ts → components/TableTotal/index.vue.d.ts} +1 -4
  44. package/dist/components/{SelectTable → TableTotal}/index.vue.js +1 -1
  45. package/dist/components/TableTotal/index2.vue.js +16 -0
  46. package/dist/components/TableTotal/index2.vue.js.map +1 -0
  47. package/dist/components/TableZoomButton/index.vue.js.map +1 -1
  48. package/dist/components/UserPicker/index.vue.js +2 -2
  49. package/dist/components/UserPicker/index2.vue.js +176 -117
  50. package/dist/components/UserPicker/index2.vue.js.map +1 -1
  51. package/dist/composables/useBatchDelete.js.map +1 -1
  52. package/dist/composables/useLayoutMenu.js +17 -16
  53. package/dist/composables/useLayoutMenu.js.map +1 -1
  54. package/dist/composables/useLoginHero.d.ts +2 -0
  55. package/dist/composables/useLoginHero.js +22 -0
  56. package/dist/composables/useLoginHero.js.map +1 -0
  57. package/dist/composables/useModule.js +39 -29
  58. package/dist/composables/useModule.js.map +1 -1
  59. package/dist/composables/usePageTitle.js +16 -14
  60. package/dist/composables/usePageTitle.js.map +1 -1
  61. package/dist/composables/useShellBreakpoint.d.ts +19 -0
  62. package/dist/composables/useShellBreakpoint.js +37 -0
  63. package/dist/composables/useShellBreakpoint.js.map +1 -0
  64. package/dist/composables/useSite.d.ts +20 -0
  65. package/dist/composables/useSite.js +18 -13
  66. package/dist/composables/useSite.js.map +1 -1
  67. package/dist/composables/useTabTitle.js.map +1 -1
  68. package/dist/composables/useTableTitle.d.ts +6 -0
  69. package/dist/composables/useTableTitle.js +11 -0
  70. package/dist/composables/useTableTitle.js.map +1 -0
  71. package/dist/composables/useTableZoom.d.ts +5 -0
  72. package/dist/composables/useTableZoom.js.map +1 -1
  73. package/dist/composables/useTheme.d.ts +2 -2
  74. package/dist/composables/useTheme.js +23 -20
  75. package/dist/composables/useTheme.js.map +1 -1
  76. package/dist/createSmartAdmin.d.ts +12 -2
  77. package/dist/createSmartAdmin.js +72 -60
  78. package/dist/createSmartAdmin.js.map +1 -1
  79. package/dist/index.d.ts +5 -2
  80. package/dist/index.js +223 -208
  81. package/dist/index.js.map +1 -1
  82. package/dist/layouts/AccentPicker.vue.js +8 -0
  83. package/dist/layouts/AccentPicker.vue.js.map +1 -0
  84. package/dist/layouts/AccentPicker2.vue.js +131 -0
  85. package/dist/layouts/AccentPicker2.vue.js.map +1 -0
  86. package/dist/layouts/AppHeader.vue.d.ts +8 -1
  87. package/dist/layouts/AppHeader.vue.js +2 -2
  88. package/dist/layouts/AppHeader2.vue.js +317 -235
  89. package/dist/layouts/AppHeader2.vue.js.map +1 -1
  90. package/dist/layouts/NoticeBell.vue.js +2 -2
  91. package/dist/layouts/NoticeBell2.vue.js +1 -1
  92. package/dist/layouts/NoticeBell2.vue.js.map +1 -1
  93. package/dist/layouts/PersonalLayout.vue.js +2 -2
  94. package/dist/layouts/PersonalLayout2.vue.js +69 -47
  95. package/dist/layouts/PersonalLayout2.vue.js.map +1 -1
  96. package/dist/layouts/SettingsDrawer.vue.js +3 -3
  97. package/dist/layouts/SettingsDrawer2.vue.js +261 -325
  98. package/dist/layouts/SettingsDrawer2.vue.js.map +1 -1
  99. package/dist/layouts/TabsBar.vue.js +2 -2
  100. package/dist/layouts/TabsBar2.vue.js +97 -69
  101. package/dist/layouts/TabsBar2.vue.js.map +1 -1
  102. package/dist/layouts/components/SideNav.vue.d.ts +3 -0
  103. package/dist/layouts/components/SideNav.vue.js +1 -1
  104. package/dist/layouts/components/SideNav2.vue.js +54 -26
  105. package/dist/layouts/components/SideNav2.vue.js.map +1 -1
  106. package/dist/layouts/default.vue.js +1 -1
  107. package/dist/layouts/default2.vue.js +170 -140
  108. package/dist/layouts/default2.vue.js.map +1 -1
  109. package/dist/lib/favicon.d.ts +1 -0
  110. package/dist/lib/favicon.js +12 -0
  111. package/dist/lib/favicon.js.map +1 -0
  112. package/dist/lib/loginHero.d.ts +16 -0
  113. package/dist/lib/loginHero.js +33 -0
  114. package/dist/lib/loginHero.js.map +1 -0
  115. package/dist/lib/logoCrop.d.ts +25 -0
  116. package/dist/lib/logoCrop.js +22 -0
  117. package/dist/lib/logoCrop.js.map +1 -0
  118. package/dist/lib/runtime.d.ts +2 -0
  119. package/dist/lib/runtime.js +1 -1
  120. package/dist/lib/runtime.js.map +1 -1
  121. package/dist/lib/securityRules.d.ts +26 -0
  122. package/dist/lib/securityRules.js +86 -0
  123. package/dist/lib/securityRules.js.map +1 -0
  124. package/dist/lib/watermark.d.ts +110 -0
  125. package/dist/lib/watermark.js +151 -0
  126. package/dist/lib/watermark.js.map +1 -0
  127. package/dist/locales/en-US.d.ts +462 -42
  128. package/dist/locales/en-US.js +491 -78
  129. package/dist/locales/en-US.js.map +1 -1
  130. package/dist/locales/kernelMenuTitles.d.ts +1 -0
  131. package/dist/locales/kernelMenuTitles.js +128 -0
  132. package/dist/locales/kernelMenuTitles.js.map +1 -0
  133. package/dist/locales/menuTitle.d.ts +3 -0
  134. package/dist/locales/menuTitle.js +14 -12
  135. package/dist/locales/menuTitle.js.map +1 -1
  136. package/dist/locales/zh-CN.d.ts +462 -42
  137. package/dist/locales/zh-CN.js +490 -81
  138. package/dist/locales/zh-CN.js.map +1 -1
  139. package/dist/router/index.js +41 -32
  140. package/dist/router/index.js.map +1 -1
  141. package/dist/router/namedPage.d.ts +4 -0
  142. package/dist/router/namedPage.js +7 -7
  143. package/dist/router/namedPage.js.map +1 -1
  144. package/dist/router/viewRegistry.js +12 -12
  145. package/dist/router/viewRegistry.js.map +1 -1
  146. package/dist/stores/app.d.ts +0 -12
  147. package/dist/stores/app.js +11 -12
  148. package/dist/stores/app.js.map +1 -1
  149. package/dist/stores/tabs.js.map +1 -1
  150. package/dist/stores/user.d.ts +10 -0
  151. package/dist/stores/user.js.map +1 -1
  152. package/dist/style.css +1 -1
  153. package/dist/theme/accentTokens.d.ts +27 -0
  154. package/dist/theme/accentTokens.js +54 -0
  155. package/dist/theme/accentTokens.js.map +1 -0
  156. package/dist/theme/accents.d.ts +21 -1
  157. package/dist/theme/accents.js +11 -2
  158. package/dist/theme/accents.js.map +1 -1
  159. package/dist/theme/mix.d.ts +58 -7
  160. package/dist/theme/mix.js +115 -30
  161. package/dist/theme/mix.js.map +1 -1
  162. package/dist/theme/naive-theme.d.ts +5 -2
  163. package/dist/theme/naive-theme.js +405 -75
  164. package/dist/theme/naive-theme.js.map +1 -1
  165. package/dist/utils/jwt.d.ts +8 -0
  166. package/dist/utils/jwt.js +14 -0
  167. package/dist/utils/jwt.js.map +1 -0
  168. package/dist/utils/menuIcon.d.ts +2 -0
  169. package/dist/utils/menuIcon.js +8 -0
  170. package/dist/utils/menuIcon.js.map +1 -0
  171. package/dist/utils/oauthBrand.d.ts +34 -9
  172. package/dist/utils/oauthBrand.js +70 -74
  173. package/dist/utils/oauthBrand.js.map +1 -1
  174. package/dist/utils/tableFilter.d.ts +88 -0
  175. package/dist/utils/tableFilter.js +116 -0
  176. package/dist/utils/tableFilter.js.map +1 -0
  177. package/dist/utils/tableToolbar.d.ts +18 -0
  178. package/dist/utils/tableToolbar.js +11 -0
  179. package/dist/utils/tableToolbar.js.map +1 -0
  180. package/dist/utils/treeFilter.d.ts +20 -0
  181. package/dist/utils/treeFilter.js +24 -0
  182. package/dist/utils/treeFilter.js.map +1 -0
  183. package/dist/views/dashboard/ShortcutPicker.vue.js +1 -1
  184. package/dist/views/dashboard/ShortcutPicker2.vue.js +73 -48
  185. package/dist/views/dashboard/ShortcutPicker2.vue.js.map +1 -1
  186. package/dist/views/dashboard/biz.vue.js +1 -1
  187. package/dist/views/dashboard/biz2.vue.js +310 -257
  188. package/dist/views/dashboard/biz2.vue.js.map +1 -1
  189. package/dist/views/dashboard/workbench.vue.js +2 -2
  190. package/dist/views/dashboard/workbench2.vue.js +141 -155
  191. package/dist/views/dashboard/workbench2.vue.js.map +1 -1
  192. package/dist/views/embed/iframe.vue.js +2 -2
  193. package/dist/views/embed/iframe2.vue.js +22 -15
  194. package/dist/views/embed/iframe2.vue.js.map +1 -1
  195. package/dist/views/error/404.vue.js +2 -2
  196. package/dist/views/error/4042.vue.js +33 -24
  197. package/dist/views/error/4042.vue.js.map +1 -1
  198. package/dist/views/error/BootError.vue.js +1 -1
  199. package/dist/views/error/BootError2.vue.js +59 -48
  200. package/dist/views/error/BootError2.vue.js.map +1 -1
  201. package/dist/views/error/MissingRoute.vue.js +2 -2
  202. package/dist/views/error/MissingRoute2.vue.js +34 -15
  203. package/dist/views/error/MissingRoute2.vue.js.map +1 -1
  204. package/dist/views/login/LoginForm.vue.d.ts +7 -1
  205. package/dist/views/login/LoginForm.vue.js +2 -2
  206. package/dist/views/login/LoginForm2.vue.js +580 -488
  207. package/dist/views/login/LoginForm2.vue.js.map +1 -1
  208. package/dist/views/login/components/LoginDesk.vue.d.ts +36 -0
  209. package/dist/views/login/components/LoginDesk.vue.js +9 -0
  210. package/dist/views/login/components/LoginDesk.vue.js.map +1 -0
  211. package/dist/views/login/components/LoginDesk2.vue.js +100 -0
  212. package/dist/views/login/components/LoginDesk2.vue.js.map +1 -0
  213. package/dist/views/login/components/LoginHeroPanel.vue.d.ts +18 -0
  214. package/dist/views/login/components/LoginHeroPanel.vue.js +8 -0
  215. package/dist/views/login/components/LoginHeroPanel.vue.js.map +1 -0
  216. package/dist/views/login/components/LoginHeroPanel2.vue.js +61 -0
  217. package/dist/views/login/components/LoginHeroPanel2.vue.js.map +1 -0
  218. package/dist/views/login/index.vue.js +1 -1
  219. package/dist/views/login/index2.vue.js +141 -71
  220. package/dist/views/login/index2.vue.js.map +1 -1
  221. package/dist/views/login/layout.d.ts +11 -0
  222. package/dist/views/login/layout.js +27 -0
  223. package/dist/views/login/layout.js.map +1 -0
  224. package/dist/views/mfa/index.vue.js +2 -2
  225. package/dist/views/mfa/index2.vue.js +367 -321
  226. package/dist/views/mfa/index2.vue.js.map +1 -1
  227. package/dist/views/module/index.vue.js +2 -2
  228. package/dist/views/module/index2.vue.js +132 -99
  229. package/dist/views/module/index2.vue.js.map +1 -1
  230. package/dist/views/oauth/callback.vue.js +2 -2
  231. package/dist/views/oauth/callback2.vue.js +65 -51
  232. package/dist/views/oauth/callback2.vue.js.map +1 -1
  233. package/dist/views/personal/bindings.vue.js +2 -2
  234. package/dist/views/personal/bindings2.vue.js +98 -94
  235. package/dist/views/personal/bindings2.vue.js.map +1 -1
  236. package/dist/views/personal/notice2.vue.js +103 -76
  237. package/dist/views/personal/notice2.vue.js.map +1 -1
  238. package/dist/views/personal/password2.vue.js +47 -40
  239. package/dist/views/personal/password2.vue.js.map +1 -1
  240. package/dist/views/personal/profile.vue.js +3 -3
  241. package/dist/views/personal/profile2.vue.js +24 -18
  242. package/dist/views/personal/profile2.vue.js.map +1 -1
  243. package/dist/views/personal/security.vue.js +2 -2
  244. package/dist/views/personal/security2.vue.js +65 -53
  245. package/dist/views/personal/security2.vue.js.map +1 -1
  246. package/dist/views/personal/sessions.vue.js +2 -2
  247. package/dist/views/personal/sessions2.vue.js +67 -62
  248. package/dist/views/personal/sessions2.vue.js.map +1 -1
  249. package/dist/views/system/ai-model/components/ProviderCard.vue.js +2 -2
  250. package/dist/views/system/ai-model/components/ProviderCard2.vue.js +142 -130
  251. package/dist/views/system/ai-model/components/ProviderCard2.vue.js.map +1 -1
  252. package/dist/views/system/ai-model/components/ProviderForm.vue.js +2 -2
  253. package/dist/views/system/ai-model/components/ProviderForm2.vue.js +71 -70
  254. package/dist/views/system/ai-model/components/ProviderForm2.vue.js.map +1 -1
  255. package/dist/views/system/ai-model/index.vue.js +2 -2
  256. package/dist/views/system/ai-model/index2.vue.js +99 -99
  257. package/dist/views/system/ai-model/index2.vue.js.map +1 -1
  258. package/dist/views/system/ai-model/presets.d.ts +1 -1
  259. package/dist/views/system/ai-model/presets.js +18 -18
  260. package/dist/views/system/ai-model/presets.js.map +1 -1
  261. package/dist/views/system/ai-usage/index.vue.js +2 -2
  262. package/dist/views/system/ai-usage/index2.vue.js +356 -258
  263. package/dist/views/system/ai-usage/index2.vue.js.map +1 -1
  264. package/dist/views/system/api-docs/index.vue.js +5 -2
  265. package/dist/views/system/api-docs/index.vue.js.map +1 -1
  266. package/dist/views/system/api-docs/index2.vue.js +92 -42
  267. package/dist/views/system/api-docs/index2.vue.js.map +1 -1
  268. package/dist/views/system/cache/index.vue.js +2 -2
  269. package/dist/views/system/cache/index2.vue.js +74 -80
  270. package/dist/views/system/cache/index2.vue.js.map +1 -1
  271. package/dist/views/system/config/components/AdminMock.vue.js +8 -0
  272. package/dist/views/system/config/components/AdminMock.vue.js.map +1 -0
  273. package/dist/views/system/config/components/AdminMock2.vue.js +93 -0
  274. package/dist/views/system/config/components/AdminMock2.vue.js.map +1 -0
  275. package/dist/views/system/config/components/AdvancedSection.vue.js +8 -0
  276. package/dist/views/system/config/components/AdvancedSection.vue.js.map +1 -0
  277. package/dist/views/system/config/components/AdvancedSection2.vue.js +163 -0
  278. package/dist/views/system/config/components/AdvancedSection2.vue.js.map +1 -0
  279. package/dist/views/system/config/components/BrandSection.vue.d.ts +7 -0
  280. package/dist/views/system/config/components/BrandSection.vue.js +8 -0
  281. package/dist/views/system/config/components/BrandSection.vue.js.map +1 -0
  282. package/dist/views/system/config/components/BrandSection2.vue.js +266 -0
  283. package/dist/views/system/config/components/BrandSection2.vue.js.map +1 -0
  284. package/dist/views/system/config/components/CfgGroup.vue.d.ts +18 -0
  285. package/dist/views/system/config/components/CfgGroup.vue.js +8 -0
  286. package/dist/views/system/config/components/CfgGroup.vue.js.map +1 -0
  287. package/dist/views/system/config/components/CfgGroup2.vue.js +22 -0
  288. package/dist/views/system/config/components/CfgGroup2.vue.js.map +1 -0
  289. package/dist/views/system/config/components/CfgRow.vue.d.ts +26 -0
  290. package/dist/views/system/config/components/CfgRow.vue.js +9 -0
  291. package/dist/views/system/config/components/CfgRow.vue.js.map +1 -0
  292. package/dist/views/system/config/components/CfgRow2.vue.js +54 -0
  293. package/dist/views/system/config/components/CfgRow2.vue.js.map +1 -0
  294. package/dist/views/system/config/components/CfgSegment.vue.d.ts +28 -0
  295. package/dist/views/system/config/components/CfgSegment.vue.js +8 -0
  296. package/dist/views/system/config/components/CfgSegment.vue.js.map +1 -0
  297. package/dist/views/system/config/components/CfgSegment2.vue.js +45 -0
  298. package/dist/views/system/config/components/CfgSegment2.vue.js.map +1 -0
  299. package/dist/views/system/config/components/ConfigFormModal.vue.js +4 -1
  300. package/dist/views/system/config/components/ConfigFormModal.vue.js.map +1 -1
  301. package/dist/views/system/config/components/ConfigFormModal2.vue.js +72 -60
  302. package/dist/views/system/config/components/ConfigFormModal2.vue.js.map +1 -1
  303. package/dist/views/system/config/components/JobSection.vue.js +8 -0
  304. package/dist/views/system/config/components/JobSection.vue.js.map +1 -0
  305. package/dist/views/system/config/components/JobSection2.vue.js +140 -0
  306. package/dist/views/system/config/components/JobSection2.vue.js.map +1 -0
  307. package/dist/views/system/config/components/LoginMock.vue.d.ts +8 -0
  308. package/dist/views/system/config/components/LoginMock.vue.js +8 -0
  309. package/dist/views/system/config/components/LoginMock.vue.js.map +1 -0
  310. package/dist/views/system/config/components/LoginMock2.vue.js +132 -0
  311. package/dist/views/system/config/components/LoginMock2.vue.js.map +1 -0
  312. package/dist/views/system/config/components/LogoCropper.vue.d.ts +10 -0
  313. package/dist/views/system/config/components/LogoCropper.vue.js +8 -0
  314. package/dist/views/system/config/components/LogoCropper.vue.js.map +1 -0
  315. package/dist/views/system/config/components/LogoCropper2.vue.js +122 -0
  316. package/dist/views/system/config/components/LogoCropper2.vue.js.map +1 -0
  317. package/dist/views/system/config/components/LogoEditor.vue.js +8 -0
  318. package/dist/views/system/config/components/LogoEditor.vue.js.map +1 -0
  319. package/dist/views/system/config/components/LogoEditor2.vue.js +161 -0
  320. package/dist/views/system/config/components/LogoEditor2.vue.js.map +1 -0
  321. package/dist/views/system/config/components/ProviderSheet.vue.d.ts +17 -0
  322. package/dist/views/system/config/components/ProviderSheet.vue.js +8 -0
  323. package/dist/views/system/config/components/ProviderSheet.vue.js.map +1 -0
  324. package/dist/views/system/config/components/ProviderSheet2.vue.js +343 -0
  325. package/dist/views/system/config/components/ProviderSheet2.vue.js.map +1 -0
  326. package/dist/{layouts/SettingRow.vue.d.ts → views/system/config/components/ScaleToFit.vue.d.ts} +2 -1
  327. package/dist/views/system/config/components/ScaleToFit.vue.js +8 -0
  328. package/dist/views/system/config/components/ScaleToFit.vue.js.map +1 -0
  329. package/dist/views/system/config/components/ScaleToFit2.vue.js +41 -0
  330. package/dist/views/system/config/components/ScaleToFit2.vue.js.map +1 -0
  331. package/dist/views/system/config/components/SectionLayout.vue.d.ts +30 -0
  332. package/dist/views/system/config/components/SectionLayout.vue.js +8 -0
  333. package/dist/views/system/config/components/SectionLayout.vue.js.map +1 -0
  334. package/dist/views/system/config/components/SectionLayout2.vue.js +69 -0
  335. package/dist/views/system/config/components/SectionLayout2.vue.js.map +1 -0
  336. package/dist/views/system/config/components/SecuritySection.vue.js +8 -0
  337. package/dist/views/system/config/components/SecuritySection.vue.js.map +1 -0
  338. package/dist/views/system/config/components/SecuritySection2.vue.js +417 -0
  339. package/dist/views/system/config/components/SecuritySection2.vue.js.map +1 -0
  340. package/dist/views/system/config/components/SensitiveSection.vue.js +8 -0
  341. package/dist/views/system/config/components/SensitiveSection.vue.js.map +1 -0
  342. package/dist/views/system/config/components/SensitiveSection2.vue.js +214 -0
  343. package/dist/views/system/config/components/SensitiveSection2.vue.js.map +1 -0
  344. package/dist/views/system/config/components/SigninSection.vue.js +8 -0
  345. package/dist/views/system/config/components/SigninSection.vue.js.map +1 -0
  346. package/dist/views/system/config/components/SigninSection2.vue.js +201 -0
  347. package/dist/views/system/config/components/SigninSection2.vue.js.map +1 -0
  348. package/dist/views/system/config/components/UploadSection.vue.js +8 -0
  349. package/dist/views/system/config/components/UploadSection.vue.js.map +1 -0
  350. package/dist/views/system/config/components/UploadSection2.vue.js +176 -0
  351. package/dist/views/system/config/components/UploadSection2.vue.js.map +1 -0
  352. package/dist/views/system/config/components/WatermarkSection.vue.js +8 -0
  353. package/dist/views/system/config/components/WatermarkSection.vue.js.map +1 -0
  354. package/dist/views/system/config/components/WatermarkSection2.vue.js +284 -0
  355. package/dist/views/system/config/components/WatermarkSection2.vue.js.map +1 -0
  356. package/dist/views/system/config/draft.d.ts +148 -0
  357. package/dist/views/system/config/draft.js +170 -0
  358. package/dist/views/system/config/draft.js.map +1 -0
  359. package/dist/views/system/config/flash.d.ts +2 -0
  360. package/dist/views/system/config/flash.js +9 -0
  361. package/dist/views/system/config/flash.js.map +1 -0
  362. package/dist/views/system/config/groups.d.ts +38 -7
  363. package/dist/views/system/config/groups.js +104 -14
  364. package/dist/views/system/config/groups.js.map +1 -1
  365. package/dist/views/system/config/index.vue.js +6 -2
  366. package/dist/views/system/config/index.vue.js.map +1 -1
  367. package/dist/views/system/config/index2.vue.js +201 -111
  368. package/dist/views/system/config/index2.vue.js.map +1 -1
  369. package/dist/views/system/config/layoutMode.d.ts +23 -0
  370. package/dist/views/system/config/layoutMode.js +28 -0
  371. package/dist/views/system/config/layoutMode.js.map +1 -0
  372. package/dist/views/system/config/providerForm.d.ts +33 -0
  373. package/dist/views/system/config/providerForm.js +63 -0
  374. package/dist/views/system/config/providerForm.js.map +1 -0
  375. package/dist/views/system/dict/index.vue.js +2 -2
  376. package/dist/views/system/dict/index2.vue.js +471 -366
  377. package/dist/views/system/dict/index2.vue.js.map +1 -1
  378. package/dist/views/system/file/index2.vue.js +91 -76
  379. package/dist/views/system/file/index2.vue.js.map +1 -1
  380. package/dist/views/system/job/index.vue.js +3 -3
  381. package/dist/views/system/job/index2.vue.js +897 -828
  382. package/dist/views/system/job/index2.vue.js.map +1 -1
  383. package/dist/views/system/job-log/components/AttemptTable.vue.d.ts +8 -0
  384. package/dist/views/system/job-log/components/AttemptTable.vue.js +5 -0
  385. package/dist/views/system/job-log/components/AttemptTable.vue.js.map +1 -0
  386. package/dist/views/system/job-log/components/AttemptTable2.vue.js +54 -0
  387. package/dist/views/system/job-log/components/AttemptTable2.vue.js.map +1 -0
  388. package/dist/views/system/job-log/index.vue.js +2 -2
  389. package/dist/views/system/job-log/index2.vue.js +193 -207
  390. package/dist/views/system/job-log/index2.vue.js.map +1 -1
  391. package/dist/views/system/job-log/runStatus.d.ts +13 -0
  392. package/dist/views/system/job-log/runStatus.js +26 -0
  393. package/dist/views/system/job-log/runStatus.js.map +1 -0
  394. package/dist/views/system/job-monitor/index.vue.js +2 -2
  395. package/dist/views/system/job-monitor/index2.vue.js +172 -180
  396. package/dist/views/system/job-monitor/index2.vue.js.map +1 -1
  397. package/dist/views/system/log/exception/index.vue.js +2 -2
  398. package/dist/views/system/log/exception/index2.vue.js +135 -96
  399. package/dist/views/system/log/exception/index2.vue.js.map +1 -1
  400. package/dist/views/system/log/login/index2.vue.js +62 -41
  401. package/dist/views/system/log/login/index2.vue.js.map +1 -1
  402. package/dist/views/system/log/op/index.vue.js +2 -2
  403. package/dist/views/system/log/op/index2.vue.js +200 -162
  404. package/dist/views/system/log/op/index2.vue.js.map +1 -1
  405. package/dist/views/system/menu/components/ButtonManager.vue.js +2 -2
  406. package/dist/views/system/menu/components/ButtonManager2.vue.js +206 -190
  407. package/dist/views/system/menu/components/ButtonManager2.vue.js.map +1 -1
  408. package/dist/views/system/menu/components/MenuFormModal.vue.js +2 -2
  409. package/dist/views/system/menu/components/MenuFormModal2.vue.js +127 -118
  410. package/dist/views/system/menu/components/MenuFormModal2.vue.js.map +1 -1
  411. package/dist/views/system/menu/index.vue.js +1 -1
  412. package/dist/views/system/menu/index2.vue.js +216 -183
  413. package/dist/views/system/menu/index2.vue.js.map +1 -1
  414. package/dist/views/system/module/index.vue.js +1 -1
  415. package/dist/views/system/module/index2.vue.js +177 -144
  416. package/dist/views/system/module/index2.vue.js.map +1 -1
  417. package/dist/views/system/monitor/index.vue.js +2 -2
  418. package/dist/views/system/monitor/index2.vue.js +134 -149
  419. package/dist/views/system/monitor/index2.vue.js.map +1 -1
  420. package/dist/views/system/notice/index.vue.js +1 -1
  421. package/dist/views/system/notice/index2.vue.js +209 -181
  422. package/dist/views/system/notice/index2.vue.js.map +1 -1
  423. package/dist/views/system/org/index.vue.js +1 -1
  424. package/dist/views/system/org/index2.vue.js +278 -248
  425. package/dist/views/system/org/index2.vue.js.map +1 -1
  426. package/dist/views/system/position/index.vue.js +5 -2
  427. package/dist/views/system/position/index.vue.js.map +1 -1
  428. package/dist/views/system/position/index2.vue.js +128 -92
  429. package/dist/views/system/position/index2.vue.js.map +1 -1
  430. package/dist/views/system/recycle/index.vue.js +2 -2
  431. package/dist/views/system/recycle/index2.vue.js +90 -67
  432. package/dist/views/system/recycle/index2.vue.js.map +1 -1
  433. package/dist/views/system/role/components/GrantMenuSheet.vue.d.ts +20 -0
  434. package/dist/views/system/role/components/GrantMenuSheet.vue.js +8 -0
  435. package/dist/views/system/role/components/GrantMenuSheet.vue.js.map +1 -0
  436. package/dist/views/system/role/components/GrantMenuSheet2.vue.js +117 -0
  437. package/dist/views/system/role/components/GrantMenuSheet2.vue.js.map +1 -0
  438. package/dist/views/system/role/components/GrantMenuTable.vue.d.ts +6 -4
  439. package/dist/views/system/role/components/GrantMenuTable.vue.js +2 -2
  440. package/dist/views/system/role/components/GrantMenuTable2.vue.js +279 -177
  441. package/dist/views/system/role/components/GrantMenuTable2.vue.js.map +1 -1
  442. package/dist/views/system/role/components/MatchText.vue.d.ts +7 -0
  443. package/dist/views/system/role/components/MatchText.vue.js +8 -0
  444. package/dist/views/system/role/components/MatchText.vue.js.map +1 -0
  445. package/dist/views/system/role/components/MatchText2.vue.js +29 -0
  446. package/dist/views/system/role/components/MatchText2.vue.js.map +1 -0
  447. package/dist/views/system/role/components/grantMenuGroups.d.ts +36 -0
  448. package/dist/views/system/role/components/grantMenuGroups.js +110 -48
  449. package/dist/views/system/role/components/grantMenuGroups.js.map +1 -1
  450. package/dist/views/system/role/index.vue.js +5 -2
  451. package/dist/views/system/role/index.vue.js.map +1 -1
  452. package/dist/views/system/role/index2.vue.js +181 -165
  453. package/dist/views/system/role/index2.vue.js.map +1 -1
  454. package/dist/views/system/session/index2.vue.js +75 -49
  455. package/dist/views/system/session/index2.vue.js.map +1 -1
  456. package/dist/views/system/user/components/ResetPasswordModal.vue.js +2 -2
  457. package/dist/views/system/user/components/ResetPasswordModal2.vue.js +2 -0
  458. package/dist/views/system/user/components/ResetPasswordModal2.vue.js.map +1 -1
  459. package/dist/views/system/user/components/UserFormModal.vue.js +2 -2
  460. package/dist/views/system/user/components/UserFormModal2.vue.js +77 -76
  461. package/dist/views/system/user/components/UserFormModal2.vue.js.map +1 -1
  462. package/dist/views/system/user/index.vue.js +2 -2
  463. package/dist/views/system/user/index2.vue.js +362 -275
  464. package/dist/views/system/user/index2.vue.js.map +1 -1
  465. package/package.json +6 -8
  466. package/dist/components/SelectTable/index.vue.d.ts +0 -76
  467. package/dist/components/SelectTable/index2.vue.js +0 -256
  468. package/dist/components/SelectTable/index2.vue.js.map +0 -1
  469. package/dist/composables/useTableRowSort.d.ts +0 -20
  470. package/dist/composables/useTableRowSort.js +0 -59
  471. package/dist/composables/useTableRowSort.js.map +0 -1
  472. package/dist/layouts/LayoutModeCards.vue.js +0 -8
  473. package/dist/layouts/LayoutModeCards.vue.js.map +0 -1
  474. package/dist/layouts/LayoutModeCards2.vue.js +0 -67
  475. package/dist/layouts/LayoutModeCards2.vue.js.map +0 -1
  476. package/dist/layouts/SettingRow.vue.js +0 -8
  477. package/dist/layouts/SettingRow.vue.js.map +0 -1
  478. package/dist/layouts/SettingRow2.vue.js +0 -23
  479. package/dist/layouts/SettingRow2.vue.js.map +0 -1
  480. package/dist/views/login/skins/AuroraGlass.vue.js +0 -8
  481. package/dist/views/login/skins/AuroraGlass.vue.js.map +0 -1
  482. package/dist/views/login/skins/AuroraGlass2.vue.js +0 -80
  483. package/dist/views/login/skins/AuroraGlass2.vue.js.map +0 -1
  484. package/dist/views/login/skins/SplitPanel.vue.js +0 -8
  485. package/dist/views/login/skins/SplitPanel.vue.js.map +0 -1
  486. package/dist/views/login/skins/SplitPanel2.vue.js +0 -85
  487. package/dist/views/login/skins/SplitPanel2.vue.js.map +0 -1
  488. package/dist/views/login/skins/Spotlight.vue.js +0 -8
  489. package/dist/views/login/skins/Spotlight.vue.js.map +0 -1
  490. package/dist/views/login/skins/Spotlight2.vue.js +0 -36
  491. package/dist/views/login/skins/Spotlight2.vue.js.map +0 -1
  492. package/dist/views/login/skins.d.ts +0 -8
  493. package/dist/views/login/skins.js +0 -13
  494. package/dist/views/login/skins.js.map +0 -1
  495. package/dist/views/system/config/components/ExternalAuthConfig.vue.js +0 -8
  496. package/dist/views/system/config/components/ExternalAuthConfig.vue.js.map +0 -1
  497. package/dist/views/system/config/components/ExternalAuthConfig2.vue.js +0 -218
  498. package/dist/views/system/config/components/ExternalAuthConfig2.vue.js.map +0 -1
  499. package/dist/views/system/config/components/GroupExtraConfig.vue.js +0 -8
  500. package/dist/views/system/config/components/GroupExtraConfig.vue.js.map +0 -1
  501. package/dist/views/system/config/components/GroupExtraConfig2.vue.js +0 -108
  502. package/dist/views/system/config/components/GroupExtraConfig2.vue.js.map +0 -1
  503. package/dist/views/system/config/components/HighSensConfig.vue.js +0 -5
  504. package/dist/views/system/config/components/HighSensConfig.vue.js.map +0 -1
  505. package/dist/views/system/config/components/HighSensConfig2.vue.js +0 -134
  506. package/dist/views/system/config/components/HighSensConfig2.vue.js.map +0 -1
  507. package/dist/views/system/config/components/JobConfig.vue.js +0 -5
  508. package/dist/views/system/config/components/JobConfig.vue.js.map +0 -1
  509. package/dist/views/system/config/components/JobConfig2.vue.js +0 -116
  510. package/dist/views/system/config/components/JobConfig2.vue.js.map +0 -1
  511. package/dist/views/system/config/components/OtherConfig.vue.js +0 -5
  512. package/dist/views/system/config/components/OtherConfig.vue.js.map +0 -1
  513. package/dist/views/system/config/components/OtherConfig2.vue.js +0 -121
  514. package/dist/views/system/config/components/OtherConfig2.vue.js.map +0 -1
  515. package/dist/views/system/config/components/SecurityConfig.vue.js +0 -8
  516. package/dist/views/system/config/components/SecurityConfig.vue.js.map +0 -1
  517. package/dist/views/system/config/components/SecurityConfig2.vue.js +0 -456
  518. package/dist/views/system/config/components/SecurityConfig2.vue.js.map +0 -1
  519. package/dist/views/system/config/components/SysBaseConfig.vue.js +0 -5
  520. package/dist/views/system/config/components/SysBaseConfig.vue.js.map +0 -1
  521. package/dist/views/system/config/components/SysBaseConfig2.vue.js +0 -107
  522. package/dist/views/system/config/components/SysBaseConfig2.vue.js.map +0 -1
  523. package/dist/views/system/config/components/UploadConfig.vue.d.ts +0 -3
  524. package/dist/views/system/config/components/UploadConfig.vue.js +0 -5
  525. package/dist/views/system/config/components/UploadConfig.vue.js.map +0 -1
  526. package/dist/views/system/config/components/UploadConfig2.vue.js +0 -135
  527. package/dist/views/system/config/components/UploadConfig2.vue.js.map +0 -1
  528. /package/dist/components/{SelectTable → TableTotal}/index.vue.js.map +0 -0
  529. /package/dist/layouts/{LayoutModeCards.vue.d.ts → AccentPicker.vue.d.ts} +0 -0
  530. /package/dist/views/{login/skins/AuroraGlass.vue.d.ts → system/config/components/AdminMock.vue.d.ts} +0 -0
  531. /package/dist/views/{login/skins/SplitPanel.vue.d.ts → system/config/components/AdvancedSection.vue.d.ts} +0 -0
  532. /package/dist/views/{login/skins/Spotlight.vue.d.ts → system/config/components/JobSection.vue.d.ts} +0 -0
  533. /package/dist/views/system/config/components/{ExternalAuthConfig.vue.d.ts → LogoEditor.vue.d.ts} +0 -0
  534. /package/dist/views/system/config/components/{HighSensConfig.vue.d.ts → SecuritySection.vue.d.ts} +0 -0
  535. /package/dist/views/system/config/components/{JobConfig.vue.d.ts → SensitiveSection.vue.d.ts} +0 -0
  536. /package/dist/views/system/config/components/{OtherConfig.vue.d.ts → SigninSection.vue.d.ts} +0 -0
  537. /package/dist/views/system/config/components/{SecurityConfig.vue.d.ts → UploadSection.vue.d.ts} +0 -0
  538. /package/dist/views/system/config/components/{SysBaseConfig.vue.d.ts → WatermarkSection.vue.d.ts} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"index2.vue.js","sources":["../../../src/components/UserPicker/index.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, h, onMounted, reactive, ref, unref } from 'vue'\nimport { NButton, NEmpty, NInput, NTree, useMessage } from 'naive-ui'\nimport { SmartTable, type SmartTableColumn, type SmartTableInst } from 'smart-naive-table'\nimport { useI18n } from 'vue-i18n'\nimport AppIcon from '#/components/AppIcon.vue'\nimport FormContainer from '#/components/FormContainer/index.vue'\nimport { orgApi, userApi } from '#/api'\nimport { buildTree } from '#/utils/tree'\nimport { translateError } from '#/utils/error'\nimport type { SysOrg, UserItem } from '#/types/api'\n\nconst props = defineProps<{ excludeIds?: number[] }>()\nconst emit = defineEmits<{ (e: 'confirm', ids: number[]): void }>()\n\nconst { t } = useI18n()\nconst message = useMessage()\n\nconst show = ref(false)\nconst tableRef = ref<SmartTableInst<UserItem>>()\n\n// ── 机构树(左面板) ──\nconst orgFlat = ref<SysOrg[]>([])\nconst orgTree = computed(() => {\n const all = { id: 0, parentId: -1, name: t('common.all'), children: buildTree(orgFlat.value) }\n return [all]\n})\nconst selectedOrgKey = ref<number | null>(null)\nconst orgId = computed(() =>\n selectedOrgKey.value && selectedOrgKey.value !== 0 ? selectedOrgKey.value : undefined,\n)\n\nonMounted(async () => {\n try {\n orgFlat.value = await orgApi.list()\n } catch {\n /* 静默 */\n }\n})\n\nfunction onOrgSelect(keys: Array<string | number>) {\n selectedOrgKey.value = (keys[0] as number) ?? null\n tableRef.value?.refresh()\n}\n\n// ── 可选用户表(中间面板) ──\nconst checkedKeys = ref<(string | number)[]>([])\nconst excludeSet = computed(() => new Set(props.excludeIds ?? []))\n\nconst fetcher = (params: { page: number; pageSize: number; name?: string }) =>\n userApi.page({\n page: params.page,\n pageSize: params.pageSize,\n name: params.name,\n orgId: orgId.value,\n })\n\nconst columns: SmartTableColumn<UserItem>[] = [\n { type: 'selection' },\n { key: 'name', title: () => t('user.name'), width: 100 },\n { key: 'account', title: () => t('user.account'), width: 120, search: true },\n {\n key: 'op',\n title: () => t('common.operation'),\n width: 70,\n render: r => {\n const already = selectedSet.value.has(r.id) || excludeSet.value.has(r.id)\n return h(\n NButton,\n {\n size: 'tiny',\n type: 'primary',\n quaternary: true,\n disabled: already,\n onClick: () => addUsers([r]),\n },\n () => (already ? t('userPicker.added') : t('userPicker.add')),\n )\n },\n },\n]\n\n// ── 已选用户(右面板) ──\nconst selected = reactive<UserItem[]>([])\nconst selectedSet = computed(() => new Set(selected.map(u => u.id)))\nconst selectedSearch = ref('')\nconst filteredSelected = computed(() => {\n const q = selectedSearch.value.trim().toLowerCase()\n if (!q) return selected\n return selected.filter(\n u => u.name.toLowerCase().includes(q) || u.account.toLowerCase().includes(q),\n )\n})\n\nfunction addUsers(users: UserItem[]) {\n for (const u of users) {\n if (!selectedSet.value.has(u.id) && !excludeSet.value.has(u.id)) {\n selected.push(u)\n }\n }\n}\n\nfunction addChecked() {\n // SmartTable 只 expose rows,别改用未公开的 tableData —— 恒为 undefined。\n // unref 兼容类型声明的 Ref 与运行时 expose 解包两种形态。\n const rows = (unref(tableRef.value?.rows) ?? []).filter(r => checkedKeys.value.includes(r.id))\n addUsers(rows)\n checkedKeys.value = []\n}\n\nfunction removeUser(id: number) {\n const idx = selected.findIndex(u => u.id === id)\n if (idx >= 0) selected.splice(idx, 1)\n}\n\nfunction clearSelected() {\n selected.splice(0, selected.length)\n}\n\n// ── 公共 API ──\nasync function open(ids?: number[]) {\n selected.splice(0, selected.length)\n checkedKeys.value = []\n selectedSearch.value = ''\n selectedOrgKey.value = null\n show.value = true\n\n if (ids?.length) {\n try {\n // ponytail: 拉一页,靠 id 过滤。200 是内核 Api:MaxPageSize 的默认上限,再大后端直接回 48001。\n // 用户超过 200 个时,排在后面的 id 解析不出名字,走下面那条退回显示 id 的分支;\n // 真要支持更大规模的用户名单,再改成分页搜索。\n const { items } = await userApi.page({ page: 1, pageSize: 200 })\n const all = items.filter(u => ids.includes(u.id))\n // 没拉到的 id(翻页之外),退回只显示 id\n const found = new Set(all.map(u => u.id))\n for (const u of all) selected.push(u)\n for (const id of ids) {\n if (!found.has(id)) selected.push({ id, account: String(id), name: String(id) } as UserItem)\n }\n } catch {\n for (const id of ids) selected.push({ id, account: String(id), name: String(id) } as UserItem)\n }\n }\n}\n\nasync function handleConfirm() {\n const ids = selected.map(u => u.id)\n emit('confirm', ids)\n}\n\ndefineExpose({ open })\n</script>\n\n<template>\n <FormContainer\n v-model:show=\"show\"\n :title=\"t('userPicker.title')\"\n :width=\"1100\"\n :on-confirm=\"handleConfirm\"\n :confirm-text=\"t('common.confirm')\"\n >\n <div class=\"user-picker\">\n <!-- 左面板:机构树 -->\n <div class=\"picker-tree\">\n <div class=\"panel-header\">{{ t('org.title') }}</div>\n <n-tree\n :data=\"orgTree\"\n key-field=\"id\"\n label-field=\"name\"\n children-field=\"children\"\n selectable\n block-line\n default-expand-all\n :selected-keys=\"selectedOrgKey != null ? [selectedOrgKey] : []\"\n @update:selected-keys=\"onOrgSelect\"\n />\n </div>\n\n <!-- 中间面板:可选用户 -->\n <div class=\"picker-table\">\n <div class=\"panel-header\">\n <span>{{ t('userPicker.available') }}</span>\n <n-button\n size=\"tiny\"\n type=\"primary\"\n :disabled=\"checkedKeys.length === 0\"\n @click=\"addChecked\"\n >\n {{ t('userPicker.addChecked') }}({{ checkedKeys.length }})\n </n-button>\n </div>\n <SmartTable\n :default-page-size=\"100\"\n ref=\"tableRef\"\n :columns=\"columns\"\n :fetcher=\"fetcher\"\n :pagination=\"{ pageSize: 10 }\"\n size=\"small\"\n storage-key=\"user-picker\"\n :tool-button=\"false\"\n :checked-row-keys=\"checkedKeys\"\n @update:checked-row-keys=\"(keys: (string | number)[]) => (checkedKeys = keys)\"\n @error=\"e => message.error(translateError(e))\"\n />\n </div>\n\n <!-- 右面板:已选用户 -->\n <div class=\"picker-selected\">\n <div class=\"panel-header\">\n <span>{{ t('userPicker.selected') }}({{ selected.length }})</span>\n <n-button\n size=\"tiny\"\n quaternary\n type=\"error\"\n :disabled=\"selected.length === 0\"\n @click=\"clearSelected\"\n >\n {{ t('userPicker.clear') }}\n </n-button>\n </div>\n <n-input\n v-model:value=\"selectedSearch\"\n size=\"small\"\n clearable\n :placeholder=\"t('common.search')\"\n style=\"margin-bottom: 8px\"\n />\n <div class=\"selected-list\">\n <div v-for=\"u in filteredSelected\" :key=\"u.id\" class=\"selected-item\">\n <span class=\"selected-name\">\n {{ u.name }}\n <span class=\"selected-account\">({{ u.account }})</span>\n </span>\n <n-button size=\"tiny\" quaternary type=\"error\" @click=\"removeUser(u.id)\">\n <template #icon><AppIcon icon=\"ph:x\" :size=\"14\" /></template>\n </n-button>\n </div>\n <n-empty\n v-if=\"filteredSelected.length === 0\"\n :description=\"t('common.noData')\"\n style=\"padding: 24px 0\"\n />\n </div>\n </div>\n </div>\n </FormContainer>\n</template>\n\n<style scoped>\n.user-picker {\n display: flex;\n gap: 12px;\n min-height: 400px;\n}\n.panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n font-size: 13px;\n font-weight: 600;\n padding: 0 0 8px;\n border-bottom: 1px solid var(--n-border-color, #e0e0e6);\n margin-bottom: 8px;\n}\n.picker-tree {\n width: 160px;\n flex-shrink: 0;\n overflow: auto;\n border-right: 1px solid var(--n-border-color, #e0e0e6);\n padding-right: 12px;\n}\n.picker-table {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n}\n.picker-selected {\n width: 200px;\n flex-shrink: 0;\n border-left: 1px solid var(--n-border-color, #e0e0e6);\n padding-left: 12px;\n display: flex;\n flex-direction: column;\n}\n.selected-list {\n flex: 1;\n overflow: auto;\n max-height: 380px;\n}\n.selected-item {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 4px 0;\n font-size: 13px;\n border-bottom: 1px solid var(--n-border-color, #e0e0e6);\n}\n.selected-item:last-child {\n border-bottom: none;\n}\n.selected-name {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.selected-account {\n color: var(--n-text-color-disabled, #999);\n font-size: 12px;\n margin-left: 2px;\n}\n</style>\n"],"names":["props","__props","emit","__emit","t","useI18n","message","useMessage","show","ref","tableRef","orgFlat","orgTree","computed","buildTree","selectedOrgKey","orgId","onMounted","orgApi","onOrgSelect","keys","_a","checkedKeys","excludeSet","fetcher","params","userApi","columns","r","already","selectedSet","h","NButton","addUsers","selected","reactive","u","selectedSearch","filteredSelected","q","users","addChecked","rows","unref","removeUser","id","idx","clearSelected","open","ids","items","all","found","handleConfirm","__expose","_createBlock","FormContainer","$event","_unref","_createElementVNode","_hoisted_1","_hoisted_2","_hoisted_3","_toDisplayString","_createVNode","NTree","_hoisted_4","_hoisted_5","_createTextVNode","SmartTable","_cache","e","translateError","_hoisted_6","_hoisted_7","NInput","_hoisted_8","_createElementBlock","_Fragment","_renderList","_hoisted_9","_hoisted_10","AppIcon","NEmpty"],"mappings":"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"}
1
+ {"version":3,"file":"index2.vue.js","sources":["../../../src/components/UserPicker/index.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, h, onMounted, reactive, ref, unref } from 'vue'\nimport { NButton, NEmpty, NInput, NTab, NTabs, NTree, NTreeSelect, useMessage } from 'naive-ui'\nimport { SmartTable, type SmartTableColumn, type SmartTableInst } from 'smart-naive-table'\nimport { useI18n } from 'vue-i18n'\nimport { useWindowSize } from '@vueuse/core'\nimport AppIcon from '#/components/AppIcon.vue'\nimport FormContainer from '#/components/FormContainer/index.vue'\nimport { useShellBreakpoint } from '#/composables/useShellBreakpoint'\nimport { orgApi, userApi } from '#/api'\nimport { buildTree } from '#/utils/tree'\nimport { translateError } from '#/utils/error'\nimport { SEARCH_ACTIONS } from '#/utils/tableFilter'\nimport type { SysOrg, UserItem } from '#/types/api'\n\nconst props = defineProps<{ excludeIds?: number[] }>()\nconst emit = defineEmits<{ (e: 'confirm', ids: number[]): void }>()\n\nconst { t } = useI18n()\nconst message = useMessage()\n\nconst show = ref(false)\nconst tableRef = ref<SmartTableInst<UserItem>>()\n\n// 屏幕形态:\n// 宽 / 中档 = 居中弹窗里的三栏(机构树 | 可选用户 | 已选);\n// 窄档(壳层 < 600)= 底部抽屉,三栏收成「可选用户 / 已选」两页,机构树换成页内的树选择;\n// 内容区 < 900 但还不到窄档时仍是弹窗,三栏同样收成两页(1100 宽的三栏在这里放不下)。\n// 三栏选择器在抽屉里太局促,所以宽 / 中档固定用弹窗,不跟随「表单形态」全局偏好。\nconst { bp } = useShellBreakpoint()\nconst { width: winW } = useWindowSize()\nconst compact = computed(() => bp.value === 'narrow' || winW.value < 900)\nconst variant = computed(() => (bp.value === 'narrow' ? 'drawer' : 'modal'))\nconst tab = ref<'users' | 'selected'>('users')\nconst btnSize = computed(() => (compact.value ? 'large' : 'small'))\n\n// ── 机构树(左面板) ──\nconst orgFlat = ref<SysOrg[]>([])\nconst orgTree = computed(() => {\n const all = { id: 0, parentId: -1, name: t('common.all'), children: buildTree(orgFlat.value) }\n return [all]\n})\nconst selectedOrgKey = ref<number | null>(null)\nconst orgId = computed(() =>\n selectedOrgKey.value && selectedOrgKey.value !== 0 ? selectedOrgKey.value : undefined,\n)\n\nonMounted(async () => {\n try {\n orgFlat.value = await orgApi.list()\n } catch {\n /* 静默 */\n }\n})\n\nfunction onOrgSelect(keys: Array<string | number>) {\n selectedOrgKey.value = (keys[0] as number) ?? null\n tableRef.value?.refresh()\n}\n// 两页形态下机构树换成树选择:没有「再点一次取消」,选「全部」(id 0)即不限机构。\nfunction onOrgPick(key: number | null) {\n selectedOrgKey.value = key ?? null\n tableRef.value?.refresh()\n}\n\n// ── 可选用户表(中间面板) ──\nconst checkedKeys = ref<(string | number)[]>([])\nconst excludeSet = computed(() => new Set(props.excludeIds ?? []))\n\nconst fetcher = (params: { page: number; pageSize: number; account?: string }) =>\n userApi.page({\n page: params.page,\n pageSize: params.pageSize,\n account: params.account,\n orgId: orgId.value,\n })\n\nconst columns: SmartTableColumn<UserItem>[] = [\n { type: 'selection' },\n { key: 'name', title: () => t('user.name'), width: 100 },\n {\n key: 'account',\n title: () => t('user.account'),\n width: 120,\n search: { actions: SEARCH_ACTIONS.fuzzy },\n },\n {\n key: 'op',\n title: () => t('common.operation'),\n width: 70,\n render: r => {\n const already = selectedSet.value.has(r.id) || excludeSet.value.has(r.id)\n return h(\n NButton,\n {\n size: 'tiny',\n type: 'primary',\n quaternary: true,\n disabled: already,\n onClick: () => addUsers([r]),\n },\n () => (already ? t('userPicker.added') : t('userPicker.add')),\n )\n },\n },\n]\n\n// ── 已选用户(右面板) ──\nconst selected = reactive<UserItem[]>([])\nconst selectedSet = computed(() => new Set(selected.map(u => u.id)))\nconst selectedSearch = ref('')\nconst filteredSelected = computed(() => {\n const q = selectedSearch.value.trim().toLowerCase()\n if (!q) return selected\n return selected.filter(\n u => u.name.toLowerCase().includes(q) || u.account.toLowerCase().includes(q),\n )\n})\n\nfunction addUsers(users: UserItem[]) {\n for (const u of users) {\n if (!selectedSet.value.has(u.id) && !excludeSet.value.has(u.id)) {\n selected.push(u)\n }\n }\n}\n\nfunction addChecked() {\n // SmartTable 只 expose rows,别改用未公开的 tableData —— 恒为 undefined。\n // unref 兼容类型声明的 Ref 与运行时 expose 解包两种形态。\n const rows = (unref(tableRef.value?.rows) ?? []).filter(r => checkedKeys.value.includes(r.id))\n addUsers(rows)\n checkedKeys.value = []\n}\n\nfunction removeUser(id: number) {\n const idx = selected.findIndex(u => u.id === id)\n if (idx >= 0) selected.splice(idx, 1)\n}\n\nfunction clearSelected() {\n selected.splice(0, selected.length)\n}\n\n// ── 公共 API ──\nasync function open(ids?: number[]) {\n selected.splice(0, selected.length)\n checkedKeys.value = []\n selectedSearch.value = ''\n selectedOrgKey.value = null\n tab.value = 'users'\n show.value = true\n\n if (ids?.length) {\n try {\n // ponytail: 拉一页,靠 id 过滤。取 200 是为了在应用把 Api:MaxPageSize 调小时也不会被后端回 48001。\n // 用户超过 200 个时,排在后面的 id 解析不出名字,走下面那条退回显示 id 的分支;\n // 真要支持更大规模的用户名单,再改成分页搜索。\n const { items } = await userApi.page({ page: 1, pageSize: 200 })\n const all = items.filter(u => ids.includes(u.id))\n // 没拉到的 id(翻页之外),退回只显示 id\n const found = new Set(all.map(u => u.id))\n for (const u of all) selected.push(u)\n for (const id of ids) {\n if (!found.has(id)) selected.push({ id, account: String(id), name: String(id) } as UserItem)\n }\n } catch {\n for (const id of ids) selected.push({ id, account: String(id), name: String(id) } as UserItem)\n }\n }\n}\n\nasync function handleConfirm() {\n const ids = selected.map(u => u.id)\n emit('confirm', ids)\n}\n\ndefineExpose({ open })\n</script>\n\n<template>\n <FormContainer\n v-model:show=\"show\"\n :variant=\"variant\"\n :title=\"t('userPicker.title')\"\n :width=\"1100\"\n :on-confirm=\"handleConfirm\"\n :confirm-text=\"t('common.confirm')\"\n >\n <n-tabs v-if=\"compact\" v-model:value=\"tab\" type=\"segment\" animated class=\"picker-tabs\">\n <n-tab name=\"users\">{{ t('userPicker.available') }}</n-tab>\n <n-tab name=\"selected\">{{ t('userPicker.selected') }}({{ selected.length }})</n-tab>\n </n-tabs>\n <div class=\"user-picker\" :class=\"{ 'is-compact': compact }\">\n <!-- 左面板:机构树(两页形态下换成可选用户页顶部的树选择) -->\n <div v-if=\"!compact\" class=\"picker-tree\">\n <div class=\"panel-header\">{{ t('org.title') }}</div>\n <n-tree\n :data=\"orgTree\"\n key-field=\"id\"\n label-field=\"name\"\n children-field=\"children\"\n selectable\n block-line\n default-expand-all\n :selected-keys=\"selectedOrgKey != null ? [selectedOrgKey] : []\"\n @update:selected-keys=\"onOrgSelect\"\n />\n </div>\n\n <!-- 中间面板:可选用户 -->\n <div v-show=\"!compact || tab === 'users'\" class=\"picker-table\">\n <n-tree-select\n v-if=\"compact\"\n :value=\"selectedOrgKey ?? 0\"\n :options=\"orgTree\"\n key-field=\"id\"\n label-field=\"name\"\n children-field=\"children\"\n default-expand-all\n size=\"large\"\n class=\"picker-org-select\"\n @update:value=\"onOrgPick\"\n />\n <div class=\"panel-header\">\n <span>{{ t('userPicker.available') }}</span>\n <n-button\n :size=\"btnSize\"\n type=\"primary\"\n :disabled=\"checkedKeys.length === 0\"\n @click=\"addChecked\"\n >\n {{ t('userPicker.addChecked') }}({{ checkedKeys.length }})\n </n-button>\n </div>\n <SmartTable\n :default-page-size=\"100\"\n ref=\"tableRef\"\n :columns=\"columns\"\n :fetcher=\"fetcher\"\n :search=\"{ container: 'table' }\"\n :pagination=\"{ pageSize: 10 }\"\n size=\"small\"\n storage-key=\"user-picker\"\n :tool-button=\"false\"\n :checked-row-keys=\"checkedKeys\"\n @update:checked-row-keys=\"(keys: (string | number)[]) => (checkedKeys = keys)\"\n @error=\"e => message.error(translateError(e))\"\n />\n </div>\n\n <!-- 右面板:已选用户 -->\n <div v-show=\"!compact || tab === 'selected'\" class=\"picker-selected\">\n <div class=\"panel-header\">\n <span>{{ t('userPicker.selected') }}({{ selected.length }})</span>\n <n-button\n :size=\"btnSize\"\n quaternary\n type=\"error\"\n :disabled=\"selected.length === 0\"\n @click=\"clearSelected\"\n >\n {{ t('userPicker.clear') }}\n </n-button>\n </div>\n <n-input\n v-model:value=\"selectedSearch\"\n :size=\"compact ? 'large' : 'small'\"\n clearable\n :placeholder=\"t('common.search')\"\n style=\"margin-bottom: 8px\"\n />\n <div class=\"selected-list\">\n <div v-for=\"u in filteredSelected\" :key=\"u.id\" class=\"selected-item\">\n <span class=\"selected-name\">\n {{ u.name }}\n <span class=\"selected-account\">({{ u.account }})</span>\n </span>\n <n-button :size=\"btnSize\" quaternary type=\"error\" @click=\"removeUser(u.id)\">\n <template #icon><AppIcon icon=\"ph:x\" :size=\"14\" /></template>\n </n-button>\n </div>\n <n-empty\n v-if=\"filteredSelected.length === 0\"\n :description=\"t('common.noData')\"\n style=\"padding: 24px 0\"\n />\n </div>\n </div>\n </div>\n </FormContainer>\n</template>\n\n<style scoped>\n/* 选择器的尺寸、分隔线、字号。 */\n.user-picker {\n display: flex;\n gap: 12px;\n min-height: min(440px, calc(100vh - 250px));\n}\n.panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n min-height: 34px;\n font-size: 13.5px;\n font-weight: 600;\n padding: 0 0 8px;\n border-bottom: 1px solid var(--hairline);\n margin-bottom: 8px;\n}\n.picker-tree {\n width: 200px;\n flex-shrink: 0;\n overflow: auto;\n border-right: 1px solid var(--hairline);\n padding-right: 12px;\n}\n.picker-table {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n}\n.picker-org-select {\n margin-bottom: 8px;\n}\n.picker-selected {\n width: 220px;\n flex-shrink: 0;\n border-left: 1px solid var(--hairline);\n padding-left: 12px;\n display: flex;\n flex-direction: column;\n min-height: 0;\n}\n.selected-list {\n flex: 1;\n min-height: 0;\n overflow: auto;\n max-height: 380px;\n}\n.selected-item {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 6px;\n padding: 2px 0;\n font-size: 13.5px;\n border-bottom: 1px solid var(--hairline);\n}\n.selected-item:last-child {\n border-bottom: none;\n}\n.selected-name {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.selected-account {\n color: var(--text-3);\n margin-left: 2px;\n}\n\n/* 两页形态:分段页签在上,当前页占满整行;已选页不再要左侧分隔线,条目行高放大到可点 */\n.picker-tabs {\n margin-bottom: 12px;\n}\n.user-picker.is-compact {\n min-height: 0;\n}\n.is-compact .picker-selected {\n width: auto;\n flex: 1;\n border-left: none;\n padding-left: 0;\n}\n.is-compact .selected-list {\n max-height: none;\n}\n.is-compact .selected-item {\n min-height: 44px;\n}\n</style>\n"],"names":["props","__props","emit","__emit","t","useI18n","message","useMessage","show","ref","tableRef","bp","useShellBreakpoint","winW","useWindowSize","compact","computed","variant","tab","btnSize","orgFlat","orgTree","buildTree","selectedOrgKey","orgId","onMounted","orgApi","onOrgSelect","keys","_a","onOrgPick","key","checkedKeys","excludeSet","fetcher","params","userApi","columns","SEARCH_ACTIONS","r","already","selectedSet","h","NButton","addUsers","selected","reactive","u","selectedSearch","filteredSelected","q","users","addChecked","rows","unref","removeUser","id","idx","clearSelected","open","ids","items","all","found","handleConfirm","__expose","_createBlock","FormContainer","$event","_unref","NTabs","_createVNode","NTab","_createTextVNode","_toDisplayString","_createElementVNode","_normalizeClass","_openBlock","_createElementBlock","_hoisted_1","_hoisted_2","NTree","_withDirectives","_hoisted_3","NTreeSelect","_hoisted_4","SmartTable","_cache","e","translateError","_vShow","_hoisted_5","_hoisted_6","NInput","_hoisted_7","_Fragment","_renderList","_hoisted_8","_hoisted_9","AppIcon","NEmpty"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"useBatchDelete.js","sources":["../../src/composables/useBatchDelete.ts"],"sourcesContent":["// 表格批量删除的样板收敛:维护勾选态 + 二次确认(挂起对话框防连点)+ 成功后清选并刷新。\n// 用在 SmartTable(经 $attrs 把 checked-row-keys 透传到内层 n-data-table)与裸 n-data-table 两处。\n// 仅限 setup 中调用(内部用 useConfirm → useI18n/useDialog)。\nimport { computed, ref } from 'vue'\nimport { useI18n } from 'vue-i18n'\nimport { useConfirm } from '#/composables/useConfirm'\n\nexport interface UseBatchDeleteOptions {\n /** 批量删除接口(收 number[] 主键)。 */\n remove: (ids: number[]) => Promise<unknown>\n /** 删除成功后刷新数据。 */\n refresh: () => void\n /** 成功 toast 文案;false = 不弹(另有提示)。缺省用 common.success。 */\n successMsg?: string | false\n /**\n * 自定义确认文案(可异步:删前要先查点东西才能把话说清楚时用,如\"这些角色关联了 N 个用户\")。\n * 缺省是按条数的通用文案。有此需求的页面若只给行内单删加警告,勾选+批量删就能绕过去。\n */\n content?: (ids: number[]) => string | Promise<string>\n}\n\nexport function useBatchDelete(opts: UseBatchDeleteOptions) {\n const { t } = useI18n()\n const { confirm } = useConfirm()\n /** 勾选的行主键(绑到表格的 checked-row-keys)。 */\n const checkedKeys = ref<Array<string | number>>([])\n const hasSelection = computed(() => checkedKeys.value.length > 0)\n\n async function run() {\n const ids = checkedKeys.value.map(Number)\n if (ids.length === 0) return\n const ok = await confirm({\n content: (await opts.content?.(ids)) ?? t('common.batchDeleteConfirm', { count: ids.length }),\n action: () => opts.remove(ids),\n successMsg: opts.successMsg,\n })\n if (ok) {\n checkedKeys.value = []\n opts.refresh()\n }\n }\n\n return { checkedKeys, hasSelection, run }\n}\n"],"names":["useBatchDelete","opts","t","useI18n","confirm","useConfirm","checkedKeys","ref","hasSelection","computed","run","ids","_a"],"mappings":";;;AAqBO,SAASA,EAAeC,GAA6B;AAC1D,QAAM,EAAE,GAAAC,EAAA,IAAMC,EAAA,GACR,EAAE,SAAAC,EAAA,IAAYC,EAAA,GAEdC,IAAcC,EAA4B,EAAE,GAC5CC,IAAeC,EAAS,MAAMH,EAAY,MAAM,SAAS,CAAC;AAEhE,iBAAeI,IAAM;;AACnB,UAAMC,IAAML,EAAY,MAAM,IAAI,MAAM;AACxC,QAAIK,EAAI,WAAW,EAAG;AAMtB,IALW,MAAMP,EAAQ;AAAA,MACvB,SAAU,QAAMQ,IAAAX,EAAK,YAAL,gBAAAW,EAAA,KAAAX,GAAeU,OAAST,EAAE,6BAA6B,EAAE,OAAOS,EAAI,OAAA,CAAQ;AAAA,MAC5F,QAAQ,MAAMV,EAAK,OAAOU,CAAG;AAAA,MAC7B,YAAYV,EAAK;AAAA,IAAA,CAClB,MAECK,EAAY,QAAQ,CAAA,GACpBL,EAAK,QAAA;AAAA,EAET;AAEA,SAAO,EAAE,aAAAK,GAAa,cAAAE,GAAc,KAAAE,EAAA;AACtC;"}
1
+ {"version":3,"file":"useBatchDelete.js","sources":["../../src/composables/useBatchDelete.ts"],"sourcesContent":["// 表格批量删除的样板收敛:维护勾选态 + 二次确认(挂起对话框防连点)+ 成功后清选并刷新。\n// 用在 SmartTable(经 $attrs 把 checked-row-keys 透传到内层 n-data-table)。\n// 仅限 setup 中调用(内部用 useConfirm → useI18n/useDialog)。\n// SmartTable 3.0 用 #batch 批量栏承载按钮(勾选后才出现),不需要 hasSelection 控制禁用;\n// hasSelection 仍返回,给批量按钮不在 #batch 里的调用方用(如字典项的窄档抽屉,按钮在抽屉底栏)。\nimport { computed, ref } from 'vue'\nimport { useI18n } from 'vue-i18n'\nimport { useConfirm } from '#/composables/useConfirm'\n\nexport interface UseBatchDeleteOptions {\n /** 批量删除接口(收 number[] 主键)。 */\n remove: (ids: number[]) => Promise<unknown>\n /** 删除成功后刷新数据。 */\n refresh: () => void\n /** 成功 toast 文案;false = 不弹(另有提示)。缺省用 common.success。 */\n successMsg?: string | false\n /**\n * 自定义确认文案(可异步:删前要先查点东西才能把话说清楚时用,如\"这些角色关联了 N 个用户\")。\n * 缺省是按条数的通用文案。有此需求的页面若只给行内单删加警告,勾选+批量删就能绕过去。\n */\n content?: (ids: number[]) => string | Promise<string>\n}\n\nexport function useBatchDelete(opts: UseBatchDeleteOptions) {\n const { t } = useI18n()\n const { confirm } = useConfirm()\n /** 勾选的行主键(绑到表格的 checked-row-keys)。 */\n const checkedKeys = ref<Array<string | number>>([])\n const hasSelection = computed(() => checkedKeys.value.length > 0)\n\n async function run() {\n const ids = checkedKeys.value.map(Number)\n if (ids.length === 0) return\n const ok = await confirm({\n content: (await opts.content?.(ids)) ?? t('common.batchDeleteConfirm', { count: ids.length }),\n action: () => opts.remove(ids),\n successMsg: opts.successMsg,\n })\n if (ok) {\n checkedKeys.value = []\n opts.refresh()\n }\n }\n\n return { checkedKeys, hasSelection, run }\n}\n"],"names":["useBatchDelete","opts","t","useI18n","confirm","useConfirm","checkedKeys","ref","hasSelection","computed","run","ids","_a"],"mappings":";;;AAuBO,SAASA,EAAeC,GAA6B;AAC1D,QAAM,EAAE,GAAAC,EAAA,IAAMC,EAAA,GACR,EAAE,SAAAC,EAAA,IAAYC,EAAA,GAEdC,IAAcC,EAA4B,EAAE,GAC5CC,IAAeC,EAAS,MAAMH,EAAY,MAAM,SAAS,CAAC;AAEhE,iBAAeI,IAAM;;AACnB,UAAMC,IAAML,EAAY,MAAM,IAAI,MAAM;AACxC,QAAIK,EAAI,WAAW,EAAG;AAMtB,IALW,MAAMP,EAAQ;AAAA,MACvB,SAAU,QAAMQ,IAAAX,EAAK,YAAL,gBAAAW,EAAA,KAAAX,GAAeU,OAAST,EAAE,6BAA6B,EAAE,OAAOS,EAAI,OAAA,CAAQ;AAAA,MAC5F,QAAQ,MAAMV,EAAK,OAAOU,CAAG;AAAA,MAC7B,YAAYV,EAAK;AAAA,IAAA,CAClB,MAECK,EAAY,QAAQ,CAAA,GACpBL,EAAK,QAAA;AAAA,EAET;AAEA,SAAO,EAAE,aAAAK,GAAa,cAAAE,GAAc,KAAAE,EAAA;AACtC;"}
@@ -1,25 +1,26 @@
1
- import { computed as l, ref as M, watch as s, h } from "vue";
2
- import { NBadge as O } from "naive-ui";
3
- import { createSharedComposable as w } from "@vueuse/core";
4
- import A from "../components/AppIcon.vue.js";
5
- import { menuBadge as I } from "./useMenuBadge.js";
1
+ import { computed as l, ref as I, watch as s, h } from "vue";
2
+ import { NBadge as M } from "naive-ui";
3
+ import { createSharedComposable as O } from "@vueuse/core";
4
+ import w from "../components/AppIcon.vue.js";
5
+ import { menuBadge as A } from "./useMenuBadge.js";
6
6
  import { router as a } from "../router/index.js";
7
7
  import { useAuthStore as K } from "../stores/auth.js";
8
8
  import { useAppStore as T } from "../stores/app.js";
9
9
  import { translateMenuTitle as m } from "../locales/menuTitle.js";
10
10
  import { isHttpUrl as W, isFullscreenPath as _ } from "../utils/url.js";
11
+ import { lineIcon as C } from "../utils/menuIcon.js";
11
12
  import { MenuType as p } from "../types/menu.js";
12
13
  function d(r) {
13
14
  return !W(r) && !_(r) ? !1 : (window.open(r, "_blank", "noopener,noreferrer"), !0);
14
15
  }
15
- function v(r, e = "ph:dot-outline-duotone") {
16
- return () => h(A, { icon: r || e, size: 18 });
16
+ function v(r, e = "ph:dot-outline") {
17
+ return () => h(w, { icon: C(r) || e, size: 18 });
17
18
  }
18
- function C(r) {
19
+ function R(r) {
19
20
  if (r)
20
21
  return () => {
21
- const e = I(r);
22
- return e == null || e === 0 || e === "" ? null : h(O, { value: e, max: 99 });
22
+ const e = A(r);
23
+ return e == null || e === 0 || e === "" ? null : h(M, { value: e, max: 99 });
23
24
  };
24
25
  }
25
26
  function y(r) {
@@ -29,7 +30,7 @@ function y(r) {
29
30
  return n.length ? {
30
31
  label: m(e.title, e.path),
31
32
  key: `cat-${e.id}`,
32
- icon: v(e.icon, "ph:folder-duotone"),
33
+ icon: v(e.icon, "ph:folder"),
33
34
  children: n
34
35
  } : null;
35
36
  }
@@ -37,7 +38,7 @@ function y(r) {
37
38
  label: m(e.title, e.path),
38
39
  key: e.path ?? `menu-${e.id}`,
39
40
  icon: v(e.icon),
40
- extra: C(e.path)
41
+ extra: R(e.path)
41
42
  };
42
43
  }).filter((e) => e !== null);
43
44
  }
@@ -51,10 +52,10 @@ function k(r) {
51
52
  if (n) return n;
52
53
  }
53
54
  }
54
- function R() {
55
+ function $() {
55
56
  const r = K(), e = T(), n = l(() => (e.locale, y(r.menuTree))), b = l(
56
57
  () => n.value.map((t) => ({ label: t.label, key: t.key, icon: t.icon, extra: t.extra }))
57
- ), c = l(() => a.currentRoute.value.path), i = M();
58
+ ), c = l(() => a.currentRoute.value.path), i = I();
58
59
  function f(t) {
59
60
  const o = n.value.find((u) => g(u, t));
60
61
  return o ? String(o.key) : void 0;
@@ -86,8 +87,8 @@ function R() {
86
87
  }
87
88
  return { menuOptions: n, l1Options: b, l2Options: S, selectedL1: i, activeKey: c, onSelect: x, onSelectL1: L };
88
89
  }
89
- const G = w(R);
90
+ const Q = O($);
90
91
  export {
91
- G as useLayoutMenu
92
+ Q as useLayoutMenu
92
93
  };
93
94
  //# sourceMappingURL=useLayoutMenu.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useLayoutMenu.js","sources":["../../src/composables/useLayoutMenu.ts"],"sourcesContent":["// auth.menuTree → n-menu 的 MenuOption,外加混合布局下顶栏一级 / 侧栏二级的选中态联动。\n// 用法:default.vue 与 AppHeader 各自 useLayoutMenu(),createSharedComposable 保证它们共享同一份选中态。\n// 坑:off-menu 路由(如 /personal/*)命中不到任何一级,此时保留上一次的一级选中,别把顶栏清空。\nimport { computed, h, ref, watch } from 'vue'\nimport { NBadge, type MenuOption } from 'naive-ui'\nimport { createSharedComposable } from '@vueuse/core'\nimport AppIcon from '#/components/AppIcon.vue'\nimport { menuBadge } from '#/composables/useMenuBadge'\nimport { router } from '#/router'\nimport { useAuthStore } from '#/stores/auth'\nimport { useAppStore } from '#/stores/app'\nimport { translateMenuTitle } from '#/locales/menuTitle'\nimport { isFullscreenPath, isHttpUrl } from '#/utils/url'\nimport { MenuType, type MenuNode } from '#/types/menu'\n\n/**\n * 新标签页打开的两类 key → window.open;返回是否已处理。\n * - 外链菜单:path 为 http(s) URL。\n * - 站内整屏页:path 以 `/fullscreen/` 开头(大屏看板),站内静态路由,但必须脱离布局壳整屏显示。\n */\nfunction openIfExternal(key: string): boolean {\n if (!isHttpUrl(key) && !isFullscreenPath(key)) return false\n window.open(key, '_blank', 'noopener,noreferrer')\n return true\n}\n\n// 无图标兜底:rail/折叠态的 n-menu 只画图标,缺图标会渲染成空槽、整项像“消失”了,故永不返回 undefined。\n// 走 AppIcon 而非裸 Icon:菜单图标是库里配的,子集外的名字要由它懒加载整集兜底,否则渲染不出来。\nfunction renderIcon(name: string | undefined, fallback = 'ph:dot-outline-duotone') {\n return () => h(AppIcon, { icon: name || fallback, size: 18 })\n}\n\n// 角标(registerMenuBadge 登记的未读数/待办数)→ n-menu 的 extra 槽。\n// 读值在渲染函数里做,故登记的 ref 一变角标就变,不必重算整棵 options。\n// 折叠 / rail 态 n-menu 只画图标、不渲染 extra,角标随之隐藏——这是 n-menu 的行为,不另做补偿。\nfunction renderBadge(path: string | undefined) {\n if (!path) return undefined\n return () => {\n const value = menuBadge(path)\n if (value === null || value === undefined || value === 0 || value === '') return null\n return h(NBadge, { value, max: 99 })\n }\n}\n\n// 菜单树 → n-menu options:剥按钮、丢空目录、页面叶子 key=路由 path。目录/叶子各自兜底图标。\nfunction toOptions(nodes: MenuNode[]): MenuOption[] {\n return nodes\n .toSorted((a, b) => a.sort - b.sort)\n .filter(n => n.type !== MenuType.Button && n.visible !== false)\n .map<MenuOption | null>(n => {\n if (n.type === MenuType.Catalog) {\n const children = toOptions(n.children ?? [])\n if (!children.length) return null\n return {\n label: translateMenuTitle(n.title, n.path),\n key: `cat-${n.id}`,\n icon: renderIcon(n.icon, 'ph:folder-duotone'),\n children,\n }\n }\n return {\n label: translateMenuTitle(n.title, n.path),\n key: n.path ?? `menu-${n.id}`,\n icon: renderIcon(n.icon),\n extra: renderBadge(n.path),\n }\n })\n .filter((o): o is MenuOption => o !== null)\n}\n\nfunction containsKey(opt: MenuOption, path: string): boolean {\n if (opt.key === path) return true\n return ((opt.children as MenuOption[]) ?? []).some(c => containsKey(c, path))\n}\nfunction firstLeafKey(opt: MenuOption): string | undefined {\n if (typeof opt.key === 'string' && opt.key.startsWith('/')) return opt.key\n for (const c of (opt.children as MenuOption[]) ?? []) {\n const k = firstLeafKey(c)\n if (k) return k\n }\n return undefined\n}\n\n/**\n * 布局菜单派生 + 一/二级选中态联动(混合布局用)。\n * createSharedComposable → default.vue 与 AppHeader 共享同一份 selectedL1,不各自漂移。\n * 走 router.currentRoute(全局 ref),不依赖组件上下文的 useRoute。\n */\nfunction useLayoutMenuImpl() {\n const auth = useAuthStore()\n const app = useAppStore()\n\n // 工作台是每个应用菜单树里的一条(Sort=0 → 排第一项),跟着应用变,不用手工 prepend。\n const menuOptions = computed<MenuOption[]>(() => {\n void app.locale // 依赖:切换语言时 i18n key 标题重算\n return toOptions(auth.menuTree)\n })\n\n // 一级(剥 children → n-menu 渲染为可选普通项,无展开箭头)。\n const l1Options = computed<MenuOption[]>(() =>\n menuOptions.value.map(o => ({ label: o.label, key: o.key, icon: o.icon, extra: o.extra })),\n )\n\n const activeKey = computed(() => router.currentRoute.value.path)\n const selectedL1 = ref<string>()\n\n function findActiveL1(path: string): string | undefined {\n const top = menuOptions.value.find(o => containsKey(o, path))\n return top ? String(top.key) : undefined\n }\n\n // 路由 → 一级同步:命中才覆写(off-menu 路由如 /personal/* 保留上次);首次 seed 头一项。\n watch(\n () => router.currentRoute.value.path,\n path => {\n const l1 = findActiveL1(path)\n if (l1) selectedL1.value = l1\n else if (selectedL1.value === undefined)\n selectedL1.value = menuOptions.value[0]?.key as string | undefined\n },\n { immediate: true },\n )\n // 菜单可能晚于首个 watch 到达(F5 重建):补 seed / 修正失效选择。\n watch(menuOptions, opts => {\n if (selectedL1.value === undefined || !opts.some(o => o.key === selectedL1.value)) {\n selectedL1.value = findActiveL1(activeKey.value) ?? (opts[0]?.key as string | undefined)\n }\n })\n\n const l2Options = computed<MenuOption[]>(() => {\n const top = menuOptions.value.find(o => o.key === selectedL1.value)\n return (top?.children as MenuOption[]) ?? []\n })\n\n function onSelect(key: string) {\n if (openIfExternal(key)) return\n if (key.startsWith('/')) router.push(key)\n }\n function onSelectL1(key: string) {\n if (openIfExternal(key)) return\n selectedL1.value = key // 先设,L2 列立即刷新,不等导航\n const top = menuOptions.value.find(o => o.key === key)\n const target = key.startsWith('/') ? key : top ? firstLeafKey(top) : undefined\n if (target) router.push(target)\n }\n\n return { menuOptions, l1Options, l2Options, selectedL1, activeKey, onSelect, onSelectL1 }\n}\n\nexport const useLayoutMenu = createSharedComposable(useLayoutMenuImpl)\n"],"names":["openIfExternal","key","isHttpUrl","isFullscreenPath","renderIcon","name","fallback","AppIcon","renderBadge","path","value","menuBadge","NBadge","toOptions","nodes","a","b","n","MenuType","children","translateMenuTitle","o","containsKey","opt","c","firstLeafKey","k","useLayoutMenuImpl","auth","useAuthStore","app","useAppStore","menuOptions","computed","l1Options","activeKey","router","selectedL1","ref","findActiveL1","top","watch","l1","_a","opts","l2Options","onSelect","onSelectL1","target","useLayoutMenu","createSharedComposable"],"mappings":"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"}
1
+ {"version":3,"file":"useLayoutMenu.js","sources":["../../src/composables/useLayoutMenu.ts"],"sourcesContent":["// auth.menuTree → n-menu 的 MenuOption,外加混合布局下顶栏一级 / 侧栏二级的选中态联动。\n// 用法:default.vue 与 AppHeader 各自 useLayoutMenu(),createSharedComposable 保证它们共享同一份选中态。\n// 坑:off-menu 路由(如 /personal/*)命中不到任何一级,此时保留上一次的一级选中,别把顶栏清空。\nimport { computed, h, ref, watch } from 'vue'\nimport { NBadge, type MenuOption } from 'naive-ui'\nimport { createSharedComposable } from '@vueuse/core'\nimport AppIcon from '#/components/AppIcon.vue'\nimport { menuBadge } from '#/composables/useMenuBadge'\nimport { router } from '#/router'\nimport { useAuthStore } from '#/stores/auth'\nimport { useAppStore } from '#/stores/app'\nimport { translateMenuTitle } from '#/locales/menuTitle'\nimport { isFullscreenPath, isHttpUrl } from '#/utils/url'\nimport { lineIcon } from '#/utils/menuIcon'\nimport { MenuType, type MenuNode } from '#/types/menu'\n\n/**\n * 新标签页打开的两类 key → window.open;返回是否已处理。\n * - 外链菜单:path 为 http(s) URL。\n * - 站内整屏页:path 以 `/fullscreen/` 开头(大屏看板),站内静态路由,但必须脱离布局壳整屏显示。\n */\nfunction openIfExternal(key: string): boolean {\n if (!isHttpUrl(key) && !isFullscreenPath(key)) return false\n window.open(key, '_blank', 'noopener,noreferrer')\n return true\n}\n\n// 无图标兜底:rail/折叠态的 n-menu 只画图标,缺图标会渲染成空槽、整项像“消失”了,故永不返回 undefined。\n// 走 AppIcon 而非裸 Icon:菜单图标是库里配的,子集外的名字要由它懒加载整集兜底,否则渲染不出来。\n// 全站统一线条款:库里存的 `-duotone` 名字在这里去掉后缀(见 utils/menuIcon),兜底图标本身也是线条款。\nfunction renderIcon(name: string | undefined, fallback = 'ph:dot-outline') {\n return () => h(AppIcon, { icon: lineIcon(name) || fallback, size: 18 })\n}\n\n// 角标(registerMenuBadge 登记的未读数/待办数)→ n-menu 的 extra 槽。\n// 读值在渲染函数里做,故登记的 ref 一变角标就变,不必重算整棵 options。\n// 折叠 / rail 态 n-menu 只画图标、不渲染 extra,角标随之隐藏——这是 n-menu 的行为,不另做补偿。\nfunction renderBadge(path: string | undefined) {\n if (!path) return undefined\n return () => {\n const value = menuBadge(path)\n if (value === null || value === undefined || value === 0 || value === '') return null\n return h(NBadge, { value, max: 99 })\n }\n}\n\n// 菜单树 → n-menu options:剥按钮、丢空目录、页面叶子 key=路由 path。目录/叶子各自兜底图标。\nfunction toOptions(nodes: MenuNode[]): MenuOption[] {\n return nodes\n .toSorted((a, b) => a.sort - b.sort)\n .filter(n => n.type !== MenuType.Button && n.visible !== false)\n .map<MenuOption | null>(n => {\n if (n.type === MenuType.Catalog) {\n const children = toOptions(n.children ?? [])\n if (!children.length) return null\n return {\n label: translateMenuTitle(n.title, n.path),\n key: `cat-${n.id}`,\n icon: renderIcon(n.icon, 'ph:folder'),\n children,\n }\n }\n return {\n label: translateMenuTitle(n.title, n.path),\n key: n.path ?? `menu-${n.id}`,\n icon: renderIcon(n.icon),\n extra: renderBadge(n.path),\n }\n })\n .filter((o): o is MenuOption => o !== null)\n}\n\nfunction containsKey(opt: MenuOption, path: string): boolean {\n if (opt.key === path) return true\n return ((opt.children as MenuOption[]) ?? []).some(c => containsKey(c, path))\n}\nfunction firstLeafKey(opt: MenuOption): string | undefined {\n if (typeof opt.key === 'string' && opt.key.startsWith('/')) return opt.key\n for (const c of (opt.children as MenuOption[]) ?? []) {\n const k = firstLeafKey(c)\n if (k) return k\n }\n return undefined\n}\n\n/**\n * 布局菜单派生 + 一/二级选中态联动(混合布局用)。\n * createSharedComposable → default.vue 与 AppHeader 共享同一份 selectedL1,不各自漂移。\n * 走 router.currentRoute(全局 ref),不依赖组件上下文的 useRoute。\n */\nfunction useLayoutMenuImpl() {\n const auth = useAuthStore()\n const app = useAppStore()\n\n // 工作台是每个应用菜单树里的一条(Sort=0 → 排第一项),跟着应用变,不用手工 prepend。\n const menuOptions = computed<MenuOption[]>(() => {\n void app.locale // 依赖:切换语言时 i18n key 标题重算\n return toOptions(auth.menuTree)\n })\n\n // 一级(剥 children → n-menu 渲染为可选普通项,无展开箭头)。\n const l1Options = computed<MenuOption[]>(() =>\n menuOptions.value.map(o => ({ label: o.label, key: o.key, icon: o.icon, extra: o.extra })),\n )\n\n const activeKey = computed(() => router.currentRoute.value.path)\n const selectedL1 = ref<string>()\n\n function findActiveL1(path: string): string | undefined {\n const top = menuOptions.value.find(o => containsKey(o, path))\n return top ? String(top.key) : undefined\n }\n\n // 路由 → 一级同步:命中才覆写(off-menu 路由如 /personal/* 保留上次);首次 seed 头一项。\n watch(\n () => router.currentRoute.value.path,\n path => {\n const l1 = findActiveL1(path)\n if (l1) selectedL1.value = l1\n else if (selectedL1.value === undefined)\n selectedL1.value = menuOptions.value[0]?.key as string | undefined\n },\n { immediate: true },\n )\n // 菜单可能晚于首个 watch 到达(F5 重建):补 seed / 修正失效选择。\n watch(menuOptions, opts => {\n if (selectedL1.value === undefined || !opts.some(o => o.key === selectedL1.value)) {\n selectedL1.value = findActiveL1(activeKey.value) ?? (opts[0]?.key as string | undefined)\n }\n })\n\n const l2Options = computed<MenuOption[]>(() => {\n const top = menuOptions.value.find(o => o.key === selectedL1.value)\n return (top?.children as MenuOption[]) ?? []\n })\n\n function onSelect(key: string) {\n if (openIfExternal(key)) return\n if (key.startsWith('/')) router.push(key)\n }\n function onSelectL1(key: string) {\n if (openIfExternal(key)) return\n selectedL1.value = key // 先设,L2 列立即刷新,不等导航\n const top = menuOptions.value.find(o => o.key === key)\n const target = key.startsWith('/') ? key : top ? firstLeafKey(top) : undefined\n if (target) router.push(target)\n }\n\n return { menuOptions, l1Options, l2Options, selectedL1, activeKey, onSelect, onSelectL1 }\n}\n\nexport const useLayoutMenu = createSharedComposable(useLayoutMenuImpl)\n"],"names":["openIfExternal","key","isHttpUrl","isFullscreenPath","renderIcon","name","fallback","AppIcon","lineIcon","renderBadge","path","value","menuBadge","NBadge","toOptions","nodes","a","b","n","MenuType","children","translateMenuTitle","o","containsKey","opt","c","firstLeafKey","k","useLayoutMenuImpl","auth","useAuthStore","app","useAppStore","menuOptions","computed","l1Options","activeKey","router","selectedL1","ref","findActiveL1","top","watch","l1","_a","opts","l2Options","onSelect","onSelectL1","target","useLayoutMenu","createSharedComposable"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ /** 登录页 Hero 当前 locale 的生效文案:配置优先,空值逐字段回退内置 i18n。 */
2
+ export declare function useLoginHero(): import('vue').ComputedRef<import('../lib/loginHero').LoginHeroCopy>;
@@ -0,0 +1,22 @@
1
+ import { computed as n } from "vue";
2
+ import { useI18n as t } from "vue-i18n";
3
+ import { resolveLoginHero as l } from "../lib/loginHero.js";
4
+ import { useSite as r } from "./useSite.js";
5
+ function f() {
6
+ const { t: e, locale: i } = t(), { site: o } = r();
7
+ return n(
8
+ () => l(
9
+ o.loginHero[i.value],
10
+ {
11
+ headline: `${e("login.headlinePre")}${e("login.headlineAccent")}${e("login.headlinePost")}`,
12
+ highlight: e("login.headlineAccent"),
13
+ features: [e("login.featRbac"), e("login.featScope"), e("login.featPortal")]
14
+ },
15
+ o.showFeatures
16
+ )
17
+ );
18
+ }
19
+ export {
20
+ f as useLoginHero
21
+ };
22
+ //# sourceMappingURL=useLoginHero.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useLoginHero.js","sources":["../../src/composables/useLoginHero.ts"],"sourcesContent":["import { computed } from 'vue'\nimport { useI18n } from 'vue-i18n'\nimport { resolveLoginHero } from '#/lib/loginHero'\nimport { useSite } from './useSite'\n\n/** 登录页 Hero 当前 locale 的生效文案:配置优先,空值逐字段回退内置 i18n。 */\nexport function useLoginHero() {\n const { t, locale } = useI18n()\n const { site } = useSite()\n\n return computed(() =>\n resolveLoginHero(\n site.loginHero[locale.value],\n {\n headline: `${t('login.headlinePre')}${t('login.headlineAccent')}${t('login.headlinePost')}`,\n highlight: t('login.headlineAccent'),\n features: [t('login.featRbac'), t('login.featScope'), t('login.featPortal')],\n },\n site.showFeatures,\n ),\n )\n}\n"],"names":["useLoginHero","t","locale","useI18n","site","useSite","computed","resolveLoginHero"],"mappings":";;;;AAMO,SAASA,IAAe;AAC7B,QAAM,EAAE,GAAAC,GAAG,QAAAC,EAAA,IAAWC,EAAA,GAChB,EAAE,MAAAC,EAAA,IAASC,EAAA;AAEjB,SAAOC;AAAA,IAAS,MACdC;AAAA,MACEH,EAAK,UAAUF,EAAO,KAAK;AAAA,MAC3B;AAAA,QACE,UAAU,GAAGD,EAAE,mBAAmB,CAAC,GAAGA,EAAE,sBAAsB,CAAC,GAAGA,EAAE,oBAAoB,CAAC;AAAA,QACzF,WAAWA,EAAE,sBAAsB;AAAA,QACnC,UAAU,CAACA,EAAE,gBAAgB,GAAGA,EAAE,iBAAiB,GAAGA,EAAE,kBAAkB,CAAC;AAAA,MAAA;AAAA,MAE7EG,EAAK;AAAA,IAAA;AAAA,EACP;AAEJ;"}
@@ -1,44 +1,54 @@
1
- import { useAuthStore as M } from "../stores/auth.js";
2
- import { useTabsStore as I } from "../stores/tabs.js";
1
+ import { useAuthStore as I } from "../stores/auth.js";
2
+ import { useTabsStore as g } from "../stores/tabs.js";
3
3
  import { useUserStore as f } from "../stores/user.js";
4
4
  import { personalApi as s } from "../api/index.js";
5
- import { buildRoutesForModule as S } from "./useAuthMenu.js";
6
- import { router as v } from "../router/index.js";
7
- let a = null;
8
- async function o(e) {
9
- return await S(e), { chooser: !1, moduleId: e };
5
+ import { buildRoutesForModule as M } from "./useAuthMenu.js";
6
+ import { router as S } from "../router/index.js";
7
+ let i = null;
8
+ async function n(r) {
9
+ return await M(r), { chooser: !1, moduleId: r };
10
10
  }
11
- function D() {
12
- const e = M();
13
- function m() {
14
- return a ?? (a = c().finally(() => {
15
- a = null;
16
- })), a;
11
+ function b() {
12
+ const r = I();
13
+ function d() {
14
+ return i ?? (i = c().finally(() => {
15
+ i = null;
16
+ })), i;
17
17
  }
18
18
  async function c() {
19
- const [{ modules: r, defaultModuleId: n }, i, l] = await Promise.all([
19
+ const [{ modules: o, defaultModuleId: t }, m, a] = await Promise.all([
20
20
  s.modules(),
21
- s.permissions().then((t) => ({ ok: !0, codes: t })).catch(() => ({ ok: !1, codes: [] })),
22
- s.profile().then((t) => ({ sadm: t.isSuperAdmin, avatar: t.avatar ?? null })).catch(() => {
23
- var t;
24
- return { sadm: ((t = f().userInfo) == null ? void 0 : t.isSuperAdmin) ?? !1, avatar: null };
21
+ s.permissions().then((e) => ({ ok: !0, codes: e })).catch(() => ({ ok: !1, codes: [] })),
22
+ s.profile().then((e) => ({
23
+ sadm: e.isSuperAdmin,
24
+ avatar: e.avatar ?? null,
25
+ orgName: e.orgName ?? null,
26
+ phoneTail: e.phone ? e.phone.slice(-4) : null
27
+ })).catch(() => {
28
+ var e;
29
+ return {
30
+ sadm: ((e = f().userInfo) == null ? void 0 : e.isSuperAdmin) ?? !1,
31
+ avatar: null,
32
+ orgName: null,
33
+ phoneTail: null
34
+ };
25
35
  })
26
36
  ]);
27
- e.modules = r, e.defaultModuleId = n ?? null, e.permissionCodes = i.codes, e.permissionsLoaded = i.ok, e.isSuperAdmin = l.sadm;
28
- const d = f();
29
- if (d.userInfo && (d.userInfo.avatar = l.avatar), r.length === 0) return { chooser: !0 };
30
- const u = e.currentModuleId;
31
- return u && r.some((t) => t.id === u) ? o(u) : r.length === 1 ? o(r[0].id) : n && r.some((t) => t.id === n) ? o(n) : { chooser: !0 };
37
+ r.modules = o, r.defaultModuleId = t ?? null, r.permissionCodes = m.codes, r.permissionsLoaded = m.ok, r.isSuperAdmin = a.sadm;
38
+ const u = f();
39
+ if (u.userInfo && (u.userInfo.avatar = a.avatar, u.userInfo.orgName = a.orgName, u.userInfo.phoneTail = a.phoneTail), o.length === 0) return { chooser: !0 };
40
+ const l = r.currentModuleId;
41
+ return l && o.some((e) => e.id === l) ? n(l) : o.length === 1 ? n(o[0].id) : t && o.some((e) => e.id === t) ? n(t) : { chooser: !0 };
32
42
  }
33
- async function p(r) {
34
- await o(r), I().clearTabs(), v.replace(e.homePath);
43
+ async function p(o) {
44
+ await n(o), g().clearTabs(), S.replace(r.homePath);
35
45
  }
36
- async function h(r) {
37
- await s.setDefaultModule(r), e.defaultModuleId = r;
46
+ async function h(o) {
47
+ await s.setDefaultModule(o), r.defaultModuleId = o;
38
48
  }
39
- return { enter: o, enterInitial: m, switchModule: p, setDefault: h };
49
+ return { enter: n, enterInitial: d, switchModule: p, setDefault: h };
40
50
  }
41
51
  export {
42
- D as useModule
52
+ b as useModule
43
53
  };
44
54
  //# sourceMappingURL=useModule.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useModule.js","sources":["../../src/composables/useModule.ts"],"sourcesContent":["// 多应用门户的进门/切换流程:登录后该直接进哪个应用、还是弹应用选择器,以及切换时清理旧应用的路由与标签。\n// enterInitial() 也是 F5/深链的恢复入口(动态路由只在内存里),路由守卫会调它。\n// 坑:权限码拉取失败时 permissionsLoaded 保持 false,v-auth 走 fail-closed 藏按钮 —— 宁可少显示,不谎报有权限。\nimport { useAuthStore } from '#/stores/auth'\nimport { useTabsStore } from '#/stores/tabs'\nimport { useUserStore } from '#/stores/user'\nimport { personalApi } from '#/api'\nimport { buildRoutesForModule } from './useAuthMenu'\nimport { router } from '#/router'\n\ntype EnterResult = { chooser: true } | { chooser: false; moduleId: number }\n\n// 进门单飞:F5/深链时守卫可能被并发导航各调一次 enterInitial,而 buildRoutesForModule 起手就 resetRouter()\n// —— 后一次会把前一次刚注册的动态路由整片摘掉,表现是偶发 404/白屏。模块级 promise 让并发合流成一次。\nlet entering: Promise<EnterResult> | null = null\n\n/** 进指定应用:重建它的动态路由。 */\nasync function enter(moduleId: number): Promise<EnterResult> {\n await buildRoutesForModule(moduleId)\n return { chooser: false, moduleId }\n}\n\n/** 门户:登录后决定直接进 / 进默认 / 弹选择器,以及切换应用。逻辑与 Naive 无关。 */\nexport function useModule() {\n const auth = useAuthStore()\n\n function enterInitial(): Promise<EnterResult> {\n entering ??= doEnterInitial().finally(() => {\n entering = null\n })\n return entering\n }\n\n async function doEnterInitial(): Promise<EnterResult> {\n // 并行拉模块 + 当前用户权限码。权限码喂 v-auth:成功(哪怕空集=超管)才标 loaded;\n // 失败不阻断进门户,但 permissionsLoaded 保持 false → v-auth fail-closed(藏按钮),不谎报\"有权限\"。\n // profile 拿超管标记喂 v-auth(只对超管 fail-open,普通用户空集则隐藏)+ 顺手回填顶栏头像;失败按普通用户处理(安全侧,不误放行)。\n const [{ modules, defaultModuleId }, perm, profile] = await Promise.all([\n personalApi.modules(),\n personalApi\n .permissions()\n .then(codes => ({ ok: true, codes }))\n .catch(() => ({ ok: false, codes: [] as string[] })),\n personalApi\n .profile()\n .then(p => ({ sadm: p.isSuperAdmin, avatar: p.avatar ?? null }))\n .catch(() => ({ sadm: useUserStore().userInfo?.isSuperAdmin ?? false, avatar: null })),\n ])\n auth.modules = modules\n auth.defaultModuleId = defaultModuleId ?? null\n auth.permissionCodes = perm.codes\n auth.permissionsLoaded = perm.ok\n auth.isSuperAdmin = profile.sadm\n // 顶栏头像:登录出参不含 avatar,这里回填(取不到按无头像处理,顶栏回落图标)\n const user = useUserStore()\n if (user.userInfo) user.userInfo.avatar = profile.avatar\n if (modules.length === 0) return { chooser: true } // 空态:选择器里提示未分配应用\n // F5/深链优先重建\"上次所在应用\"(持久化的 currentModuleId),让其动态路由复活,跨应用深链不落 404。\n const remembered = auth.currentModuleId\n if (remembered && modules.some(m => m.id === remembered)) return enter(remembered)\n if (modules.length === 1) return enter(modules[0]!.id)\n if (defaultModuleId && modules.some(m => m.id === defaultModuleId))\n return enter(defaultModuleId)\n return { chooser: true }\n }\n\n async function switchModule(moduleId: number): Promise<void> {\n await enter(moduleId)\n useTabsStore().clearTabs() // 切应用 → 标签归零(新应用路由已重建)\n router.replace(auth.homePath) // 落到新应用自己的首页\n }\n\n async function setDefault(moduleId: number): Promise<void> {\n await personalApi.setDefaultModule(moduleId)\n auth.defaultModuleId = moduleId // 本地同步,选择页角标立刻转移,不必重拉 /personal/modules\n }\n\n return { enter, enterInitial, switchModule, setDefault }\n}\n"],"names":["entering","enter","moduleId","buildRoutesForModule","useModule","auth","useAuthStore","enterInitial","doEnterInitial","modules","defaultModuleId","perm","profile","personalApi","codes","p","_a","useUserStore","user","remembered","m","switchModule","useTabsStore","router","setDefault"],"mappings":";;;;;;AAcA,IAAIA,IAAwC;AAG5C,eAAeC,EAAMC,GAAwC;AAC3D,eAAMC,EAAqBD,CAAQ,GAC5B,EAAE,SAAS,IAAO,UAAAA,EAAA;AAC3B;AAGO,SAASE,IAAY;AAC1B,QAAMC,IAAOC,EAAA;AAEb,WAASC,IAAqC;AAC5C,WAAAP,UAAaQ,IAAiB,QAAQ,MAAM;AAC1C,MAAAR,IAAW;AAAA,IACb,CAAC,IACMA;AAAA,EACT;AAEA,iBAAeQ,IAAuC;AAIpD,UAAM,CAAC,EAAE,SAAAC,GAAS,iBAAAC,EAAA,GAAmBC,GAAMC,CAAO,IAAI,MAAM,QAAQ,IAAI;AAAA,MACtEC,EAAY,QAAA;AAAA,MACZA,EACG,YAAA,EACA,KAAK,CAAAC,OAAU,EAAE,IAAI,IAAM,OAAAA,EAAA,EAAQ,EACnC,MAAM,OAAO,EAAE,IAAI,IAAO,OAAO,CAAA,IAAiB;AAAA,MACrDD,EACG,QAAA,EACA,KAAK,CAAAE,OAAM,EAAE,MAAMA,EAAE,cAAc,QAAQA,EAAE,UAAU,KAAA,EAAO,EAC9D,MAAM,MAAA;;AAAO,iBAAE,QAAMC,IAAAC,EAAA,EAAe,aAAf,gBAAAD,EAAyB,iBAAgB,IAAO,QAAQ,KAAA;AAAA,OAAO;AAAA,IAAA,CACxF;AACD,IAAAX,EAAK,UAAUI,GACfJ,EAAK,kBAAkBK,KAAmB,MAC1CL,EAAK,kBAAkBM,EAAK,OAC5BN,EAAK,oBAAoBM,EAAK,IAC9BN,EAAK,eAAeO,EAAQ;AAE5B,UAAMM,IAAOD,EAAA;AAEb,QADIC,EAAK,aAAUA,EAAK,SAAS,SAASN,EAAQ,SAC9CH,EAAQ,WAAW,EAAG,QAAO,EAAE,SAAS,GAAA;AAE5C,UAAMU,IAAad,EAAK;AACxB,WAAIc,KAAcV,EAAQ,KAAK,CAAAW,MAAKA,EAAE,OAAOD,CAAU,IAAUlB,EAAMkB,CAAU,IAC7EV,EAAQ,WAAW,IAAUR,EAAMQ,EAAQ,CAAC,EAAG,EAAE,IACjDC,KAAmBD,EAAQ,KAAK,CAAAW,MAAKA,EAAE,OAAOV,CAAe,IACxDT,EAAMS,CAAe,IACvB,EAAE,SAAS,GAAA;AAAA,EACpB;AAEA,iBAAeW,EAAanB,GAAiC;AAC3D,UAAMD,EAAMC,CAAQ,GACpBoB,EAAA,EAAe,UAAA,GACfC,EAAO,QAAQlB,EAAK,QAAQ;AAAA,EAC9B;AAEA,iBAAemB,EAAWtB,GAAiC;AACzD,UAAMW,EAAY,iBAAiBX,CAAQ,GAC3CG,EAAK,kBAAkBH;AAAA,EACzB;AAEA,SAAO,EAAE,OAAAD,GAAO,cAAAM,GAAc,cAAAc,GAAc,YAAAG,EAAA;AAC9C;"}
1
+ {"version":3,"file":"useModule.js","sources":["../../src/composables/useModule.ts"],"sourcesContent":["// 多应用门户的进门/切换流程:登录后该直接进哪个应用、还是弹应用选择器,以及切换时清理旧应用的路由与标签。\n// enterInitial() 也是 F5/深链的恢复入口(动态路由只在内存里),路由守卫会调它。\n// 坑:权限码拉取失败时 permissionsLoaded 保持 false,v-auth 走 fail-closed 藏按钮 —— 宁可少显示,不谎报有权限。\nimport { useAuthStore } from '#/stores/auth'\nimport { useTabsStore } from '#/stores/tabs'\nimport { useUserStore } from '#/stores/user'\nimport { personalApi } from '#/api'\nimport { buildRoutesForModule } from './useAuthMenu'\nimport { router } from '#/router'\n\ntype EnterResult = { chooser: true } | { chooser: false; moduleId: number }\n\n// 进门单飞:F5/深链时守卫可能被并发导航各调一次 enterInitial,而 buildRoutesForModule 起手就 resetRouter()\n// —— 后一次会把前一次刚注册的动态路由整片摘掉,表现是偶发 404/白屏。模块级 promise 让并发合流成一次。\nlet entering: Promise<EnterResult> | null = null\n\n/** 进指定应用:重建它的动态路由。 */\nasync function enter(moduleId: number): Promise<EnterResult> {\n await buildRoutesForModule(moduleId)\n return { chooser: false, moduleId }\n}\n\n/** 门户:登录后决定直接进 / 进默认 / 弹选择器,以及切换应用。逻辑与 Naive 无关。 */\nexport function useModule() {\n const auth = useAuthStore()\n\n function enterInitial(): Promise<EnterResult> {\n entering ??= doEnterInitial().finally(() => {\n entering = null\n })\n return entering\n }\n\n async function doEnterInitial(): Promise<EnterResult> {\n // 并行拉模块 + 当前用户权限码。权限码喂 v-auth:成功(哪怕空集=超管)才标 loaded;\n // 失败不阻断进门户,但 permissionsLoaded 保持 false → v-auth fail-closed(藏按钮),不谎报\"有权限\"。\n // profile 拿超管标记喂 v-auth(只对超管 fail-open,普通用户空集则隐藏)+ 顺手回填顶栏头像;失败按普通用户处理(安全侧,不误放行)。\n const [{ modules, defaultModuleId }, perm, profile] = await Promise.all([\n personalApi.modules(),\n personalApi\n .permissions()\n .then(codes => ({ ok: true, codes }))\n .catch(() => ({ ok: false, codes: [] as string[] })),\n personalApi\n .profile()\n .then(p => ({\n sadm: p.isSuperAdmin,\n avatar: p.avatar ?? null,\n orgName: p.orgName ?? null,\n phoneTail: p.phone ? p.phone.slice(-4) : null,\n }))\n .catch(() => ({\n sadm: useUserStore().userInfo?.isSuperAdmin ?? false,\n avatar: null,\n orgName: null,\n phoneTail: null,\n })),\n ])\n auth.modules = modules\n auth.defaultModuleId = defaultModuleId ?? null\n auth.permissionCodes = perm.codes\n auth.permissionsLoaded = perm.ok\n auth.isSuperAdmin = profile.sadm\n // 顶栏头像:登录出参不含 avatar,这里回填(取不到按无头像处理,顶栏回落图标)\n const user = useUserStore()\n if (user.userInfo) {\n user.userInfo.avatar = profile.avatar\n user.userInfo.orgName = profile.orgName // 水印要印机构和手机尾号,同样只有 profile 里有\n user.userInfo.phoneTail = profile.phoneTail\n }\n if (modules.length === 0) return { chooser: true } // 空态:选择器里提示未分配应用\n // F5/深链优先重建\"上次所在应用\"(持久化的 currentModuleId),让其动态路由复活,跨应用深链不落 404。\n const remembered = auth.currentModuleId\n if (remembered && modules.some(m => m.id === remembered)) return enter(remembered)\n if (modules.length === 1) return enter(modules[0]!.id)\n if (defaultModuleId && modules.some(m => m.id === defaultModuleId))\n return enter(defaultModuleId)\n return { chooser: true }\n }\n\n async function switchModule(moduleId: number): Promise<void> {\n await enter(moduleId)\n useTabsStore().clearTabs() // 切应用 → 标签归零(新应用路由已重建)\n router.replace(auth.homePath) // 落到新应用自己的首页\n }\n\n async function setDefault(moduleId: number): Promise<void> {\n await personalApi.setDefaultModule(moduleId)\n auth.defaultModuleId = moduleId // 本地同步,选择页角标立刻转移,不必重拉 /personal/modules\n }\n\n return { enter, enterInitial, switchModule, setDefault }\n}\n"],"names":["entering","enter","moduleId","buildRoutesForModule","useModule","auth","useAuthStore","enterInitial","doEnterInitial","modules","defaultModuleId","perm","profile","personalApi","codes","p","_a","useUserStore","user","remembered","m","switchModule","useTabsStore","router","setDefault"],"mappings":";;;;;;AAcA,IAAIA,IAAwC;AAG5C,eAAeC,EAAMC,GAAwC;AAC3D,eAAMC,EAAqBD,CAAQ,GAC5B,EAAE,SAAS,IAAO,UAAAA,EAAA;AAC3B;AAGO,SAASE,IAAY;AAC1B,QAAMC,IAAOC,EAAA;AAEb,WAASC,IAAqC;AAC5C,WAAAP,UAAaQ,IAAiB,QAAQ,MAAM;AAC1C,MAAAR,IAAW;AAAA,IACb,CAAC,IACMA;AAAA,EACT;AAEA,iBAAeQ,IAAuC;AAIpD,UAAM,CAAC,EAAE,SAAAC,GAAS,iBAAAC,EAAA,GAAmBC,GAAMC,CAAO,IAAI,MAAM,QAAQ,IAAI;AAAA,MACtEC,EAAY,QAAA;AAAA,MACZA,EACG,YAAA,EACA,KAAK,CAAAC,OAAU,EAAE,IAAI,IAAM,OAAAA,EAAA,EAAQ,EACnC,MAAM,OAAO,EAAE,IAAI,IAAO,OAAO,CAAA,IAAiB;AAAA,MACrDD,EACG,QAAA,EACA,KAAK,CAAAE,OAAM;AAAA,QACV,MAAMA,EAAE;AAAA,QACR,QAAQA,EAAE,UAAU;AAAA,QACpB,SAASA,EAAE,WAAW;AAAA,QACtB,WAAWA,EAAE,QAAQA,EAAE,MAAM,MAAM,EAAE,IAAI;AAAA,MAAA,EACzC,EACD,MAAM,MAAA;;AAAO;AAAA,UACZ,QAAMC,IAAAC,EAAA,EAAe,aAAf,gBAAAD,EAAyB,iBAAgB;AAAA,UAC/C,QAAQ;AAAA,UACR,SAAS;AAAA,UACT,WAAW;AAAA,QAAA;AAAA,OACX;AAAA,IAAA,CACL;AACD,IAAAX,EAAK,UAAUI,GACfJ,EAAK,kBAAkBK,KAAmB,MAC1CL,EAAK,kBAAkBM,EAAK,OAC5BN,EAAK,oBAAoBM,EAAK,IAC9BN,EAAK,eAAeO,EAAQ;AAE5B,UAAMM,IAAOD,EAAA;AAMb,QALIC,EAAK,aACPA,EAAK,SAAS,SAASN,EAAQ,QAC/BM,EAAK,SAAS,UAAUN,EAAQ,SAChCM,EAAK,SAAS,YAAYN,EAAQ,YAEhCH,EAAQ,WAAW,EAAG,QAAO,EAAE,SAAS,GAAA;AAE5C,UAAMU,IAAad,EAAK;AACxB,WAAIc,KAAcV,EAAQ,KAAK,CAAAW,MAAKA,EAAE,OAAOD,CAAU,IAAUlB,EAAMkB,CAAU,IAC7EV,EAAQ,WAAW,IAAUR,EAAMQ,EAAQ,CAAC,EAAG,EAAE,IACjDC,KAAmBD,EAAQ,KAAK,CAAAW,MAAKA,EAAE,OAAOV,CAAe,IACxDT,EAAMS,CAAe,IACvB,EAAE,SAAS,GAAA;AAAA,EACpB;AAEA,iBAAeW,EAAanB,GAAiC;AAC3D,UAAMD,EAAMC,CAAQ,GACpBoB,EAAA,EAAe,UAAA,GACfC,EAAO,QAAQlB,EAAK,QAAQ;AAAA,EAC9B;AAEA,iBAAemB,EAAWtB,GAAiC;AACzD,UAAMW,EAAY,iBAAiBX,CAAQ,GAC3CG,EAAK,kBAAkBH;AAAA,EACzB;AAEA,SAAO,EAAE,OAAAD,GAAO,cAAAM,GAAc,cAAAc,GAAc,YAAAG,EAAA;AAC9C;"}
@@ -1,20 +1,22 @@
1
- import { watchEffect as n } from "vue";
1
+ import { watchEffect as i } from "vue";
2
2
  import { useRoute as c } from "vue-router";
3
3
  import { useAppStore as l } from "../stores/app.js";
4
- import { useTabsStore as p } from "../stores/tabs.js";
5
- import { useSite as u } from "./useSite.js";
6
- import { translateMenuTitle as f } from "../locales/menuTitle.js";
7
- function w() {
8
- const e = c(), o = l(), s = p(), { site: i } = u();
9
- n(() => {
10
- o.locale;
11
- const t = s.tabs.find((a) => a.path === e.path), r = (t == null ? void 0 : t.titleFixed) && t.title || e.meta.title || "", m = r ? f(r, e.path) : "";
12
- document.title = m ? `${m} · ${i.title}` : i.title;
13
- }), n(() => {
14
- document.documentElement.lang = o.locale;
15
- });
4
+ import { useTabsStore as s } from "../stores/tabs.js";
5
+ import { useSite as f } from "./useSite.js";
6
+ import { translateMenuTitle as u } from "../locales/menuTitle.js";
7
+ import { applyFavicon as d } from "../lib/favicon.js";
8
+ import { runtime as g } from "../lib/runtime.js";
9
+ function E() {
10
+ const o = c(), r = l(), a = s(), { site: e } = f();
11
+ i(() => {
12
+ r.locale;
13
+ const t = a.tabs.find((p) => p.path === o.path), m = (t == null ? void 0 : t.titleFixed) && t.title || o.meta.title || "", n = m ? u(m, o.path) : "";
14
+ document.title = n ? `${n} · ${e.title}` : e.title;
15
+ }), i(() => {
16
+ document.documentElement.lang = r.locale;
17
+ }), g.brand.faviconFromLogo !== !1 && i(() => d(document, e.logo));
16
18
  }
17
19
  export {
18
- w as usePageTitle
20
+ E as usePageTitle
19
21
  };
20
22
  //# sourceMappingURL=usePageTitle.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"usePageTitle.js","sources":["../../src/composables/usePageTitle.ts"],"sourcesContent":["// 浏览器标题与文档语言。App.vue 调一次即可。\n//\n// 不这样动态维护的话,document.title 只会在启动时被站点名设一次,收藏夹/多窗口/历史记录里所有页面会长得一模一样;\n// <html lang> 也会硬编成 zh-CN,读屏器与浏览器翻译在英文界面下判错语言。\nimport { watchEffect } from 'vue'\nimport { useRoute } from 'vue-router'\nimport { useAppStore } from '#/stores/app'\nimport { useTabsStore } from '#/stores/tabs'\nimport { useSite } from '#/composables/useSite'\nimport { translateMenuTitle } from '#/locales/menuTitle'\n\nexport function usePageTitle(): void {\n const route = useRoute()\n const app = useAppStore()\n const tabs = useTabsStore()\n const { site } = useSite()\n\n watchEffect(() => {\n void app.locale // 依赖:切语言后 i18n key 标题要重算\n // 详情页用 useTabTitle 设过动态标题(记录名)时以它为准 —— 静态 meta.title 是「详情」这种通名。\n const tab = tabs.tabs.find(x => x.path === route.path)\n const raw = (tab?.titleFixed && tab.title) || (route.meta.title as string | undefined) || ''\n const page = raw ? translateMenuTitle(raw, route.path) : ''\n document.title = page ? `${page} · ${site.title}` : site.title\n })\n\n watchEffect(() => {\n document.documentElement.lang = app.locale\n })\n}\n"],"names":["usePageTitle","route","useRoute","app","useAppStore","tabs","useTabsStore","site","useSite","watchEffect","tab","x","raw","page","translateMenuTitle"],"mappings":";;;;;;AAWO,SAASA,IAAqB;AACnC,QAAMC,IAAQC,EAAA,GACRC,IAAMC,EAAA,GACNC,IAAOC,EAAA,GACP,EAAE,MAAAC,EAAA,IAASC,EAAA;AAEjB,EAAAC,EAAY,MAAM;AAChB,IAAKN,EAAI;AAET,UAAMO,IAAML,EAAK,KAAK,KAAK,OAAKM,EAAE,SAASV,EAAM,IAAI,GAC/CW,KAAOF,KAAA,gBAAAA,EAAK,eAAcA,EAAI,SAAWT,EAAM,KAAK,SAAgC,IACpFY,IAAOD,IAAME,EAAmBF,GAAKX,EAAM,IAAI,IAAI;AACzD,aAAS,QAAQY,IAAO,GAAGA,CAAI,MAAMN,EAAK,KAAK,KAAKA,EAAK;AAAA,EAC3D,CAAC,GAEDE,EAAY,MAAM;AAChB,aAAS,gBAAgB,OAAON,EAAI;AAAA,EACtC,CAAC;AACH;"}
1
+ {"version":3,"file":"usePageTitle.js","sources":["../../src/composables/usePageTitle.ts"],"sourcesContent":["// 浏览器标题、标签页图标与文档语言。App.vue 调一次即可。\n//\n// 不这样动态维护的话,document.title 只会在启动时被站点名设一次,收藏夹/多窗口/历史记录里所有页面会长得一模一样;\n// <html lang> 也会硬编成 zh-CN,读屏器与浏览器翻译在英文界面下判错语言。\nimport { watchEffect } from 'vue'\nimport { useRoute } from 'vue-router'\nimport { useAppStore } from '#/stores/app'\nimport { useTabsStore } from '#/stores/tabs'\nimport { useSite } from '#/composables/useSite'\nimport { translateMenuTitle } from '#/locales/menuTitle'\nimport { applyFavicon } from '#/lib/favicon'\nimport { runtime } from '#/lib/runtime'\n\nexport function usePageTitle(): void {\n const route = useRoute()\n const app = useAppStore()\n const tabs = useTabsStore()\n const { site } = useSite()\n\n watchEffect(() => {\n void app.locale // 依赖:切语言后 i18n key 标题要重算\n // 详情页用 useTabTitle 设过动态标题(记录名)时以它为准 —— 静态 meta.title 是「详情」这种通名。\n const tab = tabs.tabs.find(x => x.path === route.path)\n const raw = (tab?.titleFixed && tab.title) || (route.meta.title as string | undefined) || ''\n const page = raw ? translateMenuTitle(raw, route.path) : ''\n document.title = page ? `${page} · ${site.title}` : site.title\n })\n\n watchEffect(() => {\n document.documentElement.lang = app.locale\n })\n\n // 标签页图标跟随站点 Logo(配置中心换 Logo 保存后 loadSite(true) 即时换掉);消费方可经 brand.faviconFromLogo 关掉\n if (runtime.brand.faviconFromLogo !== false) watchEffect(() => applyFavicon(document, site.logo))\n}\n"],"names":["usePageTitle","route","useRoute","app","useAppStore","tabs","useTabsStore","site","useSite","watchEffect","tab","x","raw","page","translateMenuTitle","runtime","applyFavicon"],"mappings":";;;;;;;;AAaO,SAASA,IAAqB;AACnC,QAAMC,IAAQC,EAAA,GACRC,IAAMC,EAAA,GACNC,IAAOC,EAAA,GACP,EAAE,MAAAC,EAAA,IAASC,EAAA;AAEjB,EAAAC,EAAY,MAAM;AAChB,IAAKN,EAAI;AAET,UAAMO,IAAML,EAAK,KAAK,KAAK,OAAKM,EAAE,SAASV,EAAM,IAAI,GAC/CW,KAAOF,KAAA,gBAAAA,EAAK,eAAcA,EAAI,SAAWT,EAAM,KAAK,SAAgC,IACpFY,IAAOD,IAAME,EAAmBF,GAAKX,EAAM,IAAI,IAAI;AACzD,aAAS,QAAQY,IAAO,GAAGA,CAAI,MAAMN,EAAK,KAAK,KAAKA,EAAK;AAAA,EAC3D,CAAC,GAEDE,EAAY,MAAM;AAChB,aAAS,gBAAgB,OAAON,EAAI;AAAA,EACtC,CAAC,GAGGY,EAAQ,MAAM,oBAAoB,MAAON,EAAY,MAAMO,EAAa,UAAUT,EAAK,IAAI,CAAC;AAClG;"}
@@ -0,0 +1,19 @@
1
+ import { Ref } from 'vue';
2
+ export type ShellBreakpoint = 'wide' | 'mid' | 'narrow';
3
+ /** 壳层 narrow 的上界(不含)。与表格窄档 600 对齐,见文件头。 */
4
+ export declare const SHELL_NARROW_MAX = 600;
5
+ /** 壳层 wide 的下界(含)。 */
6
+ export declare const SHELL_WIDE_MIN = 1400;
7
+ /** 带左侧面板的页面:内容区窄于此值时面板收进抽屉。 */
8
+ export declare const SHELL_PANEL_DRAWER_MAX = 1000;
9
+ /** 纯判定,便于单测。 */
10
+ export declare function shellBreakpointOf(width: number): ShellBreakpoint;
11
+ export interface ShellBreakpointState {
12
+ /** 内容区(`.page` content box)宽度,px */
13
+ width: Ref<number>;
14
+ bp: Readonly<Ref<ShellBreakpoint>>;
15
+ }
16
+ /** 壳层调用:盯住 el 的 content box,把 { width, bp } 提供给后代。 */
17
+ export declare function provideShellBreakpoint(el: Ref<HTMLElement | undefined>): ShellBreakpointState;
18
+ /** 页面 / 组件调用:取壳层档位。壳层之外退回视口宽度(近似,够单测与独立挂载用)。 */
19
+ export declare function useShellBreakpoint(): ShellBreakpointState;
@@ -0,0 +1,37 @@
1
+ import { inject as v, computed as c, ref as h, provide as w, watch as m, onScopeDispose as S } from "vue";
2
+ import { useWindowSize as b } from "@vueuse/core";
3
+ const R = 600, l = 1400;
4
+ function u(t) {
5
+ return t >= l ? "wide" : t >= R ? "mid" : "narrow";
6
+ }
7
+ const p = Symbol("shellBreakpoint");
8
+ function E(t) {
9
+ const n = h(l), d = c(() => u(n.value)), o = { width: n, bp: d };
10
+ w(p, o);
11
+ let e;
12
+ return m(
13
+ t,
14
+ (i, _, f) => {
15
+ !i || typeof ResizeObserver > "u" || (e = new ResizeObserver((a) => {
16
+ var s;
17
+ const r = (s = a[0]) == null ? void 0 : s.contentRect.width;
18
+ r !== void 0 && (n.value = r);
19
+ }), e.observe(i), f(() => e == null ? void 0 : e.disconnect()));
20
+ },
21
+ { flush: "post" }
22
+ ), S(() => e == null ? void 0 : e.disconnect()), o;
23
+ }
24
+ function L() {
25
+ const t = v(p, null);
26
+ if (t) return t;
27
+ const { width: n } = b();
28
+ return { width: n, bp: c(() => u(n.value)) };
29
+ }
30
+ export {
31
+ R as SHELL_NARROW_MAX,
32
+ l as SHELL_WIDE_MIN,
33
+ E as provideShellBreakpoint,
34
+ u as shellBreakpointOf,
35
+ L as useShellBreakpoint
36
+ };
37
+ //# sourceMappingURL=useShellBreakpoint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useShellBreakpoint.js","sources":["../../src/composables/useShellBreakpoint.ts"],"sourcesContent":["// 壳层档位:按「内容区」宽度判(不是视口),侧栏展开 / 收起、抽屉开合都会改变档位。\n//\n// wide ≥ 1400 统计卡等页面栅格铺开\n// mid 600–1399 栅格收窄;带左侧面板的页面在内容区 < 1000 时面板收进抽屉\n// narrow < 600 整页自然滚动,不锁一屏高度;统计卡两列;设置行上下排\n//\n// 阈值 600 = smart-naive-table 的窄档(表格根节点宽 < 600 换卡片)。壳层 narrow 必须和它对齐:\n// 壳层进入「整页自然滚动」时表格一定已是卡片列表;壳层不是 narrow 时表格一定仍是表格。\n// 两层阈值错开会出现一段宽度:页面不定高、表格却还在 fill-height,表体塌成最小高度。\n// 阈值直接取 600:量的是 `.page` 的 content box(ResizeObserver 的 contentRect 本身已扣掉内边距),\n// 留白不进数字,日后改 `.page` 的内边距不用回来改阈值。\n//\n// 用法:default.vue 调 provideShellBreakpoint(el) 绑定被量的元素;页面里调 useShellBreakpoint()\n// 取 { bp, width }(没有壳层时,如单测或独立挂载,退回按视口宽度估算)。\nimport {\n computed,\n inject,\n onScopeDispose,\n provide,\n ref,\n watch,\n type InjectionKey,\n type Ref,\n} from 'vue'\nimport { useWindowSize } from '@vueuse/core'\n\nexport type ShellBreakpoint = 'wide' | 'mid' | 'narrow'\n\n/** 壳层 narrow 的上界(不含)。与表格窄档 600 对齐,见文件头。 */\nexport const SHELL_NARROW_MAX = 600\n/** 壳层 wide 的下界(含)。 */\nexport const SHELL_WIDE_MIN = 1400\n/** 带左侧面板的页面:内容区窄于此值时面板收进抽屉。 */\nexport const SHELL_PANEL_DRAWER_MAX = 1000\n\n/** 纯判定,便于单测。 */\nexport function shellBreakpointOf(width: number): ShellBreakpoint {\n return width >= SHELL_WIDE_MIN ? 'wide' : width >= SHELL_NARROW_MAX ? 'mid' : 'narrow'\n}\n\nexport interface ShellBreakpointState {\n /** 内容区(`.page` content box)宽度,px */\n width: Ref<number>\n bp: Readonly<Ref<ShellBreakpoint>>\n}\n\nconst KEY: InjectionKey<ShellBreakpointState> = Symbol('shellBreakpoint')\n\n/** 壳层调用:盯住 el 的 content box,把 { width, bp } 提供给后代。 */\nexport function provideShellBreakpoint(el: Ref<HTMLElement | undefined>): ShellBreakpointState {\n const width = ref(SHELL_WIDE_MIN) // 首帧按宽档,避免挂载瞬间闪一下 narrow 的自然滚动布局\n const bp = computed(() => shellBreakpointOf(width.value))\n const state: ShellBreakpointState = { width, bp }\n provide(KEY, state)\n\n let ro: ResizeObserver | undefined\n watch(\n el,\n (node, _old, onCleanup) => {\n if (!node || typeof ResizeObserver === 'undefined') return\n ro = new ResizeObserver(entries => {\n const w = entries[0]?.contentRect.width\n if (w !== undefined) width.value = w\n })\n ro.observe(node)\n onCleanup(() => ro?.disconnect())\n },\n { flush: 'post' },\n )\n onScopeDispose(() => ro?.disconnect())\n return state\n}\n\n/** 页面 / 组件调用:取壳层档位。壳层之外退回视口宽度(近似,够单测与独立挂载用)。 */\nexport function useShellBreakpoint(): ShellBreakpointState {\n const injected = inject(KEY, null)\n if (injected) return injected\n const { width } = useWindowSize()\n return { width, bp: computed(() => shellBreakpointOf(width.value)) }\n}\n"],"names":["SHELL_NARROW_MAX","SHELL_WIDE_MIN","shellBreakpointOf","width","KEY","provideShellBreakpoint","el","ref","bp","computed","state","provide","ro","watch","node","_old","onCleanup","entries","w","_a","onScopeDispose","useShellBreakpoint","injected","inject","useWindowSize"],"mappings":";;AA6BO,MAAMA,IAAmB,KAEnBC,IAAiB;AAKvB,SAASC,EAAkBC,GAAgC;AAChE,SAAOA,KAASF,IAAiB,SAASE,KAASH,IAAmB,QAAQ;AAChF;AAQA,MAAMI,IAA0C,OAAO,iBAAiB;AAGjE,SAASC,EAAuBC,GAAwD;AAC7F,QAAMH,IAAQI,EAAIN,CAAc,GAC1BO,IAAKC,EAAS,MAAMP,EAAkBC,EAAM,KAAK,CAAC,GAClDO,IAA8B,EAAE,OAAAP,GAAO,IAAAK,EAAA;AAC7C,EAAAG,EAAQP,GAAKM,CAAK;AAElB,MAAIE;AACJ,SAAAC;AAAA,IACEP;AAAA,IACA,CAACQ,GAAMC,GAAMC,MAAc;AACzB,MAAI,CAACF,KAAQ,OAAO,iBAAmB,QACvCF,IAAK,IAAI,eAAe,CAAAK,MAAW;;AACjC,cAAMC,KAAIC,IAAAF,EAAQ,CAAC,MAAT,gBAAAE,EAAY,YAAY;AAClC,QAAID,MAAM,WAAWf,EAAM,QAAQe;AAAA,MACrC,CAAC,GACDN,EAAG,QAAQE,CAAI,GACfE,EAAU,MAAMJ,KAAA,gBAAAA,EAAI,YAAY;AAAA,IAClC;AAAA,IACA,EAAE,OAAO,OAAA;AAAA,EAAO,GAElBQ,EAAe,MAAMR,KAAA,gBAAAA,EAAI,YAAY,GAC9BF;AACT;AAGO,SAASW,IAA2C;AACzD,QAAMC,IAAWC,EAAOnB,GAAK,IAAI;AACjC,MAAIkB,EAAU,QAAOA;AACrB,QAAM,EAAE,OAAAnB,EAAA,IAAUqB,EAAA;AAClB,SAAO,EAAE,OAAArB,GAAO,IAAIM,EAAS,MAAMP,EAAkBC,EAAM,KAAK,CAAC,EAAA;AACnE;"}
@@ -1,11 +1,17 @@
1
+ import { LoginHeroCopy } from '../lib/loginHero';
2
+ import { WatermarkSettings } from '../lib/watermark';
1
3
  export interface SiteInfo {
2
4
  title: string;
3
5
  subtitle: string;
4
6
  copyright: string;
5
7
  copyrightUrl: string;
6
8
  logo: string;
9
+ loginHero: Record<string, LoginHeroCopy>;
10
+ showFeatures: boolean;
7
11
  captchaEnabled: boolean;
8
12
  smsLoginEnabled: boolean;
13
+ /** 登录后页面的水印设置(只有版式;每个人印什么由壳层按登录用户拼) */
14
+ watermark: WatermarkSettings;
9
15
  }
10
16
  export declare function loadSite(force?: boolean): Promise<void>;
11
17
  /** 版本号不走后端配置:默认是内核版本(库构建期常量),消费方经 createSmartAdmin({ version }) 换成应用版本。 */
@@ -16,8 +22,22 @@ export declare function useSite(): {
16
22
  copyright: string;
17
23
  copyrightUrl: string;
18
24
  logo: string;
25
+ loginHero: Record<string, LoginHeroCopy>;
26
+ showFeatures: boolean;
19
27
  captchaEnabled: boolean;
20
28
  smsLoginEnabled: boolean;
29
+ watermark: {
30
+ enabled: boolean;
31
+ fields: import('../lib/watermark').WatermarkField[];
32
+ text: string;
33
+ timeFormat: import('../lib/watermark').WatermarkTimeFormat;
34
+ layout: import('../lib/watermark').WatermarkLayout;
35
+ fontSize: number;
36
+ opacity: number;
37
+ rotate: number;
38
+ density: import('../lib/watermark').WatermarkDensity;
39
+ cross: boolean;
40
+ };
21
41
  };
22
42
  appVersion: string;
23
43
  loadSite: typeof loadSite;