xto-fronted 0.1.1 → 0.1.3

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 (67) hide show
  1. package/.env.development +3 -4
  2. package/.env.production +3 -4
  3. package/bin/cli.js +104 -0
  4. package/dist/{403-MQkNUulz.js → 403-DM5wfQkM.js} +6 -6
  5. package/dist/{404-BOFYLq4X.js → 404-BurAu5LC.js} +7 -7
  6. package/dist/api/auth.d.ts +9 -8
  7. package/dist/api/menu.d.ts +3 -0
  8. package/dist/api/user.d.ts +2 -12
  9. package/dist/composables/index.d.ts +8 -0
  10. package/dist/composables/useApp.d.ts +64 -0
  11. package/dist/composables/useAuth.d.ts +19 -4
  12. package/dist/composables/useMenu.d.ts +34 -0
  13. package/dist/config/index.d.ts +11 -0
  14. package/dist/index-BNiEld34.js +15 -0
  15. package/dist/index-Be9RiEfo.js +98 -0
  16. package/dist/index-BqRv1bdN.js +1185 -0
  17. package/dist/index-CQLVXvNJ.js +15 -0
  18. package/dist/index-CyiE8n2V.js +15 -0
  19. package/dist/index-xauR1bOL.js +15 -0
  20. package/dist/index.d.ts +7 -4
  21. package/dist/index.es.js +50 -66
  22. package/dist/index.umd.js +1 -1
  23. package/dist/stores/auth.d.ts +60 -23
  24. package/dist/stores/menu.d.ts +40 -29
  25. package/dist/stores/user.d.ts +63 -84
  26. package/dist/style.css +1 -1
  27. package/dist/utils/auth.d.ts +15 -7
  28. package/dist/utils/permission.d.ts +1 -6
  29. package/dist/views/system/menu/index.vue.d.ts +1 -3
  30. package/dist/views/system/role/index.vue.d.ts +1 -3
  31. package/dist/views/system/user/index.vue.d.ts +1 -3
  32. package/package.json +27 -19
  33. package/src/api/auth.ts +34 -25
  34. package/src/api/menu.ts +13 -0
  35. package/src/api/user.ts +11 -45
  36. package/src/components/Layout/Header.vue +334 -389
  37. package/src/components/Layout/Sidebar.vue +212 -296
  38. package/src/components/Layout/Tabs.vue +19 -133
  39. package/src/composables/index.ts +9 -0
  40. package/src/composables/useApp.ts +170 -0
  41. package/src/composables/useAuth.ts +69 -44
  42. package/src/composables/useMenu.ts +141 -0
  43. package/src/config/index.ts +19 -0
  44. package/src/directives/permission.ts +40 -37
  45. package/src/index.ts +9 -4
  46. package/src/router/index.ts +70 -80
  47. package/src/stores/auth.ts +44 -31
  48. package/src/stores/menu.ts +157 -79
  49. package/src/stores/user.ts +40 -72
  50. package/src/types/api.d.ts +102 -83
  51. package/src/types/xto.d.ts +148 -148
  52. package/src/utils/auth.ts +85 -61
  53. package/src/utils/permission.ts +29 -41
  54. package/src/utils/request.ts +125 -125
  55. package/src/utils/storage.ts +10 -1
  56. package/src/views/dashboard/index.vue +31 -283
  57. package/src/views/login/index.vue +140 -247
  58. package/src/views/system/menu/index.vue +31 -380
  59. package/src/views/system/role/index.vue +31 -303
  60. package/src/views/system/user/index.vue +31 -326
  61. package/vite.config.ts +3 -3
  62. package/dist/index-BJxYdNPy.js +0 -475
  63. package/dist/index-BvnIIBR1.js +0 -142
  64. package/dist/index-CEvAq6KE.js +0 -372
  65. package/dist/index-DPkqej__.js +0 -345
  66. package/dist/index-pq9Z5K62.js +0 -184
  67. package/dist/index-vVfjShJR.js +0 -1183
