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
 
@@ -1,85 +1,100 @@
1
1
  <template>
2
2
  <div class="layout-wrapper">
3
- <!-- 左侧边栏:Logo + 菜单 + 底部操作 -->
3
+ <!-- 左侧边栏:菜单面板 + 用户面板 -->
4
4
  <div class="layout-sidebar">
5
- <!-- Logo 区域 -->
6
- <div class="sidebar-logo">
7
- <div class="logo-icon">
8
- <AppIcon style="width: 24px; height: 24px; color: var(--primary-color)" />
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
- <div class="sidebar-menu">
15
- <t-menu v-model:value="$Data.currentMenuKey" v-model:expanded="$Data.expandedKeys" width="220px" @change="onMenuClick">
16
- <template v-for="menu in $Data.userMenus" :key="menu.id">
17
- <!-- 无子菜单 -->
18
- <t-menu-item v-if="!menu.children || menu.children.length === 0" :value="menu.path">
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
- <ControlPlatformIcon style="margin-right: 8px" />
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
- {{ child.name }}
24
+ {{ menu.name }}
35
25
  </t-menu-item>
36
- </t-submenu>
37
- </template>
38
- </t-menu>
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
- <div class="sidebar-footer">
43
- <div class="footer-item" @click="handleSettings">
44
- <SettingIcon style="width: 18px; height: 18px" />
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
- </t-upload>
57
- <div class="user-info">
58
- <span class="user-name">{{ $Data.userInfo.nickname || "管理员" }}</span>
59
- <span class="user-role">{{ $Data.userInfo.role || "超级管理员" }}</span>
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
- <t-button theme="default" variant="text" size="small" @click="handleLogout">
62
- <template #icon>
63
- <CloseCircleIcon style="width: 16px; height: 16px" />
64
- </template>
65
- </t-button>
66
- </div>
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
- <RouterView />
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 { Button as TButton, DialogPlugin, Menu as TMenu, MenuItem as TMenuItem, MessagePlugin, Submenu as TSubmenu, Upload as TUpload } from "tdesign-vue-next";
80
- import { CloudIcon, CloseCircleIcon, CodeIcon, LinkIcon, MenuIcon, SettingIcon, UserIcon, ControlPlatformIcon, AppIcon, HomeIcon } from "tdesign-icons-vue-next";
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 uploadHeaders = { Authorization: `Bearer ${$Store.local.get($Config.tokenName, "")}` };
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 handleSettings() {
267
- router.push("/core/settings");
301
+ function openPasswordDialog() {
302
+ $Data.passwordForm = createPasswordForm();
303
+ $Data.passwordDialogVisible = true;
268
304
  }
269
305
 
270
- async function onAvatarUploadSuccess(res) {
271
- if (res.response?.code === 0 && res.response?.data?.url) {
272
- const avatarUrl = res.response.data.url;
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
- try {
275
- if ($Data.userInfo.id) {
276
- await $Http("/core/admin/upd", {
277
- id: $Data.userInfo.id,
278
- avatar: avatarUrl
279
- });
280
- }
311
+ if (cmd === "password") {
312
+ openPasswordDialog();
313
+ return;
314
+ }
281
315
 
282
- $Data.userInfo.avatar = avatarUrl;
283
- MessagePlugin.success("头像上传成功");
284
- } catch (error) {
285
- MessagePlugin.error(error.msg || error.message || "头像保存失败");
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
- background: var(--bg-color-container);
318
- border-radius: var(--border-radius-large);
319
- box-shadow: var(--shadow-1);
320
- overflow: hidden;
393
+ gap: var(--layout-gap);
321
394
 
322
- // Logo 区域
323
- .sidebar-logo {
395
+ .sidebar-menu-panel {
396
+ flex: 1;
397
+ min-height: 0;
324
398
  display: flex;
325
- align-items: center;
326
- gap: var(--spacing-sm);
327
- padding: var(--spacing-md) var(--spacing-md);
328
- border-bottom: 1px solid var(--border-color-light);
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-icon {
331
- width: 36px;
332
- height: 36px;
333
- min-width: 36px;
405
+ .sidebar-logo {
334
406
  display: flex;
335
407
  align-items: center;
336
- justify-content: center;
337
- background: var(--primary-color-light);
338
- border-radius: var(--border-radius);
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
- .t-menu__item {
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
- transition: all var(--transition-fast);
365
- position: relative;
366
-
367
- &:hover {
368
- background-color: var(--bg-color-hover);
369
- }
421
+ }
370
422
 
371
- &.t-is-active {
372
- background-color: var(--primary-color-light);
373
- color: var(--primary-color);
374
- font-weight: var(--font-weight-medium);
375
-
376
- &::before {
377
- content: "";
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
- .t-submenu {
392
- // 父级菜单的 header(不显示指示条)
393
- > .t-menu__item,
394
- > .t-submenu__header {
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
- &::before {
406
- display: none !important;
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
- &.t-is-active {
410
- background-color: transparent !important;
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
- .sidebar-footer {
419
- border-top: 1px solid var(--border-color-light);
420
- padding: var(--spacing-sm);
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
- .footer-item {
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-sm) var(--spacing-md);
515
+ padding: var(--spacing-xs);
427
516
  border-radius: var(--border-radius);
428
- color: var(--text-secondary);
429
517
  cursor: pointer;
430
- transition: all var(--transition-fast);
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
- .footer-user {
525
+ .sidebar-user-avatar {
526
+ width: 36px;
527
+ height: 36px;
528
+ min-width: 36px;
444
529
  display: flex;
445
530
  align-items: center;
446
- gap: var(--spacing-sm);
447
- padding: var(--spacing-sm);
448
- margin-top: var(--spacing-xs);
449
- background: var(--bg-color-secondarycontainer);
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
- img {
467
- width: 100%;
468
- height: 100%;
469
- object-fit: cover;
470
- }
536
+ img {
537
+ width: 100%;
538
+ height: 100%;
539
+ object-fit: cover;
540
+ }
541
+ }
471
542
 
472
- .avatar-overlay {
473
- position: absolute;
474
- top: 0;
475
- left: 0;
476
- right: 0;
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
- &:hover .avatar-overlay {
487
- opacity: 1;
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-info {
492
- flex: 1;
493
- min-width: 0;
494
- display: flex;
495
- flex-direction: column;
496
-
497
- .user-name {
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.7",
4
- "gitHead": "913ad3b34f63ddf0936fb338fadc78ade7edf00d",
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: "产品名称", fixed: "left", width: 160 },
111
+ { colKey: "productName", title: "产品名称" },
112
112
  { colKey: "productCode", title: "产品代号", width: 150 },
113
113
  { colKey: "productVersion", title: "产品版本", width: 130 },
114
- { colKey: "pageName", title: "页面名称", fixed: "left", width: 160 },
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, RefreshIcon } from "tdesign-icons-vue-next";
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
- <div class="image-cell">
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: "文件名", fixed: "left", minWidth: 220 },
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;