xto-fronted 0.4.85 → 0.4.86

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 (303) hide show
  1. package/dist/assets/404-BNfk6aVM.js +1 -0
  2. package/dist/assets/404-ByYjFnhI.js +1 -0
  3. package/dist/assets/404-CH5_LdtS.css +1 -0
  4. package/dist/assets/404-sqW80Hc-.css +1 -0
  5. package/dist/assets/_plugin-vue_export-helper-DlAUqK2U.js +1 -0
  6. package/dist/assets/index-BBhC8PX4.js +1 -0
  7. package/dist/assets/index-BOEFG4lP.css +1 -0
  8. package/dist/assets/index-BRR97dc6.js +1 -0
  9. package/dist/assets/index-BSa4SMHI.js +1 -0
  10. package/dist/assets/index-BihVoviB.js +1 -0
  11. package/dist/assets/index-Bmux4tGG.js +1 -0
  12. package/dist/assets/index-BrvR0Fn_.css +1 -0
  13. package/dist/assets/index-C4ZCZoPp.js +1 -0
  14. package/dist/assets/index-CMgRqiaT.js +1 -0
  15. package/dist/assets/index-CUh_s55Z.css +1 -0
  16. package/dist/assets/index-CV768Wu1.js +1 -0
  17. package/dist/assets/index-D0OnMilp.js +1 -0
  18. package/dist/assets/index-D9wlAuR_.js +1 -0
  19. package/dist/assets/index-DPkO-STg.js +1 -0
  20. package/dist/assets/index-DawJb02s.css +1 -0
  21. package/dist/assets/index-DcFOybjo.js +1 -0
  22. package/dist/assets/index-DiHSZ6SJ.js +2 -0
  23. package/dist/assets/index-GDP-IkXE.css +1 -0
  24. package/dist/assets/index-Gx75raue.js +2 -0
  25. package/dist/assets/index-JsZ6rkQj.js +1 -0
  26. package/dist/assets/index-PfV8pzQz.css +1 -0
  27. package/dist/assets/index-Swfu6yvD.css +1 -0
  28. package/dist/assets/index-eQ-JQMk3.css +1 -0
  29. package/dist/assets/vendor-42ANG6Sg.js +6 -0
  30. package/dist/assets/vite-Dw-pgLOX.js +1 -0
  31. package/dist/assets/vue-vendor-05sbU7Th.js +29 -0
  32. package/dist/assets/vue-vendor-Br-l7wbK.js +29 -0
  33. package/dist/assets/xto-base-BSTP-Yn2.js +1 -0
  34. package/dist/assets/xto-base-C-IBqjVs.js +1 -0
  35. package/dist/assets/xto-base-C6eqMPdO.css +1 -0
  36. package/dist/assets/xto-base-CL2NKZJJ.css +1 -0
  37. package/dist/assets/xto-business--V1F5Gwb.css +1 -0
  38. package/dist/assets/xto-core-DZK7Cyg0.js +1 -0
  39. package/dist/assets/xto-core-cL8BAdce.js +1 -0
  40. package/dist/assets/xto-data-BFpiDgJi.js +1 -0
  41. package/dist/assets/xto-data-CnAQAQH2.css +1 -0
  42. package/dist/assets/xto-data-Cw0dv5K5.js +1 -0
  43. package/dist/assets/xto-data-MxZsiJgi.css +1 -0
  44. package/dist/assets/xto-feedback-B2M02fn3.js +1 -0
  45. package/dist/assets/xto-feedback-Bxx38c3P.css +1 -0
  46. package/dist/assets/xto-feedback-ByaS-C7_.css +1 -0
  47. package/dist/assets/xto-feedback-CTk0sMCW.js +1 -0
  48. package/dist/assets/xto-form-C5i2lk3C.js +1 -0
  49. package/dist/assets/xto-form-CrsyAjyr.css +1 -0
  50. package/dist/assets/xto-form-Cu6q3VLG.css +1 -0
  51. package/dist/assets/xto-form-NRjKKNcY.js +1 -0
  52. package/dist/assets/xto-layout-BDD6sSlM.css +1 -0
  53. package/dist/assets/xto-layout-D1stVnJI.css +1 -0
  54. package/dist/assets/xto-navigation-BuRQVoD8.css +1 -0
  55. package/dist/assets/xto-navigation-DHsTg0WG.js +1 -0
  56. package/dist/assets/xto-navigation-XfpyMpEo.css +1 -0
  57. package/dist/assets/xto-navigation-qLRTxo68.js +1 -0
  58. package/dist/index-0h_oG71z.js +345 -0
  59. package/dist/index-1EEezXR3.js +142 -0
  60. package/dist/index-1EkaJDoD.js +142 -0
  61. package/dist/index-1VN-SSaj.js +2873 -0
  62. package/dist/index-23nX2t9j.js +142 -0
  63. package/dist/index-2RwL0s53.js +142 -0
  64. package/dist/index-2tvOdd6w.js +372 -0
  65. package/dist/index-3zeoNaqT.js +345 -0
  66. package/dist/index-8oCLh51t.js +475 -0
  67. package/dist/index-AF5JN8Up.js +142 -0
  68. package/dist/index-B02xiP9g.js +372 -0
  69. package/dist/index-B05xso4D.js +345 -0
  70. package/dist/index-B1VS4tRU.js +475 -0
  71. package/dist/index-B3_VQZ-d.js +372 -0
  72. package/dist/index-B3kL6i_g.js +345 -0
  73. package/dist/index-B4Wny0vt.js +345 -0
  74. package/dist/index-B5RdBQ-f.js +475 -0
  75. package/dist/index-B5rbuoWS.js +2835 -0
  76. package/dist/index-BAFpPlnI.js +475 -0
  77. package/dist/index-BAJakzRz.js +142 -0
  78. package/dist/index-BAOHlfVd.js +142 -0
  79. package/dist/index-BAzJWzWG.js +2852 -0
  80. package/dist/index-BEIxh_R3.js +2982 -0
  81. package/dist/index-BEWrRNps.js +475 -0
  82. package/dist/index-BFtKVmzo.js +142 -0
  83. package/dist/index-BHPrW1wN.js +142 -0
  84. package/dist/index-BHQIqN1E.js +372 -0
  85. package/dist/index-BHZ_y8lp.js +2067 -0
  86. package/dist/index-BHvnTk5Z.js +475 -0
  87. package/dist/index-BIf7CYCW.js +475 -0
  88. package/dist/index-BK1Y1z9_.js +142 -0
  89. package/dist/index-BK8qDl14.js +372 -0
  90. package/dist/index-BKnta6nv.js +372 -0
  91. package/dist/index-BLIem13z.js +345 -0
  92. package/dist/index-BNBv_FCu.js +142 -0
  93. package/dist/index-BNwtCm83.js +345 -0
  94. package/dist/index-BOEMA7WH.js +345 -0
  95. package/dist/index-BOwDukt-.js +2346 -0
  96. package/dist/index-BR9WVjrV.js +2851 -0
  97. package/dist/index-BRMkw154.js +475 -0
  98. package/dist/index-BRQBannD.js +345 -0
  99. package/dist/index-BShKtLTm.js +475 -0
  100. package/dist/index-BVpqTdd2.js +3132 -0
  101. package/dist/index-BWGQANAN.js +2851 -0
  102. package/dist/index-BZKw7U60.js +475 -0
  103. package/dist/index-BadGWG4q.js +475 -0
  104. package/dist/index-BbeWpCd3.js +345 -0
  105. package/dist/index-BeUYNx5P.js +475 -0
  106. package/dist/index-BgiGtxRr.js +142 -0
  107. package/dist/index-BhKJLk9M.js +2824 -0
  108. package/dist/index-BijsKQ3r.js +475 -0
  109. package/dist/index-BjEfspqP.js +475 -0
  110. package/dist/index-BjEnT8WQ.js +372 -0
  111. package/dist/index-BpOcz1m4.js +142 -0
  112. package/dist/index-BrRdLbLB.js +142 -0
  113. package/dist/index-BsHOXfCq.js +372 -0
  114. package/dist/index-Bt5ocakb.js +475 -0
  115. package/dist/index-BtE24Mt4.js +142 -0
  116. package/dist/index-BvcBQjw6.js +2836 -0
  117. package/dist/index-C0krZRWf.js +2859 -0
  118. package/dist/index-C1cKUqmA.js +372 -0
  119. package/dist/index-C3ANmIDM.js +475 -0
  120. package/dist/index-C5JrEkwD.js +345 -0
  121. package/dist/index-C5m4qNMQ.js +2851 -0
  122. package/dist/index-C69vu_ot.js +3147 -0
  123. package/dist/index-C6Um6eFy.js +475 -0
  124. package/dist/index-C75ePQYC.js +372 -0
  125. package/dist/index-C7wKLGhC.js +142 -0
  126. package/dist/index-C8DBDnxx.js +2836 -0
  127. package/dist/index-CAnqlIjX.js +475 -0
  128. package/dist/index-CB36fztK.js +345 -0
  129. package/dist/index-CBKo6Enz.js +345 -0
  130. package/dist/index-CBcuyFIa.js +2326 -0
  131. package/dist/index-CCxIu4ex.js +372 -0
  132. package/dist/index-CD1ZEMzL.js +2836 -0
  133. package/dist/index-CDx-6tvY.js +345 -0
  134. package/dist/index-CGrvOpdb.js +372 -0
  135. package/dist/index-CHJWNf3f.js +475 -0
  136. package/dist/index-CIb06BxE.js +372 -0
  137. package/dist/index-CLiJcB9v.js +142 -0
  138. package/dist/index-CNS6Ohfw.js +2853 -0
  139. package/dist/index-COkjB5Jm.js +142 -0
  140. package/dist/index-CS5h1O5W.js +345 -0
  141. package/dist/index-CT0deRSL.js +372 -0
  142. package/dist/index-CTQQBaf4.js +345 -0
  143. package/dist/index-CUAC0ZFB.js +475 -0
  144. package/dist/index-CVMV9Tfg.js +142 -0
  145. package/dist/index-CWOx59Vc.js +142 -0
  146. package/dist/index-CWdSR99B.js +372 -0
  147. package/dist/index-CWvOcS8Y.js +345 -0
  148. package/dist/index-C_8yJlf1.js +475 -0
  149. package/dist/index-C_MzXmh2.js +2830 -0
  150. package/dist/index-Cb7HXiBR.js +372 -0
  151. package/dist/index-CbA8oUvZ.js +142 -0
  152. package/dist/index-CbEIzXG9.js +475 -0
  153. package/dist/index-Cb_m0zz1.js +475 -0
  154. package/dist/index-Cc6HgGzc.js +142 -0
  155. package/dist/index-CcWdW9Mj.js +372 -0
  156. package/dist/index-CdAqkP8L.js +345 -0
  157. package/dist/index-CeVUHSt9.js +2847 -0
  158. package/dist/index-CejRpy0a.js +475 -0
  159. package/dist/index-Cg5wO_jJ.js +372 -0
  160. package/dist/index-CgZM1vHq.js +372 -0
  161. package/dist/index-CgofFg1D.js +372 -0
  162. package/dist/index-ChheXGDK.js +372 -0
  163. package/dist/index-ChuFHoI0.js +372 -0
  164. package/dist/index-CiOJZ6_b.js +372 -0
  165. package/dist/index-ClCWmz_7.js +2844 -0
  166. package/dist/index-CmajGrKA.js +142 -0
  167. package/dist/index-Cn_4o3fi.js +345 -0
  168. package/dist/index-CoJBI1vE.js +345 -0
  169. package/dist/index-CqLLaQ-P.js +372 -0
  170. package/dist/index-CsRhLwmR.js +475 -0
  171. package/dist/index-CttJvDTG.js +475 -0
  172. package/dist/index-Cu3m9UeX.js +345 -0
  173. package/dist/index-CyQbOMHa.js +2859 -0
  174. package/dist/index-D-NcbLKL.js +345 -0
  175. package/dist/index-D0gstkiI.js +2836 -0
  176. package/dist/index-D0krzDtx.js +475 -0
  177. package/dist/index-D1moFd4V.js +372 -0
  178. package/dist/index-D2Hs4bZj.js +345 -0
  179. package/dist/index-D4QhrTZs.js +475 -0
  180. package/dist/index-D6CC02F-.js +372 -0
  181. package/dist/index-D6s7Za5s.js +142 -0
  182. package/dist/index-D7i5bck2.js +3132 -0
  183. package/dist/index-D8YBeNfn.js +345 -0
  184. package/dist/index-D93bv6lU.js +372 -0
  185. package/dist/index-DAX_bFj5.js +142 -0
  186. package/dist/index-DBii9cjr.js +475 -0
  187. package/dist/index-DBzpSkNi.js +345 -0
  188. package/dist/index-DCuKNBck.js +3153 -0
  189. package/dist/index-DE3uKf0K.js +142 -0
  190. package/dist/index-DGAqp0QX.js +372 -0
  191. package/dist/index-DGh_w_v1.js +475 -0
  192. package/dist/index-DItKvJyI.js +475 -0
  193. package/dist/index-DKAyB0fv.js +345 -0
  194. package/dist/index-DKN4xsXi.js +2851 -0
  195. package/dist/index-DN_iIn8V.js +345 -0
  196. package/dist/index-DONIBpuJ.js +345 -0
  197. package/dist/index-DPDK8Ht4.js +2851 -0
  198. package/dist/index-DPr3ldST.js +2354 -0
  199. package/dist/index-DS1wfdxM.js +142 -0
  200. package/dist/index-DUW5cCh8.js +372 -0
  201. package/dist/index-DUv28uVd.js +142 -0
  202. package/dist/index-DVS-5SZn.js +475 -0
  203. package/dist/index-DWI51JAp.js +372 -0
  204. package/dist/index-DWVmEexu.js +475 -0
  205. package/dist/index-DXf9wUqQ.js +142 -0
  206. package/dist/index-DXmB-sjP.js +345 -0
  207. package/dist/index-DY_e_Dxv.js +372 -0
  208. package/dist/index-DZar-us7.js +142 -0
  209. package/dist/index-D_nwqVrw.js +2847 -0
  210. package/dist/index-DbEeir7h.js +2834 -0
  211. package/dist/index-Dbf5ypbh.js +142 -0
  212. package/dist/index-DcSK-2pt.js +345 -0
  213. package/dist/index-DclK-Mc7.js +2864 -0
  214. package/dist/index-DcnzaxVi.js +142 -0
  215. package/dist/index-Dd8PlF0M.js +2857 -0
  216. package/dist/index-DdkVT39s.js +345 -0
  217. package/dist/index-DeLbU1t-.js +345 -0
  218. package/dist/index-DfV_J8Te.js +345 -0
  219. package/dist/index-DgPnNd8U.js +475 -0
  220. package/dist/index-Dg_JLa7s.js +345 -0
  221. package/dist/index-Di2VPQjn.js +345 -0
  222. package/dist/index-DibHUbqc.js +372 -0
  223. package/dist/index-DjCVSrpw.js +475 -0
  224. package/dist/index-Djdb936p.js +142 -0
  225. package/dist/index-DmFL_GSt.js +142 -0
  226. package/dist/index-DmP4X2k0.js +372 -0
  227. package/dist/index-DmtmRd1r.js +372 -0
  228. package/dist/index-Dn8MA3kh.js +475 -0
  229. package/dist/index-Do7uXDSi.js +2071 -0
  230. package/dist/index-Dpv1M9Hu.js +372 -0
  231. package/dist/index-DqUuZC8f.js +372 -0
  232. package/dist/index-DtEXQIjn.js +372 -0
  233. package/dist/index-Dtw-qZ0V.js +372 -0
  234. package/dist/index-Dv3hIz8H.js +345 -0
  235. package/dist/index-Dv9jnaWp.js +345 -0
  236. package/dist/index-Dw8KZwGJ.js +2354 -0
  237. package/dist/index-DwJILh-Q.js +3149 -0
  238. package/dist/index-DwzGV3B9.js +142 -0
  239. package/dist/index-DyybaRkK.js +345 -0
  240. package/dist/index-DzerABZq.js +372 -0
  241. package/dist/index-F53NVkhc.js +142 -0
  242. package/dist/index-Fl0_k4XF.js +475 -0
  243. package/dist/index-HMYRCPrs.js +2326 -0
  244. package/dist/index-I49wpmT-.js +372 -0
  245. package/dist/index-IPv1O8Zq.js +345 -0
  246. package/dist/index-JLqnaery.js +372 -0
  247. package/dist/index-JRCQ1CYj.js +142 -0
  248. package/dist/index-L86-iO8O.js +345 -0
  249. package/dist/index-Q56EoFor.js +142 -0
  250. package/dist/index-QxKMr6p0.js +2829 -0
  251. package/dist/index-THRvW9Xm.js +2856 -0
  252. package/dist/index-WIUmTlfL.js +345 -0
  253. package/dist/index-WRrsK0pR.js +475 -0
  254. package/dist/index-Wq652QGf.js +2836 -0
  255. package/dist/index-YnSLCdjP.js +475 -0
  256. package/dist/index-Ynf0lvBE.js +142 -0
  257. package/dist/index-_OtTmb9i.js +142 -0
  258. package/dist/index-_oqoy_3D.js +142 -0
  259. package/dist/index-cl4Y-BWw.js +475 -0
  260. package/dist/index-d_eHJkDW.js +475 -0
  261. package/dist/index-dnmEyUWB.js +372 -0
  262. package/dist/index-dz6CwD6A.js +142 -0
  263. package/dist/index-g4rkaRry.js +475 -0
  264. package/dist/index-g9bRMdAX.js +142 -0
  265. package/dist/index-h4z4-a2p.js +2852 -0
  266. package/dist/index-h7BhcQYM.js +475 -0
  267. package/dist/index-hI3qofTF.js +345 -0
  268. package/dist/index-iyQQumAA.js +372 -0
  269. package/dist/index-js_OhKON.js +345 -0
  270. package/dist/index-kgb4MdHr.js +475 -0
  271. package/dist/index-logKl0VM.js +3144 -0
  272. package/dist/index-lrFMrOlR.js +3132 -0
  273. package/dist/index-mEHxtQWj.js +372 -0
  274. package/dist/index-mNm1BV3n.js +2857 -0
  275. package/dist/index-oOzAFXfr.js +142 -0
  276. package/dist/index-s3vGq0ro.js +345 -0
  277. package/dist/index-wt7AbUqc.js +2342 -0
  278. package/dist/index.es.js +1 -1
  279. package/dist/index.html +28 -0
  280. package/dist/index.umd.js +1 -8
  281. package/dist/style.css +1 -1
  282. package/package.json +87 -91
  283. package/src/App.vue +1 -30
  284. package/src/assets/styles/_root.scss +97 -141
  285. package/src/assets/styles/_variables.scss +19 -44
  286. package/src/assets/styles/index.scss +42 -267
  287. package/src/components/Layout/Sidebar.vue +2 -43
  288. package/src/components/Layout/TopMenu.vue +12 -37
  289. package/src/components/Layout/index.vue +0 -1
  290. package/src/utils/request.ts +1 -18
  291. package/src/views/dashboard/index.vue +155 -417
  292. package/src/views/error/403.vue +56 -251
  293. package/src/views/error/404.vue +56 -253
  294. package/src/views/login/index.vue +194 -586
  295. package/src/views/system/menu/index.vue +94 -403
  296. package/src/views/system/role/index.vue +69 -348
  297. package/src/views/system/user/index.vue +73 -402
  298. package/dist/index-BZaqYObA.js +0 -479
  299. package/dist/index-CbwOysFI.js +0 -641
  300. package/dist/index-Jynxhhda.js +0 -189
  301. package/dist/index-XgzSS-fV.js +0 -515
  302. package/dist/index-_iZKFlCa.js +0 -4178
  303. package/src/types/json-bigint.d.ts +0 -18
