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,7 +1,7 @@
1
1
  <script setup lang="ts">
2
2
  import { ref, reactive, computed, onMounted } from 'vue'
3
3
  import { Form, FormItem, Input, Select, Switch, InputNumber } from '@xto/form'
4
- import { Tag } from '@xto/data'
4
+ import { Card, Tag } from '@xto/data'
5
5
  import { Modal, Message } from '@xto/feedback'
6
6
  import { Space, Button } from '@xto/base'
7
7
  import { MenuType, MenuTypeOptions, Status } from '@/enums'
@@ -201,24 +201,6 @@ const getMenuIcon = (icon?: string) => {
201
201
  return iconMap[icon || ''] || '📄'
202
202
  }
203
203
 
204
- // 获取类型标签类型
205
- const getTypeTagType = (type: MenuType) => {
206
- switch (type) {
207
- case MenuType.DIRECTORY: return 'primary'
208
- case MenuType.MENU: return 'success'
209
- default: return 'warning'
210
- }
211
- }
212
-
213
- // 获取类型标签文本
214
- const getTypeTagText = (type: MenuType) => {
215
- switch (type) {
216
- case MenuType.DIRECTORY: return '目录'
217
- case MenuType.MENU: return '菜单'
218
- default: return '按钮'
219
- }
220
- }
221
-
222
204
  onMounted(() => {
223
205
  getMenuList()
224
206
  })
