xto-fronted 0.4.86 → 0.4.88

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 (319) hide show
  1. package/dist/assets/404-C9Uh6Uu-.css +1 -0
  2. package/dist/assets/404-zjGLLssH.js +1 -0
  3. package/dist/assets/index-B5xc4gQB.css +1 -0
  4. package/dist/assets/index-BDgOY6Rp.js +1 -0
  5. package/dist/assets/index-BIoRANs0.js +1 -0
  6. package/dist/assets/index-Bz0BgZQ1.js +1 -0
  7. package/dist/assets/index-CAdztNsv.css +1 -0
  8. package/dist/assets/index-CCXrcISf.css +1 -0
  9. package/dist/assets/{index-eQ-JQMk3.css → index-CfpZmcpk.css} +1 -1
  10. package/dist/assets/index-CwJSA85U.js +1 -0
  11. package/dist/assets/index-CwRA10ac.js +1 -0
  12. package/dist/assets/index-D8NDxq9d.js +1 -0
  13. package/dist/assets/index-DEB6-Iv_.js +2 -0
  14. package/dist/assets/index-DM4Ezclc.css +1 -0
  15. package/dist/assets/index-DYv7nImj.css +1 -0
  16. package/dist/assets/index-t-2Y0KhA.css +1 -0
  17. package/dist/assets/vendor-CUVPinTg.js +13 -0
  18. package/dist/assets/{vue-vendor-05sbU7Th.js → vue-vendor-DeJXJVbN.js} +7 -7
  19. package/dist/assets/{xto-base-BSTP-Yn2.js → xto-base-PwLGsxxb.js} +1 -1
  20. package/dist/assets/{xto-core-cL8BAdce.js → xto-core-CtL4zKiV.js} +1 -1
  21. package/dist/assets/{xto-data-Cw0dv5K5.js → xto-data-bCXQa7fT.js} +1 -1
  22. package/dist/assets/{xto-feedback-CTk0sMCW.js → xto-feedback-CPydp0kn.js} +1 -1
  23. package/dist/assets/{xto-form-C5i2lk3C.js → xto-form-bywohdAf.js} +1 -1
  24. package/dist/assets/{xto-navigation-DHsTg0WG.js → xto-navigation-Bbdpine9.js} +1 -1
  25. package/dist/composables/useI18n.d.ts +30 -0
  26. package/dist/index-BRvi9qW-.js +515 -0
  27. package/dist/index-Bmf0YbVq.js +189 -0
  28. package/dist/index-C2-a5KSQ.js +4233 -0
  29. package/dist/index-D25KzR0I.js +479 -0
  30. package/dist/index-DEYOivza.js +641 -0
  31. package/dist/index.d.ts +5 -0
  32. package/dist/index.es.js +64 -61
  33. package/dist/index.html +9 -9
  34. package/dist/index.umd.js +8 -1
  35. package/dist/stores/index.d.ts +1 -0
  36. package/dist/stores/locale.d.ts +42 -0
  37. package/dist/style.css +1 -1
  38. package/package.json +7 -3
  39. package/src/App.vue +48 -19
  40. package/src/assets/styles/_root.scss +183 -139
  41. package/src/assets/styles/_variables.scss +70 -45
  42. package/src/assets/styles/index.scss +267 -42
  43. package/src/components/Layout/Sidebar.vue +43 -2
  44. package/src/components/Layout/TopMenu.vue +37 -12
  45. package/src/components/Layout/index.vue +1 -0
  46. package/src/composables/useI18n.ts +44 -0
  47. package/src/index.ts +15 -1
  48. package/src/stores/index.ts +2 -1
  49. package/src/stores/locale.ts +67 -0
  50. package/src/types/json-bigint.d.ts +18 -0
  51. package/src/types/xto.d.ts +24 -0
  52. package/src/utils/request.ts +18 -1
  53. package/src/views/dashboard/index.vue +545 -283
  54. package/src/views/error/403.vue +215 -20
  55. package/src/views/error/404.vue +217 -20
  56. package/src/views/login/index.vue +483 -91
  57. package/src/views/system/menu/index.vue +690 -381
  58. package/src/views/system/role/index.vue +583 -304
  59. package/src/views/system/user/index.vue +655 -326
  60. package/dist/assets/404-BNfk6aVM.js +0 -1
  61. package/dist/assets/404-ByYjFnhI.js +0 -1
  62. package/dist/assets/404-CH5_LdtS.css +0 -1
  63. package/dist/assets/404-sqW80Hc-.css +0 -1
  64. package/dist/assets/index-BBhC8PX4.js +0 -1
  65. package/dist/assets/index-BOEFG4lP.css +0 -1
  66. package/dist/assets/index-BSa4SMHI.js +0 -1
  67. package/dist/assets/index-BihVoviB.js +0 -1
  68. package/dist/assets/index-Bmux4tGG.js +0 -1
  69. package/dist/assets/index-BrvR0Fn_.css +0 -1
  70. package/dist/assets/index-C4ZCZoPp.js +0 -1
  71. package/dist/assets/index-CMgRqiaT.js +0 -1
  72. package/dist/assets/index-CUh_s55Z.css +0 -1
  73. package/dist/assets/index-CV768Wu1.js +0 -1
  74. package/dist/assets/index-D0OnMilp.js +0 -1
  75. package/dist/assets/index-D9wlAuR_.js +0 -1
  76. package/dist/assets/index-DPkO-STg.js +0 -1
  77. package/dist/assets/index-DawJb02s.css +0 -1
  78. package/dist/assets/index-DcFOybjo.js +0 -1
  79. package/dist/assets/index-DiHSZ6SJ.js +0 -2
  80. package/dist/assets/index-GDP-IkXE.css +0 -1
  81. package/dist/assets/index-Gx75raue.js +0 -2
  82. package/dist/assets/index-JsZ6rkQj.js +0 -1
  83. package/dist/assets/index-PfV8pzQz.css +0 -1
  84. package/dist/assets/index-Swfu6yvD.css +0 -1
  85. package/dist/assets/vendor-42ANG6Sg.js +0 -6
  86. package/dist/assets/vite-Dw-pgLOX.js +0 -1
  87. package/dist/assets/vue-vendor-Br-l7wbK.js +0 -29
  88. package/dist/assets/xto-base-C-IBqjVs.js +0 -1
  89. package/dist/assets/xto-base-C6eqMPdO.css +0 -1
  90. package/dist/assets/xto-core-DZK7Cyg0.js +0 -1
  91. package/dist/assets/xto-data-BFpiDgJi.js +0 -1
  92. package/dist/assets/xto-data-CnAQAQH2.css +0 -1
  93. package/dist/assets/xto-feedback-B2M02fn3.js +0 -1
  94. package/dist/assets/xto-feedback-ByaS-C7_.css +0 -1
  95. package/dist/assets/xto-form-CrsyAjyr.css +0 -1
  96. package/dist/assets/xto-form-NRjKKNcY.js +0 -1
  97. package/dist/assets/xto-layout-D1stVnJI.css +0 -1
  98. package/dist/assets/xto-navigation-BuRQVoD8.css +0 -1
  99. package/dist/assets/xto-navigation-qLRTxo68.js +0 -1
  100. package/dist/index-0h_oG71z.js +0 -345
  101. package/dist/index-1EEezXR3.js +0 -142
  102. package/dist/index-1EkaJDoD.js +0 -142
  103. package/dist/index-1VN-SSaj.js +0 -2873
  104. package/dist/index-23nX2t9j.js +0 -142
  105. package/dist/index-2RwL0s53.js +0 -142
  106. package/dist/index-2tvOdd6w.js +0 -372
  107. package/dist/index-3zeoNaqT.js +0 -345
  108. package/dist/index-8oCLh51t.js +0 -475
  109. package/dist/index-AF5JN8Up.js +0 -142
  110. package/dist/index-B02xiP9g.js +0 -372
  111. package/dist/index-B05xso4D.js +0 -345
  112. package/dist/index-B1VS4tRU.js +0 -475
  113. package/dist/index-B3_VQZ-d.js +0 -372
  114. package/dist/index-B3kL6i_g.js +0 -345
  115. package/dist/index-B4Wny0vt.js +0 -345
  116. package/dist/index-B5RdBQ-f.js +0 -475
  117. package/dist/index-B5rbuoWS.js +0 -2835
  118. package/dist/index-BAFpPlnI.js +0 -475
  119. package/dist/index-BAJakzRz.js +0 -142
  120. package/dist/index-BAOHlfVd.js +0 -142
  121. package/dist/index-BAzJWzWG.js +0 -2852
  122. package/dist/index-BEIxh_R3.js +0 -2982
  123. package/dist/index-BEWrRNps.js +0 -475
  124. package/dist/index-BFtKVmzo.js +0 -142
  125. package/dist/index-BHPrW1wN.js +0 -142
  126. package/dist/index-BHQIqN1E.js +0 -372
  127. package/dist/index-BHZ_y8lp.js +0 -2067
  128. package/dist/index-BHvnTk5Z.js +0 -475
  129. package/dist/index-BIf7CYCW.js +0 -475
  130. package/dist/index-BK1Y1z9_.js +0 -142
  131. package/dist/index-BK8qDl14.js +0 -372
  132. package/dist/index-BKnta6nv.js +0 -372
  133. package/dist/index-BLIem13z.js +0 -345
  134. package/dist/index-BNBv_FCu.js +0 -142
  135. package/dist/index-BNwtCm83.js +0 -345
  136. package/dist/index-BOEMA7WH.js +0 -345
  137. package/dist/index-BOwDukt-.js +0 -2346
  138. package/dist/index-BR9WVjrV.js +0 -2851
  139. package/dist/index-BRMkw154.js +0 -475
  140. package/dist/index-BRQBannD.js +0 -345
  141. package/dist/index-BShKtLTm.js +0 -475
  142. package/dist/index-BVpqTdd2.js +0 -3132
  143. package/dist/index-BWGQANAN.js +0 -2851
  144. package/dist/index-BZKw7U60.js +0 -475
  145. package/dist/index-BadGWG4q.js +0 -475
  146. package/dist/index-BbeWpCd3.js +0 -345
  147. package/dist/index-BeUYNx5P.js +0 -475
  148. package/dist/index-BgiGtxRr.js +0 -142
  149. package/dist/index-BhKJLk9M.js +0 -2824
  150. package/dist/index-BijsKQ3r.js +0 -475
  151. package/dist/index-BjEfspqP.js +0 -475
  152. package/dist/index-BjEnT8WQ.js +0 -372
  153. package/dist/index-BpOcz1m4.js +0 -142
  154. package/dist/index-BrRdLbLB.js +0 -142
  155. package/dist/index-BsHOXfCq.js +0 -372
  156. package/dist/index-Bt5ocakb.js +0 -475
  157. package/dist/index-BtE24Mt4.js +0 -142
  158. package/dist/index-BvcBQjw6.js +0 -2836
  159. package/dist/index-C0krZRWf.js +0 -2859
  160. package/dist/index-C1cKUqmA.js +0 -372
  161. package/dist/index-C3ANmIDM.js +0 -475
  162. package/dist/index-C5JrEkwD.js +0 -345
  163. package/dist/index-C5m4qNMQ.js +0 -2851
  164. package/dist/index-C69vu_ot.js +0 -3147
  165. package/dist/index-C6Um6eFy.js +0 -475
  166. package/dist/index-C75ePQYC.js +0 -372
  167. package/dist/index-C7wKLGhC.js +0 -142
  168. package/dist/index-C8DBDnxx.js +0 -2836
  169. package/dist/index-CAnqlIjX.js +0 -475
  170. package/dist/index-CB36fztK.js +0 -345
  171. package/dist/index-CBKo6Enz.js +0 -345
  172. package/dist/index-CBcuyFIa.js +0 -2326
  173. package/dist/index-CCxIu4ex.js +0 -372
  174. package/dist/index-CD1ZEMzL.js +0 -2836
  175. package/dist/index-CDx-6tvY.js +0 -345
  176. package/dist/index-CGrvOpdb.js +0 -372
  177. package/dist/index-CHJWNf3f.js +0 -475
  178. package/dist/index-CIb06BxE.js +0 -372
  179. package/dist/index-CLiJcB9v.js +0 -142
  180. package/dist/index-CNS6Ohfw.js +0 -2853
  181. package/dist/index-COkjB5Jm.js +0 -142
  182. package/dist/index-CS5h1O5W.js +0 -345
  183. package/dist/index-CT0deRSL.js +0 -372
  184. package/dist/index-CTQQBaf4.js +0 -345
  185. package/dist/index-CUAC0ZFB.js +0 -475
  186. package/dist/index-CVMV9Tfg.js +0 -142
  187. package/dist/index-CWOx59Vc.js +0 -142
  188. package/dist/index-CWdSR99B.js +0 -372
  189. package/dist/index-CWvOcS8Y.js +0 -345
  190. package/dist/index-C_8yJlf1.js +0 -475
  191. package/dist/index-C_MzXmh2.js +0 -2830
  192. package/dist/index-Cb7HXiBR.js +0 -372
  193. package/dist/index-CbA8oUvZ.js +0 -142
  194. package/dist/index-CbEIzXG9.js +0 -475
  195. package/dist/index-Cb_m0zz1.js +0 -475
  196. package/dist/index-Cc6HgGzc.js +0 -142
  197. package/dist/index-CcWdW9Mj.js +0 -372
  198. package/dist/index-CdAqkP8L.js +0 -345
  199. package/dist/index-CeVUHSt9.js +0 -2847
  200. package/dist/index-CejRpy0a.js +0 -475
  201. package/dist/index-Cg5wO_jJ.js +0 -372
  202. package/dist/index-CgZM1vHq.js +0 -372
  203. package/dist/index-CgofFg1D.js +0 -372
  204. package/dist/index-ChheXGDK.js +0 -372
  205. package/dist/index-ChuFHoI0.js +0 -372
  206. package/dist/index-CiOJZ6_b.js +0 -372
  207. package/dist/index-ClCWmz_7.js +0 -2844
  208. package/dist/index-CmajGrKA.js +0 -142
  209. package/dist/index-Cn_4o3fi.js +0 -345
  210. package/dist/index-CoJBI1vE.js +0 -345
  211. package/dist/index-CqLLaQ-P.js +0 -372
  212. package/dist/index-CsRhLwmR.js +0 -475
  213. package/dist/index-CttJvDTG.js +0 -475
  214. package/dist/index-Cu3m9UeX.js +0 -345
  215. package/dist/index-CyQbOMHa.js +0 -2859
  216. package/dist/index-D-NcbLKL.js +0 -345
  217. package/dist/index-D0gstkiI.js +0 -2836
  218. package/dist/index-D0krzDtx.js +0 -475
  219. package/dist/index-D1moFd4V.js +0 -372
  220. package/dist/index-D2Hs4bZj.js +0 -345
  221. package/dist/index-D4QhrTZs.js +0 -475
  222. package/dist/index-D6CC02F-.js +0 -372
  223. package/dist/index-D6s7Za5s.js +0 -142
  224. package/dist/index-D7i5bck2.js +0 -3132
  225. package/dist/index-D8YBeNfn.js +0 -345
  226. package/dist/index-D93bv6lU.js +0 -372
  227. package/dist/index-DAX_bFj5.js +0 -142
  228. package/dist/index-DBii9cjr.js +0 -475
  229. package/dist/index-DBzpSkNi.js +0 -345
  230. package/dist/index-DCuKNBck.js +0 -3153
  231. package/dist/index-DE3uKf0K.js +0 -142
  232. package/dist/index-DGAqp0QX.js +0 -372
  233. package/dist/index-DGh_w_v1.js +0 -475
  234. package/dist/index-DItKvJyI.js +0 -475
  235. package/dist/index-DKAyB0fv.js +0 -345
  236. package/dist/index-DKN4xsXi.js +0 -2851
  237. package/dist/index-DN_iIn8V.js +0 -345
  238. package/dist/index-DONIBpuJ.js +0 -345
  239. package/dist/index-DPDK8Ht4.js +0 -2851
  240. package/dist/index-DPr3ldST.js +0 -2354
  241. package/dist/index-DS1wfdxM.js +0 -142
  242. package/dist/index-DUW5cCh8.js +0 -372
  243. package/dist/index-DUv28uVd.js +0 -142
  244. package/dist/index-DVS-5SZn.js +0 -475
  245. package/dist/index-DWI51JAp.js +0 -372
  246. package/dist/index-DWVmEexu.js +0 -475
  247. package/dist/index-DXf9wUqQ.js +0 -142
  248. package/dist/index-DXmB-sjP.js +0 -345
  249. package/dist/index-DY_e_Dxv.js +0 -372
  250. package/dist/index-DZar-us7.js +0 -142
  251. package/dist/index-D_nwqVrw.js +0 -2847
  252. package/dist/index-DbEeir7h.js +0 -2834
  253. package/dist/index-Dbf5ypbh.js +0 -142
  254. package/dist/index-DcSK-2pt.js +0 -345
  255. package/dist/index-DclK-Mc7.js +0 -2864
  256. package/dist/index-DcnzaxVi.js +0 -142
  257. package/dist/index-Dd8PlF0M.js +0 -2857
  258. package/dist/index-DdkVT39s.js +0 -345
  259. package/dist/index-DeLbU1t-.js +0 -345
  260. package/dist/index-DfV_J8Te.js +0 -345
  261. package/dist/index-DgPnNd8U.js +0 -475
  262. package/dist/index-Dg_JLa7s.js +0 -345
  263. package/dist/index-Di2VPQjn.js +0 -345
  264. package/dist/index-DibHUbqc.js +0 -372
  265. package/dist/index-DjCVSrpw.js +0 -475
  266. package/dist/index-Djdb936p.js +0 -142
  267. package/dist/index-DmFL_GSt.js +0 -142
  268. package/dist/index-DmP4X2k0.js +0 -372
  269. package/dist/index-DmtmRd1r.js +0 -372
  270. package/dist/index-Dn8MA3kh.js +0 -475
  271. package/dist/index-Do7uXDSi.js +0 -2071
  272. package/dist/index-Dpv1M9Hu.js +0 -372
  273. package/dist/index-DqUuZC8f.js +0 -372
  274. package/dist/index-DtEXQIjn.js +0 -372
  275. package/dist/index-Dtw-qZ0V.js +0 -372
  276. package/dist/index-Dv3hIz8H.js +0 -345
  277. package/dist/index-Dv9jnaWp.js +0 -345
  278. package/dist/index-Dw8KZwGJ.js +0 -2354
  279. package/dist/index-DwJILh-Q.js +0 -3149
  280. package/dist/index-DwzGV3B9.js +0 -142
  281. package/dist/index-DyybaRkK.js +0 -345
  282. package/dist/index-DzerABZq.js +0 -372
  283. package/dist/index-F53NVkhc.js +0 -142
  284. package/dist/index-Fl0_k4XF.js +0 -475
  285. package/dist/index-HMYRCPrs.js +0 -2326
  286. package/dist/index-I49wpmT-.js +0 -372
  287. package/dist/index-IPv1O8Zq.js +0 -345
  288. package/dist/index-JLqnaery.js +0 -372
  289. package/dist/index-JRCQ1CYj.js +0 -142
  290. package/dist/index-L86-iO8O.js +0 -345
  291. package/dist/index-Q56EoFor.js +0 -142
  292. package/dist/index-QxKMr6p0.js +0 -2829
  293. package/dist/index-THRvW9Xm.js +0 -2856
  294. package/dist/index-WIUmTlfL.js +0 -345
  295. package/dist/index-WRrsK0pR.js +0 -475
  296. package/dist/index-Wq652QGf.js +0 -2836
  297. package/dist/index-YnSLCdjP.js +0 -475
  298. package/dist/index-Ynf0lvBE.js +0 -142
  299. package/dist/index-_OtTmb9i.js +0 -142
  300. package/dist/index-_oqoy_3D.js +0 -142
  301. package/dist/index-cl4Y-BWw.js +0 -475
  302. package/dist/index-d_eHJkDW.js +0 -475
  303. package/dist/index-dnmEyUWB.js +0 -372
  304. package/dist/index-dz6CwD6A.js +0 -142
  305. package/dist/index-g4rkaRry.js +0 -475
  306. package/dist/index-g9bRMdAX.js +0 -142
  307. package/dist/index-h4z4-a2p.js +0 -2852
  308. package/dist/index-h7BhcQYM.js +0 -475
  309. package/dist/index-hI3qofTF.js +0 -345
  310. package/dist/index-iyQQumAA.js +0 -372
  311. package/dist/index-js_OhKON.js +0 -345
  312. package/dist/index-kgb4MdHr.js +0 -475
  313. package/dist/index-logKl0VM.js +0 -3144
  314. package/dist/index-lrFMrOlR.js +0 -3132
  315. package/dist/index-mEHxtQWj.js +0 -372
  316. package/dist/index-mNm1BV3n.js +0 -2857
  317. package/dist/index-oOzAFXfr.js +0 -142
  318. package/dist/index-s3vGq0ro.js +0 -345
  319. package/dist/index-wt7AbUqc.js +0 -2342
