@neatui/vue 2.7.0 → 2.7.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/package.json +1 -1
- package/src/components/form/Upload.vue +22 -38
- package/src/components/loader/FormLoader/FormLoader@v2.vue +178 -180
- package/src/components/loader/LimitLoader/LimitLoader@v3.vue +17 -0
- package/src/components/loader/TableLoader/index.ts +47 -0
- package/src/components/loader/TableLoader@v3/TableColView@v3.vue +155 -0
- package/src/components/loader/TableLoader@v3/TableLoader@v3.vue +636 -0
- package/src/components/loader/TableLoader@v3/index@v3.ts +41 -0
- package/src/components/loader/index.ts +2 -1
- package/src/components/tools/Pagination@a.vue +16 -17
- package/src/components/tools/Pagination@b.vue +16 -16
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div ui-flex="row lm :wrap" class="neatui-upload mb-sm-sub mr-sm-sub" v-bind="{ ...attrs }">
|
|
3
|
-
<div v-for="(file, idx) in state.files" :key="idx" ui-flex="col cm" class="flex-fixed bg-fore n-sl w-ms h-ms b-solid bk-
|
|
3
|
+
<div v-for="(file, idx) in state.files" :key="idx" ui-flex="col cm" class="flex-fixed bg-fore n-sl w-ms h-ms b-solid bk-case b-xs r-sm pr" v-bind="itemAttrs">
|
|
4
4
|
<!-- 删除按钮 -->
|
|
5
5
|
<div class="pa ot-ss or-ss bg-fore co-risk lh-xs r-xl parent-hover:show" @click="remove(idx)">
|
|
6
6
|
<svg class="block" viewBox="0 0 1024 1024" style="width: 1em; height: 1em">
|
|
@@ -147,7 +147,7 @@
|
|
|
147
147
|
</svg>
|
|
148
148
|
</template>
|
|
149
149
|
|
|
150
|
-
<!--
|
|
150
|
+
<!-- 上传状态 -->
|
|
151
151
|
<div v-if="file.status === 'uploading'" class="upload-status">
|
|
152
152
|
<div class="loading-spinner"></div>
|
|
153
153
|
<span class="status-text">上传中...</span>
|
|
@@ -155,15 +155,12 @@
|
|
|
155
155
|
<div v-else-if="file.status === 'error'" class="upload-status error">
|
|
156
156
|
<span class="status-text">上传失败</span>
|
|
157
157
|
</div>
|
|
158
|
-
|
|
159
|
-
<!-- 文件名 -->
|
|
160
|
-
<!-- <p ui-omit="1" class="fs-ss ac">{{ file.name }}</p> -->
|
|
161
158
|
</div>
|
|
162
159
|
|
|
163
160
|
<!-- 上传按钮 -->
|
|
164
161
|
<div v-if="showUploadButton">
|
|
165
|
-
<slot>
|
|
166
|
-
<label ui-flex="row cm" ui-form="@a type:upload tips:hover" :class="`upload w-ms h-ms n-sl bg-fore b-solid bk-
|
|
162
|
+
<slot name="btn">
|
|
163
|
+
<label ui-flex="row cm" ui-form="@a type:upload tips:hover" :class="`upload w-ms h-ms n-sl bg-fore b-solid bk-case b-xs r-sm ${uploadClass}`" :style="uploadStyle">
|
|
167
164
|
<div v-if="tips" ui-form-tips>
|
|
168
165
|
{{ tips }}
|
|
169
166
|
</div>
|
|
@@ -179,53 +176,40 @@
|
|
|
179
176
|
</label>
|
|
180
177
|
</slot>
|
|
181
178
|
</div>
|
|
182
|
-
<Layer :id="layerId" am="as"></Layer>
|
|
183
179
|
</div>
|
|
184
180
|
</template>
|
|
185
181
|
<script setup lang="ts">
|
|
186
|
-
import { reactive,
|
|
187
|
-
import { Image } from '../display';
|
|
188
|
-
import draggable from 'vuedraggable';
|
|
182
|
+
import { reactive, watch, onUnmounted, computed } from 'vue';
|
|
189
183
|
import Compressor from 'compressorjs';
|
|
190
|
-
import { Layer, LayerById } from '../basic';
|
|
191
|
-
import { isArray, isFunction } from '@fekit/utils';
|
|
192
|
-
|
|
193
|
-
const layerId = Math.random().toString(36).slice(-6);
|
|
194
184
|
|
|
195
185
|
interface Props {
|
|
196
186
|
modelValue?: string | any[];
|
|
197
|
-
// 文件数量限制
|
|
198
187
|
max?: number;
|
|
199
188
|
attrs?: object;
|
|
189
|
+
itemAttrs?: object;
|
|
200
190
|
uploadClass?: string;
|
|
201
191
|
uploadStyle?: string;
|
|
202
|
-
|
|
203
|
-
tips?: string; // 提示文案
|
|
204
|
-
// 文件类型
|
|
192
|
+
tips?: string;
|
|
205
193
|
accept?: string | 'image/*' | 'video/*' | 'audio/*';
|
|
206
|
-
// 是否需要抠图处理
|
|
207
|
-
crop?: boolean;
|
|
208
|
-
// 请求上传接口
|
|
209
194
|
upload?: (formData: FormData) => Promise<any>;
|
|
210
|
-
// 文件大小限制(MB)
|
|
211
195
|
maxSize?: number;
|
|
212
|
-
// 是否启用图片压缩
|
|
213
196
|
compress?: boolean;
|
|
197
|
+
disabled?: boolean;
|
|
214
198
|
}
|
|
215
199
|
|
|
216
200
|
const props = withDefaults(defineProps<Props>(), {
|
|
217
201
|
modelValue: '',
|
|
218
202
|
uploadClass: '',
|
|
219
203
|
uploadStyle: '',
|
|
220
|
-
id: '',
|
|
221
204
|
attrs: () => ({}),
|
|
205
|
+
itemAttrs: () => ({}),
|
|
222
206
|
tips: '',
|
|
223
207
|
accept: '*',
|
|
224
|
-
crop: false,
|
|
225
208
|
upload: async () => null,
|
|
226
|
-
maxSize: 10,
|
|
209
|
+
maxSize: 10,
|
|
227
210
|
compress: true,
|
|
228
|
-
max: 0
|
|
211
|
+
max: 0,
|
|
212
|
+
disabled: false,
|
|
229
213
|
});
|
|
230
214
|
|
|
231
215
|
interface UploadFile {
|
|
@@ -243,7 +227,7 @@
|
|
|
243
227
|
isInternalUpdate: boolean; // 标记是否为内部更新
|
|
244
228
|
}>({
|
|
245
229
|
files: [],
|
|
246
|
-
isInternalUpdate: false
|
|
230
|
+
isInternalUpdate: false,
|
|
247
231
|
});
|
|
248
232
|
|
|
249
233
|
const emit = defineEmits(['update:modelValue', 'change', 'error']);
|
|
@@ -331,7 +315,7 @@
|
|
|
331
315
|
success: (result) => {
|
|
332
316
|
resolve(new File([result], file.name, { type: result.type }));
|
|
333
317
|
},
|
|
334
|
-
error: reject
|
|
318
|
+
error: reject,
|
|
335
319
|
});
|
|
336
320
|
});
|
|
337
321
|
};
|
|
@@ -412,7 +396,7 @@
|
|
|
412
396
|
type: getFileType(file),
|
|
413
397
|
path: previewUrl,
|
|
414
398
|
status: 'uploading',
|
|
415
|
-
size: file.size
|
|
399
|
+
size: file.size,
|
|
416
400
|
};
|
|
417
401
|
state.files.push(uploadFile);
|
|
418
402
|
validFiles.push({ file, uploadFile });
|
|
@@ -492,7 +476,7 @@
|
|
|
492
476
|
type: 'image',
|
|
493
477
|
path: item,
|
|
494
478
|
status: 'success' as const,
|
|
495
|
-
result: item
|
|
479
|
+
result: item,
|
|
496
480
|
};
|
|
497
481
|
} else {
|
|
498
482
|
// 如果是对象
|
|
@@ -501,7 +485,7 @@
|
|
|
501
485
|
type: item.type || 'file',
|
|
502
486
|
path: item.url || item.path || '',
|
|
503
487
|
status: 'success' as const,
|
|
504
|
-
result: item
|
|
488
|
+
result: item,
|
|
505
489
|
};
|
|
506
490
|
}
|
|
507
491
|
});
|
|
@@ -512,8 +496,8 @@
|
|
|
512
496
|
type: 'image',
|
|
513
497
|
path: newValue,
|
|
514
498
|
status: 'success',
|
|
515
|
-
result: newValue
|
|
516
|
-
}
|
|
499
|
+
result: newValue,
|
|
500
|
+
},
|
|
517
501
|
];
|
|
518
502
|
} else if (newValue && typeof newValue === 'object') {
|
|
519
503
|
const objValue = newValue as any;
|
|
@@ -523,14 +507,14 @@
|
|
|
523
507
|
type: objValue.type || 'file',
|
|
524
508
|
path: objValue.url || objValue.path || '',
|
|
525
509
|
status: 'success',
|
|
526
|
-
result: newValue
|
|
527
|
-
}
|
|
510
|
+
result: newValue,
|
|
511
|
+
},
|
|
528
512
|
];
|
|
529
513
|
} else {
|
|
530
514
|
state.files = [];
|
|
531
515
|
}
|
|
532
516
|
},
|
|
533
|
-
{ immediate: true, deep: true }
|
|
517
|
+
{ immediate: true, deep: true },
|
|
534
518
|
);
|
|
535
519
|
|
|
536
520
|
// 组件销毁时清理资源
|
|
@@ -1,186 +1,184 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
<
|
|
4
|
-
<
|
|
5
|
-
<
|
|
6
|
-
<
|
|
7
|
-
<
|
|
8
|
-
|
|
9
|
-
<
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
<
|
|
15
|
-
|
|
16
|
-
<
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
<
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
<div
|
|
175
|
-
<
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
<
|
|
179
|
-
<slot name="submit"></slot>
|
|
180
|
-
</div>
|
|
2
|
+
<div :ui-row="rows" class="n-sl-sub">
|
|
3
|
+
<template v-for="(col, idx) in state.form" :key="idx">
|
|
4
|
+
<div v-if="!col.clear" :id="col._fid" :ui-col="col.media" :ui-flex="`${vertical ? 'col xm' : 'row lt'}`">
|
|
5
|
+
<template v-if="col.label">
|
|
6
|
+
<h6 v-if="vertical" :style="`${col.rules?.some((validator: any) => validator.required) ? 'text-indent: -1em' : ''}`" class="o-ls">
|
|
7
|
+
<template v-if="col.label == '*'"></template>
|
|
8
|
+
<template v-else>
|
|
9
|
+
<b v-if="col.rules?.some((validator: any) => validator.required)" class="co-risk pr" style="left: 0.1em">﹡</b>
|
|
10
|
+
<span>{{ col.label ? col.label + ':' : '' }}</span>
|
|
11
|
+
</template>
|
|
12
|
+
</h6>
|
|
13
|
+
<p v-else :class="`${clh({ ...(col.model[1] || {}) })}`" :style="`width:${state._lw + 'em'}; max-width:50%;`" class="ar nr-sm flex-fixed o-ls">
|
|
14
|
+
<template v-if="col.label == '*'"></template>
|
|
15
|
+
<template v-else>
|
|
16
|
+
<b v-if="col.rules?.some((validator: any) => validator.required)" class="co-risk">﹡</b>
|
|
17
|
+
<span>{{ col.label ? col.label + ':' : '' }}</span>
|
|
18
|
+
</template>
|
|
19
|
+
</p>
|
|
20
|
+
</template>
|
|
21
|
+
<Input v-if="col.model[0] === 'Input'" v-model="col._data[col.field]" :interacted="interacted" :rules="col.rules" class="full-w" v-bind="{ ...(col.model[1] || {}) }" />
|
|
22
|
+
<Select
|
|
23
|
+
v-else-if="col.model[0] === 'Select'"
|
|
24
|
+
v-model="col._data[col.field]"
|
|
25
|
+
:interacted="interacted"
|
|
26
|
+
:options="col.enums"
|
|
27
|
+
:rules="col?.rules"
|
|
28
|
+
class="full-w"
|
|
29
|
+
v-bind="{ ...(col.model[1] || {}) }"
|
|
30
|
+
></Select>
|
|
31
|
+
<SelectList
|
|
32
|
+
v-else-if="col.model[0] === 'SelectList'"
|
|
33
|
+
v-model="col._data[col.field]"
|
|
34
|
+
:interacted="interacted"
|
|
35
|
+
:options="col.enums"
|
|
36
|
+
:rules="col?.rules"
|
|
37
|
+
class="full-w"
|
|
38
|
+
v-bind="{ ...(col.model[1] || {}) }"
|
|
39
|
+
/>
|
|
40
|
+
<SelectTags
|
|
41
|
+
v-else-if="col.model[0] === 'SelectTags'"
|
|
42
|
+
v-model="col._data[col.field]"
|
|
43
|
+
:interacted="interacted"
|
|
44
|
+
:options="col.enums"
|
|
45
|
+
:rules="col?.rules"
|
|
46
|
+
class="full-w"
|
|
47
|
+
v-bind="{ ...(col.model[1] || {}) }"
|
|
48
|
+
/>
|
|
49
|
+
<SelectPicker
|
|
50
|
+
v-else-if="col.model[0] === 'SelectPicker'"
|
|
51
|
+
v-model="col._data[col.field]"
|
|
52
|
+
:interacted="interacted"
|
|
53
|
+
:options="col.enums"
|
|
54
|
+
:rules="col?.rules"
|
|
55
|
+
class="full-w"
|
|
56
|
+
v-bind="{ ...(col.model[1] || {}) }"
|
|
57
|
+
/>
|
|
58
|
+
<SearchSelect
|
|
59
|
+
v-else-if="col.model[0] === 'SearchSelect'"
|
|
60
|
+
v-model="col._data[col.field]"
|
|
61
|
+
:interacted="interacted"
|
|
62
|
+
:options="col.enums"
|
|
63
|
+
:rules="col.rules"
|
|
64
|
+
class="full-w"
|
|
65
|
+
v-bind="{ ...(col.model[1] || {}) }"
|
|
66
|
+
/>
|
|
67
|
+
<MoreSelect
|
|
68
|
+
v-else-if="col.model[0] === 'MoreSelect'"
|
|
69
|
+
v-model="col._data[col.field]"
|
|
70
|
+
:interacted="interacted"
|
|
71
|
+
:options="col.enums"
|
|
72
|
+
:rules="col.rules"
|
|
73
|
+
class="full-w"
|
|
74
|
+
v-bind="{ ...(col.model[1] || {}) }"
|
|
75
|
+
/>
|
|
76
|
+
<MoreSelectList
|
|
77
|
+
v-else-if="col.model[0] === 'MoreSelectList'"
|
|
78
|
+
v-model="col._data[col.field]"
|
|
79
|
+
:interacted="interacted"
|
|
80
|
+
:options="col.enums"
|
|
81
|
+
:rules="col.rules"
|
|
82
|
+
class="full-w"
|
|
83
|
+
v-bind="{ ...(col.model[1] || {}) }"
|
|
84
|
+
/>
|
|
85
|
+
<MoreSelectTags
|
|
86
|
+
v-else-if="col.model[0] === 'MoreSelectTags'"
|
|
87
|
+
v-model="col._data[col.field]"
|
|
88
|
+
:interacted="interacted"
|
|
89
|
+
:options="col.enums"
|
|
90
|
+
:rules="col.rules"
|
|
91
|
+
class="full-w"
|
|
92
|
+
v-bind="{ ...(col.model[1] || {}) }"
|
|
93
|
+
/>
|
|
94
|
+
<MoreSelectPicker
|
|
95
|
+
v-else-if="col.model[0] === 'MoreSelectPicker'"
|
|
96
|
+
v-model="col._data[col.field]"
|
|
97
|
+
:interacted="interacted"
|
|
98
|
+
:options="col.enums"
|
|
99
|
+
:rules="col.rules"
|
|
100
|
+
class="full-w"
|
|
101
|
+
v-bind="{ ...(col.model[1] || {}) }"
|
|
102
|
+
/>
|
|
103
|
+
<SearchMoreSelect
|
|
104
|
+
v-else-if="col.model[0] === 'SearchMoreSelect'"
|
|
105
|
+
v-model="col._data[col.field]"
|
|
106
|
+
:interacted="interacted"
|
|
107
|
+
:options="col.enums"
|
|
108
|
+
:rules="col.rules"
|
|
109
|
+
class="full-w"
|
|
110
|
+
v-bind="{ ...(col.model[1] || {}) }"
|
|
111
|
+
/>
|
|
112
|
+
<PageSelect
|
|
113
|
+
v-else-if="col.model[0] === 'PageSelect'"
|
|
114
|
+
v-model="col._data[col.field]"
|
|
115
|
+
:interacted="interacted"
|
|
116
|
+
:options="col.enums"
|
|
117
|
+
:rules="col.rules"
|
|
118
|
+
class="full-w"
|
|
119
|
+
v-bind="{ ...(col.model[1] || {}) }"
|
|
120
|
+
/>
|
|
121
|
+
<SelectTree
|
|
122
|
+
v-else-if="col.model[0] === 'SelectTree'"
|
|
123
|
+
v-model="col._data[col.field]"
|
|
124
|
+
:interacted="interacted"
|
|
125
|
+
:options="col.enums"
|
|
126
|
+
:rules="col.rules"
|
|
127
|
+
class="full-w"
|
|
128
|
+
v-bind="{ ...(col.model[1] || {}) }"
|
|
129
|
+
/>
|
|
130
|
+
<DatePicker
|
|
131
|
+
v-else-if="col.model[0] === 'DatePicker'"
|
|
132
|
+
v-model="col._data[col.field]"
|
|
133
|
+
:interacted="interacted"
|
|
134
|
+
:rules="col.rules"
|
|
135
|
+
class="full-w"
|
|
136
|
+
v-bind="{ ...(col.model[1] || {}) }"
|
|
137
|
+
/>
|
|
138
|
+
<DateRangePicker
|
|
139
|
+
v-else-if="col.model[0] === 'DateRangePicker'"
|
|
140
|
+
v-model="col._data[col.field]"
|
|
141
|
+
:interacted="interacted"
|
|
142
|
+
:rules="col.rules"
|
|
143
|
+
class="full-w"
|
|
144
|
+
v-bind="{ ...(col.model[1] || {}) }"
|
|
145
|
+
/>
|
|
146
|
+
<ImgUpload v-else-if="col.model[0] === 'ImgUpload'" v-model="col._data[col.field]" :interacted="interacted" :rules="col.rules" v-bind="{ ...(col.model[1] || {}) }" />
|
|
147
|
+
<Upload v-else-if="col.model[0] === 'Upload'" v-model="col._data[col.field]" :interacted="interacted" :rules="col.rules" v-bind="{ ...(col.model[1] || {}) }" />
|
|
148
|
+
<TextArea
|
|
149
|
+
v-else-if="col.model[0] === 'TextArea'"
|
|
150
|
+
v-model="col._data[col.field]"
|
|
151
|
+
:interacted="interacted"
|
|
152
|
+
:rules="col.rules"
|
|
153
|
+
v-bind="{ ...(col.model[1] || {}) }"
|
|
154
|
+
></TextArea>
|
|
155
|
+
<Switch v-else-if="col.model[0] === 'Switch'" v-model="col._data[col.field]" :interacted="interacted" :rules="col.rules" v-bind="{ ...(col.model[1] || {}) }" />
|
|
156
|
+
<Tree v-else-if="col.model[0] === 'Tree'" v-model="col._data[col.field]" :interacted="interacted" :rules="col.rules" class="mt-sm" v-bind="{ ...(col.model[1] || {}) }" />
|
|
157
|
+
<Cascader
|
|
158
|
+
v-else-if="col.model[0] === 'Cascader'"
|
|
159
|
+
v-model="col._data[col.field]"
|
|
160
|
+
:interacted="interacted"
|
|
161
|
+
:options="col.enums"
|
|
162
|
+
:rules="col.rules"
|
|
163
|
+
class="full-w"
|
|
164
|
+
v-bind="{ ...(col.model[1] || {}) }"
|
|
165
|
+
/>
|
|
166
|
+
<template v-else>
|
|
167
|
+
<slot v-if="col.slot" :name="col.slot" :col="col"></slot>
|
|
168
|
+
<slot v-else-if="col.model[0]" :name="col.model[0]" :col="col"></slot>
|
|
169
|
+
<slot v-else :name="col.field" :col="col"></slot>
|
|
170
|
+
</template>
|
|
171
|
+
</div>
|
|
172
|
+
</template>
|
|
173
|
+
<div :ui-flex="`${vertical ? 'col xm' : 'row xt'}`">
|
|
174
|
+
<div v-if="vertical">
|
|
175
|
+
<slot name="submit"></slot>
|
|
176
|
+
</div>
|
|
177
|
+
<div v-else :style="`padding-left:${state._lw + 'em'};`">
|
|
178
|
+
<slot name="submit"></slot>
|
|
181
179
|
</div>
|
|
182
180
|
</div>
|
|
183
|
-
</
|
|
181
|
+
</div>
|
|
184
182
|
</template>
|
|
185
183
|
<script lang="ts" setup>
|
|
186
184
|
import { watch, reactive, onBeforeUnmount, nextTick } from 'vue';
|
|
@@ -43,6 +43,7 @@
|
|
|
43
43
|
</template>
|
|
44
44
|
</IFollowView>
|
|
45
45
|
<button class="bg-fore" ui-btn="@a s case :border" @click="fResetLimit">{{ words['common.reset'] || '重置' }}</button>
|
|
46
|
+
<button class="bg-fore" ui-btn="@a s case :border" @click="fSearch">{{ words['common.search'] || '搜索' }}</button>
|
|
46
47
|
</div>
|
|
47
48
|
</div>
|
|
48
49
|
</template>
|
|
@@ -91,6 +92,11 @@
|
|
|
91
92
|
tools: false
|
|
92
93
|
});
|
|
93
94
|
|
|
95
|
+
// 定义emit事件
|
|
96
|
+
const emits = defineEmits<{
|
|
97
|
+
search: [param: any];
|
|
98
|
+
}>();
|
|
99
|
+
|
|
94
100
|
// 内部数据
|
|
95
101
|
const state: any = reactive({
|
|
96
102
|
name: computed(() => 'confs' + route.path?.replace(/\//g, '_')),
|
|
@@ -173,5 +179,16 @@
|
|
|
173
179
|
delete state.param[key];
|
|
174
180
|
}
|
|
175
181
|
}
|
|
182
|
+
// 触发搜索事件
|
|
183
|
+
emits('search', state.param);
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
// 搜索功能
|
|
187
|
+
const fSearch = () => {
|
|
188
|
+
// 重置页码
|
|
189
|
+
if (state.param.page) {
|
|
190
|
+
state.param.page = 1;
|
|
191
|
+
}
|
|
192
|
+
emits('search', state.param);
|
|
176
193
|
};
|
|
177
194
|
</script>
|
|
@@ -1,2 +1,49 @@
|
|
|
1
|
+
import { isFunction } from '@fekit/utils';
|
|
1
2
|
import TableLoader from './TableLoader.vue';
|
|
3
|
+
|
|
4
|
+
// 类型定义
|
|
5
|
+
interface ListItem {
|
|
6
|
+
__selected?: boolean;
|
|
7
|
+
[key: string]: any;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
type KeyExtractor<T = ListItem> = string | ((item: T) => any);
|
|
11
|
+
|
|
2
12
|
export default TableLoader;
|
|
13
|
+
|
|
14
|
+
// 是否有选中记录
|
|
15
|
+
export const hasSelected = (lists: ListItem[] = []): boolean => {
|
|
16
|
+
return lists.some((item) => item.__selected === true);
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
// 获取选中记录的数量
|
|
20
|
+
export const getSelectedCount = (lists: ListItem[] = []): number => {
|
|
21
|
+
return lists.filter((item) => item.__selected === true).length;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
// 获取选中的记录
|
|
25
|
+
export const getSelected = <T extends Record<string, any> = ListItem>(lists: T[] = [], key: KeyExtractor<T> = ''): any[] => {
|
|
26
|
+
return (
|
|
27
|
+
lists
|
|
28
|
+
?.filter((item: T) => {
|
|
29
|
+
return item.__selected === true;
|
|
30
|
+
})
|
|
31
|
+
?.map((item: T) => {
|
|
32
|
+
return isFunction(key) ? (key as (item: T) => any)(item) : key ? item[key as string] : item;
|
|
33
|
+
}) || []
|
|
34
|
+
);
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
// 全选计算属性
|
|
38
|
+
export function allSelected(lists: ListItem[] = []) {
|
|
39
|
+
return {
|
|
40
|
+
get(): boolean {
|
|
41
|
+
return lists.length > 0 && lists.every((item) => item.__selected === true);
|
|
42
|
+
},
|
|
43
|
+
set(value: boolean): void {
|
|
44
|
+
lists.forEach((item) => {
|
|
45
|
+
item.__selected = value;
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
}
|