befly-admin-ui 1.10.17 → 1.10.19

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 (39) hide show
  1. package/README.md +2 -1
  2. package/components/detailPanel.vue +0 -1
  3. package/components/pageDialog.vue +0 -1
  4. package/components/pageTableDetail.vue +1 -1
  5. package/layouts/default.vue +1 -2
  6. package/package.json +2 -2
  7. package/styles/dashboardCard.scss +228 -0
  8. package/views/config/dict/components/edit.vue +1 -1
  9. package/views/config/dict/index.vue +1 -2
  10. package/views/config/dictType/components/edit.vue +1 -1
  11. package/views/config/dictType/index.vue +0 -2
  12. package/views/config/system/components/edit.vue +1 -1
  13. package/views/config/system/index.vue +0 -2
  14. package/views/index/components/environmentInfo.vue +66 -81
  15. package/views/index/components/projectStats.vue +392 -0
  16. package/views/index/components/serviceStatus.vue +28 -105
  17. package/views/index/components/systemOverview.vue +41 -1065
  18. package/views/index/components/systemResources.vue +35 -94
  19. package/views/index/index.vue +10 -7
  20. package/views/log/email/index.vue +1 -2
  21. package/views/log/error/index.vue +1 -2
  22. package/views/log/login/index.vue +0 -1
  23. package/views/log/operate/index.vue +0 -1
  24. package/views/login_1/index.vue +1 -2
  25. package/views/people/admin/components/edit.vue +0 -6
  26. package/views/people/admin/index.vue +0 -2
  27. package/views/permission/api/index.vue +1 -2
  28. package/views/permission/menu/index.vue +1 -1
  29. package/views/permission/role/components/api.vue +1 -2
  30. package/views/permission/role/components/edit.vue +0 -6
  31. package/views/permission/role/components/menu.vue +1 -2
  32. package/views/permission/role/index.vue +0 -2
  33. package/views/resource/gallery/index.vue +1 -2
  34. package/views/index/components/addonList.vue +0 -140
  35. package/views/index/components/operationLogs.vue +0 -120
  36. package/views/index/components/performanceMetrics.vue +0 -158
  37. package/views/index/components/quickActions.vue +0 -30
  38. package/views/index/components/systemNotifications.vue +0 -139
  39. package/views/index/components/userInfo.vue +0 -188