@@ -15,7 +15,7 @@
15
15
  @use 'dark';
16
16
 
17
17
  // ==============================================
18
- // 全局通用样式
18
+ // 全局通用样式(企业级增强)
19
19
  // ==============================================
20
20
 
21
21
  // 文字截断
@@ -33,6 +33,13 @@
33
33
  overflow: hidden;
34
34
  }
35
35
 
36
+ .text-ellipsis-3 {
37
+ display: -webkit-box;
38
+ -webkit-line-clamp: 3;
39
+ -webkit-box-orient: vertical;
40
+ overflow: hidden;
41
+ }
42
+
36
43
  // Flex 布局
37
44
  .flex {
38
45
  display: flex;
@@ -50,6 +57,18 @@
50
57
  justify-content: space-between;
51
58
  }
52
59
 
60
+ .flex-start {
61
+ display: flex;
62
+ align-items: center;
63
+ justify-content: flex-start;
64
+ }
65
+
66
+ .flex-end {
67
+ display: flex;
68
+ align-items: center;
69
+ justify-content: flex-end;
70
+ }
71
+
53
72
  .flex-wrap {
54
73
  flex-wrap: wrap;
55
74
  }
@@ -58,6 +77,31 @@
58
77
  flex: 1;
59
78
  }
60
79
 
