befly-admin 3.12.17 → 3.13.0
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.
- package/README.md +12 -14
- package/index.html +1 -1
- package/package.json +10 -11
- package/src/App.vue +1 -1
- package/src/components/detailPanel.vue +15 -27
- package/src/components/pageDialog.vue +39 -63
- package/src/components/pagedTableDetail.vue +79 -132
- package/src/layouts/1.vue +1 -1
- package/src/layouts/2.vue +1 -1
- package/src/layouts/default.vue +20 -18
- package/src/{main.ts → main.js} +2 -2
- package/src/plugins/{config.ts → config.js} +3 -14
- package/src/plugins/{global.ts → global.js} +2 -2
- package/src/plugins/{http.ts → http.js} +22 -44
- package/src/plugins/{router.ts → router.js} +2 -2
- package/src/plugins/{storage.ts → storage.js} +26 -45
- package/src/utils/is.js +6 -0
- package/src/views/index2.vue +15 -2
- package/vite.config.js +1 -2
- package/src/types/auto-imports.d.ts +0 -191
- package/src/types/components.d.ts +0 -20
- package/src/types/typed-router.d.ts +0 -290
|
@@ -37,148 +37,95 @@
|
|
|
37
37
|
</div>
|
|
38
38
|
</template>
|
|
39
39
|
|
|
40
|
-
<script setup
|
|
40
|
+
<script setup>
|
|
41
41
|
defineOptions({ name: "PagedTableDetail" });
|
|
42
42
|
|
|
43
43
|
import { reactive } from "vue";
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
type
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
confirm?: DeleteConfirmContent | ((row: Row) => DeleteConfirmContent);
|
|
77
|
-
dropValues?: readonly (string | number | boolean | null | undefined)[];
|
|
78
|
-
dropKeyValue?: Record<string, readonly (string | number | boolean | null | undefined)[]>;
|
|
79
|
-
buildData?: (row: Row) => Record<string, unknown>;
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
type ListEndpoint = {
|
|
83
|
-
path: string;
|
|
84
|
-
pageKey?: string;
|
|
85
|
-
limitKey?: string;
|
|
86
|
-
dropValues?: readonly (string | number | boolean | null | undefined)[];
|
|
87
|
-
dropKeyValue?: Record<string, readonly (string | number | boolean | null | undefined)[]>;
|
|
88
|
-
buildData?: (pager: { currentPage: number; limit: number }) => Record<string, unknown>;
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
type Endpoints<Row extends TableRowData> = {
|
|
92
|
-
list?: ListEndpoint;
|
|
93
|
-
delete?: DeleteEndpoint<Row>;
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
type ListResponse<Row extends TableRowData> = {
|
|
97
|
-
lists: Row[];
|
|
98
|
-
total: number;
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
type LoadListOptions = {
|
|
102
|
-
keepSelection?: boolean;
|
|
103
|
-
allowPageFallback?: boolean;
|
|
104
|
-
};
|
|
105
|
-
|
|
106
|
-
const props = withDefaults(
|
|
107
|
-
defineProps<{
|
|
108
|
-
columns: PagedTableCol[];
|
|
109
|
-
rowKey?: string;
|
|
110
|
-
tableHeight?: string;
|
|
111
|
-
pageSize?: number;
|
|
112
|
-
endpoints?: Endpoints<TableRowData>;
|
|
113
|
-
paginationLayout?: string;
|
|
114
|
-
autoLoad?: boolean;
|
|
115
|
-
tableSlotNames?: string[];
|
|
116
|
-
}>(),
|
|
117
|
-
{
|
|
118
|
-
rowKey: "id",
|
|
119
|
-
tableHeight: "calc(100vh - var(--search-height) - var(--pagination-height) - var(--layout-gap) * 4)",
|
|
120
|
-
pageSize: 30,
|
|
121
|
-
endpoints: undefined,
|
|
122
|
-
paginationLayout: "total, prev, pager, next, jumper",
|
|
123
|
-
autoLoad: true,
|
|
124
|
-
tableSlotNames: undefined
|
|
44
|
+
const props = defineProps({
|
|
45
|
+
columns: {
|
|
46
|
+
type: Array,
|
|
47
|
+
required: true
|
|
48
|
+
},
|
|
49
|
+
rowKey: {
|
|
50
|
+
type: String,
|
|
51
|
+
default: "id"
|
|
52
|
+
},
|
|
53
|
+
tableHeight: {
|
|
54
|
+
type: String,
|
|
55
|
+
default: "calc(100vh - var(--search-height) - var(--pagination-height) - var(--layout-gap) * 4)"
|
|
56
|
+
},
|
|
57
|
+
pageSize: {
|
|
58
|
+
type: Number,
|
|
59
|
+
default: 30
|
|
60
|
+
},
|
|
61
|
+
endpoints: {
|
|
62
|
+
type: Object,
|
|
63
|
+
default: undefined
|
|
64
|
+
},
|
|
65
|
+
paginationLayout: {
|
|
66
|
+
type: String,
|
|
67
|
+
default: "total, prev, pager, next, jumper"
|
|
68
|
+
},
|
|
69
|
+
autoLoad: {
|
|
70
|
+
type: Boolean,
|
|
71
|
+
default: true
|
|
72
|
+
},
|
|
73
|
+
tableSlotNames: {
|
|
74
|
+
type: Array,
|
|
75
|
+
default: undefined
|
|
125
76
|
}
|
|
126
|
-
);
|
|
77
|
+
});
|
|
127
78
|
|
|
128
|
-
const emit = defineEmits
|
|
129
|
-
(e: "loaded", payload: { rows: TableRowData[]; total: number }): void;
|
|
130
|
-
(e: "row-change", payload: { row: TableRowData | null }): void;
|
|
131
|
-
(e: "deleted", payload: { row: TableRowData }): void;
|
|
132
|
-
}>();
|
|
79
|
+
const emit = defineEmits(["loaded", "row-change", "deleted"]);
|
|
133
80
|
|
|
134
81
|
const slots = useSlots();
|
|
135
82
|
|
|
136
83
|
const $Data = reactive({
|
|
137
|
-
rows: []
|
|
84
|
+
rows: [],
|
|
138
85
|
loading: false,
|
|
139
86
|
pager: {
|
|
140
87
|
currentPage: 1,
|
|
141
88
|
limit: props.pageSize,
|
|
142
89
|
total: 0
|
|
143
|
-
}
|
|
144
|
-
currentRow: null
|
|
145
|
-
activeRowKeys: []
|
|
90
|
+
},
|
|
91
|
+
currentRow: null,
|
|
92
|
+
activeRowKeys: []
|
|
146
93
|
});
|
|
147
94
|
|
|
148
95
|
let requestSeq = 0;
|
|
149
96
|
|
|
150
|
-
function getColKey(col
|
|
151
|
-
const record = col
|
|
97
|
+
function getColKey(col) {
|
|
98
|
+
const record = col;
|
|
152
99
|
const rawColKey = record["colKey"];
|
|
153
100
|
if (typeof rawColKey === "string") return rawColKey;
|
|
154
101
|
if (typeof rawColKey === "number") return String(rawColKey);
|
|
155
102
|
return "";
|
|
156
103
|
}
|
|
157
104
|
|
|
158
|
-
function filterValidColumns(input
|
|
105
|
+
function filterValidColumns(input) {
|
|
159
106
|
if (!Array.isArray(input)) {
|
|
160
107
|
return [];
|
|
161
108
|
}
|
|
162
109
|
|
|
163
|
-
const out
|
|
110
|
+
const out = [];
|
|
164
111
|
|
|
165
|
-
for (const col of input
|
|
112
|
+
for (const col of input) {
|
|
166
113
|
if (!col || typeof col !== "object") {
|
|
167
114
|
continue;
|
|
168
115
|
}
|
|
169
|
-
const key = getColKey(col
|
|
116
|
+
const key = getColKey(col);
|
|
170
117
|
if (key.length === 0) {
|
|
171
118
|
continue;
|
|
172
119
|
}
|
|
173
|
-
out.push(col
|
|
120
|
+
out.push(col);
|
|
174
121
|
}
|
|
175
122
|
|
|
176
123
|
return out;
|
|
177
124
|
}
|
|
178
125
|
|
|
179
|
-
function mergeDetailColumns(mainColumns
|
|
180
|
-
const out
|
|
181
|
-
const set = new Set
|
|
126
|
+
function mergeDetailColumns(mainColumns, extraColumns) {
|
|
127
|
+
const out = [];
|
|
128
|
+
const set = new Set();
|
|
182
129
|
|
|
183
130
|
for (const col of mainColumns) {
|
|
184
131
|
out.push(col);
|
|
@@ -202,15 +149,15 @@ function mergeDetailColumns(mainColumns: PrimaryTableCol[], extraColumns: Primar
|
|
|
202
149
|
return out;
|
|
203
150
|
}
|
|
204
151
|
|
|
205
|
-
function isDetail(col
|
|
206
|
-
const record = col
|
|
152
|
+
function isDetail(col) {
|
|
153
|
+
const record = col;
|
|
207
154
|
if (record["detail"] === true) return true;
|
|
208
155
|
return false;
|
|
209
156
|
}
|
|
210
157
|
|
|
211
158
|
const tableColumns = computed(() => {
|
|
212
|
-
const out
|
|
213
|
-
const cols = filterValidColumns(props.columns)
|
|
159
|
+
const out = [];
|
|
160
|
+
const cols = filterValidColumns(props.columns);
|
|
214
161
|
for (const col of cols) {
|
|
215
162
|
if (isDetail(col)) continue;
|
|
216
163
|
out.push(col);
|
|
@@ -222,8 +169,8 @@ const detailFields = computed(() => {
|
|
|
222
169
|
// 只维护一个 columns:
|
|
223
170
|
// - detail: false(默认)=> 表格展示(同时也会出现在详情里,且顺序靠前)
|
|
224
171
|
// - detail: true => 仅在详情展示(顺序靠后)
|
|
225
|
-
const extras
|
|
226
|
-
const cols = filterValidColumns(props.columns)
|
|
172
|
+
const extras = [];
|
|
173
|
+
const cols = filterValidColumns(props.columns);
|
|
227
174
|
for (const col of cols) {
|
|
228
175
|
if (!isDetail(col)) continue;
|
|
229
176
|
extras.push(col);
|
|
@@ -239,8 +186,8 @@ const detailFields = computed(() => {
|
|
|
239
186
|
|
|
240
187
|
const forwardedTableSlotNames = computed(() => {
|
|
241
188
|
if (Array.isArray(props.tableSlotNames) && props.tableSlotNames.length > 0) {
|
|
242
|
-
const out
|
|
243
|
-
const set = new Set
|
|
189
|
+
const out = [];
|
|
190
|
+
const set = new Set();
|
|
244
191
|
for (const name of props.tableSlotNames) {
|
|
245
192
|
if (typeof name !== "string") continue;
|
|
246
193
|
const trimmed = name.trim();
|
|
@@ -252,7 +199,7 @@ const forwardedTableSlotNames = computed(() => {
|
|
|
252
199
|
return out;
|
|
253
200
|
}
|
|
254
201
|
|
|
255
|
-
const names
|
|
202
|
+
const names = [];
|
|
256
203
|
const reserved = ["toolLeft", "toolRight", "detail", "dialogs", "operation", "default"]; // operation 单独处理
|
|
257
204
|
|
|
258
205
|
for (const key of Object.keys(slots)) {
|
|
@@ -263,23 +210,23 @@ const forwardedTableSlotNames = computed(() => {
|
|
|
263
210
|
return names;
|
|
264
211
|
});
|
|
265
212
|
|
|
266
|
-
function setCurrentRow(row
|
|
213
|
+
function setCurrentRow(row) {
|
|
267
214
|
$Data.currentRow = row;
|
|
268
215
|
emit("row-change", { row: row });
|
|
269
216
|
}
|
|
270
217
|
|
|
271
|
-
function getRowKeyValue(row
|
|
218
|
+
function getRowKeyValue(row) {
|
|
272
219
|
const key = props.rowKey;
|
|
273
220
|
if (!key) return null;
|
|
274
221
|
|
|
275
|
-
const record = row
|
|
222
|
+
const record = row;
|
|
276
223
|
const raw = record[key];
|
|
277
224
|
if (typeof raw === "string") return raw;
|
|
278
225
|
if (typeof raw === "number") return raw;
|
|
279
226
|
return null;
|
|
280
227
|
}
|
|
281
228
|
|
|
282
|
-
function applyAutoSelection(list
|
|
229
|
+
function applyAutoSelection(list, preferKey) {
|
|
283
230
|
if (!Array.isArray(list) || list.length === 0) {
|
|
284
231
|
setCurrentRow(null);
|
|
285
232
|
$Data.activeRowKeys = [];
|
|
@@ -297,7 +244,7 @@ function applyAutoSelection(list: TableRowData[], preferKey: string | number | n
|
|
|
297
244
|
}
|
|
298
245
|
}
|
|
299
246
|
|
|
300
|
-
const first = list[0]
|
|
247
|
+
const first = list[0];
|
|
301
248
|
const firstKey = getRowKeyValue(first);
|
|
302
249
|
setCurrentRow(first);
|
|
303
250
|
|
|
@@ -309,7 +256,7 @@ function applyAutoSelection(list: TableRowData[], preferKey: string | number | n
|
|
|
309
256
|
$Data.activeRowKeys = [firstKey];
|
|
310
257
|
}
|
|
311
258
|
|
|
312
|
-
function getLastPage(total
|
|
259
|
+
function getLastPage(total, limit) {
|
|
313
260
|
if (total <= 0) return 1;
|
|
314
261
|
if (limit <= 0) return 1;
|
|
315
262
|
const pages = Math.ceil(total / limit);
|
|
@@ -317,7 +264,7 @@ function getLastPage(total: number, limit: number): number {
|
|
|
317
264
|
return pages;
|
|
318
265
|
}
|
|
319
266
|
|
|
320
|
-
async function loadList(options
|
|
267
|
+
async function loadList(options) {
|
|
321
268
|
const listEndpoint = props.endpoints?.list;
|
|
322
269
|
if (!listEndpoint) {
|
|
323
270
|
return;
|
|
@@ -333,7 +280,7 @@ async function loadList(options?: LoadListOptions): Promise<void> {
|
|
|
333
280
|
const pageKey = listEndpoint.pageKey || "page";
|
|
334
281
|
const limitKey = listEndpoint.limitKey || "limit";
|
|
335
282
|
|
|
336
|
-
const data
|
|
283
|
+
const data = {};
|
|
337
284
|
data[pageKey] = $Data.pager.currentPage;
|
|
338
285
|
data[limitKey] = $Data.pager.limit;
|
|
339
286
|
|
|
@@ -349,10 +296,10 @@ async function loadList(options?: LoadListOptions): Promise<void> {
|
|
|
349
296
|
}
|
|
350
297
|
}
|
|
351
298
|
|
|
352
|
-
const res =
|
|
299
|
+
const res = await $Http.post(listEndpoint.path, data, {
|
|
353
300
|
dropValues: listEndpoint.dropValues,
|
|
354
301
|
dropKeyValue: listEndpoint.dropKeyValue
|
|
355
|
-
})
|
|
302
|
+
});
|
|
356
303
|
|
|
357
304
|
// 并发保护:旧请求返回后不应覆盖新请求的状态
|
|
358
305
|
if (seq !== requestSeq) {
|
|
@@ -393,7 +340,7 @@ async function loadList(options?: LoadListOptions): Promise<void> {
|
|
|
393
340
|
}
|
|
394
341
|
}
|
|
395
342
|
|
|
396
|
-
async function reload(options
|
|
343
|
+
async function reload(options) {
|
|
397
344
|
if (options?.resetPage) {
|
|
398
345
|
$Data.pager.currentPage = 1;
|
|
399
346
|
}
|
|
@@ -403,18 +350,18 @@ async function reload(options?: { keepSelection?: boolean; resetPage?: boolean }
|
|
|
403
350
|
});
|
|
404
351
|
}
|
|
405
352
|
|
|
406
|
-
function onPageChange(info
|
|
353
|
+
function onPageChange(info) {
|
|
407
354
|
$Data.pager.currentPage = info.currentPage;
|
|
408
355
|
void reload({ keepSelection: true });
|
|
409
356
|
}
|
|
410
357
|
|
|
411
|
-
function onPageSizeChange(info
|
|
358
|
+
function onPageSizeChange(info) {
|
|
412
359
|
$Data.pager.limit = info.pageSize;
|
|
413
360
|
$Data.pager.currentPage = 1;
|
|
414
361
|
void reload({ keepSelection: false });
|
|
415
362
|
}
|
|
416
363
|
|
|
417
|
-
function onActiveChange(value
|
|
364
|
+
function onActiveChange(value, context) {
|
|
418
365
|
// 禁止取消高亮:如果新值为空,保持当前选中
|
|
419
366
|
if (value.length === 0) {
|
|
420
367
|
if ($Data.activeRowKeys.length > 0) {
|
|
@@ -446,7 +393,7 @@ function onActiveChange(value: Array<string | number>, context: { activeRowList?
|
|
|
446
393
|
}
|
|
447
394
|
}
|
|
448
395
|
|
|
449
|
-
function getDeleteConfirmContent(ep
|
|
396
|
+
function getDeleteConfirmContent(ep, row) {
|
|
450
397
|
const confirm = ep.confirm;
|
|
451
398
|
if (!confirm) {
|
|
452
399
|
return {
|
|
@@ -463,7 +410,7 @@ function getDeleteConfirmContent(ep: DeleteEndpoint<TableRowData>, row: TableRow
|
|
|
463
410
|
return confirm;
|
|
464
411
|
}
|
|
465
412
|
|
|
466
|
-
async function deleteRow(row
|
|
413
|
+
async function deleteRow(row) {
|
|
467
414
|
const ep = props.endpoints?.delete;
|
|
468
415
|
if (!ep) {
|
|
469
416
|
MessagePlugin.error("未配置删除接口");
|
|
@@ -471,7 +418,7 @@ async function deleteRow(row: TableRowData): Promise<void> {
|
|
|
471
418
|
}
|
|
472
419
|
|
|
473
420
|
const idKey = ep.idKey || "id";
|
|
474
|
-
const record = row
|
|
421
|
+
const record = row;
|
|
475
422
|
const rawId = record[idKey];
|
|
476
423
|
|
|
477
424
|
if (rawId === null || rawId === undefined || rawId === "") {
|
|
@@ -481,7 +428,7 @@ async function deleteRow(row: TableRowData): Promise<void> {
|
|
|
481
428
|
|
|
482
429
|
const confirmContent = getDeleteConfirmContent(ep, row);
|
|
483
430
|
|
|
484
|
-
let dialog
|
|
431
|
+
let dialog = null;
|
|
485
432
|
let destroyed = false;
|
|
486
433
|
|
|
487
434
|
const destroy = () => {
|
|
@@ -504,7 +451,7 @@ async function deleteRow(row: TableRowData): Promise<void> {
|
|
|
504
451
|
}
|
|
505
452
|
|
|
506
453
|
try {
|
|
507
|
-
const data
|
|
454
|
+
const data = {};
|
|
508
455
|
data[idKey] = rawId;
|
|
509
456
|
|
|
510
457
|
if (ep.buildData) {
|
|
@@ -539,8 +486,8 @@ async function deleteRow(row: TableRowData): Promise<void> {
|
|
|
539
486
|
});
|
|
540
487
|
}
|
|
541
488
|
|
|
542
|
-
function buildOperationSlotProps(scope
|
|
543
|
-
const out
|
|
489
|
+
function buildOperationSlotProps(scope) {
|
|
490
|
+
const out = {};
|
|
544
491
|
|
|
545
492
|
for (const k of Object.keys(scope)) {
|
|
546
493
|
out[k] = scope[k];
|
package/src/layouts/1.vue
CHANGED
package/src/layouts/2.vue
CHANGED
package/src/layouts/default.vue
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<!-- Logo 区域 -->
|
|
6
6
|
<div class="sidebar-logo">
|
|
7
7
|
<div class="logo-icon">
|
|
8
|
-
<
|
|
8
|
+
<MenuIcon style="width: 24px; height: 24px; color: var(--primary-color)" />
|
|
9
9
|
</div>
|
|
10
10
|
<h2>{{ $Config.appTitle }}</h2>
|
|
11
11
|
</div>
|
|
@@ -17,19 +17,19 @@
|
|
|
17
17
|
<!-- 无子菜单 -->
|
|
18
18
|
<t-menu-item v-if="!menu.children || menu.children.length === 0" :value="menu.path">
|
|
19
19
|
<template #icon>
|
|
20
|
-
<
|
|
21
|
-
<
|
|
20
|
+
<LinkIcon v-if="menu.path === '/dashboard' || menu.path === '/core/' || menu.path === '/core'" style="margin-right: 8px" />
|
|
21
|
+
<CodeIcon v-else style="margin-right: 8px" />
|
|
22
22
|
</template>
|
|
23
23
|
{{ menu.name }}
|
|
24
24
|
</t-menu-item>
|
|
25
25
|
<!-- 有子菜单 -->
|
|
26
26
|
<t-submenu v-else :value="String(menu.id)" :title="menu.name">
|
|
27
27
|
<template #icon>
|
|
28
|
-
<
|
|
28
|
+
<MenuIcon style="margin-right: 8px" />
|
|
29
29
|
</template>
|
|
30
30
|
<t-menu-item v-for="child in menu.children" :key="child.id" :value="child.path">
|
|
31
31
|
<template #icon>
|
|
32
|
-
<
|
|
32
|
+
<CodeIcon style="margin-right: 8px" />
|
|
33
33
|
</template>
|
|
34
34
|
{{ child.name }}
|
|
35
35
|
</t-menu-item>
|
|
@@ -41,16 +41,16 @@
|
|
|
41
41
|
<!-- 底部操作区域 -->
|
|
42
42
|
<div class="sidebar-footer">
|
|
43
43
|
<div class="footer-item" @click="handleSettings">
|
|
44
|
-
<
|
|
44
|
+
<SettingIcon style="width: 18px; height: 18px" />
|
|
45
45
|
<span>系统设置</span>
|
|
46
46
|
</div>
|
|
47
47
|
<div class="footer-user">
|
|
48
48
|
<t-upload :action="$Config.uploadUrl" :headers="{ Authorization: $Storage.local.get('token') }" :show-upload-list="false" accept="image/*" @success="onAvatarUploadSuccess">
|
|
49
49
|
<div class="user-avatar" :class="{ 'has-avatar': $Data.userInfo.avatar }">
|
|
50
50
|
<img v-if="$Data.userInfo.avatar" :src="$Data.userInfo.avatar" alt="avatar" />
|
|
51
|
-
<
|
|
51
|
+
<UserIcon v-else style="width: 16px; height: 16px; color: #fff" />
|
|
52
52
|
<div class="avatar-overlay">
|
|
53
|
-
<
|
|
53
|
+
<CloudIcon style="width: 14px; height: 14px; color: #fff" />
|
|
54
54
|
</div>
|
|
55
55
|
</div>
|
|
56
56
|
</t-upload>
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
</div>
|
|
61
61
|
<t-button theme="default" variant="text" size="small" @click="handleLogout">
|
|
62
62
|
<template #icon>
|
|
63
|
-
<
|
|
63
|
+
<CloseCircleIcon style="width: 16px; height: 16px" />
|
|
64
64
|
</template>
|
|
65
65
|
</t-button>
|
|
66
66
|
</div>
|
|
@@ -74,18 +74,20 @@
|
|
|
74
74
|
</div>
|
|
75
75
|
</template>
|
|
76
76
|
|
|
77
|
-
<script setup
|
|
78
|
-
import { arrayToTree } from "befly-
|
|
77
|
+
<script setup>
|
|
78
|
+
import { arrayToTree } from "befly-admin-ui/utils/arrayToTree";
|
|
79
|
+
import { isString } from "../utils/is.js";
|
|
80
|
+
import { CloseCircleIcon, CloudIcon, CodeIcon, LinkIcon, MenuIcon, SettingIcon, UserIcon } from "tdesign-icons-vue-next";
|
|
79
81
|
|
|
80
82
|
import { reactive } from "vue";
|
|
81
83
|
|
|
82
84
|
const router = useRouter();
|
|
83
85
|
const route = useRoute();
|
|
84
86
|
|
|
85
|
-
const loginPath = "/
|
|
87
|
+
const loginPath = "/core/login";
|
|
86
88
|
|
|
87
89
|
const normalizePath = (path) => {
|
|
88
|
-
if (
|
|
90
|
+
if (!isString(path)) {
|
|
89
91
|
return path;
|
|
90
92
|
}
|
|
91
93
|
|
|
@@ -97,7 +99,7 @@ const normalizePath = (path) => {
|
|
|
97
99
|
// - parentPath 为空/"/" 视为根节点(空字符串)
|
|
98
100
|
// - 避免把所有一级菜单挂到 "/"(首页)下面
|
|
99
101
|
const normalizeParentPath = (parentPath) => {
|
|
100
|
-
if (
|
|
102
|
+
if (!isString(parentPath)) {
|
|
101
103
|
return "";
|
|
102
104
|
}
|
|
103
105
|
|
|
@@ -128,7 +130,7 @@ const $Data = reactive({
|
|
|
128
130
|
|
|
129
131
|
async function fetchUserMenus() {
|
|
130
132
|
try {
|
|
131
|
-
const { data } = await $Http.post("/
|
|
133
|
+
const { data } = await $Http.post("/core/menu/all");
|
|
132
134
|
const lists = Array.isArray(data?.lists) ? data.lists : [];
|
|
133
135
|
|
|
134
136
|
const normalizedLists = lists.map((menu) => {
|
|
@@ -164,7 +166,7 @@ function setActiveMenu() {
|
|
|
164
166
|
const expandedKeys = [];
|
|
165
167
|
let menu = currentMenu;
|
|
166
168
|
|
|
167
|
-
while (
|
|
169
|
+
while (isString(menu.parentPath) && menu.parentPath.length > 0) {
|
|
168
170
|
const parent = $Data.userMenusFlat.find((m) => {
|
|
169
171
|
const parentMenuPath = normalizePath(m?.path);
|
|
170
172
|
const currentParentPath = normalizeParentPath(menu?.parentPath);
|
|
@@ -185,7 +187,7 @@ function setActiveMenu() {
|
|
|
185
187
|
}
|
|
186
188
|
|
|
187
189
|
function onMenuClick(path) {
|
|
188
|
-
if (
|
|
190
|
+
if (isString(path) && path.startsWith("/")) {
|
|
189
191
|
router.push(path);
|
|
190
192
|
}
|
|
191
193
|
}
|
|
@@ -232,7 +234,7 @@ async function handleLogout() {
|
|
|
232
234
|
}
|
|
233
235
|
|
|
234
236
|
function handleSettings() {
|
|
235
|
-
router.push("/
|
|
237
|
+
router.push("/core/settings");
|
|
236
238
|
}
|
|
237
239
|
|
|
238
240
|
function onAvatarUploadSuccess(res) {
|
package/src/{main.ts → main.js}
RENAMED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// 引入 TDesign 样式
|
|
2
2
|
import "tdesign-vue-next/es/style/index.css";
|
|
3
|
-
// 引入
|
|
4
|
-
import "
|
|
3
|
+
// 引入 adminUI 的 CSS 变量
|
|
4
|
+
import "befly-admin-ui/styles/variables.scss";
|
|
5
5
|
// 引入全局基础样式(reset、通用类、滚动条等)
|
|
6
6
|
import "@/styles/global.scss";
|
|
7
7
|
import App from "./App.vue";
|
|
@@ -3,29 +3,18 @@
|
|
|
3
3
|
* 存放框架内置的配置变量,不建议修改
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
export type BeflyAdminConfig = {
|
|
7
|
-
appTitle: string;
|
|
8
|
-
apiBaseUrl: string;
|
|
9
|
-
uploadUrl: string;
|
|
10
|
-
storageNamespace: string;
|
|
11
|
-
loginPath: string;
|
|
12
|
-
homePath: string;
|
|
13
|
-
isDev: boolean;
|
|
14
|
-
isProd: boolean;
|
|
15
|
-
};
|
|
16
|
-
|
|
17
6
|
/**
|
|
18
7
|
* 内置配置对象
|
|
19
8
|
*/
|
|
20
|
-
export const $Config
|
|
9
|
+
export const $Config = {
|
|
21
10
|
appTitle: import.meta.env["VITE_APP_TITLE"] || "野蜂飞舞",
|
|
22
11
|
apiBaseUrl: import.meta.env["VITE_API_BASE_URL"] || "",
|
|
23
12
|
|
|
24
13
|
uploadUrl: import.meta.env["VITE_UPLOAD_URL"] || ((import.meta.env["VITE_API_BASE_URL"] || "").length > 0 ? `${import.meta.env["VITE_API_BASE_URL"]}/upload` : "/upload"),
|
|
25
14
|
storageNamespace: import.meta.env["VITE_STORAGE_NAMESPACE"] || "befly_admin",
|
|
26
15
|
|
|
27
|
-
loginPath: import.meta.env["VITE_LOGIN_PATH"] || "/
|
|
28
|
-
homePath: import.meta.env["VITE_HOME_PATH"] || "/
|
|
16
|
+
loginPath: import.meta.env["VITE_LOGIN_PATH"] || "/core/login",
|
|
17
|
+
homePath: import.meta.env["VITE_HOME_PATH"] || "/core/",
|
|
29
18
|
isDev: import.meta.env.DEV,
|
|
30
19
|
isProd: import.meta.env.PROD
|
|
31
20
|
};
|
|
@@ -5,10 +5,10 @@
|
|
|
5
5
|
|
|
6
6
|
export const useGlobal = defineStore("global", () => {
|
|
7
7
|
// ==================== 全局数据 ====================
|
|
8
|
-
const data = reactive
|
|
8
|
+
const data = reactive({});
|
|
9
9
|
|
|
10
10
|
// ==================== 全局方法 ====================
|
|
11
|
-
const method
|
|
11
|
+
const method = {};
|
|
12
12
|
|
|
13
13
|
// ==================== 返回 ====================
|
|
14
14
|
return {
|