xto-fronted 0.1.7 → 0.1.9

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 (86) hide show
  1. package/README.md +4 -0
  2. package/dist/components/Login/index.vue.d.ts +15 -0
  3. package/dist/config/index.d.ts +25 -5
  4. package/dist/index.d.ts +17 -4
  5. package/dist/index.es.js +1272 -55
  6. package/dist/index.umd.js +1 -1
  7. package/dist/router/dynamicRoutes.d.ts +19 -25
  8. package/dist/router/index.d.ts +24 -4
  9. package/dist/router/staticRoutes.d.ts +15 -2
  10. package/dist/stores/menu.d.ts +14 -8
  11. package/dist/style.css +1 -1
  12. package/dist/utils/request.d.ts +8 -0
  13. package/package.json +2 -10
  14. package/.env.development +0 -3
  15. package/.env.production +0 -3
  16. package/dist/403-DM5wfQkM.js +0 -31
  17. package/dist/404-BurAu5LC.js +0 -31
  18. package/dist/index-BNiEld34.js +0 -15
  19. package/dist/index-Be9RiEfo.js +0 -98
  20. package/dist/index-BqRv1bdN.js +0 -1185
  21. package/dist/index-CQLVXvNJ.js +0 -15
  22. package/dist/index-CyiE8n2V.js +0 -15
  23. package/dist/index-xauR1bOL.js +0 -15
  24. package/dist/views/dashboard/index.vue.d.ts +0 -2
  25. package/dist/views/login/index.vue.d.ts +0 -4
  26. package/dist/views/system/menu/index.vue.d.ts +0 -2
  27. package/dist/views/system/role/index.vue.d.ts +0 -2
  28. package/dist/views/system/user/index.vue.d.ts +0 -2
  29. package/index.html +0 -13
  30. package/public/vite.svg +0 -10
  31. package/src/App.vue +0 -20
  32. package/src/api/auth.ts +0 -35
  33. package/src/api/menu.ts +0 -13
  34. package/src/api/system.ts +0 -65
  35. package/src/api/user.ts +0 -12
  36. package/src/assets/styles/_dark.scss +0 -407
  37. package/src/assets/styles/_reset.scss +0 -126
  38. package/src/assets/styles/_root.scss +0 -140
  39. package/src/assets/styles/_transition.scss +0 -119
  40. package/src/assets/styles/_variables.scss +0 -45
  41. package/src/assets/styles/index.scss +0 -187
  42. package/src/components/Layout/Footer.vue +0 -17
  43. package/src/components/Layout/Header.vue +0 -335
  44. package/src/components/Layout/Sidebar.vue +0 -213
  45. package/src/components/Layout/Tabs.vue +0 -20
  46. package/src/components/Layout/index.vue +0 -62
  47. package/src/composables/index.ts +0 -9
  48. package/src/composables/useApp.ts +0 -170
  49. package/src/composables/useAuth.ts +0 -70
  50. package/src/composables/useForm.ts +0 -79
  51. package/src/composables/useMenu.ts +0 -141
  52. package/src/composables/useTable.ts +0 -97
  53. package/src/config/index.ts +0 -19
  54. package/src/directives/permission.ts +0 -41
  55. package/src/enums/index.ts +0 -63
  56. package/src/env.d.ts +0 -17
  57. package/src/index.ts +0 -44
  58. package/src/main.ts +0 -29
  59. package/src/router/dynamicRoutes.ts +0 -163
  60. package/src/router/index.ts +0 -71
  61. package/src/router/staticRoutes.ts +0 -43
  62. package/src/stores/app.ts +0 -145
  63. package/src/stores/auth.ts +0 -45
  64. package/src/stores/index.ts +0 -15
  65. package/src/stores/menu.ts +0 -158
  66. package/src/stores/user.ts +0 -41
  67. package/src/types/api.d.ts +0 -103
  68. package/src/types/global.d.ts +0 -45
  69. package/src/types/router.d.ts +0 -48
  70. package/src/types/xto.d.ts +0 -149
  71. package/src/utils/auth.ts +0 -86
  72. package/src/utils/permission.ts +0 -30
  73. package/src/utils/request.ts +0 -126
  74. package/src/utils/storage.ts +0 -72
  75. package/src/views/dashboard/index.vue +0 -32
  76. package/src/views/error/403.vue +0 -57
  77. package/src/views/error/404.vue +0 -57
  78. package/src/views/login/index.vue +0 -141
  79. package/src/views/system/menu/index.vue +0 -32
  80. package/src/views/system/role/index.vue +0 -32
  81. package/src/views/system/user/index.vue +0 -32
  82. package/tsconfig.json +0 -26
  83. package/tsconfig.node.json +0 -11
  84. package/vite.config.ts +0 -139
  85. /package/dist/{views/error → components/Error}/403.vue.d.ts +0 -0
  86. /package/dist/{views/error → components/Error}/404.vue.d.ts +0 -0