80
+ .flex-shrink-0 {
81
+ flex-shrink: 0;
82
+ }
83
+
84
+ // 方向
85
+ .flex-col {
86
+ display: flex;
87
+ flex-direction: column;
88
+ }
89
+
90
+ .flex-col-center {
91
+ display: flex;
92
+ flex-direction: column;
93
+ align-items: center;
94
+ }
95
+
96
+ // Gap 间距(8px 网格系统)
97
+ .gap-4 { gap: 4px; }
98
+ .gap-8 { gap: 8px; }
99
+ .gap-12 { gap: 12px; }
100
+ .gap-16 { gap: 16px; }
101
+ .gap-20 { gap: 20px; }
102
+ .gap-24 { gap: 24px; }
103
+ .gap-32 { gap: 32px; }
104
+
61
105
  // 文字对齐
62
106
  .text-left {
63
107
  text-align: left;
@@ -92,6 +136,14 @@
92
136
  color: var(--color-info);
93
137
  }
94
138
 
139
+ .text-secondary {
140
+ color: var(--color-text-secondary);
141
+ }
142
+
143
+ .text-placeholder {
144
+ color: var(--color-text-placeholder);
145
+ }
146
+
95
147
  // 背景
96
148
  .bg-primary {
97
149
  background-color: var(--color-primary);
@@ -109,81 +161,254 @@
109
161
  background-color: var(--color-danger);
110
162
  }
