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
@@ -13,7 +13,7 @@
13
13
 
14
14
  <!-- 菜单区域 -->
15
15
  <div class="sidebar-menu">
16
- <t-menu v-model:value="$Data.currentMenuKey" v-model:expanded="$Data.expandedKeys" width="220px" @change="onMenuClick">
16
+ <t-menu v-model:value="$Data.currentMenuKey" v-model:expanded="$Data.expandedKeys" width="220px" @change="$Method.onMenuClick">
17
17
  <template v-for="menu in $Data.userMenus" :key="menu.id">
18
18
  <!-- 无子菜单 -->
19
19
  <t-menu-item v-if="!menu.children || menu.children.length === 0" :value="menu.path">
@@ -41,7 +41,7 @@
41
41
  </div>
42
42
 
43
43
  <div class="sidebar-user-panel">
44
- <TDropdown class="sidebar-user-dropdown" trigger="click" placement="top-right" @click="onUserDropdownAction">
44
+ <TDropdown class="sidebar-user-dropdown" trigger="click" placement="top-right" @click="$Method.onUserDropdownAction">
45
45
  <div class="sidebar-user">
46
46
  <div class="sidebar-user-avatar">
47
47
  <img v-if="$Data.userInfo.avatar" :src="$Data.userInfo.avatar" alt="avatar" />
@@ -73,8 +73,18 @@
73
73
  <RouterView />
74
74
  </div>
75
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">
76
+ <PageDialog v-if="$Data.passwordDialogVisible" v-model="$Data.passwordDialogVisible" title="修改密码" :confirm-loading="$Data.passwordSubmitting" @confirm="$Method.onPasswordSubmit">
77
+ <TForm
78
+ :ref="
79
+ (value) => {
80
+ $From.passwordFormRef = value;
81
+ }
82
+ "
83
+ :model="$Data.passwordForm"
84
+ label-width="100px"
85
+ label-position="left"
86
+ :rules="$Const.passwordFormRules"
87
+ >
78
88
  <TFormItem label="新密码" prop="password">
79
89
  <TInput v-model="$Data.passwordForm.password" type="password" placeholder="请输入新密码,至少6位" autocomplete="new-password" />
80
90
  </TFormItem>
@@ -94,7 +104,7 @@ import { hashPassword } from "befly-admin-ui/utils/hashPassword";
94
104
  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
105
  import { AppIcon, ChevronDownIcon, CloseCircleIcon, ControlPlatformIcon, HomeIcon, LockOnIcon, UserIcon } from "tdesign-icons-vue-next";
96
106
 
97
- import { reactive, ref, watch } from "vue";
107
+ import { reactive, watch } from "vue";
98
108
  import { useRoute, useRouter } from "vue-router";
99
109
  import { $Http } from "@/plugins/http.js";
100
110
  import { $Config } from "@/plugins/config.js";
@@ -102,48 +112,27 @@ import { $Store } from "@/plugins/store.js";
102
112
 
103
113
  const router = useRouter();
104
114
  const route = useRoute();
105
- const passwordFormRef = ref(null);
106
-
107
- function isString(value) {
108
- return typeof value === "string";
109
- }
110
115
 
