befly-admin-ui 1.10.1 → 1.10.5

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 (35) hide show
  1. package/components/detailPanel.vue +52 -54
  2. package/components/pageDialog.vue +131 -117
  3. package/components/pageTableDetail.vue +381 -402
  4. package/layouts/default.vue +212 -215
  5. package/package.json +2 -2
  6. package/views/config/dict/components/edit.vue +83 -60
  7. package/views/config/dict/index.vue +51 -55
  8. package/views/config/dictType/components/edit.vue +81 -57
  9. package/views/config/dictType/index.vue +37 -39
  10. package/views/config/system/components/edit.vue +97 -86
  11. package/views/config/system/index.vue +35 -37
  12. package/views/index/components/addonList.vue +14 -11
  13. package/views/index/components/environmentInfo.vue +25 -22
  14. package/views/index/components/operationLogs.vue +20 -16
  15. package/views/index/components/performanceMetrics.vue +24 -21
  16. package/views/index/components/serviceStatus.vue +26 -22
  17. package/views/index/components/systemNotifications.vue +24 -19
  18. package/views/index/components/systemOverview.vue +368 -385
  19. package/views/index/components/systemResources.vue +22 -19
  20. package/views/index/components/userInfo.vue +56 -56
  21. package/views/log/email/index.vue +96 -85
  22. package/views/log/error/index.vue +111 -117
  23. package/views/log/login/index.vue +15 -13
  24. package/views/log/operate/index.vue +31 -31
  25. package/views/login_1/index.vue +50 -32
  26. package/views/people/admin/components/edit.vue +1 -1
  27. package/views/people/admin/index.vue +27 -28
  28. package/views/permission/api/index.vue +44 -45
  29. package/views/permission/menu/index.vue +35 -35
  30. package/views/permission/role/components/api.vue +143 -144
  31. package/views/permission/role/components/edit.vue +74 -52
  32. package/views/permission/role/components/menu.vue +119 -121
  33. package/views/permission/role/index.vue +47 -49
  34. package/views/resource/gallery/index.vue +77 -78
  35. package/LICENSE +0 -201
@@ -9,22 +9,22 @@
9
9
  <div class="resource-compact-item">
10
10
  <div class="resource-compact-header">
11
11
  <span class="resource-label">CPU</span>
12
- <span class="resource-value">{{ systemResources.cpu.usage }}%</span>
13
- <span class="resource-desc">{{ systemResources.cpu.cores }}核心</span>
12
+ <span class="resource-value">{{ $Data.systemResources.cpu.usage }}%</span>
13
+ <span class="resource-desc">{{ $Data.systemResources.cpu.cores }}核心</span>
14
14
  </div>
15
15
  </div>
16
16
  <div class="resource-compact-item">
17
17
  <div class="resource-compact-header">
18
18
  <span class="resource-label">内存</span>
19
- <span class="resource-value">{{ systemResources.memory.percentage }}%</span>
20
- <span class="resource-desc">{{ systemResources.memory.used }}GB / {{ systemResources.memory.total }}GB</span>
19
+ <span class="resource-value">{{ $Data.systemResources.memory.percentage }}%</span>
20
+ <span class="resource-desc">{{ $Data.systemResources.memory.used }}GB / {{ $Data.systemResources.memory.total }}GB</span>
21
21
  </div>
22
22
  </div>
23
23
  <div class="resource-compact-item">
24
24
  <div class="resource-compact-header">
25
25
  <span class="resource-label">磁盘</span>
26
- <span class="resource-value">{{ systemResources.disk.percentage }}%</span>
27
- <span class="resource-desc">{{ systemResources.disk.used }}GB / {{ systemResources.disk.total }}GB</span>
26
+ <span class="resource-value">{{ $Data.systemResources.disk.percentage }}%</span>
27
+ <span class="resource-desc">{{ $Data.systemResources.disk.used }}GB / {{ $Data.systemResources.disk.total }}GB</span>
28
28
  </div>
29
29
  </div>
30
30
  </div>
@@ -35,26 +35,29 @@
35
35
  <script setup>
36
36
  import { reactive } from "vue";
37
37
  import { ChartIcon } from "tdesign-icons-vue-next";