@@ -1,587 +1,195 @@
1
- <script setup lang="ts">
2
- import { ref, reactive } from 'vue'
3
- import { useRouter, useRoute } from 'vue-router'
4
- import { Button, Icon } from '@xto/base'
5
- import { Form, FormItem, Input, Checkbox } from '@xto/form'
6
- import { Message } from '@xto/feedback'
7
- import { login } from '@/api/auth'
8
- import { setTokenInfo } from '@/utils/auth'
9
- import { getAppId, getClientId } from '@/utils/config'
10
-
11
- const router = useRouter()
12
- const route = useRoute()
13
-
14
- const loading = ref(false)
15
- const rememberMe = ref(false)
16
-
17
- const formData = reactive({
18
- uid: '',
19
- password: ''
20
- })
21
-
22
- const rules: Record<string, any[]> = {
23
- uid: [
24
- { required: true, message: '请输入用户名', trigger: 'blur' }
25
- ],
26
- password: [
27
- { required: true, message: '请输入密码', trigger: 'blur' },
28
- { min: 6, message: '密码长度至少6位', trigger: 'blur' }
29
- ]
30
- }
31
-
32
- const formRef = ref()
33
-
34
- // 登录
35
- const handleLogin = async () => {
36
- try {
37
- await formRef.value?.validate()
38
- loading.value = true
39
-
40
- // 调用登录 API
41
- const result = await login({
42
- appId: getAppId(),
43
- clientId: getClientId(),
44
- uid: formData.uid,
45
- password: formData.password,
46
- code: true
47
- })
48
-
49
- // 保存 token
50
- setTokenInfo(result)
51
-
52
- Message.success('登录成功')
53
-
54
- // 获取重定向地址
55
- const redirect = route.query.redirect as string || '/'
56
-
57
- // 跳转到目标页面(路由守卫会自动获取用户信息和菜单)
58
- router.push(redirect)
59
- } catch (error) {
60
- console.error('登录失败:', error)
61
- } finally {
62
- loading.value = false
63
- }
64
- }
65
- </script>
66
-
67
- <template>
68
- <div class="login-page">
69
- <!-- 左侧品牌区域 -->
70
- <div class="login-brand">
71
- <div class="brand-content">
72
- <!-- Logo -->
73
- <div class="brand-logo">
74
- <div class="logo-icon">
75
- <svg viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
76
- <rect width="48" height="48" rx="12" fill="currentColor"/>
77
- <path d="M14 24L20 30L34 16" stroke="white" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
78
- </svg>
79
- </div>
80
- <span class="logo-text">XTO</span>
81
- </div>
82
-
83
- <!-- 标语 -->
84
- <div class="brand-slogan">
85
- <h1>企业级后台管理解决方案</h1>
86
- <p>开箱即用的中后台前端/设计解决方案</p>
87
- </div>
88
-
89
- <!-- 特性列表 -->
90
- <div class="brand-features">
91
- <div class="feature-item">
92
- <div class="feature-icon">
93
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
94
- <path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z"/>
95
- </svg>
96
- </div>
97
- <div class="feature-text">
98
- <h4>高性能</h4>
99
- <p>极致的渲染性能与响应速度</p>
100
- </div>
101
- </div>
102
- <div class="feature-item">
103
- <div class="feature-icon">
104
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
105
- <rect x="3" y="3" width="18" height="18" rx="2"/>
106
- <path d="M9 9h6M9 12h6M9 15h4"/>
107
- </svg>
108
- </div>
109
- <div class="feature-text">
110
- <h4>丰富组件</h4>
111
- <p>60+ 高质量业务组件</p>
112
- </div>
113
- </div>
114
- <div class="feature-item">
115
- <div class="feature-icon">
116
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
117
- <circle cx="12" cy="12" r="10"/>
118
- <path d="M12 6v6l4 2"/>
119
- </svg>
120
- </div>
121
- <div class="feature-text">
122
- <h4>持续更新</h4>
123
- <p>活跃的社区与快速迭代</p>
124
- </div>
125
- </div>
126
- </div>
127
-
128
- <!-- 底部装饰 -->
129
- <div class="brand-decoration">
130
- <div class="decoration-line"></div>
131
- <div class="decoration-dots">
132
- <span></span><span></span><span></span>
133
- </div>
134
- </div>
135
- </div>
136
-
137
- <!-- 背景装饰 -->
138
- <div class="brand-bg">
139
- <div class="bg-grid"></div>
140
- <div class="bg-glow"></div>
141
- <div class="bg-pattern"></div>
142
- </div>
143
- </div>
144
-
145
- <!-- 右侧登录区域 -->
146
- <div class="login-form-section">
147
- <div class="form-container">
148
- <!-- 头部 -->
149
- <div class="form-header">
150
- <h2>欢迎登录</h2>
151
- <p>请输入您的账户信息</p>
152
- </div>
153
-
154
- <!-- 表单 -->
155
- <Form
156
- ref="formRef"
157
- :model="formData"
158
- :rules="rules"
159
- class="login-form"
160
- label-width="0"
161
- >
162
- <FormItem prop="uid">
163
- <div class="input-wrapper">
164
- <label class="input-label">用户名</label>
165
- <Input
166
- v-model="formData.uid"
167
- placeholder="请输入用户名"
168
- size="large"
169
- >
170
- <template #prefix>
171
- <Icon name="user" :size="18" />
172
- </template>
173
- </Input>
174
- </div>
175
- </FormItem>
176
-
177
- <FormItem prop="password">
178
- <div class="input-wrapper">
179
- <label class="input-label">密码</label>
180
- <Input
181
- v-model="formData.password"
182
- type="password"
183
- placeholder="请输入密码"
184
- size="large"
185
- show-password
186
- @keyup.enter="handleLogin"
187
- >
188
- <template #prefix>
189
- <Icon name="lock" :size="18" />
190
- </template>
191
- </Input>
192
- </div>
193
- </FormItem>
194
-
195
- <div class="form-options">
196
- <Checkbox v-model="rememberMe">记住我</Checkbox>
197
- <a href="#" class="forgot-link">忘记密码?</a>
198
- </div>
199
-
200
- <FormItem>
201
- <Button
202
- type="primary"
203
- size="large"
204
- :loading="loading"
205
- class="login-btn"
206
- @click="handleLogin"
207
- >
208
- <span v-if="!loading">登 录</span>
209
- <span v-else>登录中...</span>
210
- </Button>
211
- </FormItem>
212
- </Form>
213
-
214
- <!-- 底部 -->
215
- <div class="form-footer">
216
- <p>其他登录方式</p>
217
- <div class="social-login">
218
- <button class="social-btn" title="企业微信">
219
- <svg viewBox="0 0 24 24" fill="currentColor">
220
- <path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 17.93c-3.95-.49-7-3.85-7-7.93 0-.62.08-1.21.21-1.79L9 15v1c0 1.1.9 2 2 2v1.93zm6.9-2.54c-.26-.81-1-1.39-1.9-1.39h-1v-3c0-.55-.45-1-1-1H8v-2h2c.55 0 1-.45 1-1V7h2c1.1 0 2-.9 2-2v-.41c2.93 1.19 5 4.06 5 7.41 0 2.08-.8 3.97-2.1 5.39z"/>
221
- </svg>
222
- </button>
223
- <button class="social-btn" title="钉钉">
224
- <svg viewBox="0 0 24 24" fill="currentColor">
225
- <path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm4.64 6.8c-.15 1.58-.8 5.42-1.13 7.19-.14.75-.42 1-.68 1.03-.58.05-1.02-.38-1.58-.75-.88-.58-1.38-.94-2.23-1.5-.99-.65-.35-1.01.22-1.59.15-.15 2.71-2.48 2.76-2.69a.2.2 0 00-.05-.18c-.06-.05-.14-.03-.21-.02-.09.02-1.49.95-4.22 2.79-.4.27-.76.41-1.08.4-.36-.01-1.04-.2-1.55-.37-.63-.2-1.12-.31-1.08-.66.02-.18.27-.36.74-.55 2.92-1.27 4.86-2.11 5.83-2.51 2.78-1.16 3.35-1.36 3.73-1.36.08 0 .27.02.39.12.1.08.13.19.14.27-.01.06.01.24 0 .38z"/>
226
- </svg>
227
- </button>
228
- <button class="social-btn" title="飞书">
229
- <svg viewBox="0 0 24 24" fill="currentColor">
230
- <path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z"/>
231
- </svg>
232
- </button>
233
- </div>
234
- </div>
235
- </div>
236
-
237
- <!-- 版权信息 -->
238
- <div class="copyright">
239
- <p>© 2024 XTO Team. All rights reserved.</p>
240
- </div>
241
- </div>
242
- </div>
243
- </template>
244
-
245
- <style lang="scss" scoped>
246
- .login-page {
247
- width: 100%;
248
- min-height: 100vh;
249
- display: flex;
250
- background: var(--bg-color-page);
251
- }
252
-
253
- // 左侧品牌区域
254
- .login-brand {
255
- flex: 1;
256
- position: relative;
257
- display: flex;
258
- align-items: center;
259
- justify-content: center;
260
- background: linear-gradient(135deg, #002c8c 0%, #0958d9 50%, #1677ff 100%);
261
- overflow: hidden;
262
-
263
- @media (max-width: 992px) {
264
- display: none;
265
- }
266
-
267
- .brand-content {
268
- position: relative;
269
- z-index: 2;
270
- padding: 60px;
271
- max-width: 520px;
272
- color: #fff;
273
- }
274
-
275
- .brand-logo {
276
- display: flex;
277
- align-items: center;
278
- gap: 12px;
279
- margin-bottom: 48px;
280
-
281
- .logo-icon {
282
- width: 48px;
283
- height: 48px;
284
- color: #fff;
285
- }
286
-
287
- .logo-text {
288
- font-size: 28px;
289
- font-weight: 700;
290
- letter-spacing: 2px;
291
- }
292
- }
293
-
294
- .brand-slogan {
295
- margin-bottom: 48px;
296
-
297
- h1 {
298
- font-size: 32px;
299
- font-weight: 600;
300
- line-height: 1.3;
301
- margin-bottom: 12px;
302
- }
303
-
304
- p {
305
- font-size: 16px;
306
- opacity: 0.8;
307
- line-height: 1.6;
308
- }
309
- }
310
-
311
- .brand-features {
312
- display: flex;
313
- flex-direction: column;
314
- gap: 24px;
315
-
316
- .feature-item {
317
- display: flex;
318
- align-items: flex-start;
319
- gap: 16px;
320
- padding: 16px;
321
- background: rgba(255, 255, 255, 0.1);
322
- border-radius: var(--border-radius-large);
323
- backdrop-filter: blur(10px);
324
- transition: all 0.3s ease;
325
-
326
- &:hover {
327
- background: rgba(255, 255, 255, 0.15);
328
- transform: translateX(8px);
329
- }
330
- }
331
-
332
- .feature-icon {
333
- width: 40px;
334
- height: 40px;
335
- display: flex;
336
- align-items: center;
337
- justify-content: center;
338
- background: rgba(255, 255, 255, 0.2);
339
- border-radius: var(--border-radius-base);
340
- flex-shrink: 0;
341
-
342
- svg {
343
- width: 20px;
344
- height: 20px;
345
- }
346
- }
347
-
348
- .feature-text {
349
- h4 {
350
- font-size: 15px;
351
- font-weight: 600;
352
- margin-bottom: 4px;
353
- }
354
-
355
- p {
356
- font-size: 13px;
357
- opacity: 0.8;
358
- }
359
- }
360
- }
361
-
362
- .brand-decoration {
363
- position: absolute;
364
- bottom: 60px;
365
- left: 60px;
366
- right: 60px;
367
- display: flex;
368
- align-items: center;
369
- gap: 16px;
370
-
371
- .decoration-line {
372
- flex: 1;
373
- height: 1px;
374
- background: linear-gradient(90deg, rgba(255, 255, 255, 0.3), transparent);
375
- }
376
-
377
- .decoration-dots {
378
- display: flex;
379
- gap: 8px;
380
-
381
- span {
382
- width: 6px;
383
- height: 6px;
384
- background: rgba(255, 255, 255, 0.5);
385
- border-radius: 50%;
386
- }
387
- }
388
- }
389
-
390
- // 背景装饰
391
- .brand-bg {
392
- position: absolute;
393
- inset: 0;
394
- z-index: 1;
395
- overflow: hidden;
396
-
397
- .bg-grid {
398
- position: absolute;
399
- inset: 0;
400
- background-image:
401
- linear-gradient(rgba(255, 255, 255, 0.03) 1px, transparent 1px),
402
- linear-gradient(90deg, rgba(255, 255, 255, 0.03) 1px, transparent 1px);
403
- background-size: 60px 60px;
404
- }
405
-
406
- .bg-glow {
407
- position: absolute;
408
- top: -20%;
409
- right: -10%;
410
- width: 60%;
411
- height: 60%;
412
- background: radial-gradient(circle, rgba(255, 255, 255, 0.1) 0%, transparent 70%);
413
- animation: glow-pulse 8s ease-in-out infinite;
414
- }
415
-
416
- .bg-pattern {
417
- position: absolute;
418
- bottom: -10%;
419
- left: -10%;
420
- width: 40%;
421
- height: 40%;
422
- background: radial-gradient(circle, rgba(255, 255, 255, 0.08) 0%, transparent 60%);
423
- }
424
- }
425
- }
426
-
427
- @keyframes glow-pulse {
428
- 0%, 100% { opacity: 0.6; transform: scale(1); }
429
- 50% { opacity: 1; transform: scale(1.1); }
430
- }
431
-
432
- // 右侧登录区域
433
- .login-form-section {
434
- width: 500px;
435
- min-height: 100vh;
436
- display: flex;
437
- flex-direction: column;
438
- justify-content: center;
439
- padding: 60px 80px;
440
- background: var(--bg-color);
441
-
442
- @media (max-width: 768px) {
443
- width: 100%;
444
- padding: 40px 24px;
445
- }
446
-
447
- .form-container {
448
- width: 100%;
449
- max-width: 360px;
450
- margin: 0 auto;
451
- }
452
-
453
- .form-header {
454
- margin-bottom: 40px;
455
-
456
- h2 {
457
- font-size: 28px;
458
- font-weight: 600;
459
- color: var(--color-text-primary);
460
- margin-bottom: 8px;
461
- }
462
-
463
- p {
464
- font-size: 14px;
465
- color: var(--color-text-secondary);
466
- }
467
- }
468
-
469
- .login-form {
470
- .input-wrapper {
471
- margin-bottom: 4px;
472
- }
473
-
474
- .input-label {
475
- display: block;
476
- font-size: 14px;
477
- font-weight: 500;
478
- color: var(--color-text-regular);
479
- margin-bottom: 8px;
480
- }
481
-
482
- :deep(.x-form-item) {
483
- margin-bottom: 24px;
484
- }
485
-
486
- :deep(.x-input) {
487
- --x-input-border-radius: 8px;
488
- }
489
-
490
- :deep(.x-input__prefix) {
491
- margin-right: 12px;
492
- color: var(--color-text-placeholder);
493
- }
494
- }
495
-
496
- .form-options {
497
- display: flex;
498
- justify-content: space-between;
499
- align-items: center;
500
- margin-bottom: 24px;
501
-
502
- .forgot-link {
503
- font-size: 14px;
504
- color: var(--color-primary);
505
- text-decoration: none;
506
- transition: color 0.2s;
507
-
508
- &:hover {
509
- color: var(--color-primary-dark-1);
510
- }
511
- }
512
- }
513
-
514
- .login-btn {
515
- width: 100%;
516
- height: 44px;
517
- font-size: 16px;
518
- font-weight: 500;
519
- border-radius: 8px;
520
- letter-spacing: 4px;
521
- transition: all 0.3s ease;
522
-
523
- &:hover:not(:disabled) {
524
- transform: translateY(-2px);
525
- box-shadow: 0 4px 12px rgba(22, 119, 255, 0.4);
526
- }
527
-
528
- &:active:not(:disabled) {
529
- transform: translateY(0);
530
- }
531
- }
532
-
533
- .form-footer {
534
- margin-top: 32px;
535
- padding-top: 24px;
536
- border-top: 1px solid var(--color-border-lighter);
537
- text-align: center;
538
-
539
- p {
540
- font-size: 13px;
541
- color: var(--color-text-placeholder);
542
- margin-bottom: 16px;
543
- }
544
-
545
- .social-login {
546
- display: flex;
547
- justify-content: center;
548
- gap: 16px;
549
- }
550
-
551
- .social-btn {
552
- width: 44px;
553
- height: 44px;
554
- display: flex;
555
- align-items: center;
556
- justify-content: center;
557
- background: var(--color-fill);
558
- border: none;
559
- border-radius: 50%;
560
- cursor: pointer;
561
- transition: all 0.2s ease;
562
- color: var(--color-text-secondary);
563
-
564
- svg {
565
- width: 20px;
566
- height: 20px;
567
- }
568
-
569
- &:hover {
570
- background: var(--color-primary-light-6);
571
- color: var(--color-primary);
572
- transform: translateY(-2px);
573
- }
574
- }
575
- }
576
-
577
- .copyright {
578
- margin-top: 48px;
579
- text-align: center;
580
-
581
- p {
582
- font-size: 12px;
583
- color: var(--color-text-placeholder);
584
- }
585
- }
586
- }
1
+ <script setup lang="ts">
2
+ import { ref, reactive } from 'vue'
3
+ import { useRouter, useRoute } from 'vue-router'
4
+ import { Button, Icon } from '@xto/base'
5
+ import { Form, FormItem, Input, Checkbox } from '@xto/form'
6
+ import { Message } from '@xto/feedback'
7
+ import { login } from '@/api/auth'
8
+ import { setTokenInfo } from '@/utils/auth'
9
+ import { getAppId, getClientId } from '@/utils/config'
10
+
11
+ const router = useRouter()
12
+ const route = useRoute()
13
+
14
+ const loading = ref(false)
15
+ const rememberMe = ref(false)
16
+
17
+ const formData = reactive({
18
+ uid: '',
19
+ password: ''
20
+ })
21
+
22
+ const rules: Record<string, any[]> = {
23
+ uid: [
24
+ { required: true, message: '请输入用户名', trigger: 'blur' }
25
+ ],
26
+ password: [
27
+ { required: true, message: '请输入密码', trigger: 'blur' },
28
+ { min: 6, message: '密码长度至少6位', trigger: 'blur' }
29
+ ]
30
+ }
31
+
32
+ const formRef = ref()
33
+
34
+ // 登录
35
+ const handleLogin = async () => {
36
+ try {
37
+ await formRef.value?.validate()
38
+ loading.value = true
39
+
40
+ // 调用登录 API
41
+ const result = await login({
42
+ appId: getAppId(),
43
+ clientId: getClientId(),
44
+ uid: formData.uid,
45
+ password: formData.password,
46
+ code: true
47
+ })
48
+
49
+ // 保存 token
50
+ setTokenInfo(result)
51
+
52
+ Message.success('登录成功')
53
+
54
+ // 获取重定向地址
55
+ const redirect = route.query.redirect as string || '/'
56
+
57
+ // 跳转到目标页面(路由守卫会自动获取用户信息和菜单)
58
+ router.push(redirect)
59
+ } catch (error) {
60
+ console.error('登录失败:', error)
61
+ } finally {
62
+ loading.value = false
63
+ }
64
+ }
65
+ </script>
66
+
67
+ <template>
68
+ <div class="login">
69
+ <div class="login__container">
70
+ <div class="login__header">
71
+ <img src="/vite.svg" alt="Logo" class="login__logo" />
72
+ <h1 class="login__title">Xto Demo</h1>
73
+ <p class="login__subtitle">后台管理系统</p>
74
+ </div>
75
+
76
+ <Form
77
+ ref="formRef"
78
+ :model="formData"
79
+ :rules="rules"
80
+ class="login__form"
81
+ label-width="0"
82
+ >
83
+ <FormItem prop="uid">
84
+ <Input
85
+ v-model="formData.uid"
86
+ placeholder="用户名"
87
+ size="large"
88
+ >
89
+ <template #prefix>
90
+ <Icon name="user" :size="18" />
91
+ </template>
92
+ </Input>
93
+ </FormItem>
94
+
95
+ <FormItem prop="password">
96
+ <Input
97
+ v-model="formData.password"
98
+ type="password"
99
+ placeholder="密码"
100
+ size="large"
101
+ show-password
102
+ @keyup.enter="handleLogin"
103
+ >
104
+ <template #prefix>
105
+ <Icon name="lock" :size="18" />
106
+ </template>
107
+ </Input>
108
+ </FormItem>
109
+
110
+ <FormItem>
111
+ <Checkbox v-model="rememberMe">记住我</Checkbox>
112
+ </FormItem>
113
+
114
+ <FormItem>
115
+ <Button
116
+ type="primary"
117
+ size="large"
118
+ :loading="loading"
119
+ class="login__submit"
120
+ @click="handleLogin"
121
+ >
122
+ 登录
123
+ </Button>
124
+ </FormItem>
125
+ </Form>
126
+
127
+ <div class="login__footer">
128
+ <p>请输入您的用户名和密码</p>
129
+ </div>
130
+ </div>
131
+ </div>
132
+ </template>
133
+
134
+ <style lang="scss" scoped>
135
+ .login {
136
+ width: 100%;
137
+ min-height: 100vh;
138
+ display: flex;
139
+ align-items: center;
140
+ justify-content: flex-end;
141
+ padding-right: 15%;
142
+ background: linear-gradient(135deg, var(--color-primary-light-9) 0%, var(--color-primary-light-7) 100%);
143
+
144
+ &__container {
145
+ width: 400px;
146
+ padding: 40px;
147
+ background-color: var(--bg-color);
148
+ border-radius: var(--border-radius-large);
149
+ box-shadow: var(--box-shadow-dark);
150
+ }
151
+
152
+ &__header {
153
+ text-align: center;
154
+ margin-bottom: 30px;
155
+ }
156
+
157
+ &__logo {
158
+ width: 60px;
159
+ height: 60px;
160
+ }
161
+
162
+ &__title {
163
+ font-size: 28px;
164
+ font-weight: 600;
165
+ color: var(--color-primary);
166
+ margin: 15px 0 5px;
167
+ }
168
+
169
+ &__subtitle {
170
+ font-size: 14px;
171
+ color: var(--color-text-secondary);
172
+ }
173
+
174
+ &__form {
175
+ :deep(.x-form-item) {
176
+ margin-bottom: 20px;
177
+ }
178
+
179
+ :deep(.x-input__prefix) {
180
+ margin-right: 8px;
181
+ }
182
+ }
183
+
184
+ &__submit {
185
+ width: 100%;
186
+ }
187
+
188
+ &__footer {
189
+ text-align: center;
190
+ margin-top: 20px;
191
+ font-size: 12px;
192
+ color: var(--color-text-placeholder);
193
+ }
194
+ }
587
195
  </style>