befly-admin-ui 1.10.0 → 1.10.2
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/components/detailPanel.vue +52 -54
- package/components/pageDialog.vue +131 -117
- package/components/pageTableDetail.vue +381 -398
- package/layouts/default.vue +212 -215
- package/package.json +2 -2
- package/views/config/dict/components/edit.vue +83 -60
- package/views/config/dict/index.vue +53 -68
- package/views/config/dictType/components/edit.vue +81 -57
- package/views/config/dictType/index.vue +39 -51
- package/views/config/system/components/edit.vue +97 -86
- package/views/config/system/index.vue +37 -51
- package/views/index/components/addonList.vue +14 -11
- package/views/index/components/environmentInfo.vue +25 -22
- package/views/index/components/operationLogs.vue +20 -16
- package/views/index/components/performanceMetrics.vue +24 -21
- package/views/index/components/serviceStatus.vue +26 -22
- package/views/index/components/systemNotifications.vue +24 -19
- package/views/index/components/systemOverview.vue +368 -385
- package/views/index/components/systemResources.vue +22 -19
- package/views/index/components/userInfo.vue +56 -56
- package/views/log/email/index.vue +99 -100
- package/views/log/error/index.vue +112 -130
- package/views/log/login/index.vue +17 -28
- package/views/log/operate/index.vue +33 -46
- package/views/login_1/index.vue +50 -32
- package/views/people/admin/components/edit.vue +1 -1
- package/views/people/admin/index.vue +28 -29
- package/views/permission/api/index.vue +46 -58
- package/views/permission/menu/index.vue +46 -52
- package/views/permission/role/components/api.vue +143 -144
- package/views/permission/role/components/edit.vue +74 -52
- package/views/permission/role/components/menu.vue +119 -121
- package/views/permission/role/index.vue +49 -63
- package/views/resource/gallery/index.vue +78 -88
|
@@ -1,42 +1,42 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div :class="['page-table-detail', 'page-table', { 'page-table--with-pagination':
|
|
3
|
-
<div class="main-tool">
|
|
2
|
+
<div :class="['page-table-detail', 'page-table', { 'page-table--with-pagination': $Prop.isPagination }]">
|
|
3
|
+
<div v-if="$Computed.hasToolBar" class="main-tool">
|
|
4
4
|
<div class="left">
|
|
5
|
-
<slot name="toolLeft" :reload="reload" :current-row="$Data.currentRow"></slot>
|
|
5
|
+
<slot name="toolLeft" :reload="$Method.reload" :current-row="$Data.currentRow"></slot>
|
|
6
6
|
</div>
|
|
7
7
|
<div class="right">
|
|
8
|
-
<slot name="toolRight" :reload="reload" :current-row="$Data.currentRow"></slot>
|
|
8
|
+
<slot name="toolRight" :reload="$Method.reload" :current-row="$Data.currentRow"></slot>
|
|
9
9
|
</div>
|
|
10
10
|
</div>
|
|
11
11
|
|
|
12
12
|
<div class="main-content">
|
|
13
13
|
<div class="main-table">
|
|
14
|
-
<TTable :data="$Data.rows" :columns="tableColumns" :loading="$Data.loading" :active-row-keys="$Data.activeRowKeys" :row-key="rowKey" :height="resolvedTableHeight" active-row-type="single" @active-change="onActiveChange">
|
|
14
|
+
<TTable :data="$Data.rows" :columns="$Computed.tableColumns" :loading="$Data.loading" :active-row-keys="$Data.activeRowKeys" :row-key="$Prop.rowKey" :height="$Computed.resolvedTableHeight" active-row-type="single" @active-change="$Method.onActiveChange">
|
|
15
15
|
<template #operation="scope">
|
|
16
|
-
<slot name="operation" v-bind="buildOperationSlotProps(scope)"></slot>
|
|
16
|
+
<slot name="operation" v-bind="$Method.buildOperationSlotProps(scope)"></slot>
|
|
17
17
|
</template>
|
|
18
18
|
|
|
19
|
-
<template v-for="name in tableRenderSlotNames" :key="name" v-slot:[name]="scope">
|
|
19
|
+
<template v-for="name in $Computed.tableRenderSlotNames" :key="name" v-slot:[name]="scope">
|
|
20
20
|
<slot v-if="$slots[name]" :name="name" v-bind="scope"></slot>
|
|
21
21
|
<template v-else>
|
|
22
|
-
{{ formatTableCell(scope.row, name) }}
|
|
22
|
+
{{ $Method.formatTableCell(scope.row, name) }}
|
|
23
23
|
</template>
|
|
24
24
|
</template>
|
|
25
25
|
</TTable>
|
|
26
26
|
</div>
|
|
27
27
|
|
|
28
28
|
<div class="main-detail">
|
|
29
|
-
<slot name="detail" :row="$Data.currentRow" :reload="reload">
|
|
30
|
-
<DetailPanel :data="$Data.currentRow" :fields="detailFields" />
|
|
29
|
+
<slot name="detail" :row="$Data.currentRow" :reload="$Method.reload">
|
|
30
|
+
<DetailPanel :data="$Data.currentRow" :fields="$Computed.detailFields" />
|
|
31
31
|
</slot>
|
|
32
32
|
</div>
|
|
33
33
|
</div>
|
|
34
34
|
|
|
35
|
-
<div v-if="
|
|
36
|
-
<TPagination :current-page="$Data.pager.currentPage" :page-size="$Data.pager.limit" :total="$Data.pager.total" align="right" :layout="paginationLayout" @current-change="onPageChange" @page-size-change="onPageSizeChange" />
|
|
35
|
+
<div v-if="$Prop.isPagination" class="main-page">
|
|
36
|
+
<TPagination :current-page="$Data.pager.currentPage" :page-size="$Data.pager.limit" :total="$Data.pager.total" align="right" :layout="$Prop.paginationLayout" @current-change="$Method.onPageChange" @page-size-change="$Method.onPageSizeChange" />
|
|
37
37
|
</div>
|
|
38
38
|
|
|
39
|
-
<slot name="dialogs" :reload="reload" :current-row="$Data.currentRow"></slot>
|
|
39
|
+
<slot name="dialogs" :reload="$Method.reload" :current-row="$Data.currentRow"></slot>
|
|
40
40
|
</div>
|
|
41
41
|
</template>
|
|
42
42
|
|
|
@@ -44,10 +44,10 @@
|
|
|
44
44
|
import { computed, onMounted, reactive, useSlots } from "vue";
|
|
45
45
|
import { DialogPlugin, MessagePlugin, Pagination as TPagination, Table as TTable } from "tdesign-vue-next";
|
|
46
46
|
import DetailPanel from "./detailPanel.vue";
|
|
47
|
-
import { $Http } from "@/plugins/http";
|
|
47
|
+
import { $Http } from "@/plugins/http.js";
|
|
48
48
|
import { formatFieldValue } from "../utils/formatFieldValue.js";
|
|
49
49
|
|
|
50
|
-
const
|
|
50
|
+
const $Prop = defineProps({
|
|
51
51
|
columns: {
|
|
52
52
|
type: Array,
|
|
53
53
|
required: true
|
|
@@ -86,481 +86,464 @@ const props = defineProps({
|
|
|
86
86
|
}
|
|
87
87
|
});
|
|
88
88
|
|
|
89
|
-
const
|
|
89
|
+
const $Emit = defineEmits(["loaded", "row-change", "deleted"]);
|
|
90
90
|
|
|
91
|
-
const
|
|
91
|
+
const $From = {
|
|
92
|
+
slots: useSlots(),
|
|
93
|
+
requestSeq: 0
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const $Const = {
|
|
97
|
+
reservedSlotNames: ["toolLeft", "toolRight", "detail", "dialogs", "operation", "default"]
|
|
98
|
+
};
|
|
92
99
|
|
|
93
100
|
const $Data = reactive({
|
|
94
101
|
rows: [],
|
|
95
102
|
loading: false,
|
|
96
103
|
pager: {
|
|
97
104
|
currentPage: 1,
|
|
98
|
-
limit:
|
|
105
|
+
limit: $Prop.pageSize,
|
|
99
106
|
total: 0
|
|
100
107
|
},
|
|
101
108
|
currentRow: null,
|
|
102
109
|
activeRowKeys: []
|
|
103
110
|
});
|
|
104
111
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
return [];
|
|
118
|
-
}
|
|
112
|
+
const $Method = {
|
|
113
|
+
getColKey(col) {
|
|
114
|
+
const record = col;
|
|
115
|
+
const rawColKey = record["colKey"];
|
|
116
|
+
if (typeof rawColKey === "string") return rawColKey;
|
|
117
|
+
if (typeof rawColKey === "number") return String(rawColKey);
|
|
118
|
+
return "";
|
|
119
|
+
},
|
|
120
|
+
filterValidColumns(input) {
|
|
121
|
+
if (!Array.isArray(input)) {
|
|
122
|
+
return [];
|
|
123
|
+
}
|
|
119
124
|
|
|
120
|
-
|
|
125
|
+
const out = [];
|
|
121
126
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
127
|
+
for (const col of input) {
|
|
128
|
+
if (!col || typeof col !== "object") {
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
const key = $Method.getColKey(col);
|
|
132
|
+
if (key.length === 0) {
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
out.push(col);
|
|
129
136
|
}
|
|
130
|
-
out.push(col);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
return out;
|
|
134
|
-
}
|
|
135
137
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
138
|
+
return out;
|
|
139
|
+
},
|
|
140
|
+
mergeDetailColumns(mainColumns, extraColumns) {
|
|
141
|
+
const out = [];
|
|
142
|
+
const set = new Set();
|
|
139
143
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
144
|
+
for (const col of mainColumns) {
|
|
145
|
+
out.push(col);
|
|
146
|
+
const key = $Method.getColKey(col);
|
|
147
|
+
if (key) {
|
|
148
|
+
set.add(key);
|
|
149
|
+
}
|
|
145
150
|
}
|
|
146
|
-
}
|
|
147
151
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
152
|
+
for (const col of extraColumns) {
|
|
153
|
+
const key = $Method.getColKey(col);
|
|
154
|
+
if (key && set.has(key)) {
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
out.push(col);
|
|
158
|
+
if (key) {
|
|
159
|
+
set.add(key);
|
|
160
|
+
}
|
|
156
161
|
}
|
|
157
|
-
}
|
|
158
162
|
|
|
159
|
-
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
const
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
if (
|
|
174
|
-
|
|
175
|
-
|
|
163
|
+
return out;
|
|
164
|
+
},
|
|
165
|
+
formatTableCell(row, colKey) {
|
|
166
|
+
const record = row && typeof row === "object" ? row : {};
|
|
167
|
+
const value = record[colKey];
|
|
168
|
+
const field = $Computed.columnsMeta.tableColumnMap[colKey] || {};
|
|
169
|
+
return formatFieldValue(value, field);
|
|
170
|
+
},
|
|
171
|
+
setCurrentRow(row) {
|
|
172
|
+
$Data.currentRow = row;
|
|
173
|
+
$Emit("row-change", { row: row });
|
|
174
|
+
},
|
|
175
|
+
getRowKeyValue(row) {
|
|
176
|
+
const key = $Prop.rowKey;
|
|
177
|
+
if (!key) return null;
|
|
178
|
+
|
|
179
|
+
const record = row;
|
|
180
|
+
const raw = record[key];
|
|
181
|
+
if (typeof raw === "string") return raw;
|
|
182
|
+
if (typeof raw === "number") return raw;
|
|
183
|
+
return null;
|
|
184
|
+
},
|
|
185
|
+
applyAutoSelection(list, preferKey) {
|
|
186
|
+
if (!Array.isArray(list) || list.length === 0) {
|
|
187
|
+
$Method.setCurrentRow(null);
|
|
188
|
+
$Data.activeRowKeys = [];
|
|
189
|
+
return;
|
|
176
190
|
}
|
|
177
191
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
192
|
+
if (preferKey !== null) {
|
|
193
|
+
for (const row of list) {
|
|
194
|
+
const key = $Method.getRowKeyValue(row);
|
|
195
|
+
if (key === preferKey) {
|
|
196
|
+
$Method.setCurrentRow(row);
|
|
197
|
+
$Data.activeRowKeys = [key];
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
183
201
|
}
|
|
184
202
|
|
|
185
|
-
|
|
203
|
+
const first = list[0];
|
|
204
|
+
const firstKey = $Method.getRowKeyValue(first);
|
|
205
|
+
$Method.setCurrentRow(first);
|
|
186
206
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
207
|
+
if (firstKey === null) {
|
|
208
|
+
$Data.activeRowKeys = [];
|
|
209
|
+
return;
|
|
190
210
|
}
|
|
191
|
-
}
|
|
192
211
|
|
|
193
|
-
|
|
212
|
+
$Data.activeRowKeys = [firstKey];
|
|
213
|
+
},
|
|
214
|
+
getLastPage(total, limit) {
|
|
215
|
+
if (total <= 0) return 1;
|
|
216
|
+
if (limit <= 0) return 1;
|
|
217
|
+
const pages = Math.ceil(total / limit);
|
|
218
|
+
if (!Number.isFinite(pages) || pages <= 0) return 1;
|
|
219
|
+
return pages;
|
|
220
|
+
},
|
|
221
|
+
async loadList(options) {
|
|
222
|
+
const listEndpoint = $Prop.endpoints?.list;
|
|
223
|
+
if (!listEndpoint) {
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
194
226
|
|
|
195
|
-
|
|
196
|
-
tableColumns: tableColumns,
|
|
197
|
-
detailFields: detailFields,
|
|
198
|
-
tableColumnMap: tableColumnMap,
|
|
199
|
-
formatKeys: formatKeys
|
|
200
|
-
};
|
|
201
|
-
});
|
|
227
|
+
const preferKey = options?.keepSelection ? ($Data.currentRow ? $Method.getRowKeyValue($Data.currentRow) : null) : null;
|
|
202
228
|
|
|
203
|
-
|
|
229
|
+
$From.requestSeq += 1;
|
|
230
|
+
const seq = $From.requestSeq;
|
|
204
231
|
|
|
205
|
-
|
|
232
|
+
$Data.loading = true;
|
|
233
|
+
try {
|
|
234
|
+
const pageKey = listEndpoint.pageKey || "page";
|
|
235
|
+
const limitKey = listEndpoint.limitKey || "limit";
|
|
206
236
|
|
|
207
|
-
const
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
}
|
|
211
|
-
return "calc(100vh - var(--search-height) - var(--layout-gap) * 2)";
|
|
212
|
-
});
|
|
237
|
+
const data = {};
|
|
238
|
+
data[pageKey] = $Data.pager.currentPage;
|
|
239
|
+
data[limitKey] = $Data.pager.limit;
|
|
213
240
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
}
|
|
226
|
-
return out;
|
|
227
|
-
}
|
|
241
|
+
if (listEndpoint.buildData) {
|
|
242
|
+
const extra = listEndpoint.buildData({
|
|
243
|
+
currentPage: $Data.pager.currentPage,
|
|
244
|
+
limit: $Data.pager.limit
|
|
245
|
+
});
|
|
246
|
+
if (extra && typeof extra === "object") {
|
|
247
|
+
for (const key of Object.keys(extra)) {
|
|
248
|
+
data[key] = extra[key];
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
228
252
|
|
|
229
|
-
|
|
230
|
-
const reserved = ["toolLeft", "toolRight", "detail", "dialogs", "operation", "default"]; // operation 单独处理
|
|
253
|
+
const res = await $Http(listEndpoint.path, data, listEndpoint.dropValues, listEndpoint.dropKeyValue);
|
|
231
254
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
}
|
|
255
|
+
if (seq !== $From.requestSeq) {
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
236
258
|
|
|
237
|
-
|
|
238
|
-
|
|
259
|
+
const lists = Array.isArray(res?.data?.lists) ? res.data.lists : [];
|
|
260
|
+
const total = typeof res?.data?.total === "number" ? res.data.total : 0;
|
|
261
|
+
|
|
262
|
+
const allowPageFallback = options?.allowPageFallback !== false;
|
|
263
|
+
if (allowPageFallback && lists.length === 0 && total > 0) {
|
|
264
|
+
const lastPage = $Method.getLastPage(total, $Data.pager.limit);
|
|
265
|
+
if ($Data.pager.currentPage > lastPage) {
|
|
266
|
+
$Data.pager.currentPage = lastPage;
|
|
267
|
+
await $Method.loadList({
|
|
268
|
+
keepSelection: false,
|
|
269
|
+
allowPageFallback: false
|
|
270
|
+
});
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
239
274
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
const set = new Set();
|
|
275
|
+
$Data.rows = lists;
|
|
276
|
+
$Data.pager.total = total;
|
|
243
277
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
278
|
+
$Method.applyAutoSelection(lists, preferKey);
|
|
279
|
+
$Emit("loaded", { rows: lists, total: total });
|
|
280
|
+
} catch (error) {
|
|
281
|
+
if (seq !== $From.requestSeq) {
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
MessagePlugin.error("加载数据失败");
|
|
285
|
+
} finally {
|
|
286
|
+
if (seq === $From.requestSeq) {
|
|
287
|
+
$Data.loading = false;
|
|
288
|
+
}
|
|
247
289
|
}
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
for (const key of columnsMeta.value.formatKeys) {
|
|
253
|
-
if (!key || set.has(key)) {
|
|
254
|
-
continue;
|
|
290
|
+
},
|
|
291
|
+
async reload(options) {
|
|
292
|
+
if (options?.resetPage) {
|
|
293
|
+
$Data.pager.currentPage = 1;
|
|
255
294
|
}
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
function getRowKeyValue(row) {
|
|
276
|
-
const key = props.rowKey;
|
|
277
|
-
if (!key) return null;
|
|
278
|
-
|
|
279
|
-
const record = row;
|
|
280
|
-
const raw = record[key];
|
|
281
|
-
if (typeof raw === "string") return raw;
|
|
282
|
-
if (typeof raw === "number") return raw;
|
|
283
|
-
return null;
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
function applyAutoSelection(list, preferKey) {
|
|
287
|
-
if (!Array.isArray(list) || list.length === 0) {
|
|
288
|
-
setCurrentRow(null);
|
|
289
|
-
$Data.activeRowKeys = [];
|
|
290
|
-
return;
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
if (preferKey !== null) {
|
|
294
|
-
for (const row of list) {
|
|
295
|
-
const k = getRowKeyValue(row);
|
|
296
|
-
if (k === preferKey) {
|
|
297
|
-
setCurrentRow(row);
|
|
298
|
-
$Data.activeRowKeys = [k];
|
|
295
|
+
await $Method.loadList({
|
|
296
|
+
keepSelection: options?.keepSelection,
|
|
297
|
+
allowPageFallback: true
|
|
298
|
+
});
|
|
299
|
+
},
|
|
300
|
+
onPageChange(info) {
|
|
301
|
+
$Data.pager.currentPage = info.currentPage;
|
|
302
|
+
$Method.reload({ keepSelection: true });
|
|
303
|
+
},
|
|
304
|
+
onPageSizeChange(info) {
|
|
305
|
+
$Data.pager.limit = info.pageSize;
|
|
306
|
+
$Data.pager.currentPage = 1;
|
|
307
|
+
$Method.reload({ keepSelection: false });
|
|
308
|
+
},
|
|
309
|
+
onActiveChange(value, context) {
|
|
310
|
+
if (value.length === 0) {
|
|
311
|
+
if ($Data.activeRowKeys.length > 0) {
|
|
299
312
|
return;
|
|
300
313
|
}
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
const first = list[0];
|
|
305
|
-
const firstKey = getRowKeyValue(first);
|
|
306
|
-
setCurrentRow(first);
|
|
307
|
-
|
|
308
|
-
if (firstKey === null) {
|
|
309
|
-
$Data.activeRowKeys = [];
|
|
310
|
-
return;
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
$Data.activeRowKeys = [firstKey];
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
function getLastPage(total, limit) {
|
|
317
|
-
if (total <= 0) return 1;
|
|
318
|
-
if (limit <= 0) return 1;
|
|
319
|
-
const pages = Math.ceil(total / limit);
|
|
320
|
-
if (!Number.isFinite(pages) || pages <= 0) return 1;
|
|
321
|
-
return pages;
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
async function loadList(options) {
|
|
325
|
-
const listEndpoint = props.endpoints?.list;
|
|
326
|
-
if (!listEndpoint) {
|
|
327
|
-
return;
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
const preferKey = options?.keepSelection ? ($Data.currentRow ? getRowKeyValue($Data.currentRow) : null) : null;
|
|
331
|
-
|
|
332
|
-
requestSeq += 1;
|
|
333
|
-
const seq = requestSeq;
|
|
334
|
-
|
|
335
|
-
$Data.loading = true;
|
|
336
|
-
try {
|
|
337
|
-
const pageKey = listEndpoint.pageKey || "page";
|
|
338
|
-
const limitKey = listEndpoint.limitKey || "limit";
|
|
339
314
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
if (listEndpoint.buildData) {
|
|
345
|
-
const extra = listEndpoint.buildData({
|
|
346
|
-
currentPage: $Data.pager.currentPage,
|
|
347
|
-
limit: $Data.pager.limit
|
|
348
|
-
});
|
|
349
|
-
if (extra && typeof extra === "object") {
|
|
350
|
-
for (const k of Object.keys(extra)) {
|
|
351
|
-
data[k] = extra[k];
|
|
352
|
-
}
|
|
353
|
-
}
|
|
315
|
+
$Data.activeRowKeys = [];
|
|
316
|
+
$Method.setCurrentRow(null);
|
|
317
|
+
return;
|
|
354
318
|
}
|
|
355
319
|
|
|
356
|
-
|
|
320
|
+
$Data.activeRowKeys = value;
|
|
357
321
|
|
|
358
|
-
|
|
359
|
-
if (
|
|
322
|
+
const list = context.activeRowList;
|
|
323
|
+
if (list && Array.isArray(list) && list.length > 0) {
|
|
324
|
+
const row = list[0]?.row || null;
|
|
325
|
+
$Method.setCurrentRow(row);
|
|
360
326
|
return;
|
|
361
327
|
}
|
|
362
328
|
|
|
363
|
-
const
|
|
364
|
-
const
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
if (allowPageFallback && lists.length === 0 && total > 0) {
|
|
369
|
-
const lastPage = getLastPage(total, $Data.pager.limit);
|
|
370
|
-
if ($Data.pager.currentPage > lastPage) {
|
|
371
|
-
$Data.pager.currentPage = lastPage;
|
|
372
|
-
await loadList({
|
|
373
|
-
keepSelection: false,
|
|
374
|
-
allowPageFallback: false
|
|
375
|
-
});
|
|
329
|
+
const activeKey = value[0];
|
|
330
|
+
for (const row of $Data.rows) {
|
|
331
|
+
const key = $Method.getRowKeyValue(row);
|
|
332
|
+
if (key === activeKey) {
|
|
333
|
+
$Method.setCurrentRow(row);
|
|
376
334
|
return;
|
|
377
335
|
}
|
|
378
336
|
}
|
|
337
|
+
},
|
|
338
|
+
getDeleteConfirmContent(ep, row) {
|
|
339
|
+
const confirm = ep.confirm;
|
|
340
|
+
if (!confirm) {
|
|
341
|
+
return {
|
|
342
|
+
header: "确认删除",
|
|
343
|
+
body: "确认删除该记录吗?",
|
|
344
|
+
confirmBtn: "删除"
|
|
345
|
+
};
|
|
346
|
+
}
|
|
379
347
|
|
|
380
|
-
|
|
381
|
-
|
|
348
|
+
if (typeof confirm === "function") {
|
|
349
|
+
return confirm(row);
|
|
350
|
+
}
|
|
382
351
|
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
352
|
+
return confirm;
|
|
353
|
+
},
|
|
354
|
+
async deleteRow(row) {
|
|
355
|
+
const ep = $Prop.endpoints?.delete;
|
|
356
|
+
if (!ep) {
|
|
357
|
+
MessagePlugin.error("未配置删除接口");
|
|
387
358
|
return;
|
|
388
359
|
}
|
|
389
|
-
MessagePlugin.error("加载数据失败");
|
|
390
|
-
} finally {
|
|
391
|
-
if (seq === requestSeq) {
|
|
392
|
-
$Data.loading = false;
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
360
|
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
allowPageFallback: true
|
|
404
|
-
});
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
function onPageChange(info) {
|
|
408
|
-
$Data.pager.currentPage = info.currentPage;
|
|
409
|
-
reload({ keepSelection: true });
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
function onPageSizeChange(info) {
|
|
413
|
-
$Data.pager.limit = info.pageSize;
|
|
414
|
-
$Data.pager.currentPage = 1;
|
|
415
|
-
reload({ keepSelection: false });
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
function onActiveChange(value, context) {
|
|
419
|
-
// 禁止取消高亮:如果新值为空,保持当前选中
|
|
420
|
-
if (value.length === 0) {
|
|
421
|
-
if ($Data.activeRowKeys.length > 0) {
|
|
361
|
+
const idKey = ep.idKey || "id";
|
|
362
|
+
const record = row;
|
|
363
|
+
const rawId = record[idKey];
|
|
364
|
+
|
|
365
|
+
if (rawId === null || rawId === undefined || rawId === "") {
|
|
366
|
+
MessagePlugin.error("删除失败:缺少主键");
|
|
422
367
|
return;
|
|
423
368
|
}
|
|
424
369
|
|
|
425
|
-
$
|
|
426
|
-
setCurrentRow(null);
|
|
427
|
-
return;
|
|
428
|
-
}
|
|
370
|
+
const confirmContent = $Method.getDeleteConfirmContent(ep, row);
|
|
429
371
|
|
|
430
|
-
|
|
372
|
+
let dialog = null;
|
|
373
|
+
let destroyed = false;
|
|
431
374
|
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
375
|
+
const destroy = () => {
|
|
376
|
+
if (destroyed) return;
|
|
377
|
+
destroyed = true;
|
|
378
|
+
if (dialog && typeof dialog.destroy === "function") {
|
|
379
|
+
dialog.destroy();
|
|
380
|
+
}
|
|
381
|
+
};
|
|
438
382
|
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
}
|
|
383
|
+
dialog = DialogPlugin.confirm({
|
|
384
|
+
header: confirmContent.header,
|
|
385
|
+
body: confirmContent.body,
|
|
386
|
+
status: confirmContent.status || "warning",
|
|
387
|
+
confirmBtn: confirmContent.confirmBtn || "删除",
|
|
388
|
+
cancelBtn: confirmContent.cancelBtn || "取消",
|
|
389
|
+
onConfirm: async () => {
|
|
390
|
+
if (dialog && typeof dialog.setConfirmLoading === "function") {
|
|
391
|
+
dialog.setConfirmLoading(true);
|
|
392
|
+
}
|
|
449
393
|
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
return {
|
|
454
|
-
header: "确认删除",
|
|
455
|
-
body: "确认删除该记录吗?",
|
|
456
|
-
confirmBtn: "删除"
|
|
457
|
-
};
|
|
458
|
-
}
|
|
394
|
+
try {
|
|
395
|
+
const data = {};
|
|
396
|
+
data[idKey] = rawId;
|
|
459
397
|
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
398
|
+
if (ep.buildData) {
|
|
399
|
+
const extra = ep.buildData(row);
|
|
400
|
+
if (extra && typeof extra === "object") {
|
|
401
|
+
for (const key of Object.keys(extra)) {
|
|
402
|
+
data[key] = extra[key];
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
}
|
|
463
406
|
|
|
464
|
-
|
|
465
|
-
|
|
407
|
+
await $Http(ep.path, data, ep.dropValues, ep.dropKeyValue);
|
|
408
|
+
|
|
409
|
+
MessagePlugin.success("删除成功");
|
|
410
|
+
destroy();
|
|
411
|
+
$Emit("deleted", { row: row });
|
|
412
|
+
await $Method.reload({ keepSelection: true });
|
|
413
|
+
} catch (error) {
|
|
414
|
+
MessagePlugin.error("删除失败");
|
|
415
|
+
} finally {
|
|
416
|
+
if (dialog && typeof dialog.setConfirmLoading === "function") {
|
|
417
|
+
dialog.setConfirmLoading(false);
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
},
|
|
421
|
+
onClose: () => {
|
|
422
|
+
destroy();
|
|
423
|
+
}
|
|
424
|
+
});
|
|
425
|
+
},
|
|
426
|
+
buildOperationSlotProps(scope) {
|
|
427
|
+
const out = {};
|
|
466
428
|
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
MessagePlugin.error("未配置删除接口");
|
|
471
|
-
return;
|
|
472
|
-
}
|
|
429
|
+
for (const key of Object.keys(scope)) {
|
|
430
|
+
out[key] = scope[key];
|
|
431
|
+
}
|
|
473
432
|
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
const rawId = record[idKey];
|
|
433
|
+
out["deleteRow"] = $Method.deleteRow;
|
|
434
|
+
out["reload"] = $Method.reload;
|
|
477
435
|
|
|
478
|
-
|
|
479
|
-
MessagePlugin.error("删除失败:缺少主键");
|
|
480
|
-
return;
|
|
436
|
+
return out;
|
|
481
437
|
}
|
|
438
|
+
};
|
|
439
|
+
|
|
440
|
+
const $Computed = reactive({
|
|
441
|
+
columnsMeta: computed(() => {
|
|
442
|
+
const tableColumns = [];
|
|
443
|
+
const extraDetailColumns = [];
|
|
444
|
+
const tableColumnMap = {};
|
|
445
|
+
const formatKeys = [];
|
|
446
|
+
|
|
447
|
+
const cols = $Method.filterValidColumns($Prop.columns);
|
|
448
|
+
for (const col of cols) {
|
|
449
|
+
if (col?.detail === true) {
|
|
450
|
+
extraDetailColumns.push(col);
|
|
451
|
+
continue;
|
|
452
|
+
}
|
|
482
453
|
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
let dialog = null;
|
|
486
|
-
let destroyed = false;
|
|
454
|
+
tableColumns.push(col);
|
|
487
455
|
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
if (dialog && typeof dialog.destroy === "function") {
|
|
492
|
-
dialog.destroy();
|
|
493
|
-
}
|
|
494
|
-
};
|
|
495
|
-
|
|
496
|
-
dialog = DialogPlugin.confirm({
|
|
497
|
-
header: confirmContent.header,
|
|
498
|
-
body: confirmContent.body,
|
|
499
|
-
status: confirmContent.status || "warning",
|
|
500
|
-
confirmBtn: confirmContent.confirmBtn || "删除",
|
|
501
|
-
cancelBtn: confirmContent.cancelBtn || "取消",
|
|
502
|
-
onConfirm: async () => {
|
|
503
|
-
if (dialog && typeof dialog.setConfirmLoading === "function") {
|
|
504
|
-
dialog.setConfirmLoading(true);
|
|
456
|
+
const key = $Method.getColKey(col);
|
|
457
|
+
if (!key) {
|
|
458
|
+
continue;
|
|
505
459
|
}
|
|
506
460
|
|
|
507
|
-
|
|
508
|
-
const data = {};
|
|
509
|
-
data[idKey] = rawId;
|
|
461
|
+
tableColumnMap[key] = col;
|
|
510
462
|
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
}
|
|
517
|
-
}
|
|
518
|
-
}
|
|
463
|
+
const format = col.format;
|
|
464
|
+
if ((typeof format === "string" && format.trim().length > 0) || typeof format === "function") {
|
|
465
|
+
formatKeys.push(key);
|
|
466
|
+
}
|
|
467
|
+
}
|
|
519
468
|
|
|
520
|
-
|
|
469
|
+
const detailFields = extraDetailColumns.length > 0 ? $Method.mergeDetailColumns(tableColumns, extraDetailColumns) : tableColumns;
|
|
521
470
|
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
471
|
+
return {
|
|
472
|
+
tableColumns: tableColumns,
|
|
473
|
+
detailFields: detailFields,
|
|
474
|
+
tableColumnMap: tableColumnMap,
|
|
475
|
+
formatKeys: formatKeys
|
|
476
|
+
};
|
|
477
|
+
}),
|
|
478
|
+
tableColumns: computed(() => $Computed.columnsMeta.tableColumns),
|
|
479
|
+
detailFields: computed(() => $Computed.columnsMeta.detailFields),
|
|
480
|
+
resolvedTableHeight: computed(() => {
|
|
481
|
+
if ($Prop.isPagination) {
|
|
482
|
+
return $Prop.tableHeight;
|
|
483
|
+
}
|
|
484
|
+
return "calc(100vh - var(--search-height) - var(--layout-gap) * 2)";
|
|
485
|
+
}),
|
|
486
|
+
forwardedTableSlotNames: computed(() => {
|
|
487
|
+
if (Array.isArray($Prop.tableSlotNames) && $Prop.tableSlotNames.length > 0) {
|
|
488
|
+
const out = [];
|
|
489
|
+
const set = new Set();
|
|
490
|
+
for (const name of $Prop.tableSlotNames) {
|
|
491
|
+
if (typeof name !== "string") continue;
|
|
492
|
+
const trimmed = name.trim();
|
|
493
|
+
if (trimmed.length === 0) continue;
|
|
494
|
+
if (set.has(trimmed)) continue;
|
|
495
|
+
set.add(trimmed);
|
|
496
|
+
out.push(trimmed);
|
|
532
497
|
}
|
|
533
|
-
|
|
534
|
-
onClose: () => {
|
|
535
|
-
destroy();
|
|
498
|
+
return out;
|
|
536
499
|
}
|
|
537
|
-
});
|
|
538
|
-
}
|
|
539
500
|
|
|
540
|
-
|
|
541
|
-
|
|
501
|
+
const names = [];
|
|
502
|
+
for (const key of Object.keys($From.slots)) {
|
|
503
|
+
if ($Const.reservedSlotNames.includes(key)) continue;
|
|
504
|
+
names.push(key);
|
|
505
|
+
}
|
|
542
506
|
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
507
|
+
return names;
|
|
508
|
+
}),
|
|
509
|
+
hasToolBar: computed(() => {
|
|
510
|
+
return Boolean($From.slots.toolLeft) || Boolean($From.slots.toolRight);
|
|
511
|
+
}),
|
|
512
|
+
tableRenderSlotNames: computed(() => {
|
|
513
|
+
const out = [];
|
|
514
|
+
const set = new Set();
|
|
546
515
|
|
|
547
|
-
|
|
548
|
-
|
|
516
|
+
for (const name of $Computed.forwardedTableSlotNames) {
|
|
517
|
+
if (!name || set.has(name)) {
|
|
518
|
+
continue;
|
|
519
|
+
}
|
|
520
|
+
set.add(name);
|
|
521
|
+
out.push(name);
|
|
522
|
+
}
|
|
549
523
|
|
|
550
|
-
|
|
551
|
-
|
|
524
|
+
for (const key of $Computed.columnsMeta.formatKeys) {
|
|
525
|
+
if (!key || set.has(key)) {
|
|
526
|
+
continue;
|
|
527
|
+
}
|
|
528
|
+
set.add(key);
|
|
529
|
+
out.push(key);
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
return out;
|
|
533
|
+
})
|
|
534
|
+
});
|
|
552
535
|
|
|
553
536
|
defineExpose({
|
|
554
|
-
reload: reload,
|
|
555
|
-
deleteRow: deleteRow,
|
|
537
|
+
reload: $Method.reload,
|
|
538
|
+
deleteRow: $Method.deleteRow,
|
|
556
539
|
rows: $Data.rows,
|
|
557
540
|
pager: $Data.pager,
|
|
558
541
|
currentRow: $Data.currentRow
|
|
559
542
|
});
|
|
560
543
|
|
|
561
544
|
onMounted(() => {
|
|
562
|
-
if (
|
|
563
|
-
reload({ keepSelection: false });
|
|
545
|
+
if (!$Prop.autoLoad) return;
|
|
546
|
+
$Method.reload({ keepSelection: false });
|
|
564
547
|
});
|
|
565
548
|
</script>
|
|
566
549
|
|