@befly-addon/admin 1.8.2 → 1.8.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.
@@ -1,9 +1,9 @@
1
1
  <template>
2
- <TDialog v-model:visible="$Data.visible" title="接口权限" width="900px" :append-to-body="true" :show-footer="true" top="5vh" @close="$Method.onClose">
2
+ <PageDialog v-model="dialogVisible" title="接口权限" width="900px" :confirm-loading="$Data.submitting" @confirm="onSubmit">
3
3
  <div class="comp-role-api">
4
4
  <!-- 搜索框 -->
5
5
  <div class="search-box">
6
- <TInput v-model="$Data.searchText" placeholder="搜索接口名称或路径" clearable @change="$Method.onSearch">
6
+ <TInput v-model="$Data.searchText" placeholder="搜索接口名称或路径" clearable @change="onSearch">
7
7
  <template #prefix-icon>
8
8
  <ILucideSearch />
9
9
  </template>
@@ -28,21 +28,15 @@
28
28
  </TCheckboxGroup>
29
29
  </div>
30
30
  </div>
31
-
32
- <template #footer>
33
- <div class="dialog-footer">
34
- <TSpace>
35
- <TButton theme="default" @click="$Method.onClose">取消</TButton>
36
- <TButton theme="primary" :loading="$Data.submitting" @click="$Method.onSubmit">保存</TButton>
37
- </TSpace>
38
- </div>
39
- </template>
40
- </TDialog>
31
+ </PageDialog>
41
32
  </template>
42
33
 
43
34
  <script setup lang="ts">
44
- import { Dialog as TDialog, Input as TInput, CheckboxGroup as TCheckboxGroup, Checkbox as TCheckbox, Button as TButton, Space as TSpace, MessagePlugin } from "tdesign-vue-next";
35
+ import { computed } from "vue";
36
+
37
+ import { Input as TInput, CheckboxGroup as TCheckboxGroup, Checkbox as TCheckbox, MessagePlugin } from "tdesign-vue-next";
45
38
  import ILucideSearch from "~icons/lucide/search";
39
+ import PageDialog from "@/components/pageDialog.vue";
46
40
  import { $Http } from "@/plugins/http";
47
41
 
