@befly-addon/admin 1.8.6 → 1.8.8

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 (34) hide show
  1. package/adminViews/config/dict/components/edit.vue +16 -8
  2. package/adminViews/config/dict/index.vue +3 -3
  3. package/adminViews/config/dictType/components/edit.vue +16 -8
  4. package/adminViews/config/dictType/index.vue +2 -1
  5. package/adminViews/config/system/components/edit.vue +17 -9
  6. package/adminViews/config/system/index.vue +2 -1
  7. package/adminViews/index/components/addonList.vue +10 -2
  8. package/adminViews/index/components/environmentInfo.vue +12 -2
  9. package/adminViews/index/components/operationLogs.vue +16 -2
  10. package/adminViews/index/components/performanceMetrics.vue +9 -3
  11. package/adminViews/index/components/serviceStatus.vue +11 -4
  12. package/adminViews/index/components/systemNotifications.vue +13 -2
  13. package/adminViews/index/components/systemOverview.vue +3 -2
  14. package/adminViews/index/components/systemResources.vue +10 -3
  15. package/adminViews/index/components/userInfo.vue +19 -5
  16. package/adminViews/log/email/index.vue +21 -12
  17. package/adminViews/log/login/index.vue +2 -1
  18. package/adminViews/log/operate/index.vue +2 -1
  19. package/adminViews/login_1/index.vue +11 -8
  20. package/adminViews/people/admin/components/edit.vue +17 -9
  21. package/adminViews/people/admin/index.vue +2 -1
  22. package/adminViews/permission/api/index.vue +3 -2
  23. package/adminViews/permission/menu/index.vue +3 -2
  24. package/adminViews/permission/role/components/api.vue +5 -5
  25. package/adminViews/permission/role/components/edit.vue +16 -8
  26. package/adminViews/permission/role/components/menu.vue +5 -5
  27. package/adminViews/permission/role/index.vue +2 -1
  28. package/apis/admin/cacheRefresh.ts +15 -3
  29. package/apis/api/all.ts +7 -14
  30. package/apis/menu/all.ts +21 -34
  31. package/apis/role/apis.ts +4 -12
  32. package/apis/role/menuSave.ts +10 -2
  33. package/apis/role/menus.ts +4 -11
  34. package/package.json +3 -3
@@ -24,8 +24,8 @@
24
24
  </template>
25
25
 
26
26
  <template #sendResult="{ row }">
27
- <TTag v-if="row.sendResult === 1" shape="round" theme="success" variant="light-outline">成功</TTag>
28
- <TTag v-else shape="round" theme="danger" variant="light-outline">失败</TTag>
27
+ <TTag v-if="row.sendResult === 1" shape="round" theme="success" variant="light-outline"> 成功 </TTag>
28
+ <TTag v-else shape="round" theme="danger" variant="light-outline"> 失败 </TTag>
29
29
  </template>
30
30
 
31
31
  <template #sendTime="{ row }">
@@ -35,8 +35,8 @@
35
35
  <template #detail="scope">
36
36
  <DetailPanel :data="scope.row" :fields="$Data.columns">
37
37
  <template #sendResult="slotScope">
38
- <TTag v-if="slotScope.value === 1" shape="round" theme="success" variant="light-outline">成功</TTag>
39
- <TTag v-else shape="round" theme="danger" variant="light-outline">失败</TTag>
38
+ <TTag v-if="slotScope.value === 1" shape="round" theme="success" variant="light-outline"> 成功 </TTag>
39
+ <TTag v-else shape="round" theme="danger" variant="light-outline"> 失败 </TTag>
40
40
  </template>
41
41
  <template #sendTime="slotScope">
42
42
  {{ formatTime(slotScope.value) }}
@@ -49,7 +49,7 @@
49
49
 
50
50
  <template #dialogs="scope">
51
51
  <PageDialog v-model="$Data.sendDialogVisible" title="发送邮件" :confirm-loading="$Data.sending" @confirm="(context) => onSend(scope.reload, context)" @cancel="onCancelSend" @close="onCancelSend">
52
- <TForm :ref="(el) => ($From.sendForm = el)" :data="$Data.sendForm" :rules="$Data.sendRules" label-width="80px">
52
+ <TForm ref="sendFormRef" :data="$Data.sendForm" :rules="$Data.sendRules" label-width="80px">
53
53
  <TFormItem label="收件人" name="to">