111
- const normalizePath = (path) => {
112
- if (!isString(path)) {
113
- return path;
116
+ const $Const = {
117
+ createPasswordForm() {
118
+ return {
119
+ password: "",
120
+ confirmPassword: ""
121
+ };
122
+ },
123
+ passwordFormRules: {
124
+ password: [
125
+ { required: true, message: "请输入新密码", trigger: "blur" },
126
+ { min: 6, message: "新密码至少6位", trigger: "blur" }
127
+ ],
128
+ confirmPassword: [{ required: true, message: "请再次输入新密码", trigger: "blur" }]
114
129
  }
115
-
116
- const normalized = path.replace(/\/+$/, "");
117
- return normalized.length === 0 ? "/" : normalized;
118
130
  };
119
131
 
120
- // parentPath 的归一化规则与 path 不同:
121
- // - parentPath 为空/"/" 视为根节点(空字符串)
122
- // - 避免把所有一级菜单挂到 "/"(首页)下面
123
- const normalizeParentPath = (parentPath) => {
124
- if (!isString(parentPath)) {
125
- return "";
126
- }
127
-
128
- const normalized = parentPath.replace(/\/+$/, "");
129
- if (normalized.length === 0) {
130
- return "";
131
- }
132
-
133
- if (normalized === "/") {
134
- return "";
135
- }
136
-
137
- return normalized;
132
+ const $From = {
133
+ passwordFormRef: null
138
134
  };
139
135
 
140
- function createPasswordForm() {
141
- return {
142
- password: "",
143
- confirmPassword: ""
144
- };
145
- }
146
-
147
136
  // 响应式数据
148
137
  const $Data = reactive({
149
138
  userMenus: [],
@@ -152,7 +141,7 @@ const $Data = reactive({
152
141
  currentMenuKey: "",
153
142
  passwordDialogVisible: false,
154
143
  passwordSubmitting: false,
155
- passwordForm: createPasswordForm(),
144
+ passwordForm: $Const.createPasswordForm(),
156
145
  userInfo: {
157
146
  id: 0,
158
147
  nickname: "管理员",
@@ -162,213 +151,221 @@ const $Data = reactive({
162
151
  }
163
152
  });
164
153
 
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
-
173
- function normalizeAvatarUrl(value) {
174
- if (!isString(value) || value.length === 0) {
175
- return "";
176
- }
177
-
178
- return value;
179
- }
180
-
181
- async function fetchUserInfo() {
182
- try {
183
- const res = await $Http("/core/admin/detail", {}, [""]);
184
- const userInfo = res?.data && typeof res.data === "object" ? res.data : {};
185
-
186
- $Data.userInfo.nickname = userInfo.nickname || "管理员";
187
- $Data.userInfo.role = userInfo.roleCode || userInfo.roleType || "超级管理员";
188
- $Data.userInfo.avatar = normalizeAvatarUrl(userInfo.avatar);
189
- $Data.userInfo.id = userInfo.id || 0;
190
- $Data.userInfo.roleCode = userInfo.roleCode || "";
191
- } catch (error) {
192
- MessagePlugin.error(error.msg || error.message || "获取管理员信息失败");
193
- }
194
- }
195
-
196
- async function fetchUserMenus() {
197
- try {
198
- const { data } = await $Http("/core/menu/all");
199
- const lists = Array.isArray(data?.lists) ? data.lists : [];
200
-
201
- const normalizedLists = lists.map((menu) => {
202
- const menuPath = normalizePath(menu?.path);
203
- const menuParentPath = normalizeParentPath(menu?.parentPath);
204
- return Object.assign({}, menu, { path: menuPath, parentPath: menuParentPath });
205
- });
206
-
207
- const treeResult = arrayToTree(normalizedLists, "path", "parentPath", "children", "sort");
208
-
209
- $Data.userMenusFlat = treeResult.flat;
210
- $Data.userMenus = treeResult.tree;
211
- setActiveMenu();
212
- } catch (error) {
213
- MessagePlugin.error(error.msg || error.message || "获取用户菜单失败");
214
- }
215
- }
216
-
217
- function setActiveMenu() {
218
- const currentPath = route.path;
219
- const normalizedCurrentPath = normalizePath(currentPath);
154
+ const $Method = {
155
+ isString(value) {
156
+ return typeof value === "string";
157
+ },
158
+ normalizePath(path) {
159
+ if (!$Method.isString(path)) {
160
+ return path;
161
+ }
220
162
 
221
- const currentMenu = $Data.userMenusFlat.find((menu) => {
222
- const menuPath = menu.path;
223
- const normalizedMenuPath = normalizePath(menuPath);
224
- return normalizedMenuPath === normalizedCurrentPath;
225
- });
163
+ const normalized = path.replace(/\/+$/, "");
164
+ return normalized.length === 0 ? "/" : normalized;
165
+ },
166
+ normalizeParentPath(parentPath) {
167
+ if (!$Method.isString(parentPath)) {
168
+ return "";
169
+ }
226
170
 
227
- if (!currentMenu) {
228
- return;
229
- }
171
+ const normalized = parentPath.replace(/\/+$/, "");
172
+ if (normalized.length === 0 || normalized === "/") {
173
+ return "";
174
+ }
230
175
 
231
- const expandedKeys = [];
232
- let menu = currentMenu;
176
+ return normalized;
177
+ },
178
+ normalizeAvatarUrl(value) {
179
+ if (!$Method.isString(value) || value.length === 0) {
180
+ return "";
181
+ }
233
182
 
234
- while (isString(menu.parentPath) && menu.parentPath.length > 0) {
235
- const parent = $Data.userMenusFlat.find((m) => {
236
- const parentMenuPath = normalizePath(m?.path);
237
- const currentParentPath = normalizeParentPath(menu?.parentPath);
238
- return parentMenuPath === currentParentPath;
183
+ return value;
184
+ },
185
+ async fetchUserInfo() {
186
+ try {
187
+ const res = await $Http("/core/admin/detail", {}, [""]);
188
+ const userInfo = res?.data && typeof res.data === "object" ? res.data : {};
189
+
190
+ $Data.userInfo.nickname = userInfo.nickname || "管理员";
191
+ $Data.userInfo.role = userInfo.roleCode || userInfo.roleType || "超级管理员";
192
+ $Data.userInfo.avatar = $Method.normalizeAvatarUrl(userInfo.avatar);
193
+ $Data.userInfo.id = userInfo.id || 0;
194
+ $Data.userInfo.roleCode = userInfo.roleCode || "";
195
+ } catch (error) {
196
+ MessagePlugin.error(error.msg || error.message || "获取管理员信息失败");
197
+ }
198
+ },
199
+ async fetchUserMenus() {
200
+ try {
201
+ const { data } = await $Http("/core/menu/all");
202
+ const lists = Array.isArray(data?.lists) ? data.lists : [];
203
+
204
+ const normalizedLists = lists.map((menu) => {
205
+ const menuPath = $Method.normalizePath(menu?.path);
206
+ const menuParentPath = $Method.normalizeParentPath(menu?.parentPath);
207
+ return Object.assign({}, menu, { path: menuPath, parentPath: menuParentPath });
208
+ });
209
+
210
+ const treeResult = arrayToTree(normalizedLists, "path", "parentPath", "children", "sort");
211
+
212
+ $Data.userMenusFlat = treeResult.flat;
213
+ $Data.userMenus = treeResult.tree;
214
+ $Method.setActiveMenu();
215
+ } catch (error) {
216
+ MessagePlugin.error(error.msg || error.message || "获取用户菜单失败");
217
+ }
218
+ },
219
+ setActiveMenu() {
220
+ const currentPath = route.path;
221
+ const normalizedCurrentPath = $Method.normalizePath(currentPath);
222
+
223
+ const currentMenu = $Data.userMenusFlat.find((menu) => {
224
+ const normalizedMenuPath = $Method.normalizePath(menu.path);
225
+ return normalizedMenuPath === normalizedCurrentPath;
239
226
  });
240
227
 
241
- if (parent) {
242
- expandedKeys.unshift(String(parent.id));
243
- menu = parent;
244
- continue;
228
+ if (!currentMenu) {
229
+ return;
245
230
  }
246
231
 
247
- break;
248
- }
232
+ const expandedKeys = [];
233
+ let menu = currentMenu;
249
234
 
250
- $Data.expandedKeys = expandedKeys;
251
- $Data.currentMenuKey = currentPath;
252
- }
235
+ while ($Method.isString(menu.parentPath) && menu.parentPath.length > 0) {
236
+ const parent = $Data.userMenusFlat.find((item) => {
237
+ const parentMenuPath = $Method.normalizePath(item?.path);
238
+ const currentParentPath = $Method.normalizeParentPath(menu?.parentPath);
239
+ return parentMenuPath === currentParentPath;
240
+ });
253
241
 
254
- function onMenuClick(path) {
255
- if (isString(path) && path.startsWith("/")) {
256
- router.push(path);
257
- }
258
- }
242
+ if (parent) {
243
+ expandedKeys.unshift(String(parent.id));
244
+ menu = parent;
245
+ continue;
246
+ }
259
247
 
260
- async function handleLogout() {
261
- let dialog = null;
262
- let destroyed = false;
248
+ break;
249
+ }
263
250
 
264
- const destroy = () => {
265
- if (destroyed) return;
266
- destroyed = true;
267
- if (dialog && typeof dialog.destroy === "function") {
268
- dialog.destroy();
251
+ $Data.expandedKeys = expandedKeys;
252
+ $Data.currentMenuKey = currentPath;
253
+ },
254
+ onMenuClick(path) {
255
+ if ($Method.isString(path) && path.startsWith("/")) {
256
+ router.push(path);
269
257
  }
270
- };
271
-
272
- dialog = DialogPlugin.confirm({
273
- header: "确认退出登录",
274
- body: "确定要退出登录吗?",
275
- status: "warning",
276
- onConfirm: async () => {
277
- if (dialog && typeof dialog.setConfirmLoading === "function") {
278
- dialog.setConfirmLoading(true);
258
+ },
259
+ async handleLogout() {
260
+ let dialog = null;
261
+ let destroyed = false;
262
+
263
+ const destroy = () => {
264
+ if (destroyed) return;
265
+ destroyed = true;
266
+ if (dialog && typeof dialog.destroy === "function") {
267
+ dialog.destroy();
279
268
  }
269
+ };
280
270
 
281
- try {
282
- $Store.local.remove($Config.tokenName);
283
- await router.push($Config.loginPath);
284
- MessagePlugin.success("退出成功");
285
- destroy();
286
- } catch (error) {
287
- MessagePlugin.error("退出失败");
288
- destroy();
289
- } finally {
271
+ dialog = DialogPlugin.confirm({
272
+ header: "确认退出登录",
273
+ body: "确定要退出登录吗?",
274
+ status: "warning",
275
+ onConfirm: async () => {
290
276
  if (dialog && typeof dialog.setConfirmLoading === "function") {
291
- dialog.setConfirmLoading(false);
277
+ dialog.setConfirmLoading(true);
278
+ }
279
+
280
+ try {
281
+ $Store.local.remove($Config.tokenName);
282
+ await router.push($Config.loginPath);
283
+ MessagePlugin.success("退出成功");
284
+ destroy();
285
+ } catch (_error) {
286
+ MessagePlugin.error("退出失败");
287
+ destroy();
288
+ } finally {
289
+ if (dialog && typeof dialog.setConfirmLoading === "function") {
290
+ dialog.setConfirmLoading(false);
291
+ }
292
292
  }
293
+ },
294
+ onClose: () => {
295
+ destroy();
293
296
  }
294
- },
295
- onClose: () => {
296
- destroy();
297
+ });
298
+ },
299
+ openPasswordDialog() {
300
+ $Data.passwordForm = $Const.createPasswordForm();
301
+ $Data.passwordDialogVisible = true;
302
+ },
303
+ onUserDropdownAction(data) {
304
+ const record = data;
305
+ const rawValue = record && record["value"] ? record["value"] : "";
306
+ const cmd = rawValue ? String(rawValue) : "";
307
+
308
+ if (cmd === "password") {
309
+ $Method.openPasswordDialog();
310
+ return;
297
311
  }
298
- });
299
- }
300
312
 
301
- function openPasswordDialog() {
302
- $Data.passwordForm = createPasswordForm();
303
- $Data.passwordDialogVisible = true;
304
- }
305
-
306
- function onUserDropdownAction(data) {
307
- const record = data;
308
- const rawValue = record && record["value"] ? record["value"] : "";
309
- const cmd = rawValue ? String(rawValue) : "";
310
-
311
- if (cmd === "password") {
312
- openPasswordDialog();
313
- return;
314
- }
315
-
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
- }
313
+ if (cmd === "logout") {
314
+ $Method.handleLogout();
315
+ }
316
+ },
317
+ async onPasswordSubmit(context) {
318
+ const form = $From.passwordFormRef;
319
+ if (form === null) {
320
+ MessagePlugin.warning("表单未就绪");
321
+ return;
322
+ }
327
323
 
328
- const valid = await form.validate();
329
- if (valid !== true) {
330
- return;
331
- }
324
+ const valid = await form.validate();
325
+ if (valid !== true) {
326
+ return;
327
+ }
332
328
 
333
- if ($Data.passwordForm.password !== $Data.passwordForm.confirmPassword) {
334
- MessagePlugin.error("两次输入的密码不一致");
335
- return;
336
- }
329
+ if ($Data.passwordForm.password !== $Data.passwordForm.confirmPassword) {
330
+ MessagePlugin.error("两次输入的密码不一致");
331
+ return;
332
+ }
337
333
 
338
- if (!$Data.userInfo.id) {
339
- MessagePlugin.error("用户信息未就绪");
340
- return;
341
- }
334
+ if (!$Data.userInfo.id) {
335
+ MessagePlugin.error("用户信息未就绪");
336
+ return;
337
+ }
342
338
 
343
- $Data.passwordSubmitting = true;
339
+ $Data.passwordSubmitting = true;
344
340
 
345
- try {
346
- const hashedPassword = await hashPassword($Data.passwordForm.password);
347
- const storedPassword = await hashPassword(hashedPassword);
341
+ try {
342
+ const hashedPassword = await hashPassword($Data.passwordForm.password);
343
+ const storedPassword = await hashPassword(hashedPassword);
348
344
 
349
- await $Http("/core/admin/update", {
350
- id: $Data.userInfo.id,
351
- password: storedPassword
352
- });
345
+ await $Http("/core/admin/update", {
346
+ id: $Data.userInfo.id,
347
+ password: storedPassword
348
+ });
353
349
 
354
- MessagePlugin.success("密码修改成功");
355
- if (context && typeof context.close === "function") {
356
- context.close();
350
+ MessagePlugin.success("密码修改成功");
351
+ if (context && typeof context.close === "function") {
352
+ context.close();
353
+ }
354
+ } catch (error) {
355
+ MessagePlugin.error(error.msg || error.message || "密码修改失败");
356
+ } finally {
357
+ $Data.passwordSubmitting = false;
357
358
  }
358
- } catch (error) {
359
- MessagePlugin.error(error.msg || error.message || "密码修改失败");
360
- } finally {
361
- $Data.passwordSubmitting = false;
362
359
  }
363
- }
360
+ };
364
361
 
365
- fetchUserMenus();
366
- fetchUserInfo();
362
+ $Method.fetchUserMenus();
363
+ $Method.fetchUserInfo();
367
364
 
368
365
  watch(
369
366
  () => route.path,
370
367
  () => {
371
- setActiveMenu();
368
+ $Method.setActiveMenu();
372
369
  }
373
370
  );
374
371
  </script>
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "befly-admin-ui",
3
- "version": "1.10.1",
4
- "gitHead": "c14b3572a265a384993be0d375d023f82cdd9ffd",
3
+ "version": "1.10.5",
4
+ "gitHead": "071d17be177355cdd61f30659c6e4c5873f87d39",
5
5
  "private": false,
6
6
  "description": "Befly - 管理后台功能组件",
7
7
  "keywords": [