@@ -1,335 +0,0 @@
1
- <script setup lang="ts">
2
- /**
3
- * 头部组件
4
- * 使用统一的 useApp hooks
5
- */
6
- import { ref, computed, onMounted, onUnmounted } from 'vue'
7
- import { useApp } from '@/composables'
8
- import { useAppStore } from '@/stores/app'
9
-
10
- const appStore = useAppStore()
11
- const { logout, userName, userInfo } = useApp()
12
-
13
- const dropdownVisible = ref(false)
14
- const dropdownRef = ref<HTMLElement | null>(null)
15
- const isFullscreen = ref(false)
16
-
17
- // 用户显示名称
18
- const userDisplayName = computed(() => userName.value || '用户')
19
-
20
- // 切换折叠
21
- const toggleCollapse = () => {
22
- appStore.toggleCollapse()
23
- }
24
-
25
- // 切换主题
26
- const toggleTheme = () => {
27
- appStore.toggleTheme()
28
- }
29
-
30
- // 切换全屏
31
- const toggleFullscreen = () => {
32
- if (!document.fullscreenElement) {
33
- document.documentElement.requestFullscreen()
34
- } else {
35
- document.exitFullscreen()
36
- }
37
- }
38
-
39
- // 监听全屏变化
40
- const handleFullscreenChange = () => {
41
- isFullscreen.value = !!document.fullscreenElement
42
- }
43
-
44
- // 切换下拉菜单
45
- const toggleDropdown = () => {
46
- dropdownVisible.value = !dropdownVisible.value
47
- }
48
-
49
- // 关闭下拉菜单
50
- const closeDropdown = () => {
51
- dropdownVisible.value = false
52
- }
53
-
54
- // 退出登录
55
- const handleLogout = async () => {
56
- closeDropdown()
57
- await logout()
58
- }
59
-
60
- // 点击外部关闭下拉菜单
61
- const handleClickOutside = (event: MouseEvent) => {
62
- if (dropdownRef.value && !dropdownRef.value.contains(event.target as Node)) {
63
- closeDropdown()
64
- }
65
- }
66
-
67
- onMounted(() => {
68
- document.addEventListener('click', handleClickOutside)
69
- document.addEventListener('fullscreenchange', handleFullscreenChange)
70
- })
71
-
72
- onUnmounted(() => {
73
- document.removeEventListener('click', handleClickOutside)
74
- document.removeEventListener('fullscreenchange', handleFullscreenChange)
75
- })
76
- </script>
77
-
78
- <template>
79
- <div class="header">
80
- <!-- 左侧 -->
81
- <div class="header__left">
82
- <div class="header__collapse" @click="toggleCollapse">
83
- <span>☰</span>
84
- </div>
85
- </div>
86
-
87
- <!-- 右侧 -->
88
- <div class="header__right">
89
- <!-- 全屏切换 -->
90
- <div class="header__action" @click="toggleFullscreen" :title="isFullscreen ? '退出全屏' : '全屏'">
91
- <svg v-if="isFullscreen" viewBox="0 0 24 24" width="16" height="16" fill="currentColor">
92
- <path d="M5 16h3v3h2v-5H5v2zm3-8H5v2h5V5H8v3zm6 11h2v-3h3v-2h-5v5zm2-11V5h-2v5h5V8h-3z"/>
93
- </svg>
94
- <svg v-else viewBox="0 0 24 24" width="16" height="16" fill="currentColor">
95
- <path d="M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z"/>
96
- </svg>
97
- </div>
98
-
99
- <!-- 主题切换 -->
100
- <div class="header__action" @click="toggleTheme" title="切换主题">
101
- <span v-if="appStore.isDark">🌙</span>
102
- <span v-else>☀️</span>
103
- </div>
104
-
105
- <!-- 用户头像 -->
106
- <div class="header__user" ref="dropdownRef">
107
- <div class="header__user-trigger" @click.stop="toggleDropdown">
108
- <div class="header__avatar">
109
- <span>{{ userDisplayName.charAt(0) }}</span>
110
- </div>
111
- <span class="header__user-name">{{ userDisplayName }}</span>
112
- <span class="header__user-arrow" :class="{ 'is-active': dropdownVisible }">▼</span>
113
- </div>
114
-
115
- <!-- 下拉菜单 -->
116
- <Transition name="dropdown">
117
- <div v-if="dropdownVisible" class="header__dropdown">
118
- <div class="header__dropdown-header">
119
- <div class="header__dropdown-avatar">
120
- <span>{{ userDisplayName.charAt(0) }}</span>
121
- </div>
122
- <div class="header__dropdown-info">
123
- <div class="header__dropdown-name">{{ userDisplayName }}</div>
124
- <div class="header__dropdown-role">{{ userInfo?.departmentName || '' }}</div>
125
- </div>
126
- </div>
127
- <div class="header__dropdown-divider"></div>
128
- <div class="header__dropdown-menu">
129
- <div class="header__dropdown-item header__dropdown-item--danger" @click="handleLogout">
130
- <span class="header__dropdown-icon">🚪</span>
131
- <span>退出登录</span>
132
- </div>
133
- </div>
134
- </div>
135
- </Transition>
136
- </div>
137
- </div>
138
- </div>
139
- </template>
140
-
141
- <style lang="scss" scoped>
142
- .header {
143
- display: flex;
144
- align-items: center;
145
- justify-content: space-between;
146
- padding: 0 20px;
147
- height: 100%;
148
-
149
- &__left {
150
- display: flex;
151
- align-items: center;
152
- gap: 15px;
153
- }
154
-
155
- &__collapse {
156
- width: 24px;
157
- height: 24px;
158
- display: flex;
159
- align-items: center;
160
- justify-content: center;
161
- cursor: pointer;
162
- font-size: 18px;
163
- color: var(--color-text-regular);
164
-
165
- &:hover {
166
- color: var(--color-primary);
167
- }
168
- }
169
-
170
- &__right {
171
- display: flex;
172
- align-items: center;
173
- gap: 15px;
174
- }
175
-
176
- &__action {
177
- width: 32px;
178
- height: 32px;
179
- display: flex;
180
- align-items: center;
181
- justify-content: center;
182
- cursor: pointer;
183
- border-radius: var(--border-radius-base);
184
- font-size: 16px;
185
-
186
- &:hover {
187
- background-color: var(--color-fill);
188
- }
189
- }
190
-
191
- &__user {
192
- position: relative;
193
-
194
- &-trigger {
195
- display: flex;
196
- align-items: center;
197
- gap: 8px;
198
- cursor: pointer;
199
- padding: 4px 8px;
200
- border-radius: var(--border-radius-base);
201
- transition: background-color 0.2s;
202
-
203
- &:hover {
204
- background-color: var(--color-fill);
205
- }
206
- }
207
-
208
- &-name {
209
- font-size: 14px;
210
- color: var(--color-text-primary);
211
- }
212
-
213
- &-arrow {
214
- font-size: 10px;
215
- color: var(--color-text-secondary);
216
- transition: transform 0.2s;
217
-
218
- &.is-active {
219
- transform: rotate(180deg);
220
- }
221
- }
222
- }
223
-
224
- &__avatar {
225
- width: 32px;
226
- height: 32px;
227
- border-radius: 50%;
228
- background: linear-gradient(135deg, var(--color-primary), var(--color-primary-light-3));
229
- display: flex;
230
- align-items: center;
231
- justify-content: center;
232
- color: #fff;
233
- font-size: 14px;
234
- font-weight: 500;
235
- }
236
-
237
- &__dropdown {
238
- position: absolute;
239
- top: calc(100% + 8px);
240
- right: 0;
241
- min-width: 200px;
242
- background-color: var(--bg-color);
243
- border-radius: var(--border-radius-base);
244
- box-shadow: var(--box-shadow);
245
- overflow: hidden;
246
- z-index: 100;
247
-
248
- &-header {
249
- display: flex;
250
- align-items: center;
251
- gap: 12px;
252
- padding: 16px;
253
- }
254
-
255
- &-avatar {
256
- width: 40px;
257
- height: 40px;
258
- border-radius: 50%;
259
- background: linear-gradient(135deg, var(--color-primary), var(--color-primary-light-3));
260
- display: flex;
261
- align-items: center;
262
- justify-content: center;
263
- color: #fff;
264
- font-size: 16px;
265
- font-weight: 500;
266
- }
267
-
268
- &-info {
269
- flex: 1;
270
- }
271
-
272
- &-name {
273
- font-size: 14px;
274
- font-weight: 500;
275
- color: var(--color-text-primary);
276
- }
277
-
278
- &-role {
279
- font-size: 12px;
280
- color: var(--color-text-secondary);
281
- margin-top: 2px;
282
- }
283
-
284
- &-divider {
285
- height: 1px;
286
- background-color: var(--color-border-lighter);
287
- }
288
-
289
- &-menu {
290
- padding: 8px 0;
291
- }
292
-
293
- &-item {
294
- display: flex;
295
- align-items: center;
296
- gap: 10px;
297
- padding: 10px 16px;
298
- cursor: pointer;
299
- font-size: 14px;
300
- color: var(--color-text-regular);
301
- transition: all 0.2s;
302
-
303
- &:hover {
304
- background-color: var(--color-fill);
305
- color: var(--color-text-primary);
306
- }
307
-
308
- &--danger {
309
- color: var(--color-danger);
310
-
311
- &:hover {
312
- background-color: var(--color-danger-light);
313
- color: var(--color-danger);
314
- }
315
- }
316
- }
317
-
318
- &-icon {
319
- font-size: 16px;
320
- }
321
- }
322
- }
323
-
324
- // 下拉动画
325
- .dropdown-enter-active,
326
- .dropdown-leave-active {
327
- transition: all 0.2s ease;
328
- }
329
-
330
- .dropdown-enter-from,
331
- .dropdown-leave-to {
332
- opacity: 0;
333
- transform: translateY(-10px);
334
- }
335
- </style>
@@ -1,213 +0,0 @@
1
- <script setup lang="ts">
2
- /**
3
- * 侧边栏组件
4
- * 使用统一的 useMenu 和 useApp hooks
5
- */
6
- import { useMenu } from '@/composables'
7
- import { useApp } from '@/composables'
8
- import { Menu, MenuItem, SubMenu } from '@xto/navigation'
9
- import { Button } from '@xto/base'
10
- import { Input } from '@xto/form'
11
- import config from '@/config'
12
-
13
- // 使用统一的 hooks
14
- const { logout, userName, userInfo } = useApp()
15
- const {
16
- searchKeyword,
17
- activeMenu,
18
- isCollapsed,
19
- searchResults,
20
- filteredMenuList,
21
- getMenuIcon,
22
- handleMenuSelect,
23
- handleSearchItemClick
24
- } = useMenu()
25
- </script>
26
-
27
- <template>
28
- <div class="sidebar">
29
- <!-- Logo -->
30
- <div class="sidebar__logo">
31
- <img src="/vite.svg" alt="Logo" class="sidebar__logo-img" />
32
- <span v-show="!isCollapsed" class="sidebar__logo-text">{{ config.webTitle }}</span>
33
- </div>
34
-
35
- <!-- 搜索框 -->
36
- <div v-if="!isCollapsed" class="sidebar__search">
37
- <Input
38
- v-model="searchKeyword"
39
- placeholder="搜索菜单..."
40
- size="small"
41
- clearable
42
- />
43
- <!-- 搜索结果 -->
44
- <div v-if="searchResults.length > 0" class="sidebar__search-results">
45
- <div
46
- v-for="item in searchResults"
47
- :key="item.path"
48
- class="sidebar__search-item"
49
- @click="handleSearchItemClick(item.path)"
50
- >
51
- <span class="menu-icon">{{ getMenuIcon(item.icon) }}</span>
52
- <div class="sidebar__search-item-info">
53
- <span class="sidebar__search-item-title">{{ item.title }}</span>
54
- <span v-if="item.parentTitle" class="sidebar__search-item-parent">{{ item.parentTitle }}</span>
55
- </div>
56
- </div>
57
- </div>
58
- </div>
59
-
60
- <!-- 菜单 -->
61
- <Menu
62
- :default-active="activeMenu"
63
- :collapse="isCollapsed"
64
- :collapse-transition="false"
65
- class="sidebar__menu"
66
- @select="handleMenuSelect"
67
- >
68
- <template v-for="menu in filteredMenuList" :key="menu.path">
69
- <!-- 有子菜单 -->
70
- <SubMenu v-if="menu.children && menu.children.length > 0" :index="menu.path">
71
- <template #title>
72
- <span class="menu-icon">{{ getMenuIcon(menu.icon) }}</span>
73
- <span>{{ menu.title }}</span>
74
- </template>
75
- <MenuItem
76
- v-for="child in menu.children"
77
- :key="child.path"
78
- :index="child.path"
79
- >
80
- <span class="menu-icon">{{ getMenuIcon(child.icon) }}</span>
81
- <span>{{ child.title }}</span>
82
- </MenuItem>
83
- </SubMenu>
84
- <!-- 无子菜单 -->
85
- <MenuItem v-else :index="menu.path">
86
- <span class="menu-icon">{{ getMenuIcon(menu.icon) }}</span>
87
- <span>{{ menu.title }}</span>
88
- </MenuItem>
89
- </template>
90
- </Menu>
91
-
92
- <!-- 用户信息 -->
93
- <div class="sidebar__user" v-if="!isCollapsed">
94
- <div class="sidebar__user-info">
95
- <span class="sidebar__user-name">{{ userName || '用户' }}</span>
96
- <span class="sidebar__user-role">{{ userInfo?.departmentName || '' }}</span>
97
- </div>
98
- <Button type="text" size="small" @click="logout">退出</Button>
99
- </div>
100
- </div>
101
- </template>
102
-
103
- <style lang="scss" scoped>
104
- .sidebar {
105
- height: 100%;
106
- display: flex;
107
- flex-direction: column;
108
- background-color: var(--bg-color);
109
-
110
- &__logo {
111
- height: 50px;
112
- display: flex;
113
- align-items: center;
114
- justify-content: center;
115
- gap: 10px;
116
- border-bottom: 1px solid var(--color-border-lighter);
117
- }
118
-
119
- &__logo-img {
120
- width: 32px;
121
- height: 32px;
122
- }
123
-
124
- &__logo-text {
125
- font-size: 16px;
126
- font-weight: 600;
127
- color: var(--color-primary);
128
- }
129
-
130
- &__search {
131
- padding: 10px;
132
- border-bottom: 1px solid var(--color-border-lighter);
133
- position: relative;
134
- }
135
-
136
- &__search-results {
137
- position: absolute;
138
- top: 100%;
139
- left: 0;
140
- right: 0;
141
- background-color: var(--bg-color);
142
- border: 1px solid var(--color-border-lighter);
143
- border-radius: var(--border-radius-base);
144
- box-shadow: var(--box-shadow);
145
- max-height: 300px;
146
- overflow-y: auto;
147
- z-index: 100;
148
- }
149
-
150
- &__search-item {
151
- display: flex;
152
- align-items: center;
153
- gap: 10px;
154
- padding: 10px 12px;
155
- cursor: pointer;
156
- transition: background-color 0.2s;
157
-
158
- &:hover {
159
- background-color: var(--color-fill);
160
- }
161
-
162
- &-info {
163
- display: flex;
164
- flex-direction: column;
165
- gap: 2px;
166
- }
167
-
168
- &-title {
169
- font-size: 14px;
170
- color: var(--color-text-primary);
171
- }
172
-
173
- &-parent {
174
- font-size: 12px;
175
- color: var(--color-text-secondary);
176
- }
177
- }
178
-
179
- &__menu {
180
- flex: 1;
181
- border-right: none;
182
- overflow-y: auto;
183
- }
184
-
185
- &__user {
186
- padding: 10px;
187
- border-top: 1px solid var(--color-border-lighter);
188
- display: flex;
189
- align-items: center;
190
- justify-content: space-between;
191
- }
192
-
193
- &__user-info {
194
- display: flex;
195
- flex-direction: column;
196
- gap: 2px;
197
- }
198
-
199
- &__user-name {
200
- font-size: 14px;
201
- font-weight: 500;
202
- }
203
-
204
- &__user-role {
205
- font-size: 12px;
206
- color: var(--color-text-secondary);
207
- }
208
- }
209
-
210
- .menu-icon {
211
- margin-right: 8px;
212
- }
213
- </style>
@@ -1,20 +0,0 @@
1
- <script setup lang="ts">
2
- </script>
3
-
4
- <template>
5
- <div class="tabs-wrapper">
6
- <!-- 标签页功能后期自行开发 -->
7
- </div>
8
- </template>
9
-
10
- <style lang="scss" scoped>
11
- .tabs-wrapper {
12
- width: 100%;
13
- height: 100%;
14
- display: flex;
15
- align-items: center;
16
- justify-content: center;
17
- color: var(--color-text-secondary);
18
- font-size: 12px;
19
- }
20
- </style>
@@ -1,62 +0,0 @@
1
- <script setup lang="ts">
2
- import { computed } from 'vue'
3
- import { useAppStore } from '@/stores/app'
4
- import Sidebar from './Sidebar.vue'
5
- import Header from './Header.vue'
6
-
7
- const appStore = useAppStore()
8
-
9
- const sidebarWidth = computed(() =>
10
- appStore.isCollapsed ? '64px' : '210px'
11
- )
12
- </script>
13
-
14
- <template>
15
- <div class="layout">
16
- <aside class="layout__aside" :style="{ width: sidebarWidth }">
17
- <Sidebar />
18
- </aside>
19
- <div class="layout__main">
20
- <Header class="layout__header" />
21
- <main class="layout__content">
22
- <router-view />
23
- </main>
24
- </div>
25
- </div>
26
- </template>
27
-
28
- <style lang="scss" scoped>
29
- .layout {
30
- display: flex;
31
- width: 100%;
32
- height: 100%;
33
-
34
- &__aside {
35
- transition: width 0.3s;
36
- overflow: hidden;
37
- flex-shrink: 0;
38
- height: 100%;
39
- }
40
-
41
- &__main {
42
- flex: 1;
43
- display: flex;
44
- flex-direction: column;
45
- overflow: hidden;
46
- height: 100%;
47
- }
48
-
49
- &__header {
50
- height: 50px;
51
- background-color: var(--bg-color);
52
- border-bottom: 1px solid var(--color-border-lighter);
53
- flex-shrink: 0;
54
- }
55
-
56
- &__content {
57
- flex: 1;
58
- overflow: auto;
59
- background-color: var(--bg-color-page);
60
- }
61
- }
62
- </style>
@@ -1,9 +0,0 @@
1
- /**
2
- * Composables 统一导出
3
- */
4
-
5
- export { useApp } from './useApp'
6
- export { useAuth } from './useAuth'
7
- export { useMenu } from './useMenu'
8
- export { useForm } from './useForm'
9
- export { useTable } from './useTable'