ct-component-plus 2.1.3 → 2.1.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "ct-component-plus",
3
3
  "private": false,
4
- "version": "2.1.3",
4
+ "version": "2.1.4",
5
5
  "type": "module",
6
6
  "main": "packages/components/index.js",
7
7
  "files": [
@@ -3,7 +3,9 @@ import radio from './radio';
3
3
  import checkbox from './checkbox';
4
4
  import input from './input';
5
5
  import inputRange from './input-range';
6
+ import numberInputRange from './number-input-range';
6
7
  import select from './select';
8
+ import pagingSelect from './paging-select';
7
9
  import yearSelect from './year-select';
8
10
  import datePicker from './date-picker';
9
11
  import cascader from './cascader';
@@ -34,7 +36,9 @@ const components = [
34
36
  checkbox,
35
37
  input,
36
38
  inputRange,
39
+ numberInputRange,
37
40
  select,
41
+ pagingSelect,
38
42
  yearSelect,
39
43
  datePicker,
40
44
  cascader,
@@ -79,4 +83,4 @@ export default {
79
83
  install
80
84
  }
81
85
  export { CtMessage }
82
- export * from 'element-plus'
86
+ export * from 'element-plus'
@@ -0,0 +1,9 @@
1
+ import CtNumberInputRange from "./src/number-input-range.vue";
2
+
3
+ /* istanbul ignore next */
4
+ CtNumberInputRange.install = function (Vue) {
5
+ // TODO 这里D组件名是这这里写死的,不是使用CtNumberInputRange.name的形式,因为setup里面不可以直接什么组件的name属性,故而这里没有这个属性,后续可以考虑使用defineOptions(需要安装unplugin-vue-macros插件)
6
+ Vue.component("CtNumberInputRange", CtNumberInputRange);
7
+ };
8
+
9
+ export default CtNumberInputRange;
@@ -0,0 +1,31 @@
1
+ import { buriedParamsKey, searchComponentProps } from "../../../hooks";
2
+
3
+ export const numberInputRangeEmits = [
4
+ "update:modelValue",
5
+ buriedParamsKey,
6
+ "change",
7
+ ];
8
+ export const numberInputRangeProps = {
9
+ ...searchComponentProps,
10
+ modelValue: Array,
11
+ min: Number,
12
+ max: Number,
13
+ step: {
14
+ type: Number,
15
+ default: 1,
16
+ },
17
+ precision: Number,
18
+ disabled: Boolean,
19
+ separator: {
20
+ type: String,
21
+ default: "--",
22
+ },
23
+ controlsPosition: {
24
+ type: String,
25
+ default: "right",
26
+ },
27
+ placeholder: {
28
+ type: String,
29
+ default: "请输入数字",
30
+ },
31
+ };
@@ -0,0 +1,168 @@
1
+ <template>
2
+ <div :class="[ns.b(), ns.is('disabled', disabled)]">
3
+ <div :class="[ns.e('wrapper')]">
4
+ <el-input-number
5
+ ref="inputRef1"
6
+ v-model="leftModel"
7
+ :placeholder="placeholder"
8
+ :min="min"
9
+ :max="max"
10
+ :step="step"
11
+ :precision="precision"
12
+ :disabled="disabled"
13
+ v-bind="rawAttr"
14
+ :controls-position="controlsPosition"
15
+ @change="handleChange($event, 0)"
16
+ />
17
+ <span :class="[ns.e('separator')]">
18
+ <slot name="separator">{{ separator }}</slot>
19
+ </span>
20
+ <el-input-number
21
+ ref="inputRef2"
22
+ v-model="rightModel"
23
+ :placeholder="placeholder"
24
+ :min="min"
25
+ :max="max"
26
+ :step="step"
27
+ :precision="precision"
28
+ :disabled="disabled"
29
+ v-bind="rawAttr"
30
+ :controls-position="controlsPosition"
31
+ @change="handleChange($event, 1)"
32
+ />
33
+ </div>
34
+ </div>
35
+ </template>
36
+
37
+ <script setup>
38
+ import { computed, ref } from "vue";
39
+ import { useNamespace, useBuriedParams } from "../../../hooks";
40
+ import { numberInputRangeEmits, numberInputRangeProps } from "./index";
41
+ const props = defineProps(numberInputRangeProps);
42
+ const emit = defineEmits(numberInputRangeEmits);
43
+
44
+ useBuriedParams(props, emit);
45
+ const ns = useNamespace("number-input-range");
46
+
47
+ const inputRef1 = ref(null);
48
+ const inputRef2 = ref(null);
49
+
50
+ const normalizePair = (left, right) => {
51
+ const l = left;
52
+ const r = right;
53
+ if (l !== undefined && r !== undefined && l > r) {
54
+ return [r, l];
55
+ }
56
+ return [l, r];
57
+ };
58
+
59
+ const leftModel = computed({
60
+ get() {
61
+ return Array.isArray(props.modelValue) ? props.modelValue[0] : undefined;
62
+ },
63
+ set(newValue) {
64
+ const right = Array.isArray(props.modelValue)
65
+ ? props.modelValue[1]
66
+ : undefined;
67
+ emit("update:modelValue", [newValue, right]);
68
+ },
69
+ });
70
+ const rightModel = computed({
71
+ get() {
72
+ return Array.isArray(props.modelValue) ? props.modelValue[1] : undefined;
73
+ },
74
+ set(newValue) {
75
+ const left = Array.isArray(props.modelValue)
76
+ ? props.modelValue[0]
77
+ : undefined;
78
+ emit("update:modelValue", [left, newValue]);
79
+ },
80
+ });
81
+
82
+ const handleChange = (val, index) => {
83
+ const currentLeft = index === 0
84
+ ? val
85
+ : (Array.isArray(props.modelValue) ? props.modelValue[0] : undefined);
86
+ const currentRight = index === 1
87
+ ? val
88
+ : (Array.isArray(props.modelValue) ? props.modelValue[1] : undefined);
89
+ const bothFilled = typeof currentLeft === "number" && !isNaN(currentLeft)
90
+ && typeof currentRight === "number" && !isNaN(currentRight);
91
+ if (bothFilled) {
92
+ const normalized = normalizePair(currentLeft, currentRight);
93
+ emit("update:modelValue", normalized);
94
+ emit("change", normalized, index, val);
95
+ } else {
96
+ emit("change", [currentLeft, currentRight], index, val);
97
+ }
98
+ };
99
+
100
+ defineExpose({
101
+ ref: [inputRef1, inputRef2],
102
+ });
103
+ </script>
104
+
105
+ <style lang="less">
106
+ .ct-number-input-range {
107
+ position: relative;
108
+ display: inline-flex;
109
+ width: var(--ct-component-width);
110
+ font-size: var(--ct-font-size);
111
+ color: var(--ct-border-color);
112
+ box-sizing: border-box;
113
+ vertical-align: middle;
114
+ @R: .ct-number-input-range;
115
+ &.is-disabled {
116
+ cursor: not-allowed;
117
+ --ct-component-fill-color: var(--ct-component-disabled-bg-color);
118
+ @{R}__wrapper {
119
+ .el-input__wrapper {
120
+ height: var(--ct-component-inner-height);
121
+ padding: 1px var(--ct-component-inner-padding);
122
+ box-shadow: unset;
123
+ border-radius: 0;
124
+ }
125
+ }
126
+ }
127
+ &:not(.is-disabled):hover {
128
+ --ct-component-border-color: var(--ct-component-hover-border-color);
129
+ }
130
+ &__wrapper {
131
+ display: inline-flex;
132
+ flex-grow: 1;
133
+ align-items: center;
134
+ justify-content: center;
135
+ padding: 1px 0;
136
+ background-color: var(--ct-component-fill-color);
137
+ background-image: none;
138
+ border-radius: var(--ct-component-border-radius);
139
+ transition: var(--el-transition-box-shadow);
140
+ transform: translate3d(0, 0, 0);
141
+ box-shadow: 0 0 0 1px var(--ct-component-border-color) inset;
142
+ &:focus-within {
143
+ --ct-component-border-color: var(--ct-color-primary);
144
+ }
145
+ .el-input-number {
146
+ width: calc(50% - 8px);
147
+ &.is-controls-right .el-input__wrapper {
148
+ padding: 1px var(--ct-component-inner-padding);
149
+ }
150
+ .el-input__wrapper {
151
+ padding: 1px var(--ct-component-inner-padding);
152
+ box-shadow: unset;
153
+ border-radius: 0;
154
+ }
155
+ .el-input__inner {
156
+ color: var(--ct-component-color);
157
+ font-size: inherit;
158
+ }
159
+ span[role="button"] {
160
+ display: none;
161
+ }
162
+ }
163
+ }
164
+ &__separator {
165
+ color: var(--ct-color-grey-sub);
166
+ }
167
+ }
168
+ </style>
@@ -0,0 +1,8 @@
1
+ import CtPagingSelect from "./src/paging-select.vue";
2
+
3
+ /* istanbul ignore next */
4
+ CtPagingSelect.install = function (Vue) {
5
+ Vue.component("CtPagingSelect", CtPagingSelect);
6
+ };
7
+
8
+ export default CtPagingSelect;
@@ -0,0 +1,3 @@
1
+ <template>
2
+ <ct-icon name="arrow-down_line"></ct-icon>
3
+ </template>
@@ -0,0 +1,3 @@
1
+ <template>
2
+ <ct-icon name="close_line"></ct-icon>
3
+ </template>
@@ -0,0 +1,14 @@
1
+ <template>
2
+ <div class="ct-select__empty">
3
+ <span>{{ text }}</span>
4
+ </div>
5
+ </template>
6
+
7
+ <script setup>
8
+ defineProps({
9
+ text: {
10
+ type: String,
11
+ default: "暂无数据",
12
+ },
13
+ });
14
+ </script>
@@ -0,0 +1,50 @@
1
+ import { buriedParamsKey, searchComponentProps } from "../../../hooks";
2
+ import arrowDown from "./arrow-down.vue";
3
+ import clearIcon from "./clear-icon.vue";
4
+
5
+ export const selectEmits = ["update:modelValue", buriedParamsKey];
6
+ export const selectProps = {
7
+ ...searchComponentProps,
8
+ modelValue: [String, Number, Array, Boolean],
9
+ multiple: Boolean,
10
+ filterable: Boolean,
11
+ api: String,
12
+ serviceMethod: String,
13
+ serviceParams: Object,
14
+ mapObj: {
15
+ type: Object,
16
+ default() {
17
+ return {};
18
+ },
19
+ },
20
+ pageSize: {
21
+ type: Number,
22
+ default: 50,
23
+ },
24
+ selectAllText: {
25
+ type: String,
26
+ default: "全部",
27
+ },
28
+ connectors: {
29
+ type: String,
30
+ default: "、",
31
+ },
32
+ fitInputWidth: {
33
+ type: Boolean,
34
+ default: true,
35
+ },
36
+ clearIcon: {
37
+ type: [String, Object],
38
+ default() {
39
+ return clearIcon;
40
+ },
41
+ },
42
+ suffixIcon: {
43
+ type: [String, Object],
44
+ default() {
45
+ return arrowDown;
46
+ },
47
+ },
48
+ noMatchText: String,
49
+ noDataText: String,
50
+ };
@@ -0,0 +1,438 @@
1
+ <template>
2
+ <!-- {{ rawAttr }}-- -->
3
+ <el-select
4
+ ref="selectRef"
5
+ :class="[ns.b(), ns.is('multiple', multiple)]"
6
+ v-model="valueModel"
7
+ collapse-tags
8
+ v-bind="rawAttr"
9
+ :multiple="multiple"
10
+ :filterable="filterable"
11
+ :clear-icon="clearIcon"
12
+ :suffix-icon="suffixIcon"
13
+ :fit-input-width="fitInputWidth"
14
+ :select-text="selectText"
15
+ :popper-class="ns.e('popper')"
16
+ @focus="showSearchPrefix"
17
+ @blur="hideSearchPrefix"
18
+ @click="focusSearchInput"
19
+ @visible-change="handleListSort"
20
+ >
21
+ <template #prefix>
22
+ <div
23
+ :class="[ns.e('filterable-icon')]"
24
+ v-if="filterable && showSearch && !multiple"
25
+ >
26
+ <ct-icon name="search_line"></ct-icon>
27
+ </div>
28
+ <slot name="prefix"></slot>
29
+ </template>
30
+ <div :class="[ns.e('top')]" v-if="multiple">
31
+ <div :class="[ns.e('filter')]">
32
+ <el-input v-model="keyword" ref="filterInput">
33
+ <template #prefix>
34
+ <ct-icon name="search_line"></ct-icon>
35
+ </template>
36
+ </el-input>
37
+ </div>
38
+ <div :class="[ns.e('select')]" v-if="!rawAttr.multipleLimit">
39
+ <span :class="[ns.e('select-title')]">
40
+ <span v-if="!keyword">已选{{ selectLength }}项</span>
41
+ <span v-else>检索结果</span>
42
+ </span>
43
+ </div>
44
+ </div>
45
+ <div
46
+ :class="[ns.e('options')]"
47
+ v-show="!noFilterOptions"
48
+ ref="optionsRef"
49
+ @scroll="handleScrollLoad"
50
+ >
51
+ <slot>
52
+ <el-option
53
+ v-for="(item, index) in filterOptions"
54
+ :key="item.value"
55
+ :label="item.label"
56
+ :value="item.value"
57
+ :disabled="item.disabled"
58
+ >
59
+ <slot name="option" :item="item" :index="index">
60
+ <span :title="selectTooltip ? item.label : undefined">{{
61
+ item.label
62
+ }}</span>
63
+ </slot>
64
+ </el-option>
65
+ </slot>
66
+ </div>
67
+ <Empty :text="emptyText" v-if="multiple && noFilterOptions" />
68
+ <template #empty>
69
+ <slot name="empty">
70
+ <Empty :text="emptyText" />
71
+ </slot>
72
+ </template>
73
+ </el-select>
74
+ </template>
75
+
76
+ <script setup>
77
+ import { onMounted, computed, ref, watch, inject, nextTick } from "vue";
78
+ import { selectEmits, selectProps } from "./index";
79
+ import { useNamespace, useBuriedParams } from "../../../hooks";
80
+ import { isFunction, isArray } from "../../../utils";
81
+ import Empty from "./empty.vue";
82
+ const baseDao = inject("$ctBaseDao");
83
+ const serviceConfig = inject("$ctServiceConfig");
84
+ const selectTooltip = inject("$selectTooltip");
85
+
86
+ const props = defineProps(selectProps);
87
+ const emit = defineEmits(selectEmits);
88
+
89
+ const ns = useNamespace("select");
90
+ const optionsByApi = ref([]);
91
+ const showOptions = computed(() => {
92
+ return optionsByApi.value;
93
+ });
94
+ const valueModel = computed({
95
+ get() {
96
+ return props.modelValue || (props.multiple ? [] : props.modelValue);
97
+ },
98
+ set(newValue) {
99
+ emit("update:modelValue", newValue);
100
+ },
101
+ });
102
+ const keyword = ref("");
103
+ const selectRef = ref(null);
104
+ const filterInput = ref(null);
105
+
106
+ const selectLength = computed(() => {
107
+ return valueModel.value.length;
108
+ });
109
+ const filterOptions = ref([]);
110
+ const noFilterOptions = ref(false);
111
+ const pageNo = ref(1);
112
+ const pageSize = computed(() => props.pageSize || 20);
113
+ const total = ref(0);
114
+ const loading = ref(false);
115
+ const selectObj = computed({
116
+ get() {
117
+ if (!props.multiple)
118
+ return showOptions.value.find((item) => item.value === valueModel.value);
119
+ return showOptions.value.filter((item) => {
120
+ return valueModel.value.includes(item.value);
121
+ });
122
+ },
123
+ set(newValue) {
124
+ if (!props.multiple) {
125
+ valueModel.value = newValue.value;
126
+ } else {
127
+ valueModel.value = newValue.map((item) => item.value);
128
+ }
129
+ },
130
+ });
131
+ const selectText = computed(() => {
132
+ let result = "";
133
+ if (!props.multiple) {
134
+ return result;
135
+ } else {
136
+ if (
137
+ showOptions.value.length &&
138
+ showOptions.value.length === valueModel.value.length
139
+ ) {
140
+ result = props.selectAllText;
141
+ } else {
142
+ const cnt = props.connectors;
143
+ result = selectObj.value.map((item) => item.label).join(cnt);
144
+ }
145
+ }
146
+ //nextTick(() => {
147
+ // if (selectRef.value) {
148
+ // selectRef.value.$refs.reference.input.value = result;
149
+ // }
150
+ //});
151
+ return result;
152
+ });
153
+ const emptyText = computed(() => {
154
+ return showOptions.value.length
155
+ ? props.noMatchText || "暂无匹配数据"
156
+ : props.noDataText || "暂无数据";
157
+ });
158
+ const getUseLabel = (label) => {
159
+ return typeof label === "string" ? label : String(label);
160
+ };
161
+
162
+ watch(
163
+ () => selectText.value,
164
+ (newVal) => {
165
+ if (!selectRef.value) return;
166
+ selectRef.value.selectedLabel = newVal;
167
+ }
168
+ );
169
+ watch(optionsByApi, () => {
170
+ const arr = optionsByApi.value || [];
171
+ if (arr.length) {
172
+ filterOptions.value = arr;
173
+ noFilterOptions.value = false;
174
+ } else {
175
+ filterOptions.value = [];
176
+ noFilterOptions.value = true;
177
+ }
178
+ });
179
+
180
+ const optionsRef = ref(null);
181
+ //针对多选时,已选的项要排在整个列表的最前面
182
+ const handleListSort = (val) => {
183
+ if (props.multiple) {
184
+ if (val) {
185
+ const selectedSet = new Set(valueModel.value);
186
+ filterOptions.value = [
187
+ ...filterOptions.value.filter((item) => selectedSet.has(item.value)), // 选中的项
188
+ ...filterOptions.value.filter((item) => !selectedSet.has(item.value)), // 未选中的项
189
+ ];
190
+ nextTick(() => {
191
+ optionsRef.value.scrollTop = 0;
192
+ });
193
+ } else {
194
+ keyword.value = "";
195
+ if (!valueModel.value.length) {
196
+ filterOptions.value = [...showOptions.value];
197
+ }
198
+ }
199
+ }
200
+ };
201
+ const watchServiceHandle = async (reset = false) => {
202
+ // 通过api获取数据,会监听api以及serviceParams的改变(收集到的依赖改变)都会触发重新查询
203
+ const cbs = props.cbs || {};
204
+ if (props.api && baseDao) {
205
+ try {
206
+ const method = props.serviceMethod || serviceConfig.defaultMethod;
207
+ let params = { ...(props.serviceParams || {}) };
208
+ if (reset) {
209
+ pageNo.value = 1;
210
+ optionsByApi.value = [];
211
+ }
212
+ params.keyword = keyword.value;
213
+ params.page_no = pageNo.value;
214
+ params.page_size = pageSize.value;
215
+ if (isFunction(cbs.beforeSearch)) {
216
+ const paramsHandle = await cbs.beforeSearch(params);
217
+ if (paramsHandle === false) return;
218
+ params = paramsHandle || params;
219
+ }
220
+ loading.value = true;
221
+ baseDao[method](props.api, params)
222
+ .then((res) => {
223
+ const mapObj = props.mapObj || {};
224
+ const {
225
+ list,
226
+ label = "label",
227
+ value = "value",
228
+ self,
229
+ total: totalKey = "total",
230
+ } = mapObj;
231
+ let data = [];
232
+ if (list) {
233
+ data = res[list];
234
+ } else {
235
+ data = res;
236
+ }
237
+ data = data.map((item) => {
238
+ if (self) {
239
+ return { label: getUseLabel(item), value: item };
240
+ }
241
+ return {
242
+ ...item,
243
+ label: getUseLabel(item[label]),
244
+ value: item[value],
245
+ };
246
+ });
247
+ total.value = (res && res[totalKey]) || 0;
248
+ optionsByApi.value =
249
+ pageNo.value > 1 ? optionsByApi.value.concat(data) : data;
250
+ if (isFunction(cbs.afterSearch)) {
251
+ cbs.afterSearch(res, optionsByApi, valueModel);
252
+ }
253
+ })
254
+ .finally(() => {
255
+ loading.value = false;
256
+ });
257
+ } catch (error) {
258
+ console.error(error);
259
+ }
260
+ }
261
+ if (isFunction(cbs.defineSearch)) {
262
+ try {
263
+ const defineSearchHandle = await cbs.defineSearch(
264
+ optionsByApi,
265
+ valueModel
266
+ );
267
+ if (defineSearchHandle === false) return;
268
+ if (defineSearchHandle) {
269
+ optionsByApi.value = defineSearchHandle;
270
+ }
271
+ } catch (error) {}
272
+ }
273
+ };
274
+ watch(
275
+ [
276
+ () => props.api,
277
+ () => props.serviceParams,
278
+ () => props.serviceMethod,
279
+ () => props.mapObj,
280
+ ],
281
+ (newVal, oldVal) => {
282
+ watchServiceHandle(true);
283
+ },
284
+ {
285
+ immediate: true,
286
+ }
287
+ );
288
+ watch(
289
+ () => keyword.value,
290
+ () => {
291
+ watchServiceHandle(true);
292
+ }
293
+ );
294
+
295
+ const handleScrollLoad = (e) => {
296
+ const el = e.target;
297
+ const reach = el.scrollTop + el.clientHeight >= el.scrollHeight - 2;
298
+ const hasMore = total.value > pageNo.value * pageSize.value;
299
+ if (reach && hasMore && !loading.value) {
300
+ pageNo.value += 1;
301
+ watchServiceHandle();
302
+ }
303
+ };
304
+
305
+ const focusFilter = () => {
306
+ if (filterInput.value && filterInput.value.focus) {
307
+ filterInput.value.focus();
308
+ }
309
+ };
310
+
311
+ const showSearch = ref(false);
312
+ const focusSearchInput = () => {
313
+ setTimeout(() => {
314
+ filterInput.value && filterInput.value.focus();
315
+ // keyword.value = "";
316
+ }, 300);
317
+ };
318
+ const showSearchPrefix = () => {
319
+ showSearch.value = true;
320
+ };
321
+ const hideSearchPrefix = () => {
322
+ showSearch.value = false;
323
+ };
324
+
325
+ useBuriedParams(props, emit, {
326
+ getContent: () => {
327
+ const select = selectObj.value || {};
328
+ if (isArray(select)) {
329
+ return select.map((item) => item.label);
330
+ }
331
+ return select.label;
332
+ },
333
+ });
334
+
335
+ onMounted(() => {
336
+ if (!baseDao) {
337
+ console.error("请先配置baseDao");
338
+ }
339
+ });
340
+ defineExpose({
341
+ ref: selectRef,
342
+ keyword,
343
+ filterInput,
344
+ focusFilter,
345
+ baseDao,
346
+ serviceConfig,
347
+ noFilterOptions,
348
+ selectObj,
349
+ });
350
+ </script>
351
+ <style lang="less">
352
+ .ct-select {
353
+ width: 214px;
354
+ &.el-select {
355
+ position: relative;
356
+ }
357
+ &__top {
358
+ padding: 0 16px;
359
+ font-size: var(--ct-font-size);
360
+ }
361
+ &__options {
362
+ max-height: 274px;
363
+ overflow-y: auto;
364
+ }
365
+ &__select {
366
+ display: flex;
367
+ justify-content: space-between;
368
+ align-items: center;
369
+ margin-bottom: 10px;
370
+ &-title {
371
+ color: var(--ct-color-grey-sub);
372
+ line-height: 1;
373
+ }
374
+ .el-checkbox {
375
+ height: auto;
376
+ }
377
+ }
378
+ &__filter {
379
+ margin-bottom: 16px;
380
+ .el-input {
381
+ --el-input-height: 28px;
382
+ }
383
+ }
384
+ &__popper {
385
+ &.is-multiple {
386
+ min-width: 140px;
387
+ }
388
+ .el-select-dropdown__wrap {
389
+ max-height: unset;
390
+ }
391
+ }
392
+ .el-select__tags {
393
+ display: none;
394
+ }
395
+ .el-input__prefix-inner {
396
+ & > :last-child {
397
+ margin-right: 0;
398
+ }
399
+ }
400
+ &__filterable-icon {
401
+ position: absolute;
402
+ z-index: 3;
403
+ right: var(--ct-component-inner-padding);
404
+ top: 50%;
405
+ height: calc(var(--ct-component-size) - 2px);
406
+ transform: translateY(-50%);
407
+ background-color: #fff;
408
+ }
409
+ &__empty {
410
+ display: flex;
411
+ justify-content: center;
412
+ align-items: center;
413
+ padding: 15px 16px;
414
+ color: var(--ct-color-grey-sub);
415
+ }
416
+ &.is-multiple {
417
+ &::after {
418
+ content: attr(select-text);
419
+ position: absolute;
420
+ left: var(--ct-component-inner-padding);
421
+ right: calc(var(--ct-component-inner-padding) * 2);
422
+ top: 50%;
423
+ transform: translateY(-50%);
424
+ text-overflow: ellipsis;
425
+ overflow: hidden;
426
+ white-space: nowrap;
427
+ cursor: pointer;
428
+ pointer-events: none;
429
+ }
430
+ .el-select__placeholder.is-transparent {
431
+ display: block;
432
+ }
433
+ .el-select__selected-item {
434
+ display: none;
435
+ }
436
+ }
437
+ }
438
+ </style>
@@ -1,11 +1,13 @@
1
- import CtSearchBox from './src/search-box.vue';
1
+ import CtSearchBox from "./src/search-box.vue";
2
2
 
3
- import CtInput from '../input';
4
- import CtSelect from '../select';
5
- import CtDatePicker from '../date-picker';
6
- import CtCascader from '../cascader';
7
- import CtYearSelect from '../year-select';
8
- import CtRadio from '../radio';
3
+ import CtInput from "../input";
4
+ import CtSelect from "../select";
5
+ import CtDatePicker from "../date-picker";
6
+ import CtCascader from "../cascader";
7
+ import CtYearSelect from "../year-select";
8
+ import CtRadio from "../radio";
9
+ import CtNumberInputRange from "../number-input-range";
10
+ import CtPagingSelect from "../paging-select";
9
11
 
10
12
  export const searchComponents = {
11
13
  CtInput,
@@ -13,15 +15,17 @@ export const searchComponents = {
13
15
  CtDatePicker,
14
16
  CtCascader,
15
17
  CtYearSelect,
16
- CtRadio
17
- }
18
+ CtRadio,
19
+ CtNumberInputRange,
20
+ CtPagingSelect,
21
+ };
18
22
 
19
23
  /* istanbul ignore next */
20
24
  CtSearchBox.install = function (Vue) {
21
- Vue.component('CtSearchBox', CtSearchBox);
25
+ Vue.component("CtSearchBox", CtSearchBox);
22
26
  // for (const key in searchComponents) {
23
27
  // Vue.component(key, searchComponents[key]);
24
28
  // }
25
29
  };
26
30
 
27
- export default CtSearchBox;
31
+ export default CtSearchBox;
@@ -98,7 +98,7 @@ const judgeIsHideLabelTooltip = (item) => {
98
98
 
99
99
  const clickItem = (item) => {
100
100
  emit("clickItem", item);
101
- }
101
+ };
102
102
  const getComponentClass = (item) => {
103
103
  const classList = [];
104
104
  if (item.componentClass) {
@@ -117,8 +117,16 @@ const getComponentStyle = (item) => {
117
117
  return style;
118
118
  };
119
119
  const componentAll = computed(() => {
120
- const { CtInput, CtSelect, CtDatePicker, CtCascader, CtYearSelect, CtRadio } =
121
- searchComponents;
120
+ const {
121
+ CtInput,
122
+ CtSelect,
123
+ CtDatePicker,
124
+ CtCascader,
125
+ CtYearSelect,
126
+ CtRadio,
127
+ CtNumberInputRange,
128
+ CtPagingSelect,
129
+ } = searchComponents;
122
130
  const componentMap = {
123
131
  0: CtInput,
124
132
  1: CtSelect,
@@ -127,6 +135,8 @@ const componentAll = computed(() => {
127
135
  12: CtYearSelect,
128
136
  13: "div",
129
137
  20: CtRadio,
138
+ 21: CtNumberInputRange,
139
+ 22: CtPagingSelect,
130
140
  ...userDefinedSearchComponent,
131
141
  };
132
142
  return componentMap;
@@ -239,7 +249,8 @@ onMounted(() => {});
239
249
  }
240
250
  .el-input__wrapper,
241
251
  .el-select__wrapper,
242
- .ct-year-select__wrapper {
252
+ .ct-year-select__wrapper,
253
+ .ct-number-input-range__wrapper {
243
254
  --el-select-input-focus-border-color: var(
244
255
  --ct-search-box-inner-border-color
245
256
  );
@@ -183,7 +183,10 @@ watch(
183
183
  watchEffect(async () => {
184
184
  // 输入框过滤,触发的事件
185
185
  let arr = showOptions.value.filter((item) => {
186
- return item.label && item.label.includes(keyword.value);
186
+ return (
187
+ item.label &&
188
+ item.label.toLowerCase().includes(keyword.value.toLowerCase())
189
+ );
187
190
  });
188
191
  const cbs = props.cbs || {};
189
192
  if (isFunction(cbs.filterCallback)) {