befly-admin 3.4.30 → 3.4.32
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.
- package/bunfig.toml +0 -2
- package/package.json +4 -3
- package/src/layouts/default.vue +35 -38
- package/src/types/auto-imports.d.ts +1 -0
- package/src/types/components.d.ts +38 -0
- package/src/views/index.vue +0 -9
- package/vite.config.js +8 -30
- package/src/views/internal/login.vue +0 -73
- package/src/views/test.vue +0 -57
package/bunfig.toml
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "befly-admin",
|
|
3
|
-
"version": "3.4.
|
|
3
|
+
"version": "3.4.32",
|
|
4
4
|
"description": "Befly Admin - 基于 Vue3 + OpenTiny Vue 的后台管理系统",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
@@ -29,13 +29,14 @@
|
|
|
29
29
|
"sync:admin": "bunx befly sync:admin"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
+
"@befly-addon/admin": "1.0.34",
|
|
32
33
|
"axios": "^1.13.2",
|
|
33
34
|
"pinia": "^3.0.4",
|
|
35
|
+
"tdesign-vue-next": "^1.10.6",
|
|
34
36
|
"vue": "^3.5.22",
|
|
35
37
|
"vue-router": "^4.6.3"
|
|
36
38
|
},
|
|
37
39
|
"devDependencies": {
|
|
38
|
-
"@befly-addon/admin": "1.0.32",
|
|
39
40
|
"@iconify-json/lucide": "^1.2.72",
|
|
40
41
|
"@unocss/preset-attributify": "^66.5.6",
|
|
41
42
|
"@unocss/preset-uno": "^66.5.6",
|
|
@@ -56,5 +57,5 @@
|
|
|
56
57
|
"node": ">=24.0.0",
|
|
57
58
|
"pnpm": ">=10.0.0"
|
|
58
59
|
},
|
|
59
|
-
"gitHead": "
|
|
60
|
+
"gitHead": "3593368cbf5c34f379b3b4569a7439bce9666938"
|
|
60
61
|
}
|
package/src/layouts/default.vue
CHANGED
|
@@ -9,26 +9,43 @@
|
|
|
9
9
|
<div class="user-info-bar">
|
|
10
10
|
<div class="user-text">
|
|
11
11
|
<span class="user-name">{{ $Data.userInfo.nickname || '管理员' }}</span>
|
|
12
|
-
<
|
|
12
|
+
<t-tag theme="primary" size="small" variant="light">{{ $Data.userInfo.role || '超级管理员' }}</t-tag>
|
|
13
13
|
</div>
|
|
14
|
-
<
|
|
14
|
+
<t-button variant="text" size="medium" @click="$Method.handleLogout">
|
|
15
|
+
<template #icon>
|
|
16
|
+
<i-lucide:x />
|
|
17
|
+
</template>
|
|
18
|
+
</t-button>
|
|
15
19
|
</div>
|
|
16
20
|
</div>
|
|
17
21
|
</div>
|
|
18
22
|
|
|
19
23
|
<!-- 菜单栏 -->
|
|
20
24
|
<div class="layout-menu">
|
|
21
|
-
<
|
|
22
|
-
<template
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
<
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
25
|
+
<t-menu :value="$Data.currentMenuKey" :expanded="$Data.expandedKeys" style="height: 100%" @change="$Method.onMenuClick" @expand="(value) => ($Data.expandedKeys = value)">
|
|
26
|
+
<template v-for="menu in $Data.userMenus" :key="menu.id">
|
|
27
|
+
<!-- 无子菜单 -->
|
|
28
|
+
<t-menu-item v-if="!menu.children || menu.children.length === 0" :value="menu.path">
|
|
29
|
+
<template #icon>
|
|
30
|
+
<i-lucide:home v-if="menu.path === '/addon/admin/'" />
|
|
31
|
+
<i-lucide:file-text v-else />
|
|
32
|
+
</template>
|
|
33
|
+
{{ menu.name }}
|
|
34
|
+
</t-menu-item>
|
|
35
|
+
<!-- 有子菜单 -->
|
|
36
|
+
<t-submenu v-else :value="String(menu.id)" :title="menu.name">
|
|
37
|
+
<template #icon>
|
|
38
|
+
<i-lucide:folder />
|
|
39
|
+
</template>
|
|
40
|
+
<t-menu-item v-for="child in menu.children" :key="child.id" :value="child.path">
|
|
41
|
+
<template #icon>
|
|
42
|
+
<i-lucide:file-text />
|
|
43
|
+
</template>
|
|
44
|
+
{{ child.name }}
|
|
45
|
+
</t-menu-item>
|
|
46
|
+
</t-submenu>
|
|
30
47
|
</template>
|
|
31
|
-
</
|
|
48
|
+
</t-menu>
|
|
32
49
|
</div>
|
|
33
50
|
|
|
34
51
|
<!-- 内容区域 -->
|
|
@@ -40,7 +57,6 @@
|
|
|
40
57
|
|
|
41
58
|
<script setup>
|
|
42
59
|
import { arrayToTree } from '@/utils';
|
|
43
|
-
import { iconClose } from '@opentiny/vue-icon';
|
|
44
60
|
|
|
45
61
|
const router = useRouter();
|
|
46
62
|
const route = useRoute();
|
|
@@ -55,7 +71,7 @@ const $Data = $ref({
|
|
|
55
71
|
userMenus: [],
|
|
56
72
|
userMenusFlat: [], // 一维菜单数据
|
|
57
73
|
expandedKeys: [],
|
|
58
|
-
|
|
74
|
+
currentMenuKey: '',
|
|
59
75
|
userInfo: {
|
|
60
76
|
nickname: '管理员',
|
|
61
77
|
role: '超级管理员'
|
|
@@ -96,7 +112,7 @@ const $Method = {
|
|
|
96
112
|
while (menu.pid) {
|
|
97
113
|
const parent = $Data.userMenusFlat.find((m) => m.id === menu.pid);
|
|
98
114
|
if (parent) {
|
|
99
|
-
expandedKeys.unshift(parent.id);
|
|
115
|
+
expandedKeys.unshift(String(parent.id));
|
|
100
116
|
menu = parent;
|
|
101
117
|
} else {
|
|
102
118
|
break;
|
|
@@ -106,17 +122,14 @@ const $Method = {
|
|
|
106
122
|
// 使用 nextTick 确保 DOM 更新后再设置高亮
|
|
107
123
|
nextTick(() => {
|
|
108
124
|
$Data.expandedKeys = expandedKeys;
|
|
109
|
-
|
|
110
|
-
if ($From.treeMenuRef) {
|
|
111
|
-
$From.treeMenuRef.setCurrentKey(currentMenu.id);
|
|
112
|
-
}
|
|
125
|
+
$Data.currentMenuKey = currentPath;
|
|
113
126
|
});
|
|
114
127
|
},
|
|
115
128
|
|
|
116
129
|
// 处理菜单点击
|
|
117
|
-
onMenuClick(
|
|
118
|
-
if (
|
|
119
|
-
router.push(
|
|
130
|
+
onMenuClick(path) {
|
|
131
|
+
if (path) {
|
|
132
|
+
router.push(path);
|
|
120
133
|
}
|
|
121
134
|
},
|
|
122
135
|
|
|
@@ -223,22 +236,6 @@ $Method.fetchUserMenus();
|
|
|
223
236
|
padding: 16px 12px;
|
|
224
237
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
|
|
225
238
|
border: 1px solid #e8eaed;
|
|
226
|
-
|
|
227
|
-
.tiny-tree-menu:before {
|
|
228
|
-
display: none;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
.menu-item {
|
|
232
|
-
display: flex;
|
|
233
|
-
align-items: center;
|
|
234
|
-
width: 100%;
|
|
235
|
-
padding: 2px 0;
|
|
236
|
-
transition: all 0.2s ease;
|
|
237
|
-
|
|
238
|
-
&:hover {
|
|
239
|
-
color: #0052d9;
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
239
|
}
|
|
243
240
|
|
|
244
241
|
.layout-main {
|
|
@@ -103,6 +103,7 @@ declare module 'vue' {
|
|
|
103
103
|
readonly $Config: UnwrapRef<typeof import('../config/index.js')['$Config']>
|
|
104
104
|
readonly $Http: UnwrapRef<typeof import('../plugins/http.js')['$Http']>
|
|
105
105
|
readonly $Storage: UnwrapRef<typeof import('../plugins/storage.js')['$Storage']>
|
|
106
|
+
readonly DialogPlugin: UnwrapRef<typeof import('tdesign-vue-next')['DialogPlugin']>
|
|
106
107
|
readonly EffectScope: UnwrapRef<typeof import('vue')['EffectScope']>
|
|
107
108
|
readonly MessagePlugin: UnwrapRef<typeof import('tdesign-vue-next')['MessagePlugin']>
|
|
108
109
|
readonly acceptHMRUpdate: UnwrapRef<typeof import('pinia')['acceptHMRUpdate']>
|
|
@@ -11,12 +11,46 @@ export {}
|
|
|
11
11
|
/* prettier-ignore */
|
|
12
12
|
declare module 'vue' {
|
|
13
13
|
export interface GlobalComponents {
|
|
14
|
+
'ILucide:activity': typeof import('~icons/lucide/activity')['default']
|
|
15
|
+
'ILucide:alertCircle': typeof import('~icons/lucide/alert-circle')['default']
|
|
16
|
+
'ILucide:alertTriangle': typeof import('~icons/lucide/alert-triangle')['default']
|
|
17
|
+
'ILucide:checkCircle': typeof import('~icons/lucide/check-circle')['default']
|
|
18
|
+
'ILucide:circle': typeof import('~icons/lucide/circle')['default']
|
|
19
|
+
'ILucide:clock': typeof import('~icons/lucide/clock')['default']
|
|
20
|
+
'ILucide:cloud': typeof import('~icons/lucide/cloud')['default']
|
|
21
|
+
'ILucide:code': typeof import('~icons/lucide/code')['default']
|
|
22
|
+
'ILucide:cpu': typeof import('~icons/lucide/cpu')['default']
|
|
23
|
+
'ILucide:database': typeof import('~icons/lucide/database')['default']
|
|
24
|
+
'ILucide:disc': typeof import('~icons/lucide/disc')['default']
|
|
14
25
|
'ILucide:fileText': typeof import('~icons/lucide/file-text')['default']
|
|
15
26
|
'ILucide:folder': typeof import('~icons/lucide/folder')['default']
|
|
27
|
+
'ILucide:hardDrive': typeof import('~icons/lucide/hard-drive')['default']
|
|
16
28
|
'ILucide:home': typeof import('~icons/lucide/home')['default']
|
|
29
|
+
'ILucide:info': typeof import('~icons/lucide/info')['default']
|
|
30
|
+
'ILucide:lock': typeof import('~icons/lucide/lock')['default']
|
|
31
|
+
'ILucide:mail': typeof import('~icons/lucide/mail')['default']
|
|
32
|
+
'ILucide:menu': typeof import('~icons/lucide/menu')['default']
|
|
33
|
+
'ILucide:pencil': typeof import('~icons/lucide/pencil')['default']
|
|
34
|
+
'ILucide:plus': typeof import('~icons/lucide/plus')['default']
|
|
35
|
+
'ILucide:rotateCw': typeof import('~icons/lucide/rotate-cw')['default']
|
|
36
|
+
'ILucide:search': typeof import('~icons/lucide/search')['default']
|
|
37
|
+
'ILucide:server': typeof import('~icons/lucide/server')['default']
|
|
38
|
+
'ILucide:settings': typeof import('~icons/lucide/settings')['default']
|
|
39
|
+
'ILucide:smile': typeof import('~icons/lucide/smile')['default']
|
|
40
|
+
'ILucide:square': typeof import('~icons/lucide/square')['default']
|
|
41
|
+
'ILucide:trash2': typeof import('~icons/lucide/trash2')['default']
|
|
42
|
+
'ILucide:trendingUp': typeof import('~icons/lucide/trending-up')['default']
|
|
43
|
+
'ILucide:user': typeof import('~icons/lucide/user')['default']
|
|
44
|
+
'ILucide:users': typeof import('~icons/lucide/users')['default']
|
|
45
|
+
'ILucide:webhook': typeof import('~icons/lucide/webhook')['default']
|
|
46
|
+
'ILucide:x': typeof import('~icons/lucide/x')['default']
|
|
47
|
+
'ILucide:xCircle': typeof import('~icons/lucide/x-circle')['default']
|
|
48
|
+
'ILucide:zap': typeof import('~icons/lucide/zap')['default']
|
|
17
49
|
RouterLink: typeof import('vue-router')['RouterLink']
|
|
18
50
|
RouterView: typeof import('vue-router')['RouterView']
|
|
19
51
|
TButton: typeof import('tdesign-vue-next')['Button']
|
|
52
|
+
TCheckbox: typeof import('tdesign-vue-next')['Checkbox']
|
|
53
|
+
TCheckboxGroup: typeof import('tdesign-vue-next')['CheckboxGroup']
|
|
20
54
|
TDialog: typeof import('tdesign-vue-next')['Dialog']
|
|
21
55
|
TDivider: typeof import('tdesign-vue-next')['Divider']
|
|
22
56
|
TDropdown: typeof import('tdesign-vue-next')['Dropdown']
|
|
@@ -27,11 +61,15 @@ declare module 'vue' {
|
|
|
27
61
|
TInput: typeof import('tdesign-vue-next')['Input']
|
|
28
62
|
TInputNumber: typeof import('tdesign-vue-next')['InputNumber']
|
|
29
63
|
TLink: typeof import('tdesign-vue-next')['Link']
|
|
64
|
+
TMenu: typeof import('tdesign-vue-next')['Menu']
|
|
65
|
+
TMenuItem: typeof import('tdesign-vue-next')['MenuItem']
|
|
30
66
|
TPagination: typeof import('tdesign-vue-next')['Pagination']
|
|
67
|
+
TProgress: typeof import('tdesign-vue-next')['Progress']
|
|
31
68
|
TRadio: typeof import('tdesign-vue-next')['Radio']
|
|
32
69
|
TRadioGroup: typeof import('tdesign-vue-next')['RadioGroup']
|
|
33
70
|
TSelect: typeof import('tdesign-vue-next')['Select']
|
|
34
71
|
TSpace: typeof import('tdesign-vue-next')['Space']
|
|
72
|
+
TSubmenu: typeof import('tdesign-vue-next')['Submenu']
|
|
35
73
|
TTable: typeof import('tdesign-vue-next')['Table']
|
|
36
74
|
TTag: typeof import('tdesign-vue-next')['Tag']
|
|
37
75
|
TTree: typeof import('tdesign-vue-next')['Tree']
|
package/src/views/index.vue
CHANGED
package/vite.config.js
CHANGED
|
@@ -44,7 +44,9 @@ export default defineConfig({
|
|
|
44
44
|
}),
|
|
45
45
|
|
|
46
46
|
// Vue Reactivity Transform 支持
|
|
47
|
-
ReactivityTransform(
|
|
47
|
+
ReactivityTransform({
|
|
48
|
+
exclude: []
|
|
49
|
+
}),
|
|
48
50
|
|
|
49
51
|
// API 自动导入
|
|
50
52
|
AutoImport({
|
|
@@ -122,33 +124,9 @@ export default defineConfig({
|
|
|
122
124
|
return 'framework-pinia';
|
|
123
125
|
}
|
|
124
126
|
|
|
125
|
-
//
|
|
126
|
-
if (id.includes('
|
|
127
|
-
return '
|
|
128
|
-
}
|
|
129
|
-
if (id.includes('@opentiny/vue-renderless/src/table')) {
|
|
130
|
-
return 'tiny-table';
|
|
131
|
-
}
|
|
132
|
-
if (id.includes('@opentiny/vue-renderless/src/tree')) {
|
|
133
|
-
return 'tiny-tree';
|
|
134
|
-
}
|
|
135
|
-
if (id.includes('@opentiny/vue-renderless/src/form')) {
|
|
136
|
-
return 'tiny-form';
|
|
137
|
-
}
|
|
138
|
-
if (id.includes('node_modules/@opentiny/vue-renderless/')) {
|
|
139
|
-
return 'tiny-renderless';
|
|
140
|
-
}
|
|
141
|
-
if (id.includes('node_modules/@opentiny/vue-theme/')) {
|
|
142
|
-
return 'tiny-theme';
|
|
143
|
-
}
|
|
144
|
-
if (id.includes('node_modules/@opentiny/vue-locale/')) {
|
|
145
|
-
return 'tiny-locale';
|
|
146
|
-
}
|
|
147
|
-
if (id.includes('node_modules/@opentiny/vue-common/')) {
|
|
148
|
-
return 'tiny-common';
|
|
149
|
-
}
|
|
150
|
-
if (id.includes('node_modules/@opentiny/vue-icon/')) {
|
|
151
|
-
return 'tiny-icon';
|
|
127
|
+
// TDesign Vue Next
|
|
128
|
+
if (id.includes('node_modules/tdesign-vue-next/') || id.includes('node_modules/.bun/tdesign-vue-next')) {
|
|
129
|
+
return 'tdesign';
|
|
152
130
|
}
|
|
153
131
|
|
|
154
132
|
// 工具库(独立文件)
|
|
@@ -161,7 +139,7 @@ export default defineConfig({
|
|
|
161
139
|
return 'lib-lodash';
|
|
162
140
|
}
|
|
163
141
|
|
|
164
|
-
// echarts
|
|
142
|
+
// echarts 及相关库
|
|
165
143
|
if (id.includes('node_modules/echarts/') || id.includes('node_modules/.bun/echarts')) {
|
|
166
144
|
return 'lib-echarts';
|
|
167
145
|
}
|
|
@@ -180,7 +158,7 @@ export default defineConfig({
|
|
|
180
158
|
}
|
|
181
159
|
|
|
182
160
|
// befly-addon
|
|
183
|
-
if (id.includes('@befly-addon/')) {
|
|
161
|
+
if (id.includes('@befly-addon/') || id.includes('packages/addonAdmin/') || id.includes('packages\\addonAdmin\\')) {
|
|
184
162
|
return 'befly-addon';
|
|
185
163
|
}
|
|
186
164
|
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div class="page-login">
|
|
3
|
-
<div class="login-box">
|
|
4
|
-
<h1>登录</h1>
|
|
5
|
-
<tiny-form ref="formRef" :model="$Data.form" label-position="top">
|
|
6
|
-
<tiny-form-item label="用户名" prop="username">
|
|
7
|
-
<tiny-input v-model="$Data.form.username" placeholder="请输入用户名" />
|
|
8
|
-
</tiny-form-item>
|
|
9
|
-
<tiny-form-item label="密码" prop="password">
|
|
10
|
-
<tiny-input v-model="$Data.form.password" type="password" placeholder="请输入密码" />
|
|
11
|
-
</tiny-form-item>
|
|
12
|
-
<tiny-form-item>
|
|
13
|
-
<tiny-button type="primary" @click="$Method.handleLogin">登录</tiny-button>
|
|
14
|
-
</tiny-form-item>
|
|
15
|
-
</tiny-form>
|
|
16
|
-
</div>
|
|
17
|
-
</div>
|
|
18
|
-
</template>
|
|
19
|
-
|
|
20
|
-
<script setup>
|
|
21
|
-
const router = useRouter();
|
|
22
|
-
|
|
23
|
-
const $Data = $ref({
|
|
24
|
-
form: {
|
|
25
|
-
username: '',
|
|
26
|
-
password: ''
|
|
27
|
-
}
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
const $Method = {
|
|
31
|
-
async handleLogin() {
|
|
32
|
-
// 模拟登录
|
|
33
|
-
$Storage.local.set('token', 'mock-token-123');
|
|
34
|
-
MessagePlugin.success('登录成功');
|
|
35
|
-
router.push('/');
|
|
36
|
-
}
|
|
37
|
-
};
|
|
38
|
-
</script>
|
|
39
|
-
|
|
40
|
-
<route lang="yaml">
|
|
41
|
-
meta:
|
|
42
|
-
layout: blank
|
|
43
|
-
public: true
|
|
44
|
-
title: 登录
|
|
45
|
-
</route>
|
|
46
|
-
|
|
47
|
-
<style lang="scss" scoped>
|
|
48
|
-
.page-login {
|
|
49
|
-
width: 100%;
|
|
50
|
-
height: 100%;
|
|
51
|
-
display: flex;
|
|
52
|
-
align-items: center;
|
|
53
|
-
justify-content: center;
|
|
54
|
-
|
|
55
|
-
.login-box {
|
|
56
|
-
width: 400px;
|
|
57
|
-
padding: 40px;
|
|
58
|
-
background: #fff;
|
|
59
|
-
border-radius: 8px;
|
|
60
|
-
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
|
61
|
-
|
|
62
|
-
h1 {
|
|
63
|
-
text-align: center;
|
|
64
|
-
margin-bottom: 30px;
|
|
65
|
-
color: $primary-color;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
.tiny-button {
|
|
69
|
-
width: 100%;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
</style>
|
package/src/views/test.vue
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div class="test-page">
|
|
3
|
-
<h1>TinyVue 自动导入测试</h1>
|
|
4
|
-
|
|
5
|
-
<div class="button-group">
|
|
6
|
-
<tiny-button type="primary" @click="testModal">测试 Modal</tiny-button>
|
|
7
|
-
<tiny-button type="success" @click="testMessage">测试 Message</tiny-button>
|
|
8
|
-
<tiny-button type="warning" @click="testNotify">测试 Notify</tiny-button>
|
|
9
|
-
<tiny-button type="info" @click="testMessageBox">测试 MessageBox</tiny-button>
|
|
10
|
-
</div>
|
|
11
|
-
</div>
|
|
12
|
-
</template>
|
|
13
|
-
|
|
14
|
-
<script setup>
|
|
15
|
-
// 无需导入,已自动导入:MessagePlugin, DialogPlugin, NotificationPlugin, LoadingPlugin
|
|
16
|
-
|
|
17
|
-
const testModal = () => {
|
|
18
|
-
MessagePlugin.success('这是一个成功提示');
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
const testMessage = () => {
|
|
22
|
-
Message.success('成功消息');
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
const testNotify = () => {
|
|
26
|
-
Notify.success({
|
|
27
|
-
title: '成功通知',
|
|
28
|
-
message: '这是一个成功通知的内容'
|
|
29
|
-
});
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
const testMessageBox = () => {
|
|
33
|
-
MessageBox.alert('这是一个提示框', '提示');
|
|
34
|
-
};
|
|
35
|
-
</script>
|
|
36
|
-
|
|
37
|
-
<route lang="yaml">
|
|
38
|
-
meta:
|
|
39
|
-
layout: default
|
|
40
|
-
title: 自动导入测试
|
|
41
|
-
</route>
|
|
42
|
-
|
|
43
|
-
<style lang="scss" scoped>
|
|
44
|
-
.test-page {
|
|
45
|
-
padding: 20px;
|
|
46
|
-
|
|
47
|
-
h1 {
|
|
48
|
-
color: $primary-color;
|
|
49
|
-
margin-bottom: 24px;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
.button-group {
|
|
53
|
-
display: flex;
|
|
54
|
-
gap: 12px;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
</style>
|