111
163
 
112
- // 间距
113
- .mt-10 {
114
- margin-top: 10px;
115
- }
116
-
117
- .mt-20 {
118
- margin-top: 20px;
119
- }
120
-
121
- .mb-10 {
122
- margin-bottom: 10px;
164
+ .bg-page {
165
+ background-color: var(--bg-color-page);
123
166
  }
124
167
 
125
- .mb-20 {
126
- margin-bottom: 20px;
127
- }
128
-
129
- .ml-10 {
130
- margin-left: 10px;
131
- }
132
-
133
- .mr-10 {
134
- margin-right: 10px;
168
+ .bg-card {
169
+ background-color: var(--bg-color);
135
170
  }
136
171
 
137
- .p-10 {
138
- padding: 10px;
139
- }
172
+ // 间距(8px 网格系统)
173
+ .mt-4 { margin-top: 4px; }
174
+ .mt-8 { margin-top: 8px; }
175
+ .mt-12 { margin-top: 12px; }
176
+ .mt-16 { margin-top: 16px; }
177
+ .mt-20 { margin-top: 20px; }
178
+ .mt-24 { margin-top: 24px; }
179
+ .mt-32 { margin-top: 32px; }
180
+
181
+ .mb-4 { margin-bottom: 4px; }
182
+ .mb-8 { margin-bottom: 8px; }
183
+ .mb-12 { margin-bottom: 12px; }
184
+ .mb-16 { margin-bottom: 16px; }
185
+ .mb-20 { margin-bottom: 20px; }
186
+ .mb-24 { margin-bottom: 24px; }
187
+ .mb-32 { margin-bottom: 32px; }
188
+
189
+ .ml-4 { margin-left: 4px; }
190
+ .ml-8 { margin-left: 8px; }
191
+ .ml-12 { margin-left: 12px; }
192
+ .ml-16 { margin-left: 16px; }
193
+
194
+ .mr-4 { margin-right: 4px; }
195
+ .mr-8 { margin-right: 8px; }
196
+ .mr-12 { margin-right: 12px; }
197
+ .mr-16 { margin-right: 16px; }
198
+
199
+ .p-4 { padding: 4px; }
200
+ .p-8 { padding: 8px; }
201
+ .p-12 { padding: 12px; }
202
+ .p-16 { padding: 16px; }
203
+ .p-20 { padding: 20px; }
204
+ .p-24 { padding: 24px; }
205
+ .p-32 { padding: 32px; }
206
+
207
+ .px-4 { padding-left: 4px; padding-right: 4px; }
208
+ .px-8 { padding-left: 8px; padding-right: 8px; }
209
+ .px-12 { padding-left: 12px; padding-right: 12px; }
210
+ .px-16 { padding-left: 16px; padding-right: 16px; }
211
+ .px-24 { padding-left: 24px; padding-right: 24px; }
212
+
213
+ .py-4 { padding-top: 4px; padding-bottom: 4px; }
214
+ .py-8 { padding-top: 8px; padding-bottom: 8px; }
215
+ .py-12 { padding-top: 12px; padding-bottom: 12px; }
216
+ .py-16 { padding-top: 16px; padding-bottom: 16px; }
217
+ .py-24 { padding-top: 24px; padding-bottom: 24px; }
218
+
219
+ // 卡片容器(企业级)
220
+ .card {
221
+ background-color: var(--bg-color);
222
+ border-radius: var(--border-radius-large);
223
+ box-shadow: var(--box-shadow-card);
224
+ padding: var(--spacing-lg);
225
+ transition: box-shadow 0.3s ease;
140
226
 
141
- .p-20 {
142
- padding: 20px;
227
+ &:hover {
228
+ box-shadow: var(--box-shadow-card-hover);
229
+ }
143
230
  }
144
231
 
145
- // 卡片容器
146
- .card {
232
+ .card-flat {
147
233
  background-color: var(--bg-color);
148
- border-radius: var(--border-radius-base);
149
- box-shadow: var(--box-shadow-light);
150
- padding: var(--spacing-md);
234
+ border-radius: var(--border-radius-large);
235
+ padding: var(--spacing-lg);
236
+ border: 1px solid var(--color-border-lighter);
151
237
  }
152
238
 
153
239
  // 页面容器
154
240
  .page-container {
155
- padding: var(--spacing-md);
241
+ padding: 12px;
156
242
  min-height: 100%;
243
+ background: var(--bg-color-page);
157
244
  }
158
245
 
159
- // 搜索栏
246
+ // 搜索栏(企业级)
160
247
  .search-bar {
161
248
  display: flex;
162
249
  flex-wrap: wrap;
163
- gap: var(--spacing-sm);
164
- margin-bottom: var(--spacing-md);
250
+ gap: var(--spacing-md);
251
+ margin-bottom: 12px;
252
+ padding: 12px;
253
+ background: var(--bg-color);
254
+ border-radius: var(--border-radius-large);
255
+ box-shadow: var(--box-shadow-card);
165
256
  }
166
257
 
167
- // 工具栏
258
+ // 工具栏(企业级)
168
259
  .toolbar {
169
260
  display: flex;
170
261
  align-items: center;
171
262
  justify-content: space-between;
172
- margin-bottom: var(--spacing-md);
263
+ padding: 12px;
264
+ border-bottom: 1px solid var(--color-border-lighter);
265
+ }
266
+
267
+ .toolbar-left {
268
+ display: flex;
269
+ align-items: center;
270
+ gap: var(--spacing-sm);
271
+ }
272
+
273
+ .toolbar-right {
274
+ display: flex;
275
+ align-items: center;
276
+ gap: var(--spacing-sm);
173
277
  }
174
278
 
175
- // 表格容器
279
+ // 表格容器(企业级)
176
280
  .table-container {
177
281
  background-color: var(--bg-color);
178
- border-radius: var(--border-radius-base);
179
- padding: var(--spacing-md);
282
+ border-radius: var(--border-radius-large);
283
+ box-shadow: var(--box-shadow-card);
284
+ overflow: hidden;
180
285
  }
181
286
 
182
287
  // 分页容器
183
288
  .pagination-container {
184
289
  display: flex;
185
290
  justify-content: flex-end;
186
- margin-top: var(--spacing-md);
291
+ padding: 12px;
292
+ border-top: 1px solid var(--color-border-lighter);
293
+ }
294
+
295
+ // 标签徽章
296
+ .badge {
297
+ display: inline-flex;
298
+ align-items: center;
299
+ justify-content: center;
300
+ min-width: 20px;
301
+ height: 20px;
302
+ padding: 0 6px;
303
+ font-size: 12px;
304
+ font-weight: 500;
305
+ border-radius: 10px;
306
+ background: var(--color-fill);
307
+ color: var(--color-text-secondary);
308
+ }
309
+
310
+ .badge-primary {
311
+ background: var(--color-primary-light-6);
312
+ color: var(--color-primary);
313
+ }
314
+
315
+ .badge-success {
316
+ background: var(--color-success-lighter);
317
+ color: var(--color-success);
318
+ }
319
+
320
+ .badge-warning {
321
+ background: var(--color-warning-lighter);
322
+ color: var(--color-warning);
323
+ }
324
+
325
+ .badge-danger {
326
+ background: var(--color-danger-lighter);
327
+ color: var(--color-danger);
328
+ }
329
+
330
+ // 分隔线
331
+ .divider {
332
+ height: 1px;
333
+ background: var(--color-border-lighter);
334
+ margin: var(--spacing-md) 0;
335
+ }
336
+
337
+ .divider-vertical {
338
+ width: 1px;
339
+ height: 100%;
340
+ background: var(--color-border-lighter);
341
+ margin: 0 var(--spacing-md);
342
+ }
343
+
344
+ // 空状态
345
+ .empty-state {
346
+ display: flex;
347
+ flex-direction: column;
348
+ align-items: center;
349
+ justify-content: center;
350
+ padding: 60px 20px;
351
+ color: var(--color-text-placeholder);
352
+
353
+ .empty-icon {
354
+ width: 64px;
355
+ height: 64px;
356
+ margin-bottom: 16px;
357
+ opacity: 0.5;
358
+ }
359
+
360
+ .empty-text {
361
+ font-size: 14px;
362
+ }
363
+ }
364
+
365
+ // 加载状态
366
+ .loading-state {
367
+ display: flex;
368
+ flex-direction: column;
369
+ align-items: center;
370
+ justify-content: center;
371
+ padding: 60px 20px;
372
+
373
+ .loading-spinner {
374
+ width: 32px;
375
+ height: 32px;
376
+ border: 3px solid var(--color-border-lighter);
377
+ border-top-color: var(--color-primary);
378
+ border-radius: 50%;
379
+ animation: spin 0.8s linear infinite;
380
+ }
381
+
382
+ .loading-text {
383
+ margin-top: 16px;
384
+ font-size: 14px;
385
+ color: var(--color-text-secondary);
386
+ }
387
+ }
388
+
389
+ @keyframes spin {
390
+ to { transform: rotate(360deg); }
391
+ }
392
+
393
+ // 链接样式
394
+ .link {
395
+ color: var(--color-primary);
396
+ text-decoration: none;
397
+ transition: color 0.2s ease;
398
+
399
+ &:hover {
400
+ color: var(--color-primary-dark-1);
401
+ }
402
+ }
403
+
404
+ .link-underline {
405
+ color: var(--color-primary);
406
+ text-decoration: underline;
407
+ text-underline-offset: 2px;
408
+
409
+ &:hover {
410
+ color: var(--color-primary-dark-1);
411
+ }
187
412
  }
188
413
 
189
414
  // ==============================================
@@ -1,5 +1,5 @@
1
1
  <script setup lang="ts">
2
- import { computed } from 'vue'
2
+ import { computed, ref, watch } from 'vue'
3
3
  import { useRoute, useRouter } from 'vue-router'
4
4
  import { useMenuStore } from '@/stores/menu'
5
5
  import { useUserStore } from '@/stores/user'
@@ -7,6 +7,7 @@ import { useAuthStore } from '@/stores/auth'
7
7
  import { useAppStore } from '@/stores/app'
8
8
  import { Menu } from '@xto/navigation'
9
9
  import { Button } from '@xto/base'
10
+ import { local } from '@/utils/storage'
10
11
  import SidebarMenuItem from './SidebarMenuItem.vue'
11
12
 
12
13
  // Props
@@ -33,6 +34,45 @@ const displayMenuList = computed(() => props.menuList.length > 0 ? props.menuLis
33
34
  const isCollapsed = computed(() => appStore.isCollapsed)
34
35
  const activeMenu = computed(() => route.path)
35
36
 
37
+ // 菜单展开状态持久化
38
+ const OPENED_MENUS_KEY = 'sidebar_opened_menus'
39
+ const openedMenus = ref<string[]>(local.get<string[]>(OPENED_MENUS_KEY) || [])
40
+
41
+ // 监听变化并持久化
42
+ watch(openedMenus, (val) => {
43
+ local.set(OPENED_MENUS_KEY, val)
44
+ }, { deep: true })
45
+
46
+ // 递归查找当前路由对应的父菜单路径
47
+ const findMenuPath = (menus: any[], path: string, parentUrls: string[] = []): string[] | null => {
48
+ for (const menu of menus) {
49
+ // 当前菜单匹配
50
+ if (path === menu.menuUrl || path.startsWith(menu.menuUrl + '/')) {
51
+ return [...parentUrls, menu.menuUrl]
52
+ }
53
+ // 递归查找子菜单
54
+ if (menu.children?.length) {
55
+ const result = findMenuPath(menu.children, path, [...parentUrls, menu.menuUrl])
56
+ if (result) return result
57
+ }
58
+ }
59
+ return null
60
+ }
61
+
62
+ // 监听路由变化,只展开当前路由相关的父菜单
63
+ watch([() => route.path, displayMenuList], ([path, menus]) => {
64
+ if (menus.length > 0) {
65
+ const menuPath = findMenuPath(menus, path)
66
+ if (menuPath) {
67
+ // 只保留路径上的父菜单(不包括当前页面本身)
68
+ openedMenus.value = menuPath.slice(0, -1)
69
+ } else {
70
+ // 如果找不到匹配的菜单,关闭所有
71
+ openedMenus.value = []
72
+ }
73
+ }
74
+ }, { immediate: true })
75
+
36
76
  // 菜单主题相关
37
77
  const menuBgColor = computed(() => appStore.isDark ? '#1d1e1f' : '#fff')
38
78
  const menuTextColor = computed(() => appStore.isDark ? '#cfd3dc' : '#303133')
@@ -64,7 +104,8 @@ const handleLogout = () => {
64
104
 
65
105
  <!-- 菜单 -->
66
106
  <Menu
67
- :model-value="activeMenu"
107
+ v-model="activeMenu"
108
+ v-model:openeds="openedMenus"
68
109
  mode="vertical"
69
110
  :collapse="isCollapsed"
70
111
  :collapse-transition="false"
@@ -322,19 +322,44 @@ onUnmounted(() => {
322
322
  <span class="top-menu__menu-text">{{ menu.menuName }}</span>
323
323
  </span>
324
324
  </template>
325
- <MenuItem
326
- v-for="child in menu.children"
327
- :key="child.menuUrl"
328
- :index="child.menuUrl"
329
- >
330
- <span class="top-menu__menu-content">
331
- <span class="top-menu__menu-icon">
332
- <Icon v-if="iconExists(getMenuIcon(child.icon))" :name="getMenuIcon(child.icon)" :size="16" />
333
- <span v-else class="top-menu__menu-char">{{ getFirstChar(child.menuName) }}</span>
325
+ <!-- 递归渲染子菜单 -->
326
+ <template v-for="child in menu.children" :key="child.menuUrl">
327
+ <SubMenu v-if="child.children && child.children.length > 0" :index="child.menuUrl">
328
+ <template #title>
329
+ <span class="top-menu__menu-content">
330
+ <span class="top-menu__menu-icon">
331
+ <Icon v-if="iconExists(getMenuIcon(child.icon))" :name="getMenuIcon(child.icon)" :size="16" />
332
+ <span v-else class="top-menu__menu-char">{{ getFirstChar(child.menuName) }}</span>
333
+ </span>
334
+ <span class="top-menu__menu-text">{{ child.menuName }}</span>
335
+ </span>
336
+ </template>
337
+ <!-- 三级菜单项 -->
338
+ <MenuItem
339
+ v-for="grandChild in child.children"
340
+ :key="grandChild.menuUrl"
341
+ :index="grandChild.menuUrl"
342
+ >
343
+ <span class="top-menu__menu-content">
344
+ <span class="top-menu__menu-icon">
345
+ <Icon v-if="iconExists(getMenuIcon(grandChild.icon))" :name="getMenuIcon(grandChild.icon)" :size="16" />
346
+ <span v-else class="top-menu__menu-char">{{ getFirstChar(grandChild.menuName) }}</span>
347
+ </span>
348
+ <span class="top-menu__menu-text">{{ grandChild.menuName }}</span>
349
+ </span>
350
+ </MenuItem>
351
+ </SubMenu>
352
+ <!-- 二级菜单项 -->
353
+ <MenuItem v-else :index="child.menuUrl">
354
+ <span class="top-menu__menu-content">
355
+ <span class="top-menu__menu-icon">
356
+ <Icon v-if="iconExists(getMenuIcon(child.icon))" :name="getMenuIcon(child.icon)" :size="16" />
357
+ <span v-else class="top-menu__menu-char">{{ getFirstChar(child.menuName) }}</span>
358
+ </span>
359
+ <span class="top-menu__menu-text">{{ child.menuName }}</span>
334
360
  </span>
335
- <span class="top-menu__menu-text">{{ child.menuName }}</span>
336
- </span>
337
- </MenuItem>
361
+ </MenuItem>
362
+ </template>
338
363
  </SubMenu>
339
364
  <!-- 无子菜单 -->
340
365
  <MenuItem v-else :index="menu.menuUrl">
@@ -187,6 +187,7 @@ const showMixSidebar = computed(() => {
187
187
  flex: 1;
188
188
  overflow: auto;
189
189
  background-color: var(--bg-color-page);
190
+ padding: 0;
190
191
  }
191
192
  }
192
193
  </style>
@@ -0,0 +1,44 @@
1
+ /**
2
+ * 国际化组合式函数
3
+ * 提供便捷的国际化操作
4
+ */
5
+
6
+ import { useLocaleStore } from '@/stores/locale'
7
+ import type { LocaleCode, LocaleMessages } from '@xto/core/locale'
8
+
9
+ /**
10
+ * 使用国际化
11
+ * 封装 locale store,提供更简洁的 API
12
+ */
13
+ export function useI18n() {
14
+ const localeStore = useLocaleStore()
15
+
16
+ return {
17
+ /** 当前语言代码 */
18
+ locale: localeStore.locale,
19
+ /** 当前语言名称 */
20
+ localeName: localeStore.localeName,
21
+ /** 支持的语言列表 */
22
+ locales: localeStore.locales,
23
+ /** 翻译函数 */
24
+ t: localeStore.t,
25
+ /** 当前语言包 */
26
+ messages: localeStore.messages,
27
+ /** 切换语言 */
28
+ setLocale: localeStore.changeLocale,
29
+ /** 添加自定义翻译 */
30
+ addMessages: localeStore.addMessages
31
+ }
32
+ }
33
+
34
+ /**
35
+ * 创建翻译函数
36
+ * 用于在非组件上下文中使用翻译
37
+ */
38
+ export function createTranslator() {
39
+ const localeStore = useLocaleStore()
40
+ return localeStore.t
41
+ }
42
+
43
+ // 导出类型
44
+ export type { LocaleCode, LocaleMessages }
package/src/index.ts CHANGED
@@ -3,6 +3,7 @@ import './style.scss'
3
3
 
4
4
  // 配置
5
5
  import { initAppConfig, getAppId, getClientId, getApiBaseUrl } from './utils/config'
6
+ import type { LocaleCode } from '@xto/core/locale'
6
7
 
7
8
  // XtoConfig 类型定义
8
9
  export interface XtoConfig {
@@ -12,6 +13,7 @@ export interface XtoConfig {
12
13
  apiBaseUrl?: string
13
14
  indexPath?: string
14
15
  loginPath?: string
16
+ locale?: LocaleCode
15
17
  }
16
18
 
17
19
  /**
@@ -25,6 +27,15 @@ export function createXtoApp(config: Partial<XtoConfig>) {
25
27
  clientId: config.clientId,
26
28
  apiBaseUrl: config.apiBaseUrl
27
29
  })
30
+
31
+ // 设置初始语言(如果提供)
32
+ if (config.locale) {
33
+ import('./stores/locale').then(({ useLocaleStore }) => {
34
+ const localeStore = useLocaleStore()
35
+ localeStore.changeLocale(config.locale!)
36
+ })
37
+ }
38
+
28
39
  return {
29
40
  config: {
30
41
  appName: config.appName || 'XTO App',
@@ -32,7 +43,8 @@ export function createXtoApp(config: Partial<XtoConfig>) {
32
43
  clientId: getClientId(),
33
44
  apiBaseUrl: getApiBaseUrl(),
34
45
  indexPath: config.indexPath || '/dashboard',
35
- loginPath: config.loginPath || '/login'
46
+ loginPath: config.loginPath || '/login',
47
+ locale: config.locale || 'zh-CN'
36
48
  }
37
49
  }
38
50
  }
@@ -54,6 +66,7 @@ export * from './composables/useApp'
54
66
  export * from './composables/useAuth'
55
67
  export * from './composables/useForm'
56
68
  export * from './composables/useTable'
69
+ export * from './composables/useI18n'
57
70
 
58
71
  // 工具函数
59
72
  export * from './utils/auth'
@@ -67,6 +80,7 @@ export * from './stores/app'
67
80
  export * from './stores/auth'
68
81
  export * from './stores/menu'
69
82
  export * from './stores/user'
83
+ export * from './stores/locale'
70
84
 
71
85
  // 路由
72
86
  export { default as router, resetRouter } from './router'
@@ -12,4 +12,5 @@ export default pinia
12
12
  export * from './user'
13
13
  export * from './auth'
14
14
  export * from './menu'
15
- export * from './app'
15
+ export * from './app'
16
+ export * from './locale'
@@ -0,0 +1,67 @@
1
+ /**
2
+ * 国际化状态管理
3
+ */
4
+
5
+ import { defineStore } from 'pinia'
6
+ import { ref, computed } from 'vue'
7
+ import { local } from '@/utils/storage'
8
+ import {
9
+ useLocale,
10
+ createLocaleProvider,
11
+ getSupportedLocales,
12
+ type LocaleCode,
13
+ type LocaleMessages
14
+ } from '@xto/core/locale'
15
+
16
+ export type { LocaleCode, LocaleMessages }
17
+
18
+ export const useLocaleStore = defineStore('locale', () => {
19
+ // 从本地存储获取语言设置
20
+ const savedLocale = local.get<LocaleCode>('locale') || 'zh-CN'
21
+
22
+ // 创建国际化提供者
23
+ const provider = createLocaleProvider(savedLocale)
24
+
25
+ // 状态
26
+ const locale = ref<LocaleCode>(savedLocale)
27
+ const locales = getSupportedLocales()
28
+
29
+ // 使用国际化组合式函数
30
+ const { t, messages, setLocale, mergeMessages } = useLocale()
31
+
32
+ // 当前语言名称
33
+ const localeName = computed(() => {
34
+ const found = locales.find(l => l.code === locale.value)
35
+ return found?.name || locale.value
36
+ })
37
+
38
+ // 设置语言
39
+ const changeLocale = (code: LocaleCode) => {
40
+ locale.value = code
41
+ setLocale(code)
42
+ local.set('locale', code)
43
+ provider.setLocale(code)
44
+ }
45
+
46
+ // 添加自定义翻译
47
+ const addMessages = (msgs: LocaleMessages) => {
48
+ mergeMessages(msgs)
49
+ }
50
+
51
+ // 初始化
52
+ const initLocale = () => {
53
+ setLocale(savedLocale)
54
+ }
55
+
56
+ return {
57
+ locale,
58
+ localeName,
59
+ locales,
60
+ messages,
61
+ t,
62
+ changeLocale,
63
+ addMessages,
64
+ initLocale,
65
+ provider
66
+ }
67
+ })