@@ -226,155 +208,74 @@ onMounted(() => {
226
208
 
227
209
  <template>
228
210
  <div class="menu-page">
229
- <!-- 表格 -->
230
- <div class="table-section">
211
+ <Card class="menu-card">
231
212
  <!-- 工具栏 -->
232
- <div class="table-toolbar">
233
- <div class="toolbar-left">
234
- <Button type="primary" @click="handleAdd()">
235
- <template #icon>
236
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
237
- <line x1="12" y1="5" x2="12" y2="19"/>
238
- <line x1="5" y1="12" x2="19" y2="12"/>
239
- </svg>
240
- </template>
241
- 新增菜单
242
- </Button>
243
- </div>
244
- <div class="toolbar-right">
245
- <span class="table-count">共 {{ menuList.length }} 个菜单</span>
246
- </div>
213
+ <div class="toolbar">
214
+ <Button type="primary" @click="handleAdd()">新增菜单</Button>
247
215
  </div>
248
216
 
249
- <!-- 菜单树表格 -->
250
- <div class="table-wrapper">
251
- <table class="data-table">
217
+ <!-- 菜单树 -->
218
+ <div class="menu-tree">
219
+ <table class="tree-table">
252
220
  <thead>
253
221
  <tr>
254
- <th class="col-name">菜单名称</th>
255
- <th class="col-icon">图标</th>
256
- <th class="col-path">路由路径</th>
257
- <th class="col-type">类型</th>
258
- <th class="col-sort">排序</th>
259
- <th class="col-status">状态</th>
260
- <th class="col-actions">操作</th>
222
+ <th>菜单名称</th>
223
+ <th>图标</th>
224
+ <th>路由路径</th>
225
+ <th>类型</th>
226
+ <th>排序</th>
227
+ <th>状态</th>
228
+ <th>操作</th>
261
229
  </tr>
262
230
  </thead>
263
231
  <tbody>
264
- <tr v-if="loading">
265
- <td colspan="7" class="loading-cell">
266
- <div class="loading-content">
267
- <div class="loading-spinner"></div>
268
- <span>加载中...</span>
269
- </div>
270
- </td>
271
- </tr>
272
- <tr v-else-if="menuList.length === 0">
273
- <td colspan="7" class="empty-cell">
274
- <div class="empty-content">
275
- <svg viewBox="0 0 64 41" fill="none">
276
- <g transform="translate(0 1)">
277
- <ellipse fill="#f5f5f5" cx="32" cy="33" rx="32" ry="7"/>
278
- <g stroke="var(--color-text-placeholder)" stroke-width="2">
279
- <path d="M55 12.76L44.854 1.258C44.367.474 43.656 0 42.907 0H21.093c-.749 0-1.46.474-1.947 1.257L9 12.761V22h46v-9.24z"/>
280
- <path d="M41.613 15.931c0-1.605.994-2.93 2.227-2.931H55v18.137C55 33.26 53.68 35 52.05 35H11.95C10.32 35 9 33.259 9 31.137V13h11.16c1.233 0 2.227 1.323 2.227 2.928v.022c0 1.605 1.005 2.901 2.237 2.901h14.752c1.232 0 2.237-1.308 2.237-2.913v-.007z" fill="var(--color-fill)"/>
281
- </g>
282
- </g>
283
- </svg>
284
- <span>暂无数据</span>
285
- </div>
286
- </td>
287
- </tr>
288
- <template v-else v-for="menu in menuList" :key="menu.id">
289
- <tr class="data-row tree-row--level-0">
290
- <td class="col-name">
291
- <div class="menu-info">
292
- <span class="menu-icon-wrapper">{{ getMenuIcon(menu.icon) }}</span>
293
- <span class="menu-title" @click="handleEdit(menu)">{{ menu.title }}</span>
294
- </div>
295
- </td>
296
- <td class="col-icon">
297
- <span class="icon-text">{{ getMenuIcon(menu.icon) }}</span>
298
- </td>
299
- <td class="col-path">
300
- <code class="path-code">{{ menu.path }}</code>
232
+ <template v-for="menu in menuList" :key="menu.id">
233
+ <tr class="tree-row tree-row--level-0">
234
+ <td>
235
+ <span class="menu-name" @click="handleEdit(menu)">{{ menu.title }}</span>
301
236
  </td>
302
- <td class="col-type">
303
- <Tag :type="getTypeTagType(menu.type)" size="small">
304
- {{ getTypeTagText(menu.type) }}
237
+ <td>{{ getMenuIcon(menu.icon) }}</td>
238
+ <td>{{ menu.path }}</td>
239
+ <td>
240
+ <Tag :type="menu.type === MenuType.DIRECTORY ? 'primary' : menu.type === MenuType.MENU ? 'success' : 'warning'" size="small">
241
+ {{ menu.type === MenuType.DIRECTORY ? '目录' : menu.type === MenuType.MENU ? '菜单' : '按钮' }}
305
242
  </Tag>
306
243
  </td>
307
- <td class="col-sort">
308
- <span class="sort-badge">{{ menu.sort }}</span>
309
- </td>
310
- <td class="col-status">
244
+ <td>{{ menu.sort }}</td>
245
+ <td>
311
246
  <Tag :type="menu.status === Status.ENABLED ? 'success' : 'danger'" size="small">
312
247
  {{ menu.status === Status.ENABLED ? '启用' : '禁用' }}
313
248
  </Tag>
314
249
  </td>
315
- <td class="col-actions">
316
- <Space class="action-buttons">
317
- <Button type="primary" link size="small" @click="handleAdd(menu.id)">
318
- <template #icon>
319
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
320
- <line x1="12" y1="5" x2="12" y2="19"/>
321
- <line x1="5" y1="12" x2="19" y2="12"/>
322
- </svg>
323
- </template>
324
- 新增
325
- </Button>
326
- <Button type="primary" link size="small" @click="handleEdit(menu)">
327
- <template #icon>
328
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
329
- <path d="M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7"/>
330
- <path d="M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z"/>
331
- </svg>
332
- </template>
333
- 编辑
334
- </Button>
250
+ <td>
251
+ <Space>
252
+ <Button type="primary" link size="small" @click="handleAdd(menu.id)">新增</Button>
253
+ <Button type="primary" link size="small" @click="handleEdit(menu)">编辑</Button>
335
254
  </Space>
336
255
  </td>
337
256
  </tr>
338
257
  <template v-if="menu.children" v-for="child in menu.children" :key="child.id">
339
- <tr class="data-row tree-row--level-1">
340
- <td class="col-name">
341
- <div class="menu-info">
342
- <span class="tree-indent"></span>
343
- <span class="tree-line"></span>
344
- <span class="menu-icon-wrapper">{{ getMenuIcon(child.icon) }}</span>
345
- <span class="menu-title" @click="handleEdit(child)">{{ child.title }}</span>
346
- </div>
347
- </td>
348
- <td class="col-icon">
349
- <span class="icon-text">{{ getMenuIcon(child.icon) }}</span>
350
- </td>
351
- <td class="col-path">
352
- <code class="path-code">{{ child.path }}</code>
258
+ <tr class="tree-row tree-row--level-1">
259
+ <td>
260
+ <span class="tree-indent"></span>
261
+ <span class="menu-name" @click="handleEdit(child)">{{ child.title }}</span>
353
262
  </td>
354
- <td class="col-type">
355
- <Tag :type="getTypeTagType(child.type)" size="small">
356
- {{ getTypeTagText(child.type) }}
263
+ <td>{{ getMenuIcon(child.icon) }}</td>
264
+ <td>{{ child.path }}</td>
265
+ <td>
266
+ <Tag :type="child.type === MenuType.DIRECTORY ? 'primary' : child.type === MenuType.MENU ? 'success' : 'warning'" size="small">
267
+ {{ child.type === MenuType.DIRECTORY ? '目录' : child.type === MenuType.MENU ? '菜单' : '按钮' }}
357
268
  </Tag>
358
269
  </td>
359
- <td class="col-sort">
360
- <span class="sort-badge">{{ child.sort }}</span>
361
- </td>
362
- <td class="col-status">
270
+ <td>{{ child.sort }}</td>
271
+ <td>
363
272
  <Tag :type="child.status === Status.ENABLED ? 'success' : 'danger'" size="small">
364
273
  {{ child.status === Status.ENABLED ? '启用' : '禁用' }}
365
274
  </Tag>
366
275
  </td>
367
- <td class="col-actions">
368
- <Space class="action-buttons">
369
- <Button type="primary" link size="small" @click="handleEdit(child)">
370
- <template #icon>
371
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
372
- <path d="M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7"/>
373
- <path d="M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z"/>
374
- </svg>
375
- </template>
376
- 编辑
377
- </Button>
276
+ <td>
277
+ <Space>
278
+ <Button type="primary" link size="small" @click="handleEdit(child)">编辑</Button>
378
279
  </Space>
379
280
  </td>
380
281
  </tr>
@@ -383,55 +284,44 @@ onMounted(() => {
383
284
  </tbody>
384
285
  </table>
385
286
  </div>
386
- </div>
287
+ </Card>
387
288
 
388
289
  <!-- 编辑弹窗 -->
389
- <Modal v-model="modalVisible" :title="modalTitle" width="600px" class="menu-modal">
390
- <Form ref="formRef" :model="formData" :rules="rules" label-width="80px" class="menu-form">
391
- <div class="form-grid">
392
- <FormItem label="上级菜单" class="form-item-full">
393
- <Input v-model="formData.parentId" placeholder="上级菜单ID" disabled />
394
- </FormItem>
395
- <FormItem label="菜单类型">
396
- <Select v-model="formData.type" :options="MenuTypeOptions" />
397
- </FormItem>
398
- <FormItem label="排序">
399
- <InputNumber v-model="formData.sort" :min="0" />
400
- </FormItem>
401
- <FormItem label="菜单名称" prop="name">
402
- <Input v-model="formData.name" placeholder="请输入菜单名称(路由name)" />
403
- </FormItem>
404
- <FormItem label="菜单标题" prop="title">
405
- <Input v-model="formData.title" placeholder="请输入菜单标题" />
406
- </FormItem>
407
- <FormItem label="路由路径" prop="path" class="form-item-full">
408
- <Input v-model="formData.path" placeholder="请输入路由路径" />
409
- </FormItem>
410
- <FormItem label="组件路径" class="form-item-full">
411
- <Input v-model="formData.component" placeholder="请输入组件路径" />
412
- </FormItem>
413
- <FormItem label="图标">
414
- <Input v-model="formData.icon" placeholder="请输入图标名称" />
415
- </FormItem>
416
- <FormItem label="状态">
417
- <div class="status-field">
418
- <Switch v-model="formData.status" :active-value="Status.ENABLED" :inactive-value="Status.DISABLED" />
419
- <span class="status-label">{{ formData.status === Status.ENABLED ? '启用' : '禁用' }}</span>
420
- </div>
421
- </FormItem>
422
- <FormItem label="隐藏">
423
- <div class="status-field">
424
- <Switch v-model="formData.hidden" />
425
- <span class="status-label">{{ formData.hidden ? '隐藏' : '显示' }}</span>
426
- </div>
427
- </FormItem>
428
- <FormItem label="缓存">
429
- <div class="status-field">
430
- <Switch v-model="formData.keepAlive" />
431
- <span class="status-label">{{ formData.keepAlive ? '开启' : '关闭' }}</span>
432
- </div>
433
- </FormItem>
434
- </div>
290
+ <Modal v-model="modalVisible" :title="modalTitle" width="600px">
291
+ <Form ref="formRef" :model="formData" :rules="rules" label-width="80px">
292
+ <FormItem label="上级菜单">
293
+ <Input v-model="formData.parentId" placeholder="上级菜单ID" disabled />
294
+ </FormItem>
295
+ <FormItem label="菜单类型">
296
+ <Select v-model="formData.type" :options="MenuTypeOptions" />
297
+ </FormItem>
298
+ <FormItem label="菜单名称" prop="name">
299
+ <Input v-model="formData.name" placeholder="请输入菜单名称(路由name)" />
300
+ </FormItem>
301
+ <FormItem label="菜单标题" prop="title">
302
+ <Input v-model="formData.title" placeholder="请输入菜单标题" />
303
+ </FormItem>
304
+ <FormItem label="路由路径" prop="path">
305
+ <Input v-model="formData.path" placeholder="请输入路由路径" />
306
+ </FormItem>
307
+ <FormItem label="组件路径">
308
+ <Input v-model="formData.component" placeholder="请输入组件路径" />
309
+ </FormItem>
310
+ <FormItem label="图标">
311
+ <Input v-model="formData.icon" placeholder="请输入图标名称" />
312
+ </FormItem>
313
+ <FormItem label="排序">
314
+ <InputNumber v-model="formData.sort" :min="0" />
315
+ </FormItem>
316
+ <FormItem label="状态">
317
+ <Switch v-model="formData.status" :active-value="Status.ENABLED" :inactive-value="Status.DISABLED" />
318
+ </FormItem>
319
+ <FormItem label="隐藏">
320
+ <Switch v-model="formData.hidden" />
321
+ </FormItem>
322
+ <FormItem label="缓存">
323
+ <Switch v-model="formData.keepAlive" />
324
+ </FormItem>
435
325
  </Form>
436
326
  <template #footer>
437
327
  <Space>
@@ -445,246 +335,47 @@ onMounted(() => {
445
335
 
446
336
  <style lang="scss" scoped>
447
337
  .menu-page {
448
- padding: 24px;
449
- background: var(--bg-color-page);
450
- min-height: 100%;
451
- }
452
-
453
- // 表格区域
454
- .table-section {
455
- background: var(--bg-color);
456
- border-radius: var(--border-radius-large);
457
- box-shadow: var(--box-shadow-card);
458
- overflow: hidden;
459
- }
460
-
461
- .table-toolbar {
462
- display: flex;
463
- justify-content: space-between;
464
- align-items: center;
465
- padding: 16px 24px;
466
- border-bottom: 1px solid var(--color-border-lighter);
467
-
468
- .toolbar-left {
469
- display: flex;
470
- gap: 12px;
471
- }
338
+ padding: 20px;
472
339
 
473
- .table-count {
474
- font-size: 14px;
475
- color: var(--color-text-secondary);
340
+ .toolbar {
341
+ margin-bottom: 15px;
476
342
  }
477
343
  }
478
344
 
479
- .table-wrapper {
480
- overflow-x: auto;
481
- }
482
-
483
- // 表格样式
484
- .data-table {
345
+ .tree-table {
485
346
  width: 100%;
486
347
  border-collapse: collapse;
487
348
 
488
349
  th, td {
489
- padding: 14px 16px;
350
+ padding: 12px;
490
351
  text-align: left;
491
352
  border-bottom: 1px solid var(--color-border-lighter);
492
353
  }
493
354
 
494
355
  th {
495
- font-size: 14px;
496
356
  font-weight: 500;
497
- color: var(--color-text-secondary);
498
- background: var(--color-fill-light);
499
- white-space: nowrap;
500
- }
501
-
502
- .data-row {
503
- transition: background-color 0.2s;
504
-
505
- &:hover {
506
- background: var(--color-primary-light-6);
507
- }
508
- }
509
-
510
- td {
511
- vertical-align: middle;
512
- }
513
-
514
- .loading-cell,
515
- .empty-cell {
516
- padding: 60px 20px;
357
+ color: var(--color-text-regular);
358
+ background-color: var(--color-fill-light);
517
359
  }
518
360
 
519
- .loading-content,
520
- .empty-content {
521
- display: flex;
522
- flex-direction: column;
523
- align-items: center;
524
- gap: 16px;
525
- color: var(--color-text-placeholder);
526
-
527
- svg {
528
- width: 64px;
529
- height: 41px;
361
+ .tree-row--level-1 {
362
+ td:first-child {
363
+ padding-left: 30px;
530
364
  }
531
365
  }
532
-
533
- .loading-spinner {
534
- width: 32px;
535
- height: 32px;
536
- border: 3px solid var(--color-border-lighter);
537
- border-top-color: var(--color-primary);
538
- border-radius: 50%;
539
- animation: spin 0.8s linear infinite;
540
- }
541
- }
542
-
543
- @keyframes spin {
544
- to { transform: rotate(360deg); }
545
- }
546
-
547
- // 树形结构
548
- .tree-row--level-1 {
549
- .col-name {
550
- padding-left: 40px;
551
- }
552
366
  }
553
367
 
554
368
  .tree-indent {
555
369
  display: inline-block;
556
- width: 24px;
370
+ width: 20px;
557
371
  }
558
372
 
559
- .tree-line {
560
- position: relative;
561
- display: inline-block;
562
- width: 16px;
563
- height: 1px;
564
- background: var(--color-border-light);
565
- margin-right: 8px;
566
- vertical-align: middle;
567
- }
568
-
569
- // 列样式
570
- .col-name {
571
- min-width: 200px;
572
- }
573
-
574
- .menu-info {
575
- display: flex;
576
- align-items: center;
577
- gap: 8px;
578
- }
579
-
580
- .menu-icon-wrapper {
581
- width: 28px;
582
- height: 28px;
583
- display: flex;
584
- align-items: center;
585
- justify-content: center;
586
- background: var(--color-fill-light);
587
- border-radius: 6px;
588
- font-size: 14px;
589
- }
590
-
591
- .menu-title {
592
- font-size: 14px;
593
- font-weight: 500;
594
- color: var(--color-text-primary);
373
+ .menu-name {
595
374
  cursor: pointer;
596
- transition: color 0.2s;
375
+ color: var(--color-primary);
597
376
 
598
377
  &:hover {
599
- color: var(--color-primary);
600
- }
601
- }
602
-
603
- .col-icon {
604
- width: 80px;
605
- }
606
-
607
- .icon-text {
608
- font-size: 16px;
609
- }
610
-
611
- .col-path {
612
- min-width: 140px;
613
- }
614
-
615
- .path-code {
616
- font-family: 'SF Mono', Monaco, Consolas, monospace;
617
- font-size: 12px;
618
- padding: 4px 8px;
619
- background: var(--color-fill-light);
620
- border-radius: 4px;
621
- color: var(--color-text-secondary);
622
- }
623
-
624
- .col-type {
625
- width: 80px;
626
- }
627
-
628
- .col-sort {
629
- width: 60px;
630
- }
631
-
632
- .sort-badge {
633
- display: inline-flex;
634
- align-items: center;
635
- justify-content: center;
636
- min-width: 24px;
637
- height: 24px;
638
- padding: 0 8px;
639
- background: var(--color-fill);
640
- border-radius: 12px;
641
- font-size: 12px;
642
- color: var(--color-text-secondary);
643
- }
644
-
645
- .col-status {
646
- width: 80px;
647
- }
648
-
649
- .col-actions {
650
- min-width: 140px;
651
- }
652
-
653
- .action-buttons {
654
- :deep(.x-button) {
655
- padding: 4px 8px;
656
-
657
- svg {
658
- width: 14px;
659
- height: 14px;
660
- margin-right: 4px;
661
- }
662
- }
663
- }
664
-
665
- // 弹窗表单
666
- .menu-form {
667
- padding: 16px 0;
668
-
669
- .form-grid {
670
- display: grid;
671
- grid-template-columns: repeat(2, 1fr);
672
- gap: 0 24px;
673
- }
674
-
675
- .form-item-full {
676
- grid-column: span 2;
677
- }
678
-
679
- .status-field {
680
- display: flex;
681
- align-items: center;
682
- gap: 12px;
683
- }
684
-
685
- .status-label {
686
- font-size: 14px;
687
- color: var(--color-text-secondary);
378
+ text-decoration: underline;
688
379
  }
689
380
  }
690
- </style>
381
+ </style>