befly-admin-ui 1.8.16 → 1.8.18

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.
@@ -0,0 +1,489 @@
1
+ <template>
2
+ <div class="layout-wrapper">
3
+ <!-- 左侧边栏:Logo + 菜单 + 底部操作 -->
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)" />
9
+ </div>
10
+ <h2>{{ $Config.appTitle }}</h2>
11
+ </div>
12
+
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
+ <LinkIcon 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">
31
+ <template #icon>
32
+ <ControlPlatformIcon style="margin-right: 8px" />
33
+ </template>
34
+ {{ child.name }}
35
+ </t-menu-item>
36
+ </t-submenu>
37
+ </template>
38
+ </t-menu>
39
+ </div>
40
+
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.uploadUrl" :headers="uploadHeaders" :show-upload-list="false" accept="image/*" @success="onAvatarUploadSuccess">
49
+ <div class="user-avatar" :class="{ 'has-avatar': $Data.userInfo.avatar }">
50
+ <img v-if="$Data.userInfo.avatar" :src="$Data.userInfo.avatar" alt="avatar" />
51
+ <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
+ </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>
60
+ </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>
67
+ </div>
68
+ </div>
69
+
70
+ <!-- 右侧内容区域 -->
71
+ <div class="layout-main">
72
+ <RouterView />
73
+ </div>
74
+ </div>
75
+ </template>
76
+
77
+ <script setup>
78
+ 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 } from "tdesign-icons-vue-next";
81
+
82
+ import { reactive, watch } from "vue";
83
+ import { useRoute, useRouter } from "vue-router";
84
+ import { $Config } from "@/plugins/config.js";
85
+ import { $Http } from "@/plugins/http.js";
86
+
87
+ const router = useRouter();
88
+ const route = useRoute();
89
+ const uploadHeaders = { Authorization: localStorage.getItem("yicode-token") || "" };
90
+
91
+ const loginPath = "/core/login";
92
+
93
+ function isString(value) {
94
+ return typeof value === "string";
95
+ }
96
+
97
+ const normalizePath = (path) => {
98
+ if (!isString(path)) {
99
+ return path;
100
+ }
101
+
102
+ const normalized = path.replace(/\/+$/, "");
103
+ return normalized.length === 0 ? "/" : normalized;
104
+ };
105
+
106
+ // parentPath 的归一化规则与 path 不同:
107
+ // - parentPath 为空/"/" 视为根节点(空字符串)
108
+ // - 避免把所有一级菜单挂到 "/"(首页)下面
109
+ const normalizeParentPath = (parentPath) => {
110
+ if (!isString(parentPath)) {
111
+ return "";
112
+ }
113
+
114
+ const normalized = parentPath.replace(/\/+$/, "");
115
+ if (normalized.length === 0) {
116
+ return "";
117
+ }
118
+
119
+ if (normalized === "/") {
120
+ return "";
121
+ }
122
+
123
+ return normalized;
124
+ };
125
+
126
+ // 响应式数据
127
+ const $Data = reactive({
128
+ userMenus: [],
129
+ userMenusFlat: [], // 一维菜单数据
130
+ expandedKeys: [],
131
+ currentMenuKey: "",
132
+ userInfo: {
133
+ nickname: "管理员",
134
+ role: "超级管理员",
135
+ avatar: "" // 用户头像
136
+ }
137
+ });
138
+
139
+ async function fetchUserMenus() {
140
+ try {
141
+ const { data } = await $Http.json("/core/menu/all");
142
+ const lists = Array.isArray(data?.lists) ? data.lists : [];
143
+
144
+ const normalizedLists = lists.map((menu) => {
145
+ const menuPath = normalizePath(menu?.path);
146
+ const menuParentPath = normalizeParentPath(menu?.parentPath);
147
+ return Object.assign({}, menu, { path: menuPath, parentPath: menuParentPath });
148
+ });
149
+
150
+ const treeResult = arrayToTree(normalizedLists, "path", "parentPath", "children", "sort");
151
+
152
+ $Data.userMenusFlat = treeResult.flat;
153
+ $Data.userMenus = treeResult.tree;
154
+ setActiveMenu();
155
+ } catch (error) {
156
+ MessagePlugin.error(error.msg || error.message || "获取用户菜单失败");
157
+ }
158
+ }
159
+
160
+ function setActiveMenu() {
161
+ const currentPath = route.path;
162
+ const normalizedCurrentPath = normalizePath(currentPath);
163
+
164
+ const currentMenu = $Data.userMenusFlat.find((menu) => {
165
+ const menuPath = menu.path;
166
+ const normalizedMenuPath = normalizePath(menuPath);
167
+ return normalizedMenuPath === normalizedCurrentPath;
168
+ });
169
+
170
+ if (!currentMenu) {
171
+ return;
172
+ }
173
+
174
+ const expandedKeys = [];
175
+ let menu = currentMenu;
176
+
177
+ while (isString(menu.parentPath) && menu.parentPath.length > 0) {
178
+ const parent = $Data.userMenusFlat.find((m) => {
179
+ const parentMenuPath = normalizePath(m?.path);
180
+ const currentParentPath = normalizeParentPath(menu?.parentPath);
181
+ return parentMenuPath === currentParentPath;
182
+ });
183
+
184
+ if (parent) {
185
+ expandedKeys.unshift(String(parent.id));
186
+ menu = parent;
187
+ continue;
188
+ }
189
+
190
+ break;
191
+ }
192
+
193
+ $Data.expandedKeys = expandedKeys;
194
+ $Data.currentMenuKey = currentPath;
195
+ }
196
+
197
+ function onMenuClick(path) {
198
+ if (isString(path) && path.startsWith("/")) {
199
+ router.push(path);
200
+ }
201
+ }
202
+
203
+ async function handleLogout() {
204
+ let dialog = null;
205
+ let destroyed = false;
206
+
207
+ const destroy = () => {
208
+ if (destroyed) return;
209
+ destroyed = true;
210
+ if (dialog && typeof dialog.destroy === "function") {
211
+ dialog.destroy();
212
+ }
213
+ };
214
+
215
+ dialog = DialogPlugin.confirm({
216
+ header: "确认退出登录",
217
+ body: "确定要退出登录吗?",
218
+ status: "warning",
219
+ onConfirm: async () => {
220
+ if (dialog && typeof dialog.setConfirmLoading === "function") {
221
+ dialog.setConfirmLoading(true);
222
+ }
223
+
224
+ try {
225
+ localStorage.removeItem("yicode-token");
226
+ await router.push(loginPath);
227
+ MessagePlugin.success("退出成功");
228
+ destroy();
229
+ } catch (error) {
230
+ MessagePlugin.error("退出失败");
231
+ destroy();
232
+ } finally {
233
+ if (dialog && typeof dialog.setConfirmLoading === "function") {
234
+ dialog.setConfirmLoading(false);
235
+ }
236
+ }
237
+ },
238
+ onClose: () => {
239
+ destroy();
240
+ }
241
+ });
242
+ }
243
+
244
+ function handleSettings() {
245
+ router.push("/core/settings");
246
+ }
247
+
248
+ function onAvatarUploadSuccess(res) {
249
+ if (res.response?.code === 0 && res.response?.data?.url) {
250
+ $Data.userInfo.avatar = res.response.data.url;
251
+ MessagePlugin.success("头像上传成功");
252
+ }
253
+ }
254
+
255
+ fetchUserMenus();
256
+
257
+ watch(
258
+ () => route.path,
259
+ () => {
260
+ setActiveMenu();
261
+ }
262
+ );
263
+ </script>
264
+
265
+ <style scoped lang="scss">
266
+ .layout-wrapper {
267
+ display: flex;
268
+ height: 100vh;
269
+ width: 100vw;
270
+ background: var(--bg-color-page);
271
+ padding: var(--layout-gap);
272
+ gap: var(--layout-gap);
273
+ overflow: hidden;
274
+
275
+ // 左侧边栏
276
+ .layout-sidebar {
277
+ width: var(--sidebar-width);
278
+ flex-shrink: 0;
279
+ display: flex;
280
+ flex-direction: column;
281
+ background: var(--bg-color-container);
282
+ border-radius: var(--border-radius-large);
283
+ box-shadow: var(--shadow-1);
284
+ overflow: hidden;
285
+
286
+ // Logo 区域
287
+ .sidebar-logo {
288
+ display: flex;
289
+ align-items: center;
290
+ gap: var(--spacing-sm);
291
+ padding: var(--spacing-md) var(--spacing-md);
292
+ border-bottom: 1px solid var(--border-color-light);
293
+
294
+ .logo-icon {
295
+ width: 36px;
296
+ height: 36px;
297
+ min-width: 36px;
298
+ display: flex;
299
+ align-items: center;
300
+ justify-content: center;
301
+ background: var(--primary-color-light);
302
+ border-radius: var(--border-radius);
303
+ }
304
+
305
+ h2 {
306
+ margin: 0;
307
+ font-size: var(--font-size-md);
308
+ font-weight: var(--font-weight-semibold);
309
+ color: var(--text-primary);
310
+ white-space: nowrap;
311
+ overflow: hidden;
312
+ }
313
+ }
314
+
315
+ // 菜单区域
316
+ .sidebar-menu {
317
+ flex: 1;
318
+ overflow-y: auto;
319
+ padding: var(--spacing-xs) 0;
320
+
321
+ :deep(.t-menu) {
322
+ border-right: none;
323
+ background: transparent;
324
+
325
+ // 子菜单项(非父级的菜单项)
326
+ .t-menu__item {
327
+ margin: 2px var(--spacing-sm);
328
+ border-radius: var(--border-radius);
329
+ transition: all var(--transition-fast);
330
+ position: relative;
331
+
332
+ &:hover {
333
+ background-color: var(--bg-color-hover);
334
+ }
335
+
336
+ &.t-is-active {
337
+ background-color: var(--primary-color-light);
338
+ color: var(--primary-color);
339
+ font-weight: var(--font-weight-medium);
340
+
341
+ &::before {
342
+ content: "";
343
+ position: absolute;
344
+ left: 0;
345
+ top: 50%;
346
+ transform: translateY(-50%);
347
+ width: var(--menu-active-indicator);
348
+ height: 60%;
349
+ background-color: var(--primary-color);
350
+ border-radius: 0 2px 2px 0;
351
+ }
352
+ }
353
+ }
354
+
355
+ // 父级菜单样式(有子菜单的)
356
+ .t-submenu {
357
+ // 父级菜单的 header(不显示指示条)
358
+ > .t-menu__item,
359
+ > .t-submenu__header {
360
+ margin: 2px var(--spacing-sm);
361
+ border-radius: var(--border-radius);
362
+ transition: all var(--transition-fast);
363
+ position: relative;
364
+
365
+ &:hover {
366
+ background-color: var(--bg-color-hover);
367
+ }
368
+
369
+ // 父级菜单不显示指示条和背景
370
+ &::before {
371
+ display: none !important;
372
+ }
373
+
374
+ &.t-is-active {
375
+ background-color: transparent !important;
376
+ }
377
+ }
378
+ }
379
+ }
380
+ }
381
+
382
+ // 底部操作区域
383
+ .sidebar-footer {
384
+ border-top: 1px solid var(--border-color-light);
385
+ padding: var(--spacing-sm);
386
+
387
+ .footer-item {
388
+ display: flex;
389
+ align-items: center;
390
+ gap: var(--spacing-sm);
391
+ padding: var(--spacing-sm) var(--spacing-md);
392
+ border-radius: var(--border-radius);
393
+ color: var(--text-secondary);
394
+ cursor: pointer;
395
+ transition: all var(--transition-fast);
396
+
397
+ &:hover {
398
+ background-color: var(--bg-color-hover);
399
+ color: var(--text-primary);
400
+ }
401
+
402
+ span {
403
+ font-size: var(--font-size-sm);
404
+ white-space: nowrap;
405
+ }
406
+ }
407
+
408
+ .footer-user {
409
+ display: flex;
410
+ align-items: center;
411
+ gap: var(--spacing-sm);
412
+ padding: var(--spacing-sm);
413
+ margin-top: var(--spacing-xs);
414
+ background: var(--bg-color-secondarycontainer);
415
+ border-radius: var(--border-radius);
416
+
417
+ .user-avatar {
418
+ width: 32px;
419
+ height: 32px;
420
+ min-width: 32px;
421
+ display: flex;
422
+ align-items: center;
423
+ justify-content: center;
424
+ background: var(--primary-color);
425
+ border-radius: 50%;
426
+ flex-shrink: 0;
427
+ cursor: pointer;
428
+ position: relative;
429
+ overflow: hidden;
430
+
431
+ img {
432
+ width: 100%;
433
+ height: 100%;
434
+ object-fit: cover;
435
+ }
436
+
437
+ .avatar-overlay {
438
+ position: absolute;
439
+ top: 0;
440
+ left: 0;
441
+ right: 0;
442
+ bottom: 0;
443
+ background: rgba(0, 0, 0, 0.5);
444
+ display: flex;
445
+ align-items: center;
446
+ justify-content: center;
447
+ opacity: 0;
448
+ transition: opacity var(--transition-fast);
449
+ }
450
+
451
+ &:hover .avatar-overlay {
452
+ opacity: 1;
453
+ }
454
+ }
455
+
456
+ .user-info {
457
+ flex: 1;
458
+ min-width: 0;
459
+ display: flex;
460
+ flex-direction: column;
461
+
462
+ .user-name {
463
+ font-size: var(--font-size-sm);
464
+ font-weight: var(--font-weight-medium);
465
+ color: var(--text-primary);
466
+ line-height: 1.3;
467
+ overflow: hidden;
468
+ text-overflow: ellipsis;
469
+ white-space: nowrap;
470
+ }
471
+
472
+ .user-role {
473
+ font-size: var(--font-size-xs);
474
+ color: var(--text-placeholder);
475
+ line-height: 1.3;
476
+ }
477
+ }
478
+ }
479
+ }
480
+ }
481
+
482
+ // 右侧主内容区域
483
+ .layout-main {
484
+ flex: 1;
485
+ min-width: 0;
486
+ overflow: hidden;
487
+ }
488
+ }
489
+ </style>
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "befly-admin-ui",
3
- "version": "1.8.16",
4
- "gitHead": "964aa96007544f0f7a0f129bbe1d234a5ea59a08",
3
+ "version": "1.8.18",
4
+ "gitHead": "3fab09ac346b6d336a2f60b123d4856d077f8c7d",
5
5
  "private": false,
6
6
  "description": "Befly - 管理后台功能组件",
7
7
  "keywords": [
@@ -22,6 +22,8 @@
22
22
  "package.json",
23
23
  "README.md",
24
24
  "jsconfig.json",
25
+ "components/",
26
+ "layouts/",
25
27
  "views/",
26
28
  "styles/",
27
29
  "utils/"
@@ -30,6 +32,8 @@
30
32
  "main": "package.json",
31
33
  "exports": {
32
34
  ".": "./package.json",
35
+ "./components/*": "./components/*",
36
+ "./layouts/*": "./layouts/*",
33
37
  "./styles/*": "./styles/*",
34
38
  "./utils/*": "./utils/*.js"
35
39
  },
@@ -44,8 +48,5 @@
44
48
  },
45
49
  "peerDependencies": {
46
50
  "tdesign-icons-vue-next": "^0.4.0"
47
- },
48
- "devDependencies": {
49
- "tdesign-icons-vue-next": "^0.4.0"
50
51
  }
51
52
  }
@@ -26,7 +26,7 @@
26
26
  import { computed, reactive, ref } from "vue";
27
27
 
28
28
  import { Form as TForm, FormItem as TFormItem, Input as TInput, Select as TSelect, Option as TOption, Textarea as TTextarea, InputNumber as TInputNumber, MessagePlugin } from "tdesign-vue-next";
29
- import PageDialog from "@/components/pageDialog.vue";
29
+ import PageDialog from "befly-admin-ui/components/pageDialog.vue";
30
30
  import { $Http } from "@/plugins/http";
31
31
 
32
32
  const props = defineProps({
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <PagedTableDetail class="page-dict page-table" :columns="$Data.columns" :endpoints="$Data.endpoints">
2
+ <PageTableDetail class="page-dict page-table" :columns="$Data.columns" :endpoints="$Data.endpoints">
3
3
  <template #toolLeft>
4
4
  <TButton theme="primary" @click="onAdd">
5
5
  <template #icon>
@@ -46,7 +46,7 @@
46
46
  <template #dialogs="scope">
47
47
  <EditDialog v-if="$Data.editVisible" v-model="$Data.editVisible" :action-type="$Data.actionType" :row-data="$Data.rowData" :type-list="$Data.typeList" @success="onDialogSuccess(scope.reload)" />
48
48
  </template>
49
- </PagedTableDetail>
49
+ </PageTableDetail>
50
50
  </template>
51
51
 
52
52
  <script setup>
@@ -56,7 +56,7 @@ import { Button as TButton, Dropdown as TDropdown, DropdownItem as TDropdownItem
56
56
  import { AddIcon, ChevronDownIcon, DeleteIcon, EditIcon, RefreshIcon, SearchIcon } from "tdesign-icons-vue-next";
57
57
  import EditDialog from "./components/edit.vue";
58
58
  import { $Http } from "@/plugins/http";
59
- import PagedTableDetail from "@/components/pagedTableDetail.vue";
59
+ import PageTableDetail from "befly-admin-ui/components/pagedTableDetail.vue";
60
60
  import { withDefaultColumns } from "befly-admin-ui/utils/withDefaultColumns";
61
61
 
62
62
  const $Data = reactive({
@@ -21,7 +21,7 @@
21
21
  import { computed, reactive, ref } from "vue";
22
22
 
23
23
  import { Form as TForm, FormItem as TFormItem, Input as TInput, Textarea as TTextarea, InputNumber as TInputNumber, MessagePlugin } from "tdesign-vue-next";
24
- import PageDialog from "@/components/pageDialog.vue";
24
+ import PageDialog from "befly-admin-ui/components/pageDialog.vue";
25
25
  import { $Http } from "@/plugins/http";
26
26
 
27
27
  const props = defineProps({
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <PagedTableDetail class="page-dict-type page-table" :columns="$Data.columns" :endpoints="$Data.endpoints">
2
+ <PageTableDetail class="page-dict-type page-table" :columns="$Data.columns" :endpoints="$Data.endpoints">
3
3
  <template #toolLeft>
4
4
  <TButton theme="primary" @click="onAdd">
5
5
  <template #icon>
@@ -43,7 +43,7 @@
43
43
  <template #dialogs="scope">
44
44
  <EditDialog v-if="$Data.editVisible" v-model="$Data.editVisible" :action-type="$Data.actionType" :row-data="$Data.rowData" @success="onDialogSuccess(scope.reload)" />
45
45
  </template>
46
- </PagedTableDetail>
46
+ </PageTableDetail>
47
47
  </template>
48
48
 
49
49
  <script setup>
@@ -51,7 +51,7 @@ import { reactive } from "vue";
51
51
  import { Button as TButton, Dropdown as TDropdown, DropdownItem as TDropdownItem, DropdownMenu as TDropdownMenu, Input as TInput } from "tdesign-vue-next";
52
52
  import { AddIcon, ChevronDownIcon, DeleteIcon, EditIcon, RefreshIcon, SearchIcon } from "tdesign-icons-vue-next";
53
53
  import EditDialog from "./components/edit.vue";
54
- import PagedTableDetail from "@/components/pagedTableDetail.vue";
54
+ import PageTableDetail from "befly-admin-ui/components/pagedTableDetail.vue";
55
55
  import { withDefaultColumns } from "befly-admin-ui/utils/withDefaultColumns";
56
56
 
57
57
  const $Data = reactive({
@@ -44,7 +44,7 @@
44
44
  import { computed, reactive, ref } from "vue";
45
45
 
46
46
  import { Form as TForm, FormItem as TFormItem, Input as TInput, Textarea as TTextarea, InputNumber as TInputNumber, Select as TSelect, Option as TOption, RadioGroup as TRadioGroup, Radio as TRadio, MessagePlugin } from "tdesign-vue-next";
47
- import PageDialog from "@/components/pageDialog.vue";
47
+ import PageDialog from "befly-admin-ui/components/pageDialog.vue";
48
48
  import { $Http } from "@/plugins/http";
49
49
 
50
50
  const $Prop = defineProps({
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <PagedTableDetail class="page-sys-config page-table" :columns="$Data.columns" :endpoints="$Data.endpoints" :table-slot-names="['isSystem', 'valueType', 'state']">
2
+ <PageTableDetail class="page-sys-config page-table" :columns="$Data.columns" :endpoints="$Data.endpoints" :table-slot-names="['isSystem', 'valueType', 'state']">
3
3
  <template #toolLeft="scope">
4
4
  <TButton theme="primary" @click="onAdd">
5
5
  <template #icon>
@@ -71,7 +71,7 @@
71
71
  <template #dialogs="scope">
72
72
  <EditDialog v-if="$Data.editVisible" v-model="$Data.editVisible" :action-type="$Data.actionType" :row-data="$Data.rowData" @success="onDialogSuccess(scope.reload)" />
73
73
  </template>
74
- </PagedTableDetail>
74
+ </PageTableDetail>
75
75
  </template>
76
76
 
77
77
  <script setup>
@@ -79,8 +79,8 @@ import { reactive } from "vue";
79
79
  import { Button as TButton, Dropdown as TDropdown, DropdownItem as TDropdownItem, DropdownMenu as TDropdownMenu, Option as TOption, Select as TSelect, Tag as TTag } from "tdesign-vue-next";
80
80
  import { AddIcon, ChevronDownIcon, DeleteIcon, EditIcon, RefreshIcon } from "tdesign-icons-vue-next";
81
81
  import EditDialog from "./components/edit.vue";
82
- import DetailPanel from "@/components/detailPanel.vue";
83
- import PagedTableDetail from "@/components/pagedTableDetail.vue";
82
+ import DetailPanel from "befly-admin-ui/components/detailPanel.vue";
83
+ import PageTableDetail from "befly-admin-ui/components/pagedTableDetail.vue";
84
84
  import { withDefaultColumns } from "befly-admin-ui/utils/withDefaultColumns";
85
85
 
86
86
  // 响应式数据
@@ -25,6 +25,7 @@
25
25
 
26
26
  <script setup>
27
27
  import { reactive } from "vue";
28
+ import { Tag as TTag } from "tdesign-vue-next";
28
29
  import { MenuIcon, SystemStorageIcon } from "tdesign-icons-vue-next";
29
30
  import { $Http } from "@/plugins/http";
30
31
 
@@ -35,6 +35,7 @@
35
35
 
36
36
  <script setup>
37
37
  import { reactive } from "vue";
38
+ import { Tag as TTag } from "tdesign-vue-next";
38
39
  import { CodeIcon } from "tdesign-icons-vue-next";
39
40
 
40
41
  // 组件内部数据
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <PagedTableDetail class="page-email page-table" :columns="$Data.columns" :endpoints="$Data.endpoints" :table-slot-names="['sendResult', 'sendTime']">
2
+ <PageTableDetail class="page-email page-table" :columns="$Data.columns" :endpoints="$Data.endpoints" :table-slot-names="['sendResult', 'sendTime']">
3
3
  <template #toolLeft>
4
4
  <TButton theme="primary" @click="openSendDialog">
5
5
  <template #icon>
@@ -65,17 +65,17 @@
65
65
  </TForm>
66
66
  </PageDialog>
67
67
  </template>
68
- </PagedTableDetail>
68
+ </PageTableDetail>
69
69
  </template>
70
70
 
71
71
  <script setup>
72
72
  import { reactive, ref } from "vue";
73
73
  import { Button as TButton, Form as TForm, FormItem as TFormItem, Input as TInput, MessagePlugin, Space as TSpace, Tag as TTag, Textarea as TTextarea } from "tdesign-vue-next";
74
74
  import { CheckCircleIcon, RefreshIcon, SendIcon } from "tdesign-icons-vue-next";
75
- import PageDialog from "@/components/pageDialog.vue";
76
- import DetailPanel from "@/components/detailPanel.vue";
75
+ import PageDialog from "befly-admin-ui/components/pageDialog.vue";
76
+ import DetailPanel from "befly-admin-ui/components/detailPanel.vue";
77
77
  import { $Http } from "@/plugins/http";
78
- import PagedTableDetail from "@/components/pagedTableDetail.vue";
78
+ import PageTableDetail from "befly-admin-ui/components/pagedTableDetail.vue";
79
79
  import { withDefaultColumns } from "befly-admin-ui/utils/withDefaultColumns";
80
80
  const sendFormRef = ref(null);
81
81