48
42
  const $Prop = defineProps({
@@ -56,10 +50,23 @@ const $Prop = defineProps({
56
50
  }
57
51
  });
58
52
 
59
- const $Emit = defineEmits(["update:modelValue", "success"]);
53
+ const $Emit = defineEmits<{
54
+ (e: "update:modelValue", value: boolean): void;
55
+ (e: "success"): void;
56
+ }>();
57
+
58
+ type PageDialogEventContext = {
59
+ close: () => void;
60
+ };
61
+
62
+ const dialogVisible = computed({
63
+ get: () => $Prop.modelValue,
64
+ set: (value) => {
65
+ $Emit("update:modelValue", value);
66
+ }
67
+ });
60
68
 
61
69
  const $Data = $ref({
62
- visible: false,
63
70
  submitting: false,
64
71
  apiData: [],
65
72
  filteredApiData: [],
@@ -67,184 +74,176 @@ const $Data = $ref({
67
74
  checkedApiPaths: []
68
75
  });
69
76
 
70
- // 方法集合
71
- const $Method = {
72
- async initData() {
73
- $Method.onShow();
74
- await Promise.all([$Method.apiApiAll(), $Method.apiRoleApiDetail()]);
77
+ async function initData(): Promise<void> {
78
+ await Promise.all([apiApiAll(), apiRoleApiDetail()]);
75
79
 
76
- // auth=0(免登录)接口默认选中:与角色已有权限做并集,不覆盖。
77
- const merged = new Set();
78
- const current = Array.isArray($Data.checkedApiPaths) ? $Data.checkedApiPaths : [];
79
- for (const p of current) {
80
+ const merged = new Set<string>();
81
+ const current = Array.isArray($Data.checkedApiPaths) ? $Data.checkedApiPaths : [];
82
+ for (const p of current) {
83
+ if (typeof p === "string") {
80
84
  merged.add(p);
81
85
  }
86
+ }
82
87
 
83
- const groups = Array.isArray($Data.apiData) ? $Data.apiData : [];
84
- for (const group of groups) {
85
- const apis = group && group.apis;
86
- const list = Array.isArray(apis) ? apis : [];
87
- for (const api of list) {
88
- const isPublic = api && (api.auth === 0 || api.auth === "0" || api.auth === false);
89
- if (isPublic && typeof api.value === "string" && api.value) {
90
- merged.add(api.value);
91
- }
88
+ const groups = Array.isArray($Data.apiData) ? ($Data.apiData as unknown[]) : [];
89
+ for (const group of groups) {
90
+ const groupRecord = group && typeof group === "object" ? (group as Record<string, unknown>) : null;
91
+ const apis = groupRecord && Array.isArray(groupRecord["apis"]) ? (groupRecord["apis"] as unknown[]) : [];
92
+ for (const api of apis) {
93
+ const apiRecord = api && typeof api === "object" ? (api as Record<string, unknown>) : null;
94
+ const authValue = apiRecord ? apiRecord["auth"] : undefined;
95
+ const isPublic = authValue === 0 || authValue === "0" || authValue === false;
96
+ const value = apiRecord && typeof apiRecord["value"] === "string" ? String(apiRecord["value"]) : "";
97
+ if (isPublic && value) {
98
+ merged.add(value);
92
99
  }
93
100
  }
101
+ }
94
102
 
95
- $Data.checkedApiPaths = Array.from(merged);
96
- $Data.filteredApiData = $Data.apiData;
97
- },
98
-
99
- onShow() {
100
- setTimeout(() => {
101
- $Data.visible = $Prop.modelValue;
102
- }, 100);
103
- },
104
-
105
- onClose() {
106
- $Data.visible = false;
107
- setTimeout(() => {
108
- $Emit("update:modelValue", false);
109
- }, 300);
110
- },
111
-
112
- // 加载所有接口
113
- async apiApiAll() {
114
- try {
115
- const res = await $Http.post(
116
- "/addon/admin/api/all",
117
- {},
118
- {
119
- dropValues: [""]
120
- }
121
- );
122
-
123
- // 将接口列表按 parentPath 分组展示(routePath 已迁移为 path)
124
- const apiMap = new Map();
125
-
126
- const lists = res && res.data && Array.isArray(res.data.lists) ? res.data.lists : [];
127
- for (const api of lists) {
128
- const apiPath = api && typeof api.path === "string" ? api.path : "";
129
- if (!apiPath) {
130
- continue;
131
- }
132
-
133
- const parentPath = api && typeof api.parentPath === "string" ? api.parentPath : "";
134
- const groupKey = parentPath || "(未分组)";
135
-
136
- if (!apiMap.has(groupKey)) {
137
- apiMap.set(groupKey, {
138
- name: groupKey,
139
- title: groupKey,
140
- apis: []
141
- });
142
- }
103
+ $Data.checkedApiPaths = Array.from(merged) as never;
104
+ $Data.filteredApiData = $Data.apiData;
105
+ }
143
106
 
144
- apiMap.get(groupKey).apis.push({
145
- value: apiPath,
146
- name: (api && typeof api.name === "string" ? api.name : "") || apiPath,
147
- path: apiPath,
148
- label: `${(api && typeof api.name === "string" ? api.name : "") || ""} ${apiPath ? `(${apiPath})` : ""}`.trim(),
149
- description: api ? api.description : undefined,
150
- auth: api ? api.auth : undefined,
151
- parentPath: parentPath
152
- });
107
+ async function apiApiAll(): Promise<void> {
108
+ try {
109
+ const res = await $Http.post(
110
+ "/addon/admin/api/all",
111
+ {},
112
+ {
113
+ dropValues: [""]
153
114
  }
115
+ );
116
+
117
+ const apiMap = new Map<string, { name: string; title: string; apis: unknown[] }>();
118
+
119
+ const resRecord = res && typeof res === "object" ? (res as Record<string, unknown>) : null;
120
+ const resData = resRecord && resRecord["data"] && typeof resRecord["data"] === "object" ? (resRecord["data"] as Record<string, unknown>) : null;
121
+ const lists = resData && Array.isArray(resData["lists"]) ? (resData["lists"] as unknown[]) : [];
122
+ for (const api of lists) {
123
+ const apiRecord = api && typeof api === "object" ? (api as Record<string, unknown>) : null;
124
+ const apiPath = apiRecord && typeof apiRecord["path"] === "string" ? String(apiRecord["path"]) : "";
125
+ if (!apiPath) {
126
+ continue;
127
+ }
128
+
129
+ const parentPath = apiRecord && typeof apiRecord["parentPath"] === "string" ? String(apiRecord["parentPath"]) : "";
130
+ const groupKey = parentPath || "(未分组)";
154
131
 
155
- const groups = Array.from(apiMap.values());
156
- for (const group of groups) {
157
- group.apis.sort((a, b) => {
158
- const ap = typeof a.path === "string" ? a.path : "";
159
- const bp = typeof b.path === "string" ? b.path : "";
160
- return ap.localeCompare(bp);
132
+ if (!apiMap.has(groupKey)) {
133
+ apiMap.set(groupKey, {
134
+ name: groupKey,
135
+ title: groupKey,
136
+ apis: []
161
137
  });
162
138
  }
163
139
 
164
- groups.sort((a, b) => {
165
- const at = typeof a.title === "string" ? a.title : "";
166
- const bt = typeof b.title === "string" ? b.title : "";
167
- return at.localeCompare(bt);
140
+ apiMap.get(groupKey)?.apis.push({
141
+ value: apiPath,
142
+ name: (apiRecord && typeof apiRecord["name"] === "string" ? String(apiRecord["name"]) : "") || apiPath,
143
+ path: apiPath,
144
+ label: `${(apiRecord && typeof apiRecord["name"] === "string" ? String(apiRecord["name"]) : "") || ""} ${apiPath ? `(${apiPath})` : ""}`.trim(),
145
+ description: apiRecord ? apiRecord["description"] : undefined,
146
+ auth: apiRecord ? apiRecord["auth"] : undefined,
147
+ parentPath: parentPath
168
148
  });
149
+ }
169
150
 
170
- $Data.apiData = groups;
171
- } catch (error) {
172
- MessagePlugin.error("加载接口失败");
151
+ const groups = Array.from(apiMap.values());
152
+ for (const group of groups) {
153
+ group.apis.sort((a, b) => {
154
+ const ap = typeof a.path === "string" ? a.path : "";
155
+ const bp = typeof b.path === "string" ? b.path : "";
156
+ return ap.localeCompare(bp);
157
+ });
173
158
  }
174
- },
175
159
 
176
- // 加载该角色已分配的接口
177
- async apiRoleApiDetail() {
178
- if (!$Prop.rowData.id) return;
179
-
180
- try {
181
- const res = await $Http.post(
182
- "/addon/admin/role/apis",
183
- {
184
- roleCode: $Prop.rowData.code
185
- },
186
- {
187
- dropValues: [""]
188
- }
189
- );
160
+ groups.sort((a, b) => {
161
+ const at = typeof a.title === "string" ? a.title : "";
162
+ const bt = typeof b.title === "string" ? b.title : "";
163
+ return at.localeCompare(bt);
164
+ });
190
165
 
191
- $Data.checkedApiPaths = res.data.apiPaths || [];
192
- } catch (error) {
193
- MessagePlugin.error("加载数据失败");
194
- }
195
- },
166
+ $Data.apiData = groups as never;
167
+ } catch (error) {
168
+ MessagePlugin.error("加载接口失败");
169
+ }
170
+ }
196
171
 
197
- // 搜索过滤
198
- onSearch() {
199
- if (!$Data.searchText) {
200
- $Data.filteredApiData = $Data.apiData;
201
- return;
202
- }
172
+ async function apiRoleApiDetail(): Promise<void> {
173
+ if (!$Prop.rowData.id) return;
174
+
175
+ try {
176
+ const res = await $Http.post(
177
+ "/addon/admin/role/apis",
178
+ {
179
+ roleCode: $Prop.rowData.code
180
+ },
181
+ {
182
+ dropValues: [""]
183
+ }
184
+ );
203
185
 
204
- const searchLower = $Data.searchText.toLowerCase();
205
- $Data.filteredApiData = $Data.apiData
206
- .map((group) => {
207
- const apis = group.apis.filter((api) => {
208
- const label = api && typeof api.label === "string" ? api.label : "";
209
- const name = api && typeof api.name === "string" ? api.name : "";
210
- const path = api && typeof api.path === "string" ? api.path : "";
211
- return label.toLowerCase().includes(searchLower) || name.toLowerCase().includes(searchLower) || path.toLowerCase().includes(searchLower);
212
- });
213
- return {
214
- name: group.name,
215
- title: group.title,
216
- apis: apis
217
- };
218
- })
219
- .filter((group) => group.apis.length > 0);
220
- },
186
+ const resRecord = res && typeof res === "object" ? (res as Record<string, unknown>) : null;
187
+ const resData = resRecord && resRecord["data"] && typeof resRecord["data"] === "object" ? (resRecord["data"] as Record<string, unknown>) : null;
188
+ $Data.checkedApiPaths = resData && Array.isArray(resData["apiPaths"]) ? (resData["apiPaths"] as never) : ([] as never);
189
+ } catch (error) {
190
+ MessagePlugin.error("加载数据失败");
191
+ }
192
+ }
221
193
 
222
- // 提交表单
223
- async onSubmit() {
224
- try {
225
- $Data.submitting = true;
194
+ function onSearch(): void {
195
+ if (!$Data.searchText) {
196
+ $Data.filteredApiData = $Data.apiData;
197
+ return;
198
+ }
226
199
 
227
- const res = await $Http.post("/addon/admin/role/apiSave", {
228
- roleCode: $Prop.rowData.code,
229
- apiPaths: $Data.checkedApiPaths
200
+ const searchLower = String($Data.searchText).toLowerCase();
201
+ $Data.filteredApiData = ($Data.apiData as unknown[])
202
+ .map((group) => {
203
+ const groupRecord = group && typeof group === "object" ? (group as Record<string, unknown>) : null;
204
+ const groupApis = groupRecord && Array.isArray(groupRecord["apis"]) ? (groupRecord["apis"] as unknown[]) : [];
205
+ const apis = groupApis.filter((api) => {
206
+ const apiRecord = api && typeof api === "object" ? (api as Record<string, unknown>) : null;
207
+ const label = apiRecord && typeof apiRecord["label"] === "string" ? String(apiRecord["label"]) : "";
208
+ const name = apiRecord && typeof apiRecord["name"] === "string" ? String(apiRecord["name"]) : "";
209
+ const path = apiRecord && typeof apiRecord["path"] === "string" ? String(apiRecord["path"]) : "";
210
+ return label.toLowerCase().includes(searchLower) || name.toLowerCase().includes(searchLower) || path.toLowerCase().includes(searchLower);
230
211
  });
212
+ return {
213
+ name: groupRecord && typeof groupRecord["name"] === "string" ? String(groupRecord["name"]) : "",
214
+ title: groupRecord && typeof groupRecord["title"] === "string" ? String(groupRecord["title"]) : "",
215
+ apis: apis
216
+ };
217
+ })
218
+ .filter((group) => group.apis.length > 0) as never;
219
+ }
220
+
221
+ async function onSubmit(context?: PageDialogEventContext): Promise<void> {
222
+ try {
223
+ $Data.submitting = true;
231
224
 
232
- if (res.code === 0) {
233
- MessagePlugin.success("保存成功");
234
- $Data.visible = false;
235
- $Emit("success");
236
- } else {
237
- MessagePlugin.error(res.msg || "保存失败");
225
+ const res = await $Http.post("/addon/admin/role/apiSave", {
226
+ roleCode: $Prop.rowData.code,
227
+ apiPaths: $Data.checkedApiPaths
228
+ });
229
+
230
+ if (res.code === 0) {
231
+ MessagePlugin.success("保存成功");
232
+ $Emit("success");
233
+ if (context && typeof context.close === "function") {
234
+ context.close();
238
235
  }
239
- } catch (error) {
240
- MessagePlugin.error("保存失败");
241
- } finally {
242
- $Data.submitting = false;
236
+ } else {
237
+ MessagePlugin.error(res.msg || "保存失败");
243
238
  }
239
+ } catch (error) {
240
+ MessagePlugin.error("保存失败");
241
+ } finally {
242
+ $Data.submitting = false;
244
243
  }
245
- };
244
+ }
246
245
 
247
- $Method.initData();
246
+ initData();
248
247
  </script>
249
248
 
250
249
  <style scoped lang="scss">
@@ -295,7 +294,7 @@ $Method.initData();
295
294
 
296
295
  .group-header {
297
296
  padding: 12px 16px;
298
- background-color: var(--bg-color-hover);
297
+ background-color: var(--primary-color-light);
299
298
  font-weight: 500;
300
299
  font-size: var(--font-size-sm);
301
300
  color: var(--text-primary);
@@ -305,11 +304,11 @@ $Method.initData();
305
304
 
306
305
  &::before {
307
306
  content: "";
308
- width: 8px;
309
- height: 8px;
307
+ width: 12px;
308
+ height: 12px;
310
309
  border-radius: 50%;
311
310
  background-color: var(--primary-color);
312
- opacity: 0.3;
311
+ box-shadow: 0 0 0 2px var(--bg-color-container);
313
312
  flex-shrink: 0;
314
313
  }
315
314
  }
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <TDialog v-model:visible="$Data.visible" :header="$Prop.actionType === 'upd' ? '更新角色' : '添加角色'" width="600px" :append-to-body="true" :show-footer="true" :esc-closable="false" top="10vh" @close="$Method.onClose">
2
+ <PageDialog v-model="dialogVisible" :title="$Prop.actionType === 'upd' ? '更新角色' : '添加角色'" :confirm-loading="$Data.submitting" @confirm="onSubmit">
3
3
  <div class="comp-role-edit">
4
4
  <TForm :model="$Data.formData" label-width="120px" label-position="left" :rules="$Data2.formRules" :ref="(el) => ($From.form = el)">
5
5
  <TFormItem label="角色名称" prop="name">
@@ -22,17 +22,14 @@
22
22
  </TFormItem>
23
23
  </TForm>
24
24
  </div>
25
- <template #footer>
26
- <TButton @click="$Method.onClose">取消</TButton>
27
- <TButton theme="primary" :loading="$Data.submitting" @click="$Method.onSubmit">确定</TButton>
28
- </template>
29
- </TDialog>
25
+ </PageDialog>
30
26
  </template>
31
27
 
32
28
  <script setup lang="ts">
29
+ import { computed } from "vue";
30
+
33
31
  import {
34
32
  //
35
- Dialog as TDialog,
36
33
  Form as TForm,
37
34
  FormItem as TFormItem,
38
35
  Input as TInput,
@@ -42,6 +39,7 @@ import {
42
39
  Button as TButton,
43
40
  MessagePlugin
44
41
  } from "tdesign-vue-next";
42
+ import PageDialog from "@/components/pageDialog.vue";
45
43
  import { $Http } from "@/plugins/http";
46
44
  import { fieldClear } from "befly-shared/utils/fieldClear";
47
45
 
@@ -60,7 +58,14 @@ const $Prop = defineProps({
60
58
  }
61
59
  });
62
60
 
63
- const $Emit = defineEmits(["update:modelValue", "success"]);
61
+ const $Emit = defineEmits<{
62
+ (e: "update:modelValue", value: boolean): void;
63
+ (e: "success"): void;
64
+ }>();
65
+
66
+ type PageDialogEventContext = {
67
+ close: () => void;
68
+ };
64
69
 
65
70
  // 表单引用
66
71
  const $From = $shallowRef({
@@ -70,7 +75,6 @@ const $From = $shallowRef({
70
75
  const $Computed = {};
71
76
 
72
77
  const $Data = $ref({
73
- visible: false,
74
78
  submitting: false,
75
79
  formData: {
76
80
  id: 0,
@@ -93,45 +97,39 @@ const $Data2 = $shallowRef({
93
97
  }
94
98
  });
95
99
 
96
- // 方法集合
97
- const $Method = {
98
- async initData() {
99
- if ($Prop.actionType === "upd" && $Prop.rowData.id) {
100
- $Data.formData = Object.assign({}, $Prop.rowData);
101
- }
102
- $Method.onShow();
103
- },
104
- onShow() {
105
- setTimeout(() => {
106
- $Data.visible = $Prop.modelValue;
107
- }, 100);
108
- },
109
- // 关闭抽屉事件
110
- onClose() {
111
- $Data.visible = false;
112
- setTimeout(() => {
113
- $Emit("update:modelValue", false);
114
- }, 300);
115
- },
116
- async onSubmit() {
117
- try {
118
- const valid = await $From.form.validate();
119
- if (!valid) return;
100
+ async function initData(): Promise<void> {
101
+ if ($Prop.actionType === "upd" && $Prop.rowData.id) {
102
+ $Data.formData = Object.assign({}, $Prop.rowData);
103
+ }
104
+ }
105
+
106
+ const dialogVisible = computed({
107
+ get: () => $Prop.modelValue,
108
+ set: (value) => {
109
+ $Emit("update:modelValue", value);
110
+ }
111
+ });
112
+
113
+ async function onSubmit(context?: PageDialogEventContext): Promise<void> {
114
+ try {
115
+ const valid = await $From.form.validate();
116
+ if (!valid) return;
120
117
 
121
- $Data.submitting = true;
122
- const formData = $Prop.actionType === "add" ? fieldClear($Data.formData, { omitKeys: ["id", "state"] }) : $Data.formData;
123
- const res = await $Http.post($Prop.actionType === "upd" ? "/addon/admin/role/upd" : "/addon/admin/role/ins", formData);
118
+ $Data.submitting = true;
119
+ const formData = $Prop.actionType === "add" ? fieldClear($Data.formData, { omitKeys: ["id", "state"] }) : $Data.formData;
120
+ const res = await $Http.post($Prop.actionType === "upd" ? "/addon/admin/role/upd" : "/addon/admin/role/ins", formData);
124
121
 
125
- MessagePlugin.success(res.msg);
126
- $Emit("success");
127
- $Method.onClose();
128
- } catch (error) {
129
- MessagePlugin.error(error.msg || "提交失败");
130
- } finally {
131
- $Data.submitting = false;
122
+ MessagePlugin.success(res.msg);
123
+ $Emit("success");
124
+ if (context && typeof context.close === "function") {
125
+ context.close();
132
126
  }
127
+ } catch (error) {
128
+ MessagePlugin.error((error as { msg?: string }).msg || "提交失败");
129
+ } finally {
130
+ $Data.submitting = false;
133
131
  }
134
- };
132
+ }
135
133
 
136
- $Method.initData();
134
+ initData();
137
135
  </script>