befly-admin-ui 1.9.7 → 1.9.10
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.
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div class="page-table-detail page-table">
|
|
2
|
+
<div :class="['page-table-detail', 'page-table', { 'page-table--with-pagination': props.isPagination }]">
|
|
3
3
|
<div class="main-tool">
|
|
4
4
|
<div class="left">
|
|
5
5
|
<slot name="toolLeft" :reload="reload" :current-row="$Data.currentRow"></slot>
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
</div>
|
|
33
33
|
</div>
|
|
34
34
|
|
|
35
|
-
<div class="main-page">
|
|
35
|
+
<div v-if="props.isPagination" class="main-page">
|
|
36
36
|
<TPagination :current-page="$Data.pager.currentPage" :page-size="$Data.pager.limit" :total="$Data.pager.total" align="right" :layout="paginationLayout" @current-change="onPageChange" @page-size-change="onPageSizeChange" />
|
|
37
37
|
</div>
|
|
38
38
|
|
package/layouts/default.vue
CHANGED
|
@@ -1,85 +1,100 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="layout-wrapper">
|
|
3
|
-
<!--
|
|
3
|
+
<!-- 左侧边栏:菜单面板 + 用户面板 -->
|
|
4
4
|
<div class="layout-sidebar">
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
<div class="logo
|
|
8
|
-
<
|
|
5
|
+
<div class="sidebar-menu-panel">
|
|
6
|
+
<!-- Logo 区域 -->
|
|
7
|
+
<div class="sidebar-logo">
|
|
8
|
+
<div class="logo-icon">
|
|
9
|
+
<AppIcon style="width: 24px; height: 24px; color: var(--primary-color)" />
|
|
10
|
+
</div>
|
|
11
|
+
<h2>{{ $Config.appTitle }}</h2>
|
|
9
12
|
</div>
|
|
10
|
-
<h2>{{ $Config.appTitle }}</h2>
|
|
11
|
-
</div>
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
<template #icon>
|
|
20
|
-
<HomeIcon v-if="menu.path === '/dashboard' || menu.path === '/core/' || menu.path === '/core'" style="margin-right: 8px" />
|
|
21
|
-
<ControlPlatformIcon v-else style="margin-right: 8px" />
|
|
22
|
-
</template>
|
|
23
|
-
{{ menu.name }}
|
|
24
|
-
</t-menu-item>
|
|
25
|
-
<!-- 有子菜单 -->
|
|
26
|
-
<t-submenu v-else :value="String(menu.id)" :title="menu.name">
|
|
27
|
-
<template #icon>
|
|
28
|
-
<AppIcon style="margin-right: 8px" />
|
|
29
|
-
</template>
|
|
30
|
-
<t-menu-item v-for="child in menu.children" :key="child.id" :value="child.path">
|
|
14
|
+
<!-- 菜单区域 -->
|
|
15
|
+
<div class="sidebar-menu">
|
|
16
|
+
<t-menu v-model:value="$Data.currentMenuKey" v-model:expanded="$Data.expandedKeys" width="220px" @change="onMenuClick">
|
|
17
|
+
<template v-for="menu in $Data.userMenus" :key="menu.id">
|
|
18
|
+
<!-- 无子菜单 -->
|
|
19
|
+
<t-menu-item v-if="!menu.children || menu.children.length === 0" :value="menu.path">
|
|
31
20
|
<template #icon>
|
|
32
|
-
<
|
|
21
|
+
<HomeIcon v-if="menu.path === '/dashboard' || menu.path === '/core/' || menu.path === '/core'" style="margin-right: 8px" />
|
|
22
|
+
<ControlPlatformIcon v-else style="margin-right: 8px" />
|
|
33
23
|
</template>
|
|
34
|
-
{{
|
|
24
|
+
{{ menu.name }}
|
|
35
25
|
</t-menu-item>
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
26
|
+
<!-- 有子菜单 -->
|
|
27
|
+
<t-submenu v-else :value="String(menu.id)" :title="menu.name">
|
|
28
|
+
<template #icon>
|
|
29
|
+
<AppIcon style="margin-right: 8px" />
|
|
30
|
+
</template>
|
|
31
|
+
<t-menu-item v-for="child in menu.children" :key="child.id" :value="child.path">
|
|
32
|
+
<template #icon>
|
|
33
|
+
<ControlPlatformIcon style="margin-right: 8px" />
|
|
34
|
+
</template>
|
|
35
|
+
{{ child.name }}
|
|
36
|
+
</t-menu-item>
|
|
37
|
+
</t-submenu>
|
|
38
|
+
</template>
|
|
39
|
+
</t-menu>
|
|
40
|
+
</div>
|
|
39
41
|
</div>
|
|
40
42
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
<span>系统设置</span>
|
|
46
|
-
</div>
|
|
47
|
-
<div class="footer-user">
|
|
48
|
-
<t-upload :action="$Config.uploadPath" :headers="uploadHeaders" :show-upload-list="false" accept="image/*" @success="onAvatarUploadSuccess">
|
|
49
|
-
<div class="user-avatar" :class="{ 'has-avatar': $Data.userInfo.avatar }">
|
|
43
|
+
<div class="sidebar-user-panel">
|
|
44
|
+
<TDropdown class="sidebar-user-dropdown" trigger="click" placement="top-right" @click="onUserDropdownAction">
|
|
45
|
+
<div class="sidebar-user">
|
|
46
|
+
<div class="sidebar-user-avatar">
|
|
50
47
|
<img v-if="$Data.userInfo.avatar" :src="$Data.userInfo.avatar" alt="avatar" />
|
|
51
48
|
<UserIcon v-else style="width: 16px; height: 16px; color: #fff" />
|
|
52
|
-
<div class="avatar-overlay">
|
|
53
|
-
<CloudIcon style="width: 14px; height: 14px; color: #fff" />
|
|
54
|
-
</div>
|
|
55
49
|
</div>
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
50
|
+
<div class="sidebar-user-info">
|
|
51
|
+
<span class="user-name">{{ $Data.userInfo.nickname || "管理员" }}</span>
|
|
52
|
+
<span class="user-role">{{ $Data.userInfo.role || "超级管理员" }}</span>
|
|
53
|
+
</div>
|
|
54
|
+
<ChevronDownIcon class="sidebar-user-arrow" style="width: 16px; height: 16px" />
|
|
60
55
|
</div>
|
|
61
|
-
<
|
|
62
|
-
<
|
|
63
|
-
<
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
56
|
+
<TDropdownMenu slot="dropdown">
|
|
57
|
+
<TDropdownItem value="password">
|
|
58
|
+
<LockOnIcon style="width: 14px; height: 14px; margin-right: 6px" />
|
|
59
|
+
修改密码
|
|
60
|
+
</TDropdownItem>
|
|
61
|
+
<TDropdownItem value="logout" :divider="true">
|
|
62
|
+
<CloseCircleIcon style="width: 14px; height: 14px; margin-right: 6px" />
|
|
63
|
+
退出登录
|
|
64
|
+
</TDropdownItem>
|
|
65
|
+
</TDropdownMenu>
|
|
66
|
+
</TDropdown>
|
|
67
67
|
</div>
|
|
68
68
|
</div>
|
|
69
69
|
|
|
70
70
|
<!-- 右侧内容区域 -->
|
|
71
71
|
<div class="layout-main">
|
|
72
|
-
<
|
|
72
|
+
<div class="main-content">
|
|
73
|
+
<RouterView />
|
|
74
|
+
</div>
|
|
75
|
+
|
|
76
|
+
<PageDialog v-if="$Data.passwordDialogVisible" v-model="$Data.passwordDialogVisible" title="修改密码" :confirm-loading="$Data.passwordSubmitting" @confirm="onPasswordSubmit">
|
|
77
|
+
<TForm ref="passwordFormRef" :model="$Data.passwordForm" label-width="100px" label-position="left" :rules="passwordFormRules">
|
|
78
|
+
<TFormItem label="新密码" prop="password">
|
|
79
|
+
<TInput v-model="$Data.passwordForm.password" type="password" placeholder="请输入新密码,至少6位" autocomplete="new-password" />
|
|
80
|
+
</TFormItem>
|
|
81
|
+
<TFormItem label="确认密码" prop="confirmPassword">
|
|
82
|
+
<TInput v-model="$Data.passwordForm.confirmPassword" type="password" placeholder="请再次输入新密码" autocomplete="new-password" />
|
|
83
|
+
</TFormItem>
|
|
84
|
+
</TForm>
|
|
85
|
+
</PageDialog>
|
|
73
86
|
</div>
|
|
74
87
|
</div>
|
|
75
88
|
</template>
|
|
76
89
|
|
|
77
90
|
<script setup>
|
|
78
91
|
import { arrayToTree } from "befly-admin-ui/utils/arrayToTree";
|
|
79
|
-
import
|
|
80
|
-
import {
|
|
92
|
+
import PageDialog from "befly-admin-ui/components/pageDialog.vue";
|
|
93
|
+
import { hashPassword } from "befly-admin-ui/utils/hashPassword";
|
|
94
|
+
import { DialogPlugin, Dropdown as TDropdown, DropdownItem as TDropdownItem, DropdownMenu as TDropdownMenu, Form as TForm, FormItem as TFormItem, Input as TInput, Menu as TMenu, MenuItem as TMenuItem, MessagePlugin, Submenu as TSubmenu } from "tdesign-vue-next";
|
|
95
|
+
import { AppIcon, ChevronDownIcon, CloseCircleIcon, ControlPlatformIcon, HomeIcon, LockOnIcon, UserIcon } from "tdesign-icons-vue-next";
|
|
81
96
|
|
|
82
|
-
import { reactive, watch } from "vue";
|
|
97
|
+
import { reactive, ref, watch } from "vue";
|
|
83
98
|
import { useRoute, useRouter } from "vue-router";
|
|
84
99
|
import { $Http } from "@/plugins/http.js";
|
|
85
100
|
import { $Config } from "@/plugins/config.js";
|
|
@@ -87,7 +102,7 @@ import { $Store } from "@/plugins/store.js";
|
|
|
87
102
|
|
|
88
103
|
const router = useRouter();
|
|
89
104
|
const route = useRoute();
|
|
90
|
-
const
|
|
105
|
+
const passwordFormRef = ref(null);
|
|
91
106
|
|
|
92
107
|
function isString(value) {
|
|
93
108
|
return typeof value === "string";
|
|
@@ -122,19 +137,39 @@ const normalizeParentPath = (parentPath) => {
|
|
|
122
137
|
return normalized;
|
|
123
138
|
};
|
|
124
139
|
|
|
140
|
+
function createPasswordForm() {
|
|
141
|
+
return {
|
|
142
|
+
password: "",
|
|
143
|
+
confirmPassword: ""
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
125
147
|
// 响应式数据
|
|
126
148
|
const $Data = reactive({
|
|
127
149
|
userMenus: [],
|
|
128
150
|
userMenusFlat: [], // 一维菜单数据
|
|
129
151
|
expandedKeys: [],
|
|
130
152
|
currentMenuKey: "",
|
|
153
|
+
passwordDialogVisible: false,
|
|
154
|
+
passwordSubmitting: false,
|
|
155
|
+
passwordForm: createPasswordForm(),
|
|
131
156
|
userInfo: {
|
|
157
|
+
id: 0,
|
|
132
158
|
nickname: "管理员",
|
|
133
159
|
role: "超级管理员",
|
|
134
|
-
avatar: ""
|
|
160
|
+
avatar: "",
|
|
161
|
+
roleCode: ""
|
|
135
162
|
}
|
|
136
163
|
});
|
|
137
164
|
|
|
165
|
+
const passwordFormRules = {
|
|
166
|
+
password: [
|
|
167
|
+
{ required: true, message: "请输入新密码", trigger: "blur" },
|
|
168
|
+
{ min: 6, message: "新密码至少6位", trigger: "blur" }
|
|
169
|
+
],
|
|
170
|
+
confirmPassword: [{ required: true, message: "请再次输入新密码", trigger: "blur" }]
|
|
171
|
+
};
|
|
172
|
+
|
|
138
173
|
function normalizeAvatarUrl(value) {
|
|
139
174
|
if (!isString(value) || value.length === 0) {
|
|
140
175
|
return "";
|
|
@@ -263,27 +298,67 @@ async function handleLogout() {
|
|
|
263
298
|
});
|
|
264
299
|
}
|
|
265
300
|
|
|
266
|
-
function
|
|
267
|
-
|
|
301
|
+
function openPasswordDialog() {
|
|
302
|
+
$Data.passwordForm = createPasswordForm();
|
|
303
|
+
$Data.passwordDialogVisible = true;
|
|
268
304
|
}
|
|
269
305
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
306
|
+
function onUserDropdownAction(data) {
|
|
307
|
+
const record = data;
|
|
308
|
+
const rawValue = record && record["value"] ? record["value"] : "";
|
|
309
|
+
const cmd = rawValue ? String(rawValue) : "";
|
|
273
310
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
avatar: avatarUrl
|
|
279
|
-
});
|
|
280
|
-
}
|
|
311
|
+
if (cmd === "password") {
|
|
312
|
+
openPasswordDialog();
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
281
315
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
316
|
+
if (cmd === "logout") {
|
|
317
|
+
handleLogout();
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
async function onPasswordSubmit(context) {
|
|
322
|
+
const form = passwordFormRef.value;
|
|
323
|
+
if (form === null) {
|
|
324
|
+
MessagePlugin.warning("表单未就绪");
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
const valid = await form.validate();
|
|
329
|
+
if (valid !== true) {
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
if ($Data.passwordForm.password !== $Data.passwordForm.confirmPassword) {
|
|
334
|
+
MessagePlugin.error("两次输入的密码不一致");
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
if (!$Data.userInfo.id) {
|
|
339
|
+
MessagePlugin.error("用户信息未就绪");
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
$Data.passwordSubmitting = true;
|
|
344
|
+
|
|
345
|
+
try {
|
|
346
|
+
const hashedPassword = await hashPassword($Data.passwordForm.password);
|
|
347
|
+
const storedPassword = await hashPassword(hashedPassword);
|
|
348
|
+
|
|
349
|
+
await $Http("/core/admin/upd", {
|
|
350
|
+
id: $Data.userInfo.id,
|
|
351
|
+
password: storedPassword
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
MessagePlugin.success("密码修改成功");
|
|
355
|
+
if (context && typeof context.close === "function") {
|
|
356
|
+
context.close();
|
|
286
357
|
}
|
|
358
|
+
} catch (error) {
|
|
359
|
+
MessagePlugin.error(error.msg || error.message || "密码修改失败");
|
|
360
|
+
} finally {
|
|
361
|
+
$Data.passwordSubmitting = false;
|
|
287
362
|
}
|
|
288
363
|
}
|
|
289
364
|
|
|
@@ -312,87 +387,60 @@ watch(
|
|
|
312
387
|
.layout-sidebar {
|
|
313
388
|
width: var(--sidebar-width);
|
|
314
389
|
flex-shrink: 0;
|
|
390
|
+
min-height: 0;
|
|
315
391
|
display: flex;
|
|
316
392
|
flex-direction: column;
|
|
317
|
-
|
|
318
|
-
border-radius: var(--border-radius-large);
|
|
319
|
-
box-shadow: var(--shadow-1);
|
|
320
|
-
overflow: hidden;
|
|
393
|
+
gap: var(--layout-gap);
|
|
321
394
|
|
|
322
|
-
|
|
323
|
-
|
|
395
|
+
.sidebar-menu-panel {
|
|
396
|
+
flex: 1;
|
|
397
|
+
min-height: 0;
|
|
324
398
|
display: flex;
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
399
|
+
flex-direction: column;
|
|
400
|
+
background: var(--bg-color-container);
|
|
401
|
+
border-radius: var(--border-radius-large);
|
|
402
|
+
box-shadow: var(--shadow-1);
|
|
403
|
+
overflow: hidden;
|
|
329
404
|
|
|
330
|
-
.logo
|
|
331
|
-
width: 36px;
|
|
332
|
-
height: 36px;
|
|
333
|
-
min-width: 36px;
|
|
405
|
+
.sidebar-logo {
|
|
334
406
|
display: flex;
|
|
335
407
|
align-items: center;
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
border-
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
h2 {
|
|
342
|
-
margin: 0;
|
|
343
|
-
font-size: var(--font-size-md);
|
|
344
|
-
font-weight: var(--font-weight-semibold);
|
|
345
|
-
color: var(--text-primary);
|
|
346
|
-
white-space: nowrap;
|
|
347
|
-
overflow: hidden;
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
// 菜单区域
|
|
352
|
-
.sidebar-menu {
|
|
353
|
-
flex: 1;
|
|
354
|
-
overflow-y: auto;
|
|
355
|
-
padding: var(--spacing-xs) 0;
|
|
356
|
-
|
|
357
|
-
:deep(.t-menu) {
|
|
358
|
-
border-right: none;
|
|
359
|
-
background: transparent;
|
|
408
|
+
gap: var(--spacing-sm);
|
|
409
|
+
padding: var(--spacing-md) var(--spacing-md);
|
|
410
|
+
border-bottom: 1px solid var(--border-color-light);
|
|
360
411
|
|
|
361
|
-
|
|
362
|
-
|
|
412
|
+
.logo-icon {
|
|
413
|
+
width: 36px;
|
|
414
|
+
height: 36px;
|
|
415
|
+
min-width: 36px;
|
|
416
|
+
display: flex;
|
|
417
|
+
align-items: center;
|
|
418
|
+
justify-content: center;
|
|
419
|
+
background: var(--primary-color-light);
|
|
363
420
|
border-radius: var(--border-radius);
|
|
364
|
-
|
|
365
|
-
position: relative;
|
|
366
|
-
|
|
367
|
-
&:hover {
|
|
368
|
-
background-color: var(--bg-color-hover);
|
|
369
|
-
}
|
|
421
|
+
}
|
|
370
422
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
position: absolute;
|
|
379
|
-
left: 0;
|
|
380
|
-
top: 50%;
|
|
381
|
-
transform: translateY(-50%);
|
|
382
|
-
width: var(--menu-active-indicator);
|
|
383
|
-
height: 60%;
|
|
384
|
-
background-color: var(--primary-color);
|
|
385
|
-
border-radius: 0 2px 2px 0;
|
|
386
|
-
}
|
|
387
|
-
}
|
|
423
|
+
h2 {
|
|
424
|
+
margin: 0;
|
|
425
|
+
font-size: var(--font-size-md);
|
|
426
|
+
font-weight: var(--font-weight-semibold);
|
|
427
|
+
color: var(--text-primary);
|
|
428
|
+
white-space: nowrap;
|
|
429
|
+
overflow: hidden;
|
|
388
430
|
}
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
.sidebar-menu {
|
|
434
|
+
flex: 1;
|
|
435
|
+
min-height: 0;
|
|
436
|
+
overflow-y: auto;
|
|
437
|
+
padding: var(--spacing-xs) 0;
|
|
389
438
|
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
// margin: 2px var(--spacing-sm);
|
|
439
|
+
:deep(.t-menu) {
|
|
440
|
+
border-right: none;
|
|
441
|
+
background: transparent;
|
|
442
|
+
|
|
443
|
+
.t-menu__item {
|
|
396
444
|
border-radius: var(--border-radius);
|
|
397
445
|
transition: all var(--transition-fast);
|
|
398
446
|
position: relative;
|
|
@@ -401,116 +449,127 @@ watch(
|
|
|
401
449
|
background-color: var(--bg-color-hover);
|
|
402
450
|
}
|
|
403
451
|
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
452
|
+
&.t-is-active {
|
|
453
|
+
background-color: var(--primary-color-light);
|
|
454
|
+
color: var(--primary-color);
|
|
455
|
+
font-weight: var(--font-weight-medium);
|
|
456
|
+
|
|
457
|
+
&::before {
|
|
458
|
+
content: "";
|
|
459
|
+
position: absolute;
|
|
460
|
+
left: 0;
|
|
461
|
+
top: 50%;
|
|
462
|
+
transform: translateY(-50%);
|
|
463
|
+
width: var(--menu-active-indicator);
|
|
464
|
+
height: 60%;
|
|
465
|
+
background-color: var(--primary-color);
|
|
466
|
+
border-radius: 0 2px 2px 0;
|
|
467
|
+
}
|
|
407
468
|
}
|
|
469
|
+
}
|
|
408
470
|
|
|
409
|
-
|
|
410
|
-
|
|
471
|
+
.t-submenu {
|
|
472
|
+
> .t-menu__item,
|
|
473
|
+
> .t-submenu__header {
|
|
474
|
+
border-radius: var(--border-radius);
|
|
475
|
+
transition: all var(--transition-fast);
|
|
476
|
+
position: relative;
|
|
477
|
+
|
|
478
|
+
&:hover {
|
|
479
|
+
background-color: var(--bg-color-hover);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
&::before {
|
|
483
|
+
display: none !important;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
&.t-is-active {
|
|
487
|
+
background-color: transparent !important;
|
|
488
|
+
}
|
|
411
489
|
}
|
|
412
490
|
}
|
|
413
491
|
}
|
|
414
492
|
}
|
|
415
493
|
}
|
|
416
494
|
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
495
|
+
.sidebar-user-panel {
|
|
496
|
+
flex-shrink: 0;
|
|
497
|
+
height: var(--pagination-height);
|
|
498
|
+
display: flex;
|
|
499
|
+
align-items: center;
|
|
500
|
+
padding: 0 var(--spacing-md);
|
|
501
|
+
background: var(--bg-color-container);
|
|
502
|
+
border-radius: var(--border-radius-large);
|
|
503
|
+
box-shadow: var(--shadow-1);
|
|
504
|
+
|
|
505
|
+
.sidebar-user-dropdown {
|
|
506
|
+
display: block;
|
|
507
|
+
width: 100%;
|
|
508
|
+
}
|
|
421
509
|
|
|
422
|
-
.
|
|
510
|
+
.sidebar-user {
|
|
511
|
+
width: 100%;
|
|
423
512
|
display: flex;
|
|
424
513
|
align-items: center;
|
|
425
514
|
gap: var(--spacing-sm);
|
|
426
|
-
padding: var(--spacing-
|
|
515
|
+
padding: var(--spacing-xs);
|
|
427
516
|
border-radius: var(--border-radius);
|
|
428
|
-
color: var(--text-secondary);
|
|
429
517
|
cursor: pointer;
|
|
430
|
-
transition:
|
|
518
|
+
transition: background-color var(--transition-fast);
|
|
431
519
|
|
|
432
520
|
&:hover {
|
|
433
521
|
background-color: var(--bg-color-hover);
|
|
434
|
-
color: var(--text-primary);
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
span {
|
|
438
|
-
font-size: var(--font-size-sm);
|
|
439
|
-
white-space: nowrap;
|
|
440
522
|
}
|
|
441
523
|
}
|
|
442
524
|
|
|
443
|
-
.
|
|
525
|
+
.sidebar-user-avatar {
|
|
526
|
+
width: 36px;
|
|
527
|
+
height: 36px;
|
|
528
|
+
min-width: 36px;
|
|
444
529
|
display: flex;
|
|
445
530
|
align-items: center;
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
border-radius: var(--border-radius);
|
|
451
|
-
|
|
452
|
-
.user-avatar {
|
|
453
|
-
width: 32px;
|
|
454
|
-
height: 32px;
|
|
455
|
-
min-width: 32px;
|
|
456
|
-
display: flex;
|
|
457
|
-
align-items: center;
|
|
458
|
-
justify-content: center;
|
|
459
|
-
background: var(--primary-color);
|
|
460
|
-
border-radius: 50%;
|
|
461
|
-
flex-shrink: 0;
|
|
462
|
-
cursor: pointer;
|
|
463
|
-
position: relative;
|
|
464
|
-
overflow: hidden;
|
|
531
|
+
justify-content: center;
|
|
532
|
+
background: var(--primary-color);
|
|
533
|
+
border-radius: 50%;
|
|
534
|
+
overflow: hidden;
|
|
465
535
|
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
536
|
+
img {
|
|
537
|
+
width: 100%;
|
|
538
|
+
height: 100%;
|
|
539
|
+
object-fit: cover;
|
|
540
|
+
}
|
|
541
|
+
}
|
|
471
542
|
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
bottom: 0;
|
|
478
|
-
background: rgba(0, 0, 0, 0.5);
|
|
479
|
-
display: flex;
|
|
480
|
-
align-items: center;
|
|
481
|
-
justify-content: center;
|
|
482
|
-
opacity: 0;
|
|
483
|
-
transition: opacity var(--transition-fast);
|
|
484
|
-
}
|
|
543
|
+
.sidebar-user-info {
|
|
544
|
+
flex: 1;
|
|
545
|
+
min-width: 0;
|
|
546
|
+
display: flex;
|
|
547
|
+
flex-direction: column;
|
|
485
548
|
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
549
|
+
.user-name {
|
|
550
|
+
font-size: var(--font-size-sm);
|
|
551
|
+
font-weight: var(--font-weight-medium);
|
|
552
|
+
color: var(--text-primary);
|
|
553
|
+
line-height: 1.3;
|
|
554
|
+
white-space: nowrap;
|
|
555
|
+
overflow: hidden;
|
|
556
|
+
text-overflow: ellipsis;
|
|
489
557
|
}
|
|
490
558
|
|
|
491
|
-
.user-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
font-size: var(--font-size-sm);
|
|
499
|
-
font-weight: var(--font-weight-medium);
|
|
500
|
-
color: var(--text-primary);
|
|
501
|
-
line-height: 1.3;
|
|
502
|
-
overflow: hidden;
|
|
503
|
-
text-overflow: ellipsis;
|
|
504
|
-
white-space: nowrap;
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
.user-role {
|
|
508
|
-
font-size: var(--font-size-xs);
|
|
509
|
-
color: var(--text-placeholder);
|
|
510
|
-
line-height: 1.3;
|
|
511
|
-
}
|
|
559
|
+
.user-role {
|
|
560
|
+
font-size: var(--font-size-xs);
|
|
561
|
+
color: var(--text-placeholder);
|
|
562
|
+
line-height: 1.3;
|
|
563
|
+
white-space: nowrap;
|
|
564
|
+
overflow: hidden;
|
|
565
|
+
text-overflow: ellipsis;
|
|
512
566
|
}
|
|
513
567
|
}
|
|
568
|
+
|
|
569
|
+
.sidebar-user-arrow {
|
|
570
|
+
color: var(--text-placeholder);
|
|
571
|
+
flex-shrink: 0;
|
|
572
|
+
}
|
|
514
573
|
}
|
|
515
574
|
}
|
|
516
575
|
|
|
@@ -518,7 +577,15 @@ watch(
|
|
|
518
577
|
.layout-main {
|
|
519
578
|
flex: 1;
|
|
520
579
|
min-width: 0;
|
|
580
|
+
display: flex;
|
|
581
|
+
flex-direction: column;
|
|
521
582
|
overflow: hidden;
|
|
583
|
+
|
|
584
|
+
.main-content {
|
|
585
|
+
flex: 1;
|
|
586
|
+
min-height: 0;
|
|
587
|
+
overflow: hidden;
|
|
588
|
+
}
|
|
522
589
|
}
|
|
523
590
|
}
|
|
524
591
|
</style>
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "befly-admin-ui",
|
|
3
|
-
"version": "1.9.
|
|
4
|
-
"gitHead": "
|
|
3
|
+
"version": "1.9.10",
|
|
4
|
+
"gitHead": "50fca5a7f581822abfdc886fcd77f2fce3db47ca",
|
|
5
5
|
"private": false,
|
|
6
6
|
"description": "Befly - 管理后台功能组件",
|
|
7
7
|
"keywords": [
|
|
@@ -45,5 +45,11 @@
|
|
|
45
45
|
"dev": "vite",
|
|
46
46
|
"build": "vite build",
|
|
47
47
|
"preview": "vite preview"
|
|
48
|
+
},
|
|
49
|
+
"dependencies": {
|
|
50
|
+
"tdesign-icons-vue-next": "^0.4.4",
|
|
51
|
+
"tdesign-vue-next": "^1.19.2",
|
|
52
|
+
"vue": "^3.5.34",
|
|
53
|
+
"vue-router": "^5.0.6"
|
|
48
54
|
}
|
|
49
55
|
}
|
|
@@ -108,10 +108,10 @@ import { withDefaultColumns } from "befly-admin-ui/utils/withDefaultColumns";
|
|
|
108
108
|
|
|
109
109
|
const $Data = reactive({
|
|
110
110
|
columns: withDefaultColumns([
|
|
111
|
-
{ colKey: "productName", title: "产品名称"
|
|
111
|
+
{ colKey: "productName", title: "产品名称" },
|
|
112
112
|
{ colKey: "productCode", title: "产品代号", width: 150 },
|
|
113
113
|
{ colKey: "productVersion", title: "产品版本", width: 130 },
|
|
114
|
-
{ colKey: "pageName", title: "页面名称"
|
|
114
|
+
{ colKey: "pageName", title: "页面名称" },
|
|
115
115
|
{ colKey: "pagePath", title: "页面路径", width: 220, ellipsis: true },
|
|
116
116
|
{ colKey: "errorType", title: "错误类型", width: 120 },
|
|
117
117
|
{ colKey: "deviceType", title: "设备类型", width: 110 },
|
|
@@ -8,14 +8,6 @@
|
|
|
8
8
|
</TButton>
|
|
9
9
|
</template>
|
|
10
10
|
|
|
11
|
-
<template #toolRight="scope">
|
|
12
|
-
<TButton shape="circle" @click="onReload(scope.reload)">
|
|
13
|
-
<template #icon>
|
|
14
|
-
<RefreshIcon />
|
|
15
|
-
</template>
|
|
16
|
-
</TButton>
|
|
17
|
-
</template>
|
|
18
|
-
|
|
19
11
|
<template #state="{ row }">
|
|
20
12
|
<TTag v-if="row.state === 1" shape="round" theme="success" variant="light-outline">正常</TTag>
|
|
21
13
|
<TTag v-else-if="row.state === 2" shape="round" theme="warning" variant="light-outline">禁用</TTag>
|
|
@@ -50,7 +42,7 @@
|
|
|
50
42
|
<script setup>
|
|
51
43
|
import { reactive } from "vue";
|
|
52
44
|
import { Button as TButton, Dropdown as TDropdown, DropdownItem as TDropdownItem, DropdownMenu as TDropdownMenu, Tag as TTag } from "tdesign-vue-next";
|
|
53
|
-
import { AddIcon, ChevronDownIcon, DeleteIcon, EditIcon
|
|
45
|
+
import { AddIcon, ChevronDownIcon, DeleteIcon, EditIcon } from "tdesign-icons-vue-next";
|
|
54
46
|
import EditDialog from "./components/edit.vue";
|
|
55
47
|
import PageTableDetail from "befly-admin-ui/components/pageTableDetail.vue";
|
|
56
48
|
import { withDefaultColumns } from "befly-admin-ui/utils/withDefaultColumns";
|
|
@@ -88,10 +80,6 @@ function onAdd() {
|
|
|
88
80
|
onAction("add", {});
|
|
89
81
|
}
|
|
90
82
|
|
|
91
|
-
function onReload(reload) {
|
|
92
|
-
reload({ keepSelection: true });
|
|
93
|
-
}
|
|
94
|
-
|
|
95
83
|
function onDialogSuccess(reload) {
|
|
96
84
|
reload({ keepSelection: true });
|
|
97
85
|
}
|
|
@@ -25,9 +25,7 @@
|
|
|
25
25
|
</template>
|
|
26
26
|
|
|
27
27
|
<template #thumbnail="{ row }">
|
|
28
|
-
<
|
|
29
|
-
<TImage class="image-thumb" :src="row.url" :alt="row.fileName" fit="cover" gallery overlay-trigger="hover" />
|
|
30
|
-
</div>
|
|
28
|
+
<TImage class="table-image" :src="row.url" :alt="row.fileName" fit="cover" shape="round" gallery overlay-trigger="hover" />
|
|
31
29
|
</template>
|
|
32
30
|
|
|
33
31
|
<template #fileSize="{ row }">
|
|
@@ -101,7 +99,7 @@ const $Data = reactive({
|
|
|
101
99
|
keyword: "",
|
|
102
100
|
columns: withDefaultColumns([
|
|
103
101
|
{ colKey: "thumbnail", title: "缩略图", width: 96 },
|
|
104
|
-
{ colKey: "fileName", title: "文件名"
|
|
102
|
+
{ colKey: "fileName", title: "文件名" },
|
|
105
103
|
{ colKey: "fileExt", title: "扩展名", width: 100, format: formatFileExt },
|
|
106
104
|
{ colKey: "fileSize", title: "大小", width: 110 },
|
|
107
105
|
{ colKey: "isImage", title: "类型", width: 90 },
|
|
@@ -214,20 +212,6 @@ function onUploadSuccess(res, reload) {
|
|
|
214
212
|
}
|
|
215
213
|
}
|
|
216
214
|
|
|
217
|
-
.image-cell {
|
|
218
|
-
display: flex;
|
|
219
|
-
align-items: center;
|
|
220
|
-
width: 100%;
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
.image-thumb {
|
|
224
|
-
width: 100%;
|
|
225
|
-
height: 56px;
|
|
226
|
-
border-radius: 10px;
|
|
227
|
-
overflow: hidden;
|
|
228
|
-
background: #f3f6fb;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
215
|
.gallery-detail {
|
|
232
216
|
display: flex;
|
|
233
217
|
flex-direction: column;
|