54
54
  <TInput v-model="$Data.sendForm.to" placeholder="请输入收件人邮箱" />
55
55
  </TFormItem>
@@ -69,6 +69,7 @@
69
69
  </template>
70
70
 
71
71
  <script setup lang="ts">
72
+ import { reactive, ref } from "vue";
72
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";
73
74
  import ILucideRotateCw from "~icons/lucide/rotate-cw";
74
75
  import ILucideSend from "~icons/lucide/send";
@@ -79,12 +80,14 @@ import { $Http } from "@/plugins/http";
79
80
  import PagedTableDetail from "@/components/pagedTableDetail.vue";
80
81
  import { withDefaultColumns } from "befly-shared/utils/withDefaultColumns";
81
82
 
82
- const $From = $shallowRef({
83
- sendForm: null
84
- });
83
+ type TDesignFormInstance = {
84
+ validate: () => Promise<unknown>;
85
+ };
86
+
87
+ const sendFormRef = ref<TDesignFormInstance | null>(null);
85
88
 
86
89
  // 响应式数据
87
- const $Data = $ref({
90
+ const $Data = reactive({
88
91
  columns: withDefaultColumns([
89
92
  { colKey: "username", title: "发送人", fixed: "left" },
90
93
  { colKey: "toEmail", title: "收件人" },
@@ -142,7 +145,13 @@ type PageDialogEventContext = {
142
145
  };
143
146
 
144
147
  async function onSend(reload: ((options: { keepSelection?: boolean; resetPage?: boolean }) => void) | null, context?: PageDialogEventContext): Promise<void> {
145
- const valid = await $From.sendForm?.validate();
148
+ const form = sendFormRef.value;
149
+ if (!form) {
150
+ MessagePlugin.warning("表单未就绪");
151
+ return;
152
+ }
153
+
154
+ const valid = await form.validate();
146
155
  if (valid !== true) return;
147
156
 
148
157
  $Data.sending = true;
@@ -168,7 +177,7 @@ async function onSend(reload: ((options: { keepSelection?: boolean; resetPage?:
168
177
  } else {
169
178
  MessagePlugin.error(res.msg || "发送失败");
170
179
  }
171
- } catch (error) {
180
+ } catch (_error) {
172
181
  MessagePlugin.error("发送失败");
173
182
  } finally {
174
183
  $Data.sending = false;
@@ -183,7 +192,7 @@ async function onVerify(): Promise<void> {
183
192
  } else {
184
193
  MessagePlugin.error(res.msg || "配置异常");
185
194
  }
186
- } catch (error) {
195
+ } catch (_error) {
187
196
  MessagePlugin.error("验证失败");
188
197
  }
189
198
  }
@@ -39,6 +39,7 @@
39
39
  </template>
40
40
 
41
41
  <script setup lang="ts">
42
+ import { reactive } from "vue";
42
43
  import { Button as TButton, Tag as TTag } from "tdesign-vue-next";
43
44
  import ILucideRotateCw from "~icons/lucide/rotate-cw";
44
45
  import DetailPanel from "@/components/detailPanel.vue";
@@ -46,7 +47,7 @@ import PagedTableDetail from "@/components/pagedTableDetail.vue";
46
47
  import { withDefaultColumns } from "befly-shared/utils/withDefaultColumns";
47
48
 
48
49
  // 响应式数据
49
- const $Data = $ref({
50
+ const $Data = reactive({
50
51
  columns: withDefaultColumns([
51
52
  { colKey: "username", title: "用户名", fixed: "left" },
52
53
  { colKey: "ip", title: "登录IP" },
@@ -62,6 +62,7 @@
62
62
  </template>
63
63
 
64
64
  <script setup lang="ts">
65
+ import { reactive } from "vue";
65
66
  import { Button as TButton, Option as TOption, Select as TSelect, Tag as TTag } from "tdesign-vue-next";
66
67
  import ILucideRotateCw from "~icons/lucide/rotate-cw";
67
68
  import DetailPanel from "@/components/detailPanel.vue";
@@ -69,7 +70,7 @@ import PagedTableDetail from "@/components/pagedTableDetail.vue";
69
70
  import { withDefaultColumns } from "befly-shared/utils/withDefaultColumns";
70
71
 
71
72
  // 响应式数据
72
- const $Data = $ref({
73
+ const $Data = reactive({
73
74
  columns: withDefaultColumns([
74
75
  { colKey: "username", title: "操作人", fixed: "left", width: 100 },
75
76
  { colKey: "module", title: "模块", width: 100 },
@@ -21,7 +21,7 @@
21
21
  <p class="login-subtitle">请登录您的账户</p>
22
22
  </div>
23
23
 
24
- <TForm :model="$Data.formData" :rules="$Data.formRules" :ref="(el) => ($From.form = el)" class="login-form" :show-message="false" label-width="0">
24
+ <TForm :model="$Data.formData" :rules="$Data.formRules" ref="formRef" class="login-form" :show-message="false" label-width="0">
25
25
  <TFormItem prop="account">
26
26
  <TInputAdornment>
27
27
  <template #prepend>
@@ -49,7 +49,7 @@
49
49
 
50
50
  <div class="form-options">
51
51
  <TCheckbox v-model="$Data.rememberMe">记住我</TCheckbox>
52
- <a href="#" class="link-text">忘记密码?</a>
52
+ <a href="#" class="link-text"> 忘记密码? </a>
53
53
  </div>
54
54
 
55
55
  <TButton theme="primary" class="login-btn" size="large" block :loading="$Data.loading" @click="apiLogin"> 登录 </TButton>
@@ -64,6 +64,7 @@
64
64
  </template>
65
65
 
66
66
  <script setup lang="ts">
67
+ import { reactive, ref } from "vue";
67
68
  import { useRouter } from "vue-router";
68
69
  import { Form as TForm, FormItem as TFormItem, Input as TInput, Button as TButton, Checkbox as TCheckbox, InputAdornment as TInputAdornment, Select as TSelect, Option as TOption, MessagePlugin } from "tdesign-vue-next";
69
70
  import ILucideUser from "~icons/lucide/user";
@@ -74,13 +75,10 @@ import { hashPassword } from "befly-shared/utils/hashPassword";
74
75
 
75
76
  const router = useRouter();
76
77
 
77
- // 表单引用
78
- const $From = $shallowRef({
79
- form: null
80
- });
78
+ const formRef = ref<null | { validate: () => Promise<boolean> }>(null);
81
79
 
82
80
  // 数据定义
83
- const $Data = $ref({
81
+ const $Data = reactive({
84
82
  loading: false,
85
83
  rememberMe: false,
86
84
  formRules: {
@@ -96,7 +94,12 @@ const $Data = $ref({
96
94
 
97
95
  async function apiLogin(): Promise<void> {
98
96
  try {
99
- await $From.form.validate();
97
+ if (formRef.value === null) {
98
+ MessagePlugin.error("表单未就绪");
99
+ return;
100
+ }
101
+
102
+ await formRef.value.validate();
100
103
 
101
104
  $Data.loading = true;
102
105
 
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <PageDialog v-model="dialogVisible" :title="$Prop.actionType === 'upd' ? '编辑管理员' : '添加管理员'" :confirm-loading="$Data.submitting" @confirm="onSubmit">
3
3
  <div class="dialog-wrapper">
4
- <TForm :model="$Data.formData" label-width="80px" label-position="left" label-align="left" :rules="$Data2.formRules" :ref="(el) => ($From.form = el)">
4
+ <TForm :model="$Data.formData" label-width="80px" label-position="left" label-align="left" :rules="$Data2.formRules" ref="formRef">
5
5
  <TFormItem label="角色" prop="roleCode">
6
6
  <TSelect v-model="$Data.formData.roleCode" :options="$Data.allRoleLists" :keys="$Data.keys" placeholder="请选择角色" />
7
7
  </TFormItem>
@@ -26,7 +26,7 @@
26
26
  </template>
27
27
 
28
28
  <script setup lang="ts">
29
- import { computed } from "vue";
29
+ import { computed, reactive, ref } from "vue";
30
30
 
31
31
  import {
32
32
  //
@@ -68,9 +68,11 @@ type PageDialogEventContext = {
68
68
  };
69
69
 
70
70
  // 表单引用
71
- const $From = $shallowRef({
72
- form: null
73
- });
71
+ type TDesignFormInstance = {
72
+ validate: () => Promise<unknown>;
73
+ };
74
+
75
+ const formRef = ref<TDesignFormInstance | null>(null);
74
76
 
75
77
  const dialogVisible = computed({
76
78
  get: () => $Prop.modelValue,
@@ -79,7 +81,7 @@ const dialogVisible = computed({
79
81
  }
80
82
  });
81
83
 
82
- const $Data = $ref({
84
+ const $Data = reactive({
83
85
  submitting: false,
84
86
  allRoleLists: [],
85
87
  keys: {
@@ -96,7 +98,7 @@ const $Data = $ref({
96
98
  }
97
99
  });
98
100
 
99
- const $Data2 = $shallowRef({
101
+ const $Data2 = reactive({
100
102
  formRules: {
101
103
  username: [{ required: true, message: "请输入用户名", trigger: "blur" }],
102
104
  password: [
@@ -125,14 +127,20 @@ async function apiRoleLists(): Promise<void> {
125
127
  }
126
128
  );
127
129
  $Data.allRoleLists = result.data || [];
128
- } catch (error) {
130
+ } catch (_error) {
129
131
  MessagePlugin.error("加载角色列表失败");
130
132
  }
131
133
  }
132
134
 
133
135
  async function onSubmit(context?: PageDialogEventContext): Promise<void> {
134
136
  try {
135
- const valid = await $From.form.validate();
137
+ const form = formRef.value;
138
+ if (!form) {
139
+ MessagePlugin.warning("表单未就绪");
140
+ return;
141
+ }
142
+
143
+ const valid = await form.validate();
136
144
  if (!valid) return;
137
145
 
138
146
  $Data.submitting = true;
@@ -48,6 +48,7 @@
48
48
  </template>
49
49
 
50
50
  <script setup lang="ts">
51
+ import { reactive } from "vue";
51
52
  import { Button as TButton, Dropdown as TDropdown, DropdownItem as TDropdownItem, DropdownMenu as TDropdownMenu, Tag as TTag } from "tdesign-vue-next";
52
53
  import ILucidePlus from "~icons/lucide/plus";
53
54
  import ILucideRotateCw from "~icons/lucide/rotate-cw";
@@ -59,7 +60,7 @@ import PagedTableDetail from "@/components/pagedTableDetail.vue";
59
60
  import { withDefaultColumns } from "befly-shared/utils/withDefaultColumns";
60
61
 
61
62
  // 响应式数据
62
- const $Data = $ref({
63
+ const $Data = reactive({
63
64
  columns: withDefaultColumns([
64
65
  { colKey: "username", title: "用户名", fixed: "left" },
65
66
  { colKey: "nickname", title: "昵称" },
@@ -59,6 +59,7 @@
59
59
  </template>
60
60
 
61
61
  <script setup lang="ts">
62
+ import { reactive } from "vue";
62
63
  import { Button as TButton, Table as TTable, Tag as TTag, Input as TInput, MessagePlugin } from "tdesign-vue-next";
63
64
  import ILucideRotateCw from "~icons/lucide/rotate-cw";
64
65
  import ILucideSearch from "~icons/lucide/search";
@@ -67,7 +68,7 @@ import { $Http } from "@/plugins/http";
67
68
  import { withDefaultColumns } from "befly-shared/utils/withDefaultColumns";
68
69
 
69
70
  // 响应式数据
70
- const $Data = $ref({
71
+ const $Data = reactive({
71
72
  tableData: [],
72
73
  allData: [],
73
74
  loading: false,
@@ -108,7 +109,7 @@ async function loadApiAll(): Promise<void> {
108
109
  $Data.currentRow = null;
109
110
  $Data.activeRowKeys = [];
110
111
  }
111
- } catch (error) {
112
+ } catch (_error) {
112
113
  MessagePlugin.error("加载数据失败");
113
114
  } finally {
114
115
  $Data.loading = false;
@@ -40,6 +40,7 @@
40
40
  </template>
41
41
 
42
42
  <script setup lang="ts">
43
+ import { reactive } from "vue";
43
44
  import { Button as TButton, Table as TTable, Tag as TTag, MessagePlugin } from "tdesign-vue-next";
44
45
  import ILucideRotateCw from "~icons/lucide/rotate-cw";
45
46
  import DetailPanel from "@/components/detailPanel.vue";
@@ -48,7 +49,7 @@ import { arrayToTree } from "befly-shared/utils/arrayToTree";
48
49
  import { withDefaultColumns } from "befly-shared/utils/withDefaultColumns";
49
50
 
50
51
  // 响应式数据
51
- const $Data = $ref({
52
+ const $Data = reactive({
52
53
  tableData: [],
53
54
  loading: false,
54
55
  columns: withDefaultColumns([
@@ -89,7 +90,7 @@ async function apiMenuList(): Promise<void> {
89
90
  $Data.currentRow = null;
90
91
  $Data.activeRowKeys = [];
91
92
  }
92
- } catch (error) {
93
+ } catch (_error) {
93
94
  MessagePlugin.error("加载数据失败");
94
95
  } finally {
95
96
  $Data.loading = false;
@@ -32,7 +32,7 @@
32
32
  </template>
33
33
 
34
34
  <script setup lang="ts">
35
- import { computed } from "vue";
35
+ import { computed, reactive } from "vue";
36
36
 
37
37
  import { Input as TInput, CheckboxGroup as TCheckboxGroup, Checkbox as TCheckbox, MessagePlugin } from "tdesign-vue-next";
38
38
  import ILucideSearch from "~icons/lucide/search";
@@ -66,7 +66,7 @@ const dialogVisible = computed({
66
66
  }
67
67
  });
68
68
 
69
- const $Data = $ref({
69
+ const $Data = reactive({
70
70
  submitting: false,
71
71
  apiData: [],
72
72
  filteredApiData: [],
@@ -164,7 +164,7 @@ async function apiApiAll(): Promise<void> {
164
164
  });
165
165
 
166
166
  $Data.apiData = groups as never;
167
- } catch (error) {
167
+ } catch (_error) {
168
168
  MessagePlugin.error("加载接口失败");
169
169
  }
170
170
  }
@@ -186,7 +186,7 @@ async function apiRoleApiDetail(): Promise<void> {
186
186
  const resRecord = res && typeof res === "object" ? (res as Record<string, unknown>) : null;
187
187
  const resData = resRecord && resRecord["data"] && typeof resRecord["data"] === "object" ? (resRecord["data"] as Record<string, unknown>) : null;
188
188
  $Data.checkedApiPaths = resData && Array.isArray(resData["apiPaths"]) ? (resData["apiPaths"] as never) : ([] as never);
189
- } catch (error) {
189
+ } catch (_error) {
190
190
  MessagePlugin.error("加载数据失败");
191
191
  }
192
192
  }
@@ -236,7 +236,7 @@ async function onSubmit(context?: PageDialogEventContext): Promise<void> {
236
236
  } else {
237
237
  MessagePlugin.error(res.msg || "保存失败");
238
238
  }
239
- } catch (error) {
239
+ } catch (_error) {
240
240
  MessagePlugin.error("保存失败");
241
241
  } finally {
242
242
  $Data.submitting = false;
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <PageDialog v-model="dialogVisible" :title="$Prop.actionType === 'upd' ? '更新角色' : '添加角色'" :confirm-loading="$Data.submitting" @confirm="onSubmit">
3
3
  <div class="comp-role-edit">
4
- <TForm :model="$Data.formData" label-width="120px" label-position="left" :rules="$Data2.formRules" :ref="(el) => ($From.form = el)">
4
+ <TForm :model="$Data.formData" label-width="120px" label-position="left" :rules="$Data2.formRules" ref="formRef">
5
5
  <TFormItem label="角色名称" prop="name">
6
6
  <TInput v-model="$Data.formData.name" placeholder="请输入角色名称" />
7
7
  </TFormItem>
@@ -26,7 +26,7 @@
26
26
  </template>
27
27
 
28
28
  <script setup lang="ts">
29
- import { computed } from "vue";
29
+ import { computed, reactive, ref } from "vue";
30
30
 
31
31
  import {
32
32
  //
@@ -68,13 +68,15 @@ type PageDialogEventContext = {
68
68
  };
69
69
 
70
70
  // 表单引用
71
- const $From = $shallowRef({
72
- form: null
73
- });
71
+ type TDesignFormInstance = {
72
+ validate: () => Promise<unknown>;
73
+ };
74
+
75
+ const formRef = ref<TDesignFormInstance | null>(null);
74
76
 
75
77
  const $Computed = {};
76
78
 
77
- const $Data = $ref({
79
+ const $Data = reactive({
78
80
  submitting: false,
79
81
  formData: {
80
82
  id: 0,
@@ -86,7 +88,7 @@ const $Data = $ref({
86
88
  }
87
89
  });
88
90
 
89
- const $Data2 = $shallowRef({
91
+ const $Data2 = reactive({
90
92
  formRules: {
91
93
  name: [{ required: true, message: "请输入角色名称", trigger: "blur" }],
92
94
  code: [
@@ -112,7 +114,13 @@ const dialogVisible = computed({
112
114
 
113
115
  async function onSubmit(context?: PageDialogEventContext): Promise<void> {
114
116
  try {
115
- const valid = await $From.form.validate();
117
+ const form = formRef.value;
118
+ if (!form) {
119
+ MessagePlugin.warning("表单未就绪");
120
+ return;
121
+ }
122
+
123
+ const valid = await form.validate();
116
124
  if (!valid) return;
117
125
 
118
126
  $Data.submitting = true;
@@ -33,7 +33,7 @@
33
33
  </template>
34
34
 
35
35
  <script setup lang="ts">
36
- import { computed } from "vue";
36
+ import { computed, reactive } from "vue";
37
37
 
38
38
  import { CheckboxGroup as TCheckboxGroup, Checkbox as TCheckbox, Input as TInput, MessagePlugin } from "tdesign-vue-next";
39
39
  import ILucideSearch from "~icons/lucide/search";
@@ -68,7 +68,7 @@ const dialogVisible = computed({
68
68
  }
69
69
  });
70
70
 
71
- const $Data = $ref({
71
+ const $Data = reactive({
72
72
  submitting: false,
73
73
  searchText: "",
74
74
  menuGroups: [],
@@ -134,7 +134,7 @@ async function apiMenuAll(): Promise<void> {
134
134
  }
135
135
 
136
136
  $Data.menuGroups = groups as never;
137
- } catch (error) {
137
+ } catch (_error) {
138
138
  MessagePlugin.error("加载菜单失败");
139
139
  }
140
140
  }
@@ -154,7 +154,7 @@ async function apiRoleMenuDetail(): Promise<void> {
154
154
  );
155
155
 
156
156
  $Data.checkedMenuPaths = Array.isArray(res.data) ? res.data : [];
157
- } catch (error) {
157
+ } catch (_error) {
158
158
  MessagePlugin.error("加载数据失败");
159
159
  }
160
160
  }
@@ -204,7 +204,7 @@ async function onSubmit(context?: PageDialogEventContext): Promise<void> {
204
204
  } else {
205
205
  MessagePlugin.error(res.msg || "保存失败");
206
206
  }
207
- } catch (error) {
207
+ } catch (_error) {
208
208
  MessagePlugin.error("保存失败");
209
209
  } finally {
210
210
  $Data.submitting = false;
@@ -71,6 +71,7 @@
71
71
  </template>
72
72
 
73
73
  <script setup lang="ts">
74
+ import { reactive } from "vue";
74
75
  import { Button as TButton, Dropdown as TDropdown, DropdownItem as TDropdownItem, DropdownMenu as TDropdownMenu, Tag as TTag } from "tdesign-vue-next";
75
76
  import ILucidePlus from "~icons/lucide/plus";
76
77
  import ILucideRotateCw from "~icons/lucide/rotate-cw";
@@ -86,7 +87,7 @@ import PagedTableDetail from "@/components/pagedTableDetail.vue";
86
87
  import { withDefaultColumns } from "befly-shared/utils/withDefaultColumns";
87
88
 
88
89
  // 响应式数据
89
- const $Data = $ref({
90
+ const $Data = reactive({
90
91
  columns: withDefaultColumns([
91
92
  { colKey: "name", title: "角色名称" },
92
93
  { colKey: "code", title: "角色代码", width: 150 },
@@ -4,7 +4,9 @@
4
4
  * 功能:
5
5
  * 1. 刷新接口缓存(apis:all)
6
6
  * 2. 刷新菜单缓存(menus:all)
7
- * 3. 刷新角色权限缓存(role:info:{code})
7
+ * 3. 刷新角色缓存(role:info:{code})
8
+ * 4. 重建角色接口权限缓存(role:apis:{code},Set)
9
+ * 5. 重建角色菜单权限缓存(role:menus:{code},Set)
8
10
  *
9
11
  * 使用场景:
10
12
  * - 执行数据库同步后
@@ -22,7 +24,8 @@ const route: ApiRoute = {
22
24
  apis: { success: false, count: 0 },
23
25
  menus: { success: false, count: 0 },
24
26
  roles: { success: false, count: 0 },
25
- roleApiPermissions: { success: false }
27
+ roleApiPermissions: { success: false },
28
+ roleMenuPermissions: { success: false }
26
29
  };
27
30
 
28
31
  // 1. 刷新接口缓存
@@ -89,8 +92,17 @@ const route: ApiRoute = {
89
92
  results["roleApiPermissions"] = { success: false, error: error.message };
90
93
  }
91
94
 
95
+ // 5. 重建角色菜单权限缓存
96
+ try {
97
+ await befly.cache.rebuildRoleMenuPermissions();
98
+ results["roleMenuPermissions"] = { success: true };
99
+ } catch (error: any) {
100
+ befly.logger.error({ err: error, msg: "重建角色菜单权限缓存失败" });
101
+ results["roleMenuPermissions"] = { success: false, error: error.message };
102
+ }
103
+
92
104
  // 检查是否全部成功
93
- const allSuccess = results["apis"].success && results["menus"].success && results["roles"].success && results["roleApiPermissions"].success;
105
+ const allSuccess = results["apis"].success && results["menus"].success && results["roles"].success && results["roleApiPermissions"].success && results["roleMenuPermissions"].success;
94
106
 
95
107
  if (allSuccess) {
96
108
  return befly.tool.Yes("全部缓存刷新成功", results);
package/apis/api/all.ts CHANGED
@@ -1,28 +1,21 @@
1
- import type { DbJsonRow } from "../../utils/dbJsonRow";
2
1
  import type { ApiRoute } from "befly/types/api";
2
+ import type { JsonValue, KeyValue } from "befly/types/common";
3
+
4
+ type ApiRow = KeyValue<JsonValue>;
3
5
 
4
6
  const route: ApiRoute = {
5
7
  name: "获取所有接口",
6
8
  handler: async (befly) => {
7
9
  try {
8
10
  // 从缓存获取所有接口
9
- let allApis: unknown[] = await befly.cache.getApis();
11
+ const allApis = (await befly.cache.getApis()) as ApiRow[];
10
12
 
11
- // 如果缓存不存在,从数据库查询并缓存
13
+ // 强制缓存:不回退 DB
12
14
  if (allApis.length === 0) {
13
- const result = await befly.db.getAll<DbJsonRow>({
14
- table: "addon_admin_api",
15
- orderBy: ["id#ASC"]
16
- });
17
- allApis = result.data.lists;
18
-
19
- // 缓存到 Redis
20
- if (allApis.length > 0) {
21
- await befly.cache.cacheApis();
22
- }
15
+ return befly.tool.No("接口缓存不存在,请刷新缓存", { lists: [] });
23
16
  }
24
17
 
25
- const lists = allApis.filter((api): api is Record<string, unknown> => typeof api === "object" && api !== null).map((api) => api as DbJsonRow);
18
+ const lists = allApis.filter((api) => api && typeof api === "object");
26
19
 
27
20
  return befly.tool.Yes("操作成功", { lists: lists });
28
21
  } catch (error: unknown) {
package/apis/menu/all.ts CHANGED
@@ -1,61 +1,48 @@
1
1
  /**
2
2
  * 获取当前用户的菜单权限
3
3
  * 说明:
4
- * 1. 从 Redis 缓存读取所有菜单(如果缓存不存在则从数据库查询并缓存)
5
- * 2. 根据当前登录用户的角色过滤可访问的菜单
6
- * 3. 返回一维数组(由前端构建树形结构)
7
- * 4. 仅返回状态为启用的菜单
4
+ * 1. 从 Redis 缓存读取所有菜单(强制:不回退 DB)
5
+ * 2. 从 Redis Set 读取角色菜单权限(role:menus:{roleCode}),拿到该角色可访问的菜单 path 列表
6
+ * 3. 根据角色菜单 path 列表过滤可访问的菜单
7
+ * 4. 返回一维数组(由前端构建树形结构)
8
+ * 5. 仅返回状态为启用的菜单
8
9
  */
9
10
 
10
- import type { DbJsonRow } from "../../utils/dbJsonRow";
11
11
  import type { ApiRoute } from "befly/types/api";
12
+ import type { JsonValue, KeyValue } from "befly/types/common";
13
+
14
+ type MenuRow = KeyValue<JsonValue>;
12
15
 
13
16
  const route: ApiRoute = {
14
17
  name: "获取用户菜单",
15
18
  handler: async (befly, ctx) => {
16
19
  try {
17
- // 2. 查询角色信息获取菜单权限(使用 roleCode 而非 roleId)
18
- const role = await befly.db.getOne<{ id?: number; menus?: unknown }>({
19
- table: "addon_admin_role",
20
- where: { code: ctx.user["roleCode"] }
21
- });
22
-
23
- if (!role.data?.id) {
24
- return befly.tool.No("角色不存在", { lists: [] });
20
+ const roleCode = typeof ctx.user["roleCode"] === "string" ? ctx.user["roleCode"] : "";
21
+ if (roleCode.length === 0) {
22
+ return befly.tool.No("角色缺失", { lists: [] });
25
23
  }
26
24
 
27
- // 3. 解析菜单路径列表(menu.path 数组,array_text)
28
- const rawMenuPaths = Array.isArray(role.data.menus) ? role.data.menus : [];
29
- const menuPaths = rawMenuPaths.map((p: unknown) => (typeof p === "string" ? p.trim() : "")).filter((p: string) => p.length > 0);
25
+ // 2. Redis Set 读取角色菜单权限(由 core 的 cache 体系维护)
26
+ // 约定:key = role:menus:{roleCode}(会自动加上 Redis prefix)
27
+ const menuPaths = await befly.cache.getRoleMenuPermissions(roleCode);
30
28
 
31
29
  if (menuPaths.length === 0) {
32
30
  return befly.tool.Yes("菜单为空", { lists: [] });
33
31
  }
34
32
 
35
- // 4. 从缓存获取所有菜单
36
- let allMenus: unknown[] = await befly.cache.getMenus();
37
-
38
- // 如果缓存不存在,从数据库查询
39
- if (allMenus.length === 0) {
40
- const result = await befly.db.getAll<DbJsonRow>({
41
- table: "addon_admin_menu"
42
- });
43
- allMenus = result.data.lists;
44
- }
33
+ // 4. 从缓存获取所有菜单(强制:不回退 DB)
34
+ const allMenus = (await befly.cache.getMenus()) as MenuRow[];
45
35
 
46
36
  if (allMenus.length === 0) {
47
- return befly.tool.Yes("菜单为空", { lists: [] });
37
+ return befly.tool.No("菜单缓存不存在,请刷新缓存", { lists: [] });
48
38
  }
49
39
 
50
40
  // 5. 根据角色权限过滤菜单(按 menu.path)
51
41
  const menuPathSet = new Set<string>(menuPaths);
52
- const authorizedMenus = allMenus
53
- .filter((menu): menu is Record<string, unknown> => typeof menu === "object" && menu !== null)
54
- .filter((menu) => {
55
- const path = menu["path"];
56
- return typeof path === "string" && menuPathSet.has(path);
57
- })
58
- .map((menu) => menu as DbJsonRow);
42
+ const authorizedMenus = allMenus.filter((menu) => {
43
+ const path = menu["path"];
44
+ return typeof path === "string" && menuPathSet.has(path);
45
+ });
59
46
 
60
47
  // 6. 返回一维数组(由前端构建树形结构)
61
48
  return befly.tool.Yes("获取菜单成功", { lists: authorizedMenus });