@@ -1,158 +0,0 @@
1
- <template>
2
- <div class="section-block">
3
- <div class="section-header flex items-center gap-2">
4
- <ChartIcon />
5
- <h2>性能指标</h2>
6
- </div>
7
- <div class="section-content">
8
- <div class="performance-grid">
9
- <div class="perf-metric">
10
- <div class="perf-info">
11
- <div class="perf-label">平均响应</div>
12
- <div class="perf-value">{{ $Data.performanceMetrics.avgResponseTime }}ms</div>
13
- </div>
14
- </div>
15
- <div class="perf-metric">
16
- <div class="perf-info">
17
- <div class="perf-label">QPS</div>
18
- <div class="perf-value">{{ $Data.performanceMetrics.qps }}/s</div>
19
- </div>
20
- </div>
21
- <div class="perf-metric">
22
- <div class="perf-info">
23
- <div class="perf-label">错误率</div>
24
- <div class="perf-value">{{ $Data.performanceMetrics.errorRate }}%</div>
25
- </div>
26
- </div>
27
- <div class="perf-metric">
28
- <div class="perf-info">
29
- <div class="perf-label">活跃连接</div>
30
- <div class="perf-value">{{ $Data.performanceMetrics.activeConnections }}</div>
31
- </div>
32
- </div>
33
- </div>
34
- <!-- 最慢接口提示 -->
35
- <div v-if="$Data.performanceMetrics.slowestApi" class="perf-slowest">
36
- <ErrorTriangleIcon />
37
- <span>最慢接口: {{ $Data.performanceMetrics.slowestApi.path }} ({{ $Data.performanceMetrics.slowestApi.time }}ms)</span>
38
- </div>
39
- </div>
40
- </div>
41
- </template>
42
-
43
- <script setup>
44
- import { ChartIcon, ErrorTriangleIcon } from "tdesign-icons-vue-next";
45
- import { reactive } from "vue";
46
-
47
- import { $Http } from "@/plugins/http.js";
48
-
49
- // 组件内部数据
50
- const $Data = reactive({
51
- performanceMetrics: {
52
- avgResponseTime: 0,
53
- qps: 0,
54
- errorRate: 0,
55
- activeConnections: 0,
56
- slowestApi: null
57
- }
58
- });
59
-
60
- const $Method = {
61
- fetchData: async function () {
62
- try {
63
- const res = await $Http("/core/dashboard/performanceMetrics", {}, [""]);
64
- Object.assign($Data.performanceMetrics, res.data);
65
- } catch (_error) {
66
- // 静默失败:不阻断页面展示
67
- }
68
- }
69
- };
70
-
71
- $Method.fetchData();
72
- </script>
73
-
74
- <style scoped lang="scss">
75
- .performance-grid {
76
- display: grid;
77
- grid-template-columns: repeat(4, minmax(0, 1fr));
78
- gap: 10px;
79
- margin-bottom: 8px;
80
-
81
- .perf-metric {
82
- display: flex;
83
- align-items: flex-start;
84
- justify-content: center;
85
- min-height: 92px;
86
- padding: 14px;
87
- background: linear-gradient(180deg, rgba(var(--primary-color-rgb), 0.018), rgba(255, 255, 255, 0.96));
88
- border-radius: 8px;
89
- border: 1px solid rgba(0, 0, 0, 0.06);
90
- transition: all 0.2s;
91
-
92
- &:hover {
93
- background: rgba(var(--primary-color-rgb), 0.05);
94
- border-color: var(--primary-color);
95
- box-shadow: 0 8px 18px rgba(31, 35, 41, 0.08);
96
- }
97
-
98
- .perf-info {
99
- display: flex;
100
- flex-direction: column;
101
- justify-content: center;
102
- gap: 4px;
103
- flex: 1;
104
- width: 100%;
105
- min-width: 0;
106
-
107
- .perf-label {
108
- font-size: 12px;
109
- color: var(--text-secondary);
110
- line-height: 1.2;
111
- }
112
-
113
- .perf-value {
114
- font-size: 22px;
115
- font-weight: 700;
116
- line-height: 1.1;
117
- letter-spacing: -0.3px;
118
- font-variant-numeric: tabular-nums;
119
- color: var(--primary-color);
120
- }
121
- }
122
- }
123
- }
124
-
125
- @media (max-width: 1200px) {
126
- .performance-grid {
127
- grid-template-columns: repeat(2, minmax(0, 1fr));
128
- }
129
- }
130
-
131
- .perf-slowest {
132
- display: flex;
133
- align-items: flex-start;
134
- gap: 6px;
135
- padding: 8px 10px;
136
- background: rgba(var(--warning-color-rgb), 0.05);
137
- border-radius: 8px;
138
- border: 1px solid rgba(var(--warning-color-rgb), 0.2);
139
- font-size: 12px;
140
- color: var(--warning-color);
141
- word-break: break-word;
142
- }
143
-
144
- .warning-tip {
145
- padding: var(--spacing-sm) var(--spacing-md);
146
- background: rgba(var(--warning-color-rgb), 0.05);
147
- border-radius: var(--border-radius-small);
148
- border: 1px solid rgba(var(--warning-color-rgb), 0.2);
149
- font-size: 14px;
150
- color: var(--warning-color);
151
- }
152
-
153
- @media (max-width: 640px) {
154
- .performance-grid {
155
- grid-template-columns: 1fr;
156
- }
157
- }
158
- </style>
@@ -1,30 +0,0 @@
1
- <template>
2
- <div class="section-block">
3
- <div class="section-content">
4
- <TButton theme="primary" size="large" @click="handleClearCache">
5
- <template #prefix>
6
- <RefreshIcon />
7
- </template>
8
- 刷新缓存
9
- </TButton>
10
- </div>
11
- </div>
12
- </template>
13
-
14
- <script setup>
15
- import { RefreshIcon } from "tdesign-icons-vue-next";
16
- import { Button as TButton } from "tdesign-vue-next";
17
-
18
- const handleClearCache = () => {
19
- // TODO: 接入刷新缓存接口
20
- };
21
- </script>
22
-
23
- <style scoped lang="scss">
24
- .section-block {
25
- .section-content {
26
- display: flex;
27
- justify-content: center;
28
- }
29
- }
30
- </style>
@@ -1,139 +0,0 @@
1
- <template>
2
- <div class="section-block">
3
- <div class="section-header flex items-center gap-2">
4
- <NotificationIcon />
5
- <h2>系统通知</h2>
6
- </div>
7
- <div class="section-content">
8
- <div class="notification-compact-list">
9
- <div v-for="notification in $Const.notifications" :key="notification.id" class="notification-compact-item">
10
- <div class="notification-icon" :class="`type-${notification.type}`">
11
- <InfoCircleIcon v-if="notification.type === 'info'" />
12
- <CheckCircleIcon v-else-if="notification.type === 'success'" />
13
- <ErrorTriangleIcon v-else-if="notification.type === 'warning'" />
14
- <CloseCircleIcon v-else-if="notification.type === 'error'" />
15
- <NotificationIcon v-else />
16
- </div>
17
- <div class="notification-content">
18
- <span class="notification-title">{{ notification.title }}</span>
19
- <span class="notification-time">{{ $Method.formatTime(notification.createdAt) }}</span>
20
- </div>
21
- <TTag v-if="!notification.isRead" type="primary" size="small">新</TTag>
22
- </div>
23
- </div>
24
- </div>
25
- </div>
26
- </template>
27
-
28
- <script setup>
29
- import { CheckCircleIcon, CloseCircleIcon, ErrorTriangleIcon, InfoCircleIcon, NotificationIcon } from "tdesign-icons-vue-next";
30
- import { Tag as TTag } from "tdesign-vue-next";
31
- import { reactive } from "vue";
32
-
33
- // 组件内部数据
34
- const $Const = {
35
- notifications: [
36
- { id: 1, type: "warning", title: "系统更新提醒 - v1.1.0 版本已发布", isRead: false, createdAt: Date.now() - 3600000 },
37
- { id: 2, type: "info", title: "数据备份完成 - 今日凌晨自动备份成功", isRead: true, createdAt: Date.now() - 21600000 },
38
- { id: 3, type: "error", title: "SSL证书即将过期 - 请及时更新证书", isRead: false, createdAt: Date.now() - 86400000 },
39
- { id: 4, type: "success", title: "性能优化完成 - 响应速度提升30%", isRead: true, createdAt: Date.now() - 172800000 }
40
- ]
41
- };
42
-
43
- const $Method = {
44
- formatTime: function (timestamp) {
45
- const date = new Date(timestamp);
46
- const now = Date.now();
47
- const diff = now - timestamp;
48
-
49
- if (diff < 3600000) {
50
- return `${Math.floor(diff / 60000)}分钟前`;
51
- }
52
- if (diff < 86400000) {
53
- return `${Math.floor(diff / 3600000)}小时前`;
54
- }
55
-
56
- const month = String(date.getMonth() + 1).padStart(2, "0");
57
- const day = String(date.getDate()).padStart(2, "0");
58
- return `${month}-${day}`;
59
- }
60
- };
61
- </script>
62
-
63
- <style scoped lang="scss">
64
- .notification-compact-list {
65
- display: flex;
66
- flex-direction: column;
67
- gap: var(--spacing-xs);
68
-
69
- .notification-compact-item {
70
- display: flex;
71
- align-items: center;
72
- gap: var(--spacing-sm);
73
- padding: var(--spacing-sm) var(--spacing-md);
74
- background: rgba(var(--primary-color-rgb), 0.02);
75
- border-radius: var(--border-radius-small);
76
- border: 1px solid var(--border-color);
77
- transition: all 0.2s;
78
-
79
- &:hover {
80
- background: rgba(var(--primary-color-rgb), 0.05);
81
- border-color: var(--primary-color);
82
- }
83
-
84
- .notification-icon {
85
- display: flex;
86
- align-items: center;
87
- justify-content: center;
88
- width: 32px;
89
- height: 32px;
90
- border-radius: var(--border-radius-small);
91
- flex-shrink: 0;
92
-
93
- &.type-info {
94
- background: rgba(var(--primary-color-rgb), 0.1);
95
- color: var(--primary-color);
96
- }
97
-
98
- &.type-success {
99
- background: rgba(var(--success-color-rgb), 0.1);
100
- color: var(--success-color);
101
- }
102
-
103
- &.type-warning {
104
- background: rgba(var(--warning-color-rgb), 0.1);
105
- color: var(--warning-color);
106
- }
107
-
108
- &.type-error {
109
- background: rgba(var(--error-color-rgb), 0.1);
110
- color: var(--error-color);
111
- }
112
- }
113
-
114
- .notification-content {
115
- display: flex;
116
- align-items: center;
117
- gap: var(--spacing-sm);
118
- flex: 1;
119
- min-width: 0;
120
-
121
- .notification-title {
122
- font-size: 14px;
123
- color: var(--text-primary);
124
- font-weight: 500;
125
- overflow: hidden;
126
- text-overflow: ellipsis;
127
- white-space: nowrap;
128
- flex: 1;
129
- }
130
-
131
- .notification-time {
132
- font-size: 14px;
133
- color: var(--text-placeholder);
134
- flex-shrink: 0;
135
- }
136
- }
137
- }
138
- }
139
- </style>
@@ -1,188 +0,0 @@
1
- <template>
2
- <div class="section-block user-info-card">
3
- <div class="user-header">
4
- <div class="user-avatar">
5
- <UserIcon />
6
- </div>
7
- <div class="user-basic">
8
- <div class="user-name">
9
- {{ $Data.userInfo.nickname || $Data.userInfo.name || $Data.userInfo.username || "未设置" }}
10
- </div>
11
- <div class="user-role">{{ $Data.userInfo.role?.name || "普通用户" }}</div>
12
- </div>
13
- </div>
14
- <div class="user-details">
15
- <div class="detail-item">
16
- <MailIcon />
17
- <span>{{ $Data.userInfo.email || "未设置" }}</span>
18
- </div>
19
- <div v-if="$Data.userInfo.phone" class="detail-item">
20
- <CallIcon />
21
- <span>{{ $Data.userInfo.phone }}</span>
22
- </div>
23
- <div v-if="$Data.userInfo.lastLoginTime" class="detail-item">
24
- <TimeIcon />
25
- <span>{{ $Method.formatTime($Data.userInfo.lastLoginTime) }}</span>
26
- </div>
27
- </div>
28
-
29
- <!-- 仅 dev 角色显示刷新缓存按钮 -->
30
- <div v-if="$Data.userInfo.roleCode === 'dev'" class="user-actions">
31
- <TButton theme="primary" size="mini" :loading="$Data.refreshing" @click="$Method.handleRefreshCache">
32
- <template #icon>
33
- <RefreshIcon />
34
- </template>
35
- 刷新缓存
36
- </TButton>
37
- </div>
38
- </div>
39
- </template>
40
-
41
- <script setup>
42
- import { CallIcon, MailIcon, RefreshIcon, TimeIcon, UserIcon } from "tdesign-icons-vue-next";
43
- import { Button as TButton, MessagePlugin } from "tdesign-vue-next";
44
- import { reactive } from "vue";
45
-
46
- import { $Http } from "@/plugins/http.js";
47
-
48
- // 响应式数据
49
- const $Data = reactive({
50
- userInfo: {},
51
- refreshing: false
52
- });
53
-
54
- const $Method = {
55
- fetchData: async function () {
56
- try {
57
- const res = await $Http("/core/admin/detail", {}, [""]);
58
- Object.assign($Data.userInfo, res.data);
59
- } catch (error) {
60
- MessagePlugin.error(error.msg || error.message || "获取用户信息失败");
61
- }
62
- },
63
- handleRefreshCache: async function () {
64
- try {
65
- $Data.refreshing = true;
66
- const result = await $Http("/core/admin/cacheRefresh");
67
-
68
- const apis = result.data.apis;
69
- const menus = result.data.menus;
70
- const roles = result.data.roles;
71
- const messages = [];
72
-
73
- if (apis && apis.success) {
74
- messages.push(`接口缓存: ${apis.count} 个`);
75
- }
76
- if (menus && menus.success) {
77
- messages.push(`菜单缓存: ${menus.count} 个`);
78
- }
79
- if (roles && roles.success) {
80
- messages.push(`角色缓存: ${roles.count} 个`);
81
- }
82
-
83
- MessagePlugin.success(`缓存刷新成功!${messages.join(",")}`);
84
- } catch (error) {
85
- MessagePlugin.error(error.msg || error.message || "刷新缓存失败,请稍后重试");
86
- } finally {
87
- $Data.refreshing = false;
88
- }
89
- },
90
- formatTime: function (timestamp) {
91
- if (!timestamp) return "";
92
- const date = new Date(Number(timestamp));
93
- const now = new Date();
94
- const diff = now.getTime() - date.getTime();
95
-
96
- if (diff < 60000) {
97
- return "刚刚";
98
- }
99
- if (diff < 3600000) {
100
- return `${Math.floor(diff / 60000)}分钟前`;
101
- }
102
- if (diff < 86400000) {
103
- return `${Math.floor(diff / 3600000)}小时前`;
104
- }
105
- if (diff < 604800000) {
106
- return `${Math.floor(diff / 86400000)}天前`;
107
- }
108
- return `${date.getMonth() + 1}月${date.getDate()}日`;
109
- }
110
- };
111
-
112
- $Method.fetchData();
113
- </script>
114
-
115
- <style scoped lang="scss">
116
- .user-info-card {
117
- background-color: #fff;
118
- padding: 15px;
119
- .user-header {
120
- display: flex;
121
- align-items: center;
122
- gap: 12px;
123
- padding-bottom: 12px;
124
- border-bottom: 1px solid var(--border-color);
125
-
126
- .user-avatar {
127
- width: 48px;
128
- height: 48px;
129
- background: linear-gradient(135deg, var(--primary-color), #764ba2);
130
- border-radius: 50%;
131
- display: flex;
132
- align-items: center;
133
- justify-content: center;
134
- color: white;
135
- flex-shrink: 0;
136
- }
137
-
138
- .user-basic {
139
- flex: 1;
140
- min-width: 0;
141
-
142
- .user-name {
143
- font-size: 16px;
144
- font-weight: 600;
145
- color: var(--text-primary);
146
- margin-bottom: 4px;
147
- overflow: hidden;
148
- text-overflow: ellipsis;
149
- white-space: nowrap;
150
- }
151
-
152
- .user-role {
153
- font-size: 12px;
154
- color: var(--text-secondary);
155
- }
156
- }
157
- }
158
-
159
- .user-details {
160
- display: flex;
161
- flex-direction: column;
162
- gap: 8px;
163
- margin-top: 12px;
164
-
165
- .detail-item {
166
- display: flex;
167
- align-items: center;
168
- gap: 8px;
169
- font-size: 12px;
170
- color: var(--text-secondary);
171
-
172
- span {
173
- overflow: hidden;
174
- text-overflow: ellipsis;
175
- white-space: nowrap;
176
- }
177
- }
178
- }
179
-
180
- .user-actions {
181
- margin-top: 16px;
182
- padding-top: 12px;
183
- border-top: 1px solid var(--border-color);
184
- display: flex;
185
- justify-content: center;
186
- }
187
- }
188
- </style>