befly-admin-ui 1.10.1 → 1.10.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components/detailPanel.vue +52 -54
- package/components/pageDialog.vue +131 -117
- package/components/pageTableDetail.vue +381 -402
- 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 +51 -55
- package/views/config/dictType/components/edit.vue +81 -57
- package/views/config/dictType/index.vue +37 -39
- package/views/config/system/components/edit.vue +97 -86
- package/views/config/system/index.vue +35 -37
- 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 +96 -85
- package/views/log/error/index.vue +111 -117
- package/views/log/login/index.vue +15 -13
- package/views/log/operate/index.vue +31 -31
- package/views/login_1/index.vue +50 -32
- package/views/people/admin/components/edit.vue +1 -1
- package/views/people/admin/index.vue +27 -28
- package/views/permission/api/index.vue +44 -45
- package/views/permission/menu/index.vue +35 -35
- 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 +47 -49
- package/views/resource/gallery/index.vue +77 -78
- package/LICENSE +0 -201
|
@@ -1,42 +1,42 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div :class="['page-table-detail', 'page-table', { 'page-table--with-pagination':
|
|
3
|
-
<div v-if="hasToolBar" 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,485 +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
|
-
|
|
193
|
-
const detailFields = extraDetailColumns.length > 0 ? mergeDetailColumns(tableColumns, extraDetailColumns) : tableColumns;
|
|
194
|
-
|
|
195
|
-
return {
|
|
196
|
-
tableColumns: tableColumns,
|
|
197
|
-
detailFields: detailFields,
|
|
198
|
-
tableColumnMap: tableColumnMap,
|
|
199
|
-
formatKeys: formatKeys
|
|
200
|
-
};
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
const tableColumns = computed(() => columnsMeta.value.tableColumns);
|
|
204
|
-
|
|
205
|
-
const detailFields = computed(() => columnsMeta.value.detailFields);
|
|
206
|
-
|
|
207
|
-
const resolvedTableHeight = computed(() => {
|
|
208
|
-
if (props.isPagination) {
|
|
209
|
-
return props.tableHeight;
|
|
210
|
-
}
|
|
211
|
-
return "calc(100vh - var(--search-height) - var(--layout-gap) * 2)";
|
|
212
|
-
});
|
|
213
211
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
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
225
|
}
|
|
226
|
-
return out;
|
|
227
|
-
}
|
|
228
226
|
|
|
229
|
-
|
|
230
|
-
const reserved = ["toolLeft", "toolRight", "detail", "dialogs", "operation", "default"]; // operation 单独处理
|
|
227
|
+
const preferKey = options?.keepSelection ? ($Data.currentRow ? $Method.getRowKeyValue($Data.currentRow) : null) : null;
|
|
231
228
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
names.push(key);
|
|
235
|
-
}
|
|
229
|
+
$From.requestSeq += 1;
|
|
230
|
+
const seq = $From.requestSeq;
|
|
236
231
|
|
|
237
|
-
|
|
238
|
-
|
|
232
|
+
$Data.loading = true;
|
|
233
|
+
try {
|
|
234
|
+
const pageKey = listEndpoint.pageKey || "page";
|
|
235
|
+
const limitKey = listEndpoint.limitKey || "limit";
|
|
239
236
|
|
|
240
|
-
const
|
|
241
|
-
|
|
242
|
-
|
|
237
|
+
const data = {};
|
|
238
|
+
data[pageKey] = $Data.pager.currentPage;
|
|
239
|
+
data[limitKey] = $Data.pager.limit;
|
|
243
240
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
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
|
+
}
|
|
247
252
|
|
|
248
|
-
|
|
249
|
-
if (!name || set.has(name)) {
|
|
250
|
-
continue;
|
|
251
|
-
}
|
|
252
|
-
set.add(name);
|
|
253
|
-
out.push(name);
|
|
254
|
-
}
|
|
253
|
+
const res = await $Http(listEndpoint.path, data, listEndpoint.dropValues, listEndpoint.dropKeyValue);
|
|
255
254
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
}
|
|
260
|
-
set.add(key);
|
|
261
|
-
out.push(key);
|
|
262
|
-
}
|
|
255
|
+
if (seq !== $From.requestSeq) {
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
263
258
|
|
|
264
|
-
|
|
265
|
-
|
|
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
|
+
}
|
|
266
274
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
const value = record[colKey];
|
|
270
|
-
const field = columnsMeta.value.tableColumnMap[colKey] || {};
|
|
271
|
-
return formatFieldValue(value, field);
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
function setCurrentRow(row) {
|
|
275
|
-
$Data.currentRow = row;
|
|
276
|
-
emit("row-change", { row: row });
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
function getRowKeyValue(row) {
|
|
280
|
-
const key = props.rowKey;
|
|
281
|
-
if (!key) return null;
|
|
282
|
-
|
|
283
|
-
const record = row;
|
|
284
|
-
const raw = record[key];
|
|
285
|
-
if (typeof raw === "string") return raw;
|
|
286
|
-
if (typeof raw === "number") return raw;
|
|
287
|
-
return null;
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
function applyAutoSelection(list, preferKey) {
|
|
291
|
-
if (!Array.isArray(list) || list.length === 0) {
|
|
292
|
-
setCurrentRow(null);
|
|
293
|
-
$Data.activeRowKeys = [];
|
|
294
|
-
return;
|
|
295
|
-
}
|
|
275
|
+
$Data.rows = lists;
|
|
276
|
+
$Data.pager.total = total;
|
|
296
277
|
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
if (
|
|
301
|
-
setCurrentRow(row);
|
|
302
|
-
$Data.activeRowKeys = [k];
|
|
278
|
+
$Method.applyAutoSelection(lists, preferKey);
|
|
279
|
+
$Emit("loaded", { rows: lists, total: total });
|
|
280
|
+
} catch (error) {
|
|
281
|
+
if (seq !== $From.requestSeq) {
|
|
303
282
|
return;
|
|
304
283
|
}
|
|
284
|
+
MessagePlugin.error("加载数据失败");
|
|
285
|
+
} finally {
|
|
286
|
+
if (seq === $From.requestSeq) {
|
|
287
|
+
$Data.loading = false;
|
|
288
|
+
}
|
|
305
289
|
}
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
const listEndpoint = props.endpoints?.list;
|
|
330
|
-
if (!listEndpoint) {
|
|
331
|
-
return;
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
const preferKey = options?.keepSelection ? ($Data.currentRow ? getRowKeyValue($Data.currentRow) : null) : null;
|
|
335
|
-
|
|
336
|
-
requestSeq += 1;
|
|
337
|
-
const seq = requestSeq;
|
|
338
|
-
|
|
339
|
-
$Data.loading = true;
|
|
340
|
-
try {
|
|
341
|
-
const pageKey = listEndpoint.pageKey || "page";
|
|
342
|
-
const limitKey = listEndpoint.limitKey || "limit";
|
|
343
|
-
|
|
344
|
-
const data = {};
|
|
345
|
-
data[pageKey] = $Data.pager.currentPage;
|
|
346
|
-
data[limitKey] = $Data.pager.limit;
|
|
347
|
-
|
|
348
|
-
if (listEndpoint.buildData) {
|
|
349
|
-
const extra = listEndpoint.buildData({
|
|
350
|
-
currentPage: $Data.pager.currentPage,
|
|
351
|
-
limit: $Data.pager.limit
|
|
352
|
-
});
|
|
353
|
-
if (extra && typeof extra === "object") {
|
|
354
|
-
for (const k of Object.keys(extra)) {
|
|
355
|
-
data[k] = extra[k];
|
|
356
|
-
}
|
|
290
|
+
},
|
|
291
|
+
async reload(options) {
|
|
292
|
+
if (options?.resetPage) {
|
|
293
|
+
$Data.pager.currentPage = 1;
|
|
294
|
+
}
|
|
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) {
|
|
312
|
+
return;
|
|
357
313
|
}
|
|
314
|
+
|
|
315
|
+
$Data.activeRowKeys = [];
|
|
316
|
+
$Method.setCurrentRow(null);
|
|
317
|
+
return;
|
|
358
318
|
}
|
|
359
319
|
|
|
360
|
-
|
|
320
|
+
$Data.activeRowKeys = value;
|
|
361
321
|
|
|
362
|
-
|
|
363
|
-
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);
|
|
364
326
|
return;
|
|
365
327
|
}
|
|
366
328
|
|
|
367
|
-
const
|
|
368
|
-
const
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
if (allowPageFallback && lists.length === 0 && total > 0) {
|
|
373
|
-
const lastPage = getLastPage(total, $Data.pager.limit);
|
|
374
|
-
if ($Data.pager.currentPage > lastPage) {
|
|
375
|
-
$Data.pager.currentPage = lastPage;
|
|
376
|
-
await loadList({
|
|
377
|
-
keepSelection: false,
|
|
378
|
-
allowPageFallback: false
|
|
379
|
-
});
|
|
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);
|
|
380
334
|
return;
|
|
381
335
|
}
|
|
382
336
|
}
|
|
337
|
+
},
|
|
338
|
+
getDeleteConfirmContent(ep, row) {
|
|
339
|
+
const confirm = ep.confirm;
|
|
340
|
+
if (!confirm) {
|
|
341
|
+
return {
|
|
342
|
+
header: "确认删除",
|
|
343
|
+
body: "确认删除该记录吗?",
|
|
344
|
+
confirmBtn: "删除"
|
|
345
|
+
};
|
|
346
|
+
}
|
|
383
347
|
|
|
384
|
-
|
|
385
|
-
|
|
348
|
+
if (typeof confirm === "function") {
|
|
349
|
+
return confirm(row);
|
|
350
|
+
}
|
|
386
351
|
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
352
|
+
return confirm;
|
|
353
|
+
},
|
|
354
|
+
async deleteRow(row) {
|
|
355
|
+
const ep = $Prop.endpoints?.delete;
|
|
356
|
+
if (!ep) {
|
|
357
|
+
MessagePlugin.error("未配置删除接口");
|
|
391
358
|
return;
|
|
392
359
|
}
|
|
393
|
-
MessagePlugin.error("加载数据失败");
|
|
394
|
-
} finally {
|
|
395
|
-
if (seq === requestSeq) {
|
|
396
|
-
$Data.loading = false;
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
360
|
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
allowPageFallback: true
|
|
408
|
-
});
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
function onPageChange(info) {
|
|
412
|
-
$Data.pager.currentPage = info.currentPage;
|
|
413
|
-
reload({ keepSelection: true });
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
function onPageSizeChange(info) {
|
|
417
|
-
$Data.pager.limit = info.pageSize;
|
|
418
|
-
$Data.pager.currentPage = 1;
|
|
419
|
-
reload({ keepSelection: false });
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
function onActiveChange(value, context) {
|
|
423
|
-
// 禁止取消高亮:如果新值为空,保持当前选中
|
|
424
|
-
if (value.length === 0) {
|
|
425
|
-
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("删除失败:缺少主键");
|
|
426
367
|
return;
|
|
427
368
|
}
|
|
428
369
|
|
|
429
|
-
$
|
|
430
|
-
setCurrentRow(null);
|
|
431
|
-
return;
|
|
432
|
-
}
|
|
370
|
+
const confirmContent = $Method.getDeleteConfirmContent(ep, row);
|
|
433
371
|
|
|
434
|
-
|
|
372
|
+
let dialog = null;
|
|
373
|
+
let destroyed = false;
|
|
435
374
|
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
375
|
+
const destroy = () => {
|
|
376
|
+
if (destroyed) return;
|
|
377
|
+
destroyed = true;
|
|
378
|
+
if (dialog && typeof dialog.destroy === "function") {
|
|
379
|
+
dialog.destroy();
|
|
380
|
+
}
|
|
381
|
+
};
|
|
442
382
|
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
}
|
|
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
|
+
}
|
|
453
393
|
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
return {
|
|
458
|
-
header: "确认删除",
|
|
459
|
-
body: "确认删除该记录吗?",
|
|
460
|
-
confirmBtn: "删除"
|
|
461
|
-
};
|
|
462
|
-
}
|
|
394
|
+
try {
|
|
395
|
+
const data = {};
|
|
396
|
+
data[idKey] = rawId;
|
|
463
397
|
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
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
|
+
}
|
|
467
406
|
|
|
468
|
-
|
|
469
|
-
|
|
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 = {};
|
|
470
428
|
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
MessagePlugin.error("未配置删除接口");
|
|
475
|
-
return;
|
|
476
|
-
}
|
|
429
|
+
for (const key of Object.keys(scope)) {
|
|
430
|
+
out[key] = scope[key];
|
|
431
|
+
}
|
|
477
432
|
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
const rawId = record[idKey];
|
|
433
|
+
out["deleteRow"] = $Method.deleteRow;
|
|
434
|
+
out["reload"] = $Method.reload;
|
|
481
435
|
|
|
482
|
-
|
|
483
|
-
MessagePlugin.error("删除失败:缺少主键");
|
|
484
|
-
return;
|
|
436
|
+
return out;
|
|
485
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
|
+
}
|
|
486
453
|
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
let dialog = null;
|
|
490
|
-
let destroyed = false;
|
|
454
|
+
tableColumns.push(col);
|
|
491
455
|
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
if (dialog && typeof dialog.destroy === "function") {
|
|
496
|
-
dialog.destroy();
|
|
497
|
-
}
|
|
498
|
-
};
|
|
499
|
-
|
|
500
|
-
dialog = DialogPlugin.confirm({
|
|
501
|
-
header: confirmContent.header,
|
|
502
|
-
body: confirmContent.body,
|
|
503
|
-
status: confirmContent.status || "warning",
|
|
504
|
-
confirmBtn: confirmContent.confirmBtn || "删除",
|
|
505
|
-
cancelBtn: confirmContent.cancelBtn || "取消",
|
|
506
|
-
onConfirm: async () => {
|
|
507
|
-
if (dialog && typeof dialog.setConfirmLoading === "function") {
|
|
508
|
-
dialog.setConfirmLoading(true);
|
|
456
|
+
const key = $Method.getColKey(col);
|
|
457
|
+
if (!key) {
|
|
458
|
+
continue;
|
|
509
459
|
}
|
|
510
460
|
|
|
511
|
-
|
|
512
|
-
const data = {};
|
|
513
|
-
data[idKey] = rawId;
|
|
461
|
+
tableColumnMap[key] = col;
|
|
514
462
|
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
}
|
|
521
|
-
}
|
|
522
|
-
}
|
|
463
|
+
const format = col.format;
|
|
464
|
+
if ((typeof format === "string" && format.trim().length > 0) || typeof format === "function") {
|
|
465
|
+
formatKeys.push(key);
|
|
466
|
+
}
|
|
467
|
+
}
|
|
523
468
|
|
|
524
|
-
|
|
469
|
+
const detailFields = extraDetailColumns.length > 0 ? $Method.mergeDetailColumns(tableColumns, extraDetailColumns) : tableColumns;
|
|
525
470
|
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
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);
|
|
536
497
|
}
|
|
537
|
-
|
|
538
|
-
onClose: () => {
|
|
539
|
-
destroy();
|
|
498
|
+
return out;
|
|
540
499
|
}
|
|
541
|
-
});
|
|
542
|
-
}
|
|
543
500
|
|
|
544
|
-
|
|
545
|
-
|
|
501
|
+
const names = [];
|
|
502
|
+
for (const key of Object.keys($From.slots)) {
|
|
503
|
+
if ($Const.reservedSlotNames.includes(key)) continue;
|
|
504
|
+
names.push(key);
|
|
505
|
+
}
|
|
546
506
|
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
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();
|
|
550
515
|
|
|
551
|
-
|
|
552
|
-
|
|
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
|
+
}
|
|
553
523
|
|
|
554
|
-
|
|
555
|
-
|
|
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
|
+
});
|
|
556
535
|
|
|
557
536
|
defineExpose({
|
|
558
|
-
reload: reload,
|
|
559
|
-
deleteRow: deleteRow,
|
|
537
|
+
reload: $Method.reload,
|
|
538
|
+
deleteRow: $Method.deleteRow,
|
|
560
539
|
rows: $Data.rows,
|
|
561
540
|
pager: $Data.pager,
|
|
562
541
|
currentRow: $Data.currentRow
|
|
563
542
|
});
|
|
564
543
|
|
|
565
544
|
onMounted(() => {
|
|
566
|
-
if (
|
|
567
|
-
reload({ keepSelection: false });
|
|
545
|
+
if (!$Prop.autoLoad) return;
|
|
546
|
+
$Method.reload({ keepSelection: false });
|
|
568
547
|
});
|
|
569
548
|
</script>
|
|
570
549
|
|