@@ -1,381 +1,32 @@
1
- <script setup lang="ts">
2
- import { ref, reactive, computed, onMounted } from 'vue'
3
- import { Form, FormItem, Input, Select, Switch, InputNumber } from '@xto/form'
4
- import { Card, Tag } from '@xto/data'
5
- import { Modal, Message } from '@xto/feedback'
6
- import { Space, Button } from '@xto/base'
7
- import { MenuType, MenuTypeOptions, Status } from '@/enums'
8
-
9
- // 菜单数据类型
10
- interface Menu {
11
- id: number
12
- parentId: number | null
13
- name: string
14
- path: string
15
- component: string
16
- redirect: string
17
- icon: string
18
- title: string
19
- type: MenuType
20
- sort: number
21
- status: Status
22
- hidden: boolean
23
- keepAlive: boolean
24
- children?: Menu[]
25
- }
26
-
27
- // Mock 数据
28
- const mockMenus: Menu[] = [
29
- {
30
- id: 1,
31
- parentId: null,
32
- name: 'Dashboard',
33
- path: '/dashboard',
34
- component: 'dashboard/index',
35
- redirect: '',
36
- icon: 'dashboard',
37
- title: '仪表盘',
38
- type: MenuType.MENU,
39
- sort: 1,
40
- status: Status.ENABLED,
41
- hidden: false,
42
- keepAlive: true
43
- },
44
- {
45
- id: 2,
46
- parentId: null,
47
- name: 'System',
48
- path: '/system',
49
- component: '',
50
- redirect: '/system/user',
51
- icon: 'setting',
52
- title: '系统管理',
53
- type: MenuType.DIRECTORY,
54
- sort: 2,
55
- status: Status.ENABLED,
56
- hidden: false,
57
- keepAlive: false,
58
- children: [
59
- {
60
- id: 21,
61
- parentId: 2,
62
- name: 'SystemUser',
63
- path: '/system/user',
64
- component: 'system/user/index',
65
- redirect: '',
66
- icon: 'user',
67
- title: '用户管理',
68
- type: MenuType.MENU,
69
- sort: 1,
70
- status: Status.ENABLED,
71
- hidden: false,
72
- keepAlive: true
73
- },
74
- {
75
- id: 22,
76
- parentId: 2,
77
- name: 'SystemRole',
78
- path: '/system/role',
79
- component: 'system/role/index',
80
- redirect: '',
81
- icon: 'role',
82
- title: '角色管理',
83
- type: MenuType.MENU,
84
- sort: 2,
85
- status: Status.ENABLED,
86
- hidden: false,
87
- keepAlive: true
88
- },
89
- {
90
- id: 23,
91
- parentId: 2,
92
- name: 'SystemMenu',
93
- path: '/system/menu',
94
- component: 'system/menu/index',
95
- redirect: '',
96
- icon: 'menu',
97
- title: '菜单管理',
98
- type: MenuType.MENU,
99
- sort: 3,
100
- status: Status.ENABLED,
101
- hidden: false,
102
- keepAlive: true
103
- }
104
- ]
105
- }
106
- ]
107
-
108
- const loading = ref(false)
109
- const menuList = ref<Menu[]>([])
110
-
111
- // 弹窗
112
- const modalVisible = ref(false)
113
- const modalTitle = computed(() => formData.id ? '编辑菜单' : '新增菜单')
114
- const formData = reactive({
115
- id: 0,
116
- parentId: null as number | null,
117
- name: '',
118
- path: '',
119
- component: '',
120
- redirect: '',
121
- icon: '',
122
- title: '',
123
- type: MenuType.MENU,
124
- sort: 0,
125
- status: Status.ENABLED,
126
- hidden: false,
127
- keepAlive: true
128
- })
129
-
130
- const rules: Record<string, any[]> = {
131
- name: [
132
- { required: true, message: '请输入菜单名称', trigger: 'blur' }
133
- ],
134
- path: [
135
- { required: true, message: '请输入路由路径', trigger: 'blur' }
136
- ],
137
- title: [
138
- { required: true, message: '请输入菜单标题', trigger: 'blur' }
139
- ]
140
- }
141
-
142
- const formRef = ref()
143
-
144
- // 获取菜单列表
145
- const getMenuList = () => {
146
- loading.value = true
147
- setTimeout(() => {
148
- menuList.value = mockMenus
149
- loading.value = false
150
- }, 300)
151
- }
152
-
153
- // 新增
154
- const handleAdd = (parentId: number | null = null) => {
155
- Object.assign(formData, {
156
- id: 0,
157
- parentId,
158
- name: '',
159
- path: '',
160
- component: '',
161
- redirect: '',
162
- icon: '',
163
- title: '',
164
- type: MenuType.MENU,
165
- sort: 0,
166
- status: Status.ENABLED,
167
- hidden: false,
168
- keepAlive: true
169
- })
170
- modalVisible.value = true
171
- }
172
-
173
- // 编辑
174
- const handleEdit = (node: Menu) => {
175
- Object.assign(formData, node)
176
- modalVisible.value = true
177
- }
178
-
179
- // 提交
180
- const handleSubmit = async () => {
181
- try {
182
- await formRef.value?.validate()
183
- Message.success(formData.id ? '编辑成功' : '新增成功')
184
- modalVisible.value = false
185
- getMenuList()
186
- } catch (error) {
187
- console.error(error)
188
- }
189
- }
190
-
191
- // 菜单图标
192
- const getMenuIcon = (icon?: string) => {
193
- const iconMap: Record<string, string> = {
194
- dashboard: '📊',
195
- system: '⚙️',
196
- user: '👤',
197
- role: '👥',
198
- menu: '📋',
199
- setting: '🔧'
200
- }
201
- return iconMap[icon || ''] || '📄'
202
- }
203
-
204
- onMounted(() => {
205
- getMenuList()
206
- })
207
- </script>
208
-
209
- <template>
210
- <div class="menu-page">
211
- <Card class="menu-card">
212
- <!-- 工具栏 -->
213
- <div class="toolbar">
214
- <Button type="primary" @click="handleAdd()">新增菜单</Button>
215
- </div>
216
-
217
- <!-- 菜单树 -->
218
- <div class="menu-tree">
219
- <table class="tree-table">
220
- <thead>
221
- <tr>
222
- <th>菜单名称</th>
223
- <th>图标</th>
224
- <th>路由路径</th>
225
- <th>类型</th>
226
- <th>排序</th>
227
- <th>状态</th>
228
- <th>操作</th>
229
- </tr>
230
- </thead>
231
- <tbody>
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>
236
- </td>
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 ? '菜单' : '按钮' }}
242
- </Tag>
243
- </td>
244
- <td>{{ menu.sort }}</td>
245
- <td>
246
- <Tag :type="menu.status === Status.ENABLED ? 'success' : 'danger'" size="small">
247
- {{ menu.status === Status.ENABLED ? '启用' : '禁用' }}
248
- </Tag>
249
- </td>
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>
254
- </Space>
255
- </td>
256
- </tr>
257
- <template v-if="menu.children" v-for="child in menu.children" :key="child.id">
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>
262
- </td>
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 ? '菜单' : '按钮' }}
268
- </Tag>
269
- </td>
270
- <td>{{ child.sort }}</td>
271
- <td>
272
- <Tag :type="child.status === Status.ENABLED ? 'success' : 'danger'" size="small">
273
- {{ child.status === Status.ENABLED ? '启用' : '禁用' }}
274
- </Tag>
275
- </td>
276
- <td>
277
- <Space>
278
- <Button type="primary" link size="small" @click="handleEdit(child)">编辑</Button>
279
- </Space>
280
- </td>
281
- </tr>
282
- </template>
283
- </template>
284
- </tbody>
285
- </table>
286
- </div>
287
- </Card>
288
-
289
- <!-- 编辑弹窗 -->
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>
325
- </Form>
326
- <template #footer>
327
- <Space>
328
- <Button @click="modalVisible = false">取消</Button>
329
- <Button type="primary" @click="handleSubmit">确定</Button>
330
- </Space>
331
- </template>
332
- </Modal>
333
- </div>
334
- </template>
335
-
336
- <style lang="scss" scoped>
337
- .menu-page {
338
- padding: 20px;
339
-
340
- .toolbar {
341
- margin-bottom: 15px;
342
- }
343
- }
344
-
345
- .tree-table {
346
- width: 100%;
347
- border-collapse: collapse;
348
-
349
- th, td {
350
- padding: 12px;
351
- text-align: left;
352
- border-bottom: 1px solid var(--color-border-lighter);
353
- }
354
-
355
- th {
356
- font-weight: 500;
357
- color: var(--color-text-regular);
358
- background-color: var(--color-fill-light);
359
- }
360
-
361
- .tree-row--level-1 {
362
- td:first-child {
363
- padding-left: 30px;
364
- }
365
- }
366
- }
367
-
368
- .tree-indent {
369
- display: inline-block;
370
- width: 20px;
371
- }
372
-
373
- .menu-name {
374
- cursor: pointer;
375
- color: var(--color-primary);
376
-
377
- &:hover {
378
- text-decoration: underline;
379
- }
380
- }
1
+ <script setup lang="ts">
2
+ </script>
3
+
4
+ <template>
5
+ <div class="page">
6
+ <div class="page__placeholder">
7
+ <h2>菜单管理</h2>
8
+ <p>功能开发中...</p>
9
+ </div>
10
+ </div>
11
+ </template>
12
+
13
+ <style lang="scss" scoped>
14
+ .page {
15
+ padding: 20px;
16
+ height: 100%;
17
+
18
+ &__placeholder {
19
+ display: flex;
20
+ flex-direction: column;
21
+ align-items: center;
22
+ justify-content: center;
23
+ height: 100%;
24
+ color: var(--color-text-secondary);
25
+
26
+ h2 {
27
+ margin-bottom: 10px;
28
+ color: var(--color-text-primary);
29
+ }
30
+ }
31
+ }
381
32
  </style>