38
- import { $Http } from "@/plugins/http";
38
+ import { $Http } from "@/plugins/http.js";
39
39
 
40
40
  // 组件内部数据
41
- const systemResources = reactive({
42
- cpu: { usage: 0, cores: 0 },
43
- memory: { used: 0, total: 0, percentage: 0 },
44
- disk: { used: 0, total: 0, percentage: 0 }
41
+ const $Data = reactive({
42
+ systemResources: {
43
+ cpu: { usage: 0, cores: 0 },
44
+ memory: { used: 0, total: 0, percentage: 0 },
45
+ disk: { used: 0, total: 0, percentage: 0 }
46
+ }
45
47
  });
46
48
 
47
- // 获取数据
48
- const fetchData = async () => {
49
- try {
50
- const res = await $Http("/core/dashboard/systemResources", {}, [""]);
51
- Object.assign(systemResources, res.data);
52
- } catch (_error) {
53
- // 静默失败:不阻断页面展示
49
+ const $Method = {
50
+ async fetchData() {
51
+ try {
52
+ const res = await $Http("/core/dashboard/systemResources", {}, [""]);
53
+ Object.assign($Data.systemResources, res.data);
54
+ } catch (_error) {
55
+ // 静默失败:不阻断页面展示
56
+ }
54
57
  }
55
58
  };
56
59
 
57
- fetchData();
60
+ $Method.fetchData();
58
61
  </script>
59
62
 
60
63
  <style scoped lang="scss">
@@ -22,13 +22,13 @@
22
22
  </div>
23
23
  <div v-if="$Data.userInfo.lastLoginTime" class="detail-item">
24
24
  <TimeIcon />
25
- <span>{{ formatTime($Data.userInfo.lastLoginTime) }}</span>
25
+ <span>{{ $Method.formatTime($Data.userInfo.lastLoginTime) }}</span>
26
26
  </div>
27
27
  </div>
28
28
 
29
29
  <!-- 仅 dev 角色显示刷新缓存按钮 -->
30
30
  <div v-if="$Data.userInfo.roleCode === 'dev'" class="user-actions">
31
- <TButton theme="primary" size="mini" :loading="$Data.refreshing" @click="handleRefreshCache">
31
+ <TButton theme="primary" size="mini" :loading="$Data.refreshing" @click="$Method.handleRefreshCache">
32
32
  <template #icon>
33
33
  <RefreshIcon />
34
34
  </template>
@@ -42,7 +42,7 @@
42
42
  import { reactive } from "vue";
43
43
  import { Button as TButton, MessagePlugin } from "tdesign-vue-next";
44
44
  import { CallIcon, MailIcon, RefreshIcon, TimeIcon, UserIcon } from "tdesign-icons-vue-next";
45
- import { $Http } from "@/plugins/http";
45
+ import { $Http } from "@/plugins/http.js";
46
46
 
47
47
  // 响应式数据
48
48
  const $Data = reactive({
@@ -50,65 +50,65 @@ const $Data = reactive({
50
50
  refreshing: false
51
51
  });
52
52
 
53
- async function fetchData() {
54
- try {
55
- const res = await $Http("/core/admin/detail", {}, [""]);
56
- Object.assign($Data.userInfo, res.data);
57
- } catch (error) {
58
- MessagePlugin.error(error.msg || error.message || "获取用户信息失败");
59
- }
60
- }
61
-
62
- async function handleRefreshCache() {
63
- try {
64
- $Data.refreshing = true;
65
- const result = await $Http("/core/admin/cacheRefresh");
66
-
67
- const apis = result.data.apis;
68
- const menus = result.data.menus;
69
- const roles = result.data.roles;
70
- const messages = [];
53
+ const $Method = {
54
+ async fetchData() {
55
+ try {
56
+ const res = await $Http("/core/admin/detail", {}, [""]);
57
+ Object.assign($Data.userInfo, res.data);
58
+ } catch (error) {
59
+ MessagePlugin.error(error.msg || error.message || "获取用户信息失败");
60
+ }
61
+ },
62
+ async handleRefreshCache() {
63
+ try {
64
+ $Data.refreshing = true;
65
+ const result = await $Http("/core/admin/cacheRefresh");
66
+
67
+ const apis = result.data.apis;
68
+ const menus = result.data.menus;
69
+ const roles = result.data.roles;
70
+ const messages = [];
71
+
72
+ if (apis && apis.success) {
73
+ messages.push(`接口缓存: ${apis.count} 个`);
74
+ }
75
+ if (menus && menus.success) {
76
+ messages.push(`菜单缓存: ${menus.count} 个`);
77
+ }
78
+ if (roles && roles.success) {
79
+ messages.push(`角色缓存: ${roles.count} 个`);
80
+ }
71
81
 
72
- if (apis && apis.success) {
73
- messages.push(`接口缓存: ${apis.count} 个`);
82
+ MessagePlugin.success(`缓存刷新成功!${messages.join(",")}`);
83
+ } catch (error) {
84
+ MessagePlugin.error(error.msg || error.message || "刷新缓存失败,请稍后重试");
85
+ } finally {
86
+ $Data.refreshing = false;
74
87
  }
75
- if (menus && menus.success) {
76
- messages.push(`菜单缓存: ${menus.count} 个`);
88
+ },
89
+ formatTime(timestamp) {
90
+ if (!timestamp) return "";
91
+ const date = new Date(Number(timestamp));
92
+ const now = new Date();
93
+ const diff = now.getTime() - date.getTime();
94
+
95
+ if (diff < 60000) {
96
+ return "刚刚";
77
97
  }
78
- if (roles && roles.success) {
79
- messages.push(`角色缓存: ${roles.count} 个`);
98
+ if (diff < 3600000) {
99
+ return `${Math.floor(diff / 60000)}分钟前`;
80
100
  }
81
-
82
- MessagePlugin.success(`缓存刷新成功!${messages.join(",")}`);
83
- } catch (error) {
84
- MessagePlugin.error(error.msg || error.message || "刷新缓存失败,请稍后重试");
85
- } finally {
86
- $Data.refreshing = false;
87
- }
88
- }
89
-
90
- function formatTime(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)}天前`;
101
+ if (diff < 86400000) {
102
+ return `${Math.floor(diff / 3600000)}小时前`;
103
+ }
104
+ if (diff < 604800000) {
105
+ return `${Math.floor(diff / 86400000)}天前`;
106
+ }
107
+ return `${date.getMonth() + 1}月${date.getDate()}日`;
107
108
  }
108
- return `${date.getMonth() + 1}月${date.getDate()}日`;
109
- }
109
+ };
110
110
 
111
- fetchData();
111
+ $Method.fetchData();
112
112
  </script>
113
113
 
114
114
  <style scoped lang="scss">
@@ -1,13 +1,13 @@
1
1
  <template>
2
2
  <PageTableDetail class="page-email page-table" :columns="$Data.columns" :endpoints="$Data.endpoints" :table-slot-names="['sendResult', 'sendTime']">
3
3
  <template #toolLeft>
4
- <TButton theme="primary" @click="openSendDialog">
4
+ <TButton theme="primary" @click="$Method.openSendDialog">
5
5
  <template #icon>
6
6
  <SendIcon />
7
7
  </template>
8
8
  发送邮件
9
9
  </TButton>
10
- <TButton variant="outline" @click="onVerify">
10
+ <TButton variant="outline" @click="$Method.onVerify">
11
11
  <template #icon>
12
12
  <CheckCircleIcon />
13
13
  </template>
@@ -21,7 +21,7 @@
21
21
  </template>
22
22
 
23
23
  <template #sendTime="{ row }">
24
- {{ formatTime(row.sendTime) }}
24
+ {{ $Method.formatTime(row.sendTime) }}
25
25
  </template>
26
26
 
27
27
  <template #detail="scope">
@@ -31,7 +31,7 @@
31
31
  <TTag v-else shape="round" theme="danger" variant="light-outline">失败</TTag>
32
32
  </template>
33
33
  <template #sendTime="slotScope">
34
- {{ formatTime(slotScope.value) }}
34
+ {{ $Method.formatTime(slotScope.value) }}
35
35
  </template>
36
36
  <template #content="slotScope">
37
37
  <div class="email-content" v-html="slotScope.value"></div>
@@ -40,8 +40,17 @@
40
40
  </template>
41
41
 
42
42
  <template #dialogs="scope">
43
- <PageDialog v-model="$Data.sendDialogVisible" title="发送邮件" :confirm-loading="$Data.sending" @confirm="(context) => onSend(scope.reload, context)" @cancel="onCancelSend" @close="onCancelSend">
44
- <TForm ref="sendFormRef" :data="$Data.sendForm" :rules="$Data.sendRules" label-width="80px">
43
+ <PageDialog v-model="$Data.sendDialogVisible" title="发送邮件" :confirm-loading="$Data.sending" @confirm="(context) => $Method.onSend(scope.reload, context)" @cancel="$Method.onCancelSend" @close="$Method.onCancelSend">
44
+ <TForm
45
+ :ref="
46
+ (value) => {
47
+ $From.sendFormRef = value;
48
+ }
49
+ "
50
+ :data="$Data.sendForm"
51
+ :rules="$Const.sendRules"
52
+ label-width="80px"
53
+ >
45
54
  <TFormItem label="收件人" name="to">
46
55
  <TInput v-model="$Data.sendForm.to" placeholder="请输入收件人邮箱" />
47
56
  </TFormItem>
@@ -61,15 +70,34 @@
61
70
  </template>
62
71
 
63
72
  <script setup>
64
- import { reactive, ref } from "vue";
65
- 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";
73
+ import { reactive } from "vue";
74
+ import { Button as TButton, Form as TForm, FormItem as TFormItem, Input as TInput, MessagePlugin, Tag as TTag, Textarea as TTextarea } from "tdesign-vue-next";
66
75
  import { CheckCircleIcon, SendIcon } from "tdesign-icons-vue-next";
67
76
  import PageDialog from "befly-admin-ui/components/pageDialog.vue";
68
77
  import DetailPanel from "befly-admin-ui/components/detailPanel.vue";
69
- import { $Http } from "@/plugins/http";
78
+ import { $Http } from "@/plugins/http.js";
70
79
  import PageTableDetail from "befly-admin-ui/components/pageTableDetail.vue";
71
80
  import { withDefaultColumns } from "befly-admin-ui/utils/withDefaultColumns";
72
- const sendFormRef = ref(null);
81
+
82
+ const $Const = {
83
+ createSendForm() {
84
+ return {
85
+ to: "",
86
+ cc: "",
87
+ subject: "",
88
+ content: ""
89
+ };
90
+ },
91
+ sendRules: {
92
+ to: [{ required: true, message: "请输入收件人邮箱", trigger: "blur" }],
93
+ subject: [{ required: true, message: "请输入邮件主题", trigger: "blur" }],
94
+ content: [{ required: true, message: "请输入邮件内容", trigger: "blur" }]
95
+ }
96
+ };
97
+
98
+ const $From = {
99
+ sendFormRef: null
100
+ };
73
101
 
74
102
  // 响应式数据
75
103
  const $Data = reactive({
@@ -94,89 +122,72 @@ const $Data = reactive({
94
122
  },
95
123
  sendDialogVisible: false,
96
124
  sending: false,
97
- sendForm: {
98
- to: "",
99
- cc: "",
100
- subject: "",
101
- content: ""
102
- },
103
- sendRules: {
104
- to: [{ required: true, message: "请输入收件人邮箱", trigger: "blur" }],
105
- subject: [{ required: true, message: "请输入邮件主题", trigger: "blur" }],
106
- content: [{ required: true, message: "请输入邮件内容", trigger: "blur" }]
107
- }
125
+ sendForm: $Const.createSendForm()
108
126
  });
109
127
 
110
- function onCancelSend() {
111
- $Data.sendDialogVisible = false;
112
- }
113
-
114
- function openSendDialog() {
115
- $Data.sendForm = {
116
- to: "",
117
- cc: "",
118
- subject: "",
119
- content: ""
120
- };
121
- $Data.sendDialogVisible = true;
122
- }
123
-
124
- async function onSend(reload, context) {
125
- const form = sendFormRef.value;
126
- if (!form) {
127
- MessagePlugin.warning("表单未就绪");
128
- return;
129
- }
128
+ const $Method = {
129
+ onCancelSend() {
130
+ $Data.sendDialogVisible = false;
131
+ },
132
+ openSendDialog() {
133
+ $Data.sendForm = $Const.createSendForm();
134
+ $Data.sendDialogVisible = true;
135
+ },
136
+ async onSend(reload, context) {
137
+ const form = $From.sendFormRef;
138
+ if (!form) {
139
+ MessagePlugin.warning("表单未就绪");
140
+ return;
141
+ }
130
142
 
131
- const valid = await form.validate();
132
- if (valid !== true) return;
143
+ const valid = await form.validate();
144
+ if (valid !== true) return;
133
145
 
134
- $Data.sending = true;
135
- try {
136
- const res = await $Http("/core/email/send", {
137
- to: $Data.sendForm.to,
138
- subject: $Data.sendForm.subject,
139
- content: $Data.sendForm.content,
140
- cc: $Data.sendForm.cc || undefined,
141
- isHtml: true
142
- });
146
+ $Data.sending = true;
147
+ try {
148
+ await $Http("/core/email/send", {
149
+ to: $Data.sendForm.to,
150
+ subject: $Data.sendForm.subject,
151
+ content: $Data.sendForm.content,
152
+ cc: $Data.sendForm.cc || undefined,
153
+ isHtml: true
154
+ });
143
155
 
144
- MessagePlugin.success("发送成功");
145
- if (context && typeof context.close === "function") {
146
- context.close();
147
- } else {
148
- $Data.sendDialogVisible = false;
156
+ MessagePlugin.success("发送成功");
157
+ if (context && typeof context.close === "function") {
158
+ context.close();
159
+ } else {
160
+ $Data.sendDialogVisible = false;
161
+ }
162
+ if (reload) {
163
+ reload({ keepSelection: false, resetPage: true });
164
+ }
165
+ } catch (error) {
166
+ MessagePlugin.error(error.msg || error.message || "发送失败");
167
+ } finally {
168
+ $Data.sending = false;
149
169
  }
150
- if (reload) {
151
- reload({ keepSelection: false, resetPage: true });
170
+ },
171
+ async onVerify() {
172
+ try {
173
+ await $Http("/core/email/verify");
174
+ MessagePlugin.success("邮件服务配置正常");
175
+ } catch (error) {
176
+ MessagePlugin.error(error.msg || error.message || "验证失败");
152
177
  }
153
- } catch (error) {
154
- MessagePlugin.error(error.msg || error.message || "发送失败");
155
- } finally {
156
- $Data.sending = false;
157
- }
158
- }
159
-
160
- async function onVerify() {
161
- try {
162
- await $Http("/core/email/verify");
163
- MessagePlugin.success("邮件服务配置正常");
164
- } catch (error) {
165
- MessagePlugin.error(error.msg || error.message || "验证失败");
178
+ },
179
+ formatTime(timestamp) {
180
+ if (!timestamp) return "-";
181
+ const date = new Date(timestamp);
182
+ const year = date.getFullYear();
183
+ const month = String(date.getMonth() + 1).padStart(2, "0");
184
+ const day = String(date.getDate()).padStart(2, "0");
185
+ const hours = String(date.getHours()).padStart(2, "0");
186
+ const minutes = String(date.getMinutes()).padStart(2, "0");
187
+ const seconds = String(date.getSeconds()).padStart(2, "0");
188
+ return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
166
189
  }
167
- }
168
-
169
- function formatTime(timestamp) {
170
- if (!timestamp) return "-";
171
- const date = new Date(timestamp);
172
- const year = date.getFullYear();
173
- const month = String(date.getMonth() + 1).padStart(2, "0");
174
- const day = String(date.getDate()).padStart(2, "0");
175
- const hours = String(date.getHours()).padStart(2, "0");
176
- const minutes = String(date.getMinutes()).padStart(2, "0");
177
- const seconds = String(date.getSeconds()).padStart(2, "0");
178
- return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
179
- }
190
+ };
180
191
  </script>
181
192
 
182
193
  <style scoped lang="scss">