ci-plus 1.4.3 → 1.4.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ci-plus",
3
- "version": "1.4.3",
3
+ "version": "1.4.5",
4
4
  "description": "ci组件库",
5
5
  "main": "./index.ts",
6
6
  "scripts": {
@@ -14,7 +14,7 @@
14
14
 
15
15
  <script setup lang="ts">
16
16
  import { onMounted, nextTick, watch } from 'vue'
17
- import JsBarcode from 'jsbarcode' //'./jsbarcode.js' //'https://cdn.jsdelivr.net/npm/jsbarcode@3.11.6/+esm'
17
+ import JsBarcode from './jsbarcode.js' //'./jsbarcode.js' //'https://cdn.jsdelivr.net/npm/jsbarcode@3.11.6/+esm'
18
18
  interface Props {
19
19
  value: String // 条码文本
20
20
  type?: String // 类型
@@ -1,38 +1,56 @@
1
1
  <template>
2
- <div style="width: 100%">
3
- <el-select-v2
4
- :size="props.size ?? 'small'"
5
- placeholder="请选择"
6
- :model-value="props.modelValue"
7
- @update:model-value="(val) => emits('update:modelValue', val)"
8
- :options="temporary_options"
9
- @change="
10
- (val) =>
11
- emits('change', val, temporary_options.find((v) => v[props.prop.value] == val) ?? null)
12
- "
13
- filterable
14
- style="width: 100%"
15
- remote
16
- :remote-method="getOptions"
17
- :props="props.prop"
18
- :height="200"
19
- :disabled="props.disabled"
20
- :loading="select_loading"
21
- v-bind="$attrs"
22
- >
23
- <template #prefix>
24
- <span class="el-input-number__increase" @click.stop="openTable">
25
- <el-icon>
26
- <Operation />
27
- </el-icon>
28
- </span>
29
- </template>
30
- <template #loading>
31
- <svg class="circular" viewBox="0 0 50 50">
32
- <circle class="path" cx="25" cy="25" r="20" fill="none" />
33
- </svg>
34
- </template>
35
- </el-select-v2>
2
+ <div class="ll-vue-div">
3
+ <div style="display: flex; width: 100%">
4
+ <el-select-v2
5
+ :size="props.size ?? 'small'"
6
+ placeholder="请搜索"
7
+ :model-value="props.modelValue"
8
+ @update:model-value="(val: any) => emits('update:modelValue', val)"
9
+ :options="temporary_options"
10
+ @change="(val: string | string[]) => onSelectChange(val)"
11
+ filterable
12
+ remote
13
+ :remote-method="getOptions"
14
+ :props="props.prop"
15
+ :height="200"
16
+ :disabled="props.disabled"
17
+ :loading="select_loading"
18
+ v-bind="$attrs"
19
+ :multiple="props.mul"
20
+ :collapse-tags="props.mul"
21
+ collapse-tags-tooltip
22
+ popper-class="l-popper"
23
+ style="flex: 1"
24
+ >
25
+ <template #loading>
26
+ <svg class="circular" viewBox="0 0 50 50">
27
+ <circle class="path" cx="25" cy="25" r="20" fill="none" />
28
+ </svg>
29
+ </template>
30
+ <template #footer>
31
+ <div v-if="basic.footerShow">以上为选中数据,非全部选项,请远程搜索</div>
32
+ <div v-else>
33
+ <el-pagination
34
+ v-model:current-page="basic.s_page"
35
+ small
36
+ layout="prev, pager, next"
37
+ :pager-count="5"
38
+ :page-size="10"
39
+ :total="basic.s_count"
40
+ />
41
+ </div>
42
+ </template>
43
+ </el-select-v2>
44
+ <span
45
+ class="l_increase"
46
+ :class="props.disabled ? 'l_increase-disabled' : ''"
47
+ @click.stop="!props.disabled ? openTable() : ''"
48
+ >
49
+ <el-icon>
50
+ <Operation />
51
+ </el-icon>
52
+ </span>
53
+ </div>
36
54
  <el-dialog
37
55
  class="L-dialog"
38
56
  v-model="basic.is_dialogTable"
@@ -60,7 +78,7 @@
60
78
  </template>
61
79
  <el-button-group>
62
80
  <el-tooltip
63
- v-if="aim && chooseRow.length"
81
+ v-if="chooseRow.length"
64
82
  effect="dark"
65
83
  content="清空选项"
66
84
  placement="top-start"
@@ -75,7 +93,7 @@
75
93
  ></el-button>
76
94
  </el-tooltip>
77
95
  <el-tooltip
78
- v-if="chooseRow.length"
96
+ v-if="aim && chooseRow.length"
79
97
  effect="dark"
80
98
  :content="is_aim ? '取消查询' : '查询已选中信息'"
81
99
  placement="top-start"
@@ -92,8 +110,8 @@
92
110
  </el-col>
93
111
  <el-col v-else :span="16" class="flex">
94
112
  <el-tag v-if="props.modelValue && props.modelValue.length" closable @close="closeTag">
95
- {{ tagLabel }}</el-tag
96
- >
113
+ {{ tagLabel }}
114
+ </el-tag>
97
115
  </el-col>
98
116
  <el-col :span="8">
99
117
  <el-input
@@ -103,7 +121,7 @@
103
121
  @change="getTableData({}, true)"
104
122
  >
105
123
  <template #append>
106
- <el-button icon="Search" @click="getTableData({}, true)" />
124
+ <el-button :icon="Search" @click="getTableData({}, true)" />
107
125
  </template>
108
126
  </el-input>
109
127
  </el-col>
@@ -142,13 +160,17 @@
142
160
  @next-click="getTableData()"
143
161
  style="margin-top: 3px"
144
162
  />
163
+ <div>
164
+ <el-button @click="basic.is_dialogTable = false" style="float: right"> 关闭 </el-button>
165
+ </div>
145
166
  </div>
146
167
  </el-dialog>
147
168
  </div>
148
169
  </template>
149
170
 
150
171
  <script setup lang="ts">
151
- import { reactive, h, ref, onMounted, toRef, watch } from 'vue'
172
+ import { reactive, h, ref, onMounted, watch } from 'vue'
173
+ import { Operation, Search } from '@element-plus/icons-vue'
152
174
  import { ElMessage, ElTable } from 'element-plus'
153
175
  import axios from 'axios'
154
176
  import { SelectSuffix, Basic, AnyO } from './types'
@@ -162,13 +184,17 @@ const basic = reactive<Basic>({
162
184
  page: 1,
163
185
  limit: 30,
164
186
  count: 0,
187
+ s_page: 1,
188
+ s_count: 0,
165
189
  loading: false,
166
190
  is_dialogTable: false,
191
+ footerShow: false,
167
192
  search: ''
168
193
  })
169
194
  const select_loading = ref(false)
170
195
  const is_aim = ref(false)
171
196
  const tagLabel = ref('')
197
+ const filterkey = ref('')
172
198
  const tableData = ref<AnyO[]>([])
173
199
  const temporary_options = ref<AnyO[]>([])
174
200
  const chooseRow = ref<AnyO[]>([])
@@ -177,11 +203,19 @@ const tableRowColor = ({ row, rowIndex }: { row: AnyO; rowIndex: number }) => {
177
203
  return 'success-row'
178
204
  return ''
179
205
  }
206
+ watch(
207
+ () => basic.s_page,
208
+ () => {
209
+ getOptions(filterkey.value, true)
210
+ }
211
+ )
180
212
  const rowClick = (row: AnyO) => {
181
213
  if (!props.mul) {
214
+ temporary_options.value = [row]
215
+ basic.footerShow = true
216
+ tagLabel.value = row[props.prop.label]
182
217
  emits('update:modelValue', row[props.prop.value])
183
218
  emits('change', row[props.prop.value], row)
184
- tagLabel.value = row[props.prop.label]
185
219
  if (!props.isExist) basic.is_dialogTable = false
186
220
  } else {
187
221
  if (chooseRow.value.find((v) => v[props.prop.value] == row[props.prop.value]))
@@ -190,10 +224,28 @@ const rowClick = (row: AnyO) => {
190
224
  1
191
225
  )
192
226
  else chooseRow.value.push(row)
193
- // tableRef.value.toggleRowSelection(row, undefined)
194
227
  sendMulValue()
195
228
  }
196
229
  }
230
+ //下拉框选择
231
+ const onSelectChange = (val: string | string[]) => {
232
+ if (Array.isArray(val) && props.mul) {
233
+ let thisPageChooseRows = temporary_options.value.filter(
234
+ (v) => !v.disabled && val.some((k: string) => k == v[props.prop.value])
235
+ )
236
+ thisPageChooseRows.forEach((v) => {
237
+ if (!chooseRow.value.find((x) => x[props.prop.value] == v[props.prop.value])) {
238
+ chooseRow.value.push(v)
239
+ }
240
+ })
241
+ chooseRow.value = chooseRow.value.filter((v) =>
242
+ val.some((k: string) => k == v[props.prop.value])
243
+ )
244
+ emits('change', val, chooseRow.value)
245
+ } else {
246
+ emits('change', val, temporary_options.value.find((v) => v[props.prop.value] == val) ?? null)
247
+ }
248
+ }
197
249
  const closeTag = (row?: AnyO) => {
198
250
  if (!props.mul) {
199
251
  emits('update:modelValue', '')
@@ -213,29 +265,38 @@ const empty = () => {
213
265
  }
214
266
  const sendMulValue = () => {
215
267
  let values = chooseRow.value.map((v) => v[props.prop.value])
268
+ basic.footerShow = true
269
+ temporary_options.value = chooseRow.value
216
270
  emits('update:modelValue', values)
217
271
  emits('change', values, chooseRow.value)
218
272
  }
273
+ // const openTable = () => {
274
+ // basic.is_dialogTable = true
275
+ // if (!tableData.value.length) getTableData()
276
+ // let searchObj: AnyO = {}
277
+ // searchObj[props.searchKey ? props.searchKey : 'search'] = props.modelValue
278
+ // if (props.modelValue && props.modelValue.length)
279
+ // getAxios(props.where ? props.where : searchObj, true).then((res) => {
280
+ // if (res.code == 200 && res.data.length) {
281
+ // if (props.mul) chooseRow.value = res.data
282
+ // else tagLabel.value = res.data[0]?.[props.prop.label]
283
+ // } else {
284
+ // tagLabel.value = ''
285
+ // chooseRow.value = []
286
+ // }
287
+ // setCurrent()
288
+ // })
289
+ // else {
290
+ // tagLabel.value = ''
291
+ // chooseRow.value = []
292
+ // }
293
+ // }
219
294
  const openTable = () => {
220
295
  basic.is_dialogTable = true
221
296
  if (!tableData.value.length) getTableData()
222
- let searchObj: AnyO = {}
223
- searchObj[props.searchKey ? props.searchKey : 'search'] = props.modelValue
224
- if (props.modelValue && props.modelValue.length)
225
- getAxios(props.where ? props.where : searchObj, true).then((res) => {
226
- if (res.code == 200 && res.data.length) {
227
- if (props.mul) chooseRow.value = res.data
228
- else tagLabel.value = res.data[0]?.[props.prop.label]
229
- } else {
230
- tagLabel.value = ''
231
- chooseRow.value = []
232
- }
233
- setCurrent()
234
- })
235
- else {
236
- tagLabel.value = ''
237
- chooseRow.value = []
238
- }
297
+ else setCurrent(true)
298
+ otherChangeTo()
299
+ // temporary_options.value = chooseRow.value
239
300
  }
240
301
  const appointGet = () => {
241
302
  if (!is_aim.value) {
@@ -254,15 +315,16 @@ const getTableData = (obj = {}, page1 = false) => {
254
315
  setCurrent()
255
316
  })
256
317
  }
257
- const setCurrent = () => {
318
+ //单页数据
319
+ const setCurrent = (openTable?: boolean) => {
258
320
  if (props.mul) {
321
+ if (openTable) chooseRow.value = []
259
322
  let clickRows = tableData.value.filter((v) =>
260
323
  (props.modelValue || []).includes(v[props.prop.value])
261
324
  )
262
325
  clickRows.forEach((v) => {
263
326
  if (!chooseRow.value.find((x) => x[props.prop.value] == v[props.prop.value])) {
264
327
  chooseRow.value.push(v)
265
- // tableRef.value!.toggleRowSelection(v,true)
266
328
  }
267
329
  })
268
330
  } else {
@@ -297,15 +359,22 @@ const getAxios = async (obj = {}, page1 = false): Promise<any> => {
297
359
  })
298
360
  return data
299
361
  }
300
- const getOptions = (val: string) => {
301
- if (!val) return
362
+ const getOptions = (val: string, is_return = false) => {
363
+ // 5/28 解决如果先点击选择框然后点表格选择,无法展示下拉选项,需要初始化下拉数据
364
+ if (!val && !is_return) return
365
+ if (filterkey.value !== val) {
366
+ filterkey.value = val
367
+ basic.s_page = 1
368
+ }
369
+ basic.footerShow = false
302
370
  select_loading.value = true
303
371
  let searchObj: AnyO = {}
304
372
  searchObj[props.searchKey ? props.searchKey : 'search'] = val
305
373
  axios({
306
374
  ...props.axiosConfig,
307
375
  params: {
308
- page: 1,
376
+ page: basic.s_page,
377
+ limit: 10,
309
378
  ...searchObj,
310
379
  ...props.axiosConfig.params
311
380
  }
@@ -314,24 +383,65 @@ const getOptions = (val: string) => {
314
383
  let res = res_.data
315
384
  select_loading.value = false
316
385
  if (res.code !== 200) return ElMessage.warning(res.msg)
386
+ basic.s_count = res.count ?? res.data.length
317
387
  if (props.getData) temporary_options.value = props.getData(res.data) || []
318
388
  else temporary_options.value = res.data || []
319
- temporary_options.value = res.data
389
+ if (props.mul) {
390
+ let ohterPageChoose = chooseRow.value.filter(
391
+ (v) => !temporary_options.value.some((x) => x[props.prop.value] == v[props.prop.value])
392
+ )
393
+ ohterPageChoose.forEach((v) => (v.disabled = true))
394
+ temporary_options.value.push(...ohterPageChoose)
395
+ }
320
396
  })
321
397
  .catch((err) => {
322
398
  select_loading.value = false
323
399
  ElMessage.error(err.code)
324
400
  })
325
401
  }
402
+ const otherChangeTo = () => {
403
+ let searchObj: AnyO = {}
404
+ searchObj[props.searchKey ? props.searchKey : 'search'] = props.mul
405
+ ? JSON.stringify(props.modelValue)
406
+ : props.modelValue
407
+ if (props.modelValue && props.modelValue.length)
408
+ getAxios(props.where ? props.where : searchObj, true).then((res) => {
409
+ if (res.code == 200 && res.data.length) {
410
+ if (!props.mul) tagLabel.value = res.data[0]?.[props.prop.label]
411
+ temporary_options.value = res.data
412
+ basic.footerShow = true
413
+ } else {
414
+ tagLabel.value = ''
415
+ chooseRow.value = []
416
+ }
417
+ })
418
+ else {
419
+ tagLabel.value = ''
420
+ chooseRow.value = []
421
+ }
422
+ }
423
+ onMounted(() => {
424
+ if (!props.modelValue) getOptions('', true)
425
+ else otherChangeTo()
426
+ })
427
+ defineExpose({ otherChangeTo })
326
428
  </script>
327
429
 
328
430
  <style lang="scss">
431
+ .el-table .success-row {
432
+ --el-table-tr-bg-color: #cdedff;
433
+ }
434
+
329
435
  .L-dialog {
330
436
  .flex {
331
437
  display: flex;
332
438
  align-items: center;
333
439
  }
334
440
 
441
+ .el-dialog__body {
442
+ height: calc(100% - 27px);
443
+ }
444
+
335
445
  .el-table__body tr.current-row > td.el-table__cell {
336
446
  background-color: #bbe7ff !important;
337
447
  }
@@ -342,8 +452,42 @@ const getOptions = (val: string) => {
342
452
  }
343
453
  }
344
454
 
345
- .el-table .success-row {
346
- --el-table-tr-bg-color: #cdedff;
455
+ .ll-vue-div {
456
+ width: 100%;
457
+ }
458
+
459
+ .l_increase {
460
+ align-items: center;
461
+ background: var(--el-fill-color-light);
462
+ color: var(--el-text-color-regular);
463
+ box-shadow: 0 0 0 1px var(--el-border-color) inset;
464
+ border-top-right-radius: var(--el-border-radius-base);
465
+ border-bottom-right-radius: var(--el-border-radius-base);
466
+ cursor: pointer;
467
+ display: flex;
468
+ font-size: 13px;
469
+ height: auto;
470
+ justify-content: center;
471
+ -webkit-user-select: none;
472
+ -moz-user-select: none;
473
+ -ms-user-select: none;
474
+ user-select: none;
475
+ width: 32px;
476
+ z-index: 1;
477
+ }
478
+ .l_increase:hover {
479
+ background-color: #bbe7ff;
480
+ color: #222;
481
+ }
482
+ .l_increase-disabled:hover {
483
+ background-color: var(--el-fill-color-light);
484
+ color: var(--el-text-color-regular);
485
+ cursor: no-drop;
486
+ }
487
+
488
+ .el-select__wrapper {
489
+ border-top-right-radius: unset;
490
+ border-bottom-right-radius: unset;
347
491
  }
348
492
 
349
493
  .circular {
@@ -362,4 +506,20 @@ const getOptions = (val: string) => {
362
506
  stroke: var(--el-color-primary);
363
507
  stroke-linecap: round;
364
508
  }
509
+
510
+ .el-select-dropdown__list.el-vl__window {
511
+ min-width: 200px;
512
+ }
513
+
514
+ .el-select-dropdown {
515
+ min-width: 200px;
516
+ }
517
+
518
+ .l-popper {
519
+ min-width: 200px;
520
+ }
521
+
522
+ .el-select-dropdown__footer {
523
+ padding: 3px;
524
+ }
365
525
  </style>
@@ -3,44 +3,76 @@ import { TableColumnInstance, ColumnCls } from 'element-plus'
3
3
  import { AxiosRequestConfig } from 'axios';
4
4
  export type Props<T> = Partial<Omit<T, `$${string}` | `_${string}` | '$' | '_'>>
5
5
  export interface Scope<T> {
6
- row: T,
7
- $index: number,
8
- column: ColumnCls<T>
6
+ row: T,
7
+ $index: number,
8
+ column: ColumnCls<T>
9
9
  }
10
10
  export interface AnyO {
11
- [key: string]: any
11
+ [key: string]: any
12
12
  }
13
13
  export interface SelectColumn {
14
- col: Props<TableColumnInstance>
15
- scope?(props: any): string
16
- component?: (createVNode: typeof h, data: Scope<any>) => ComponentIns
14
+ col: Props<TableColumnInstance>
15
+ scope?(props: any): string
16
+ component?: (createVNode: typeof h, data: Scope<any>) => ComponentIns
17
17
  }
18
18
  export interface SelectSuffix {
19
- title?: string //弹出层标题
20
- modelValue?: string | string[] //下拉框value
21
- columns: SelectColumn[] // 表格列配置
22
- mul?: boolean //多选
23
- aim?: boolean
24
- disabled?: boolean
25
- size?: "" | "default" | "small" | "large"
26
- prop: { //下拉框字段
27
- label: string
28
- value: string
29
- }
30
- where?: { //弹出层打开需要展示Label的请求的params
31
- [key: string]: string
32
- }
33
- axiosConfig: AxiosRequestConfig //Axios请求配置
34
- isExist?: boolean // 是否选中关闭,单选默认true,多选默认false
35
- searchKey?: string // 模糊搜索字段,默认search,
36
- // selectConfig?:Props<ISelectV2Props>
37
- getData?: (params: any) => any[] // 获取数据的方法::getData="(data: any) => data.data"
19
+ title?: string //弹出层标题
20
+ modelValue?: string | string[] //下拉框value
21
+ columns: SelectColumn[] // 表格列配置
22
+ mul?: boolean //多选
23
+ aim?: boolean
24
+ disabled?: boolean
25
+ size?: "" | "default" | "small" | "large"
26
+ prop: { //下拉框字段
27
+ label: string
28
+ value: string
29
+ }
30
+ where?: { //弹出层打开需要展示Label的请求的params
31
+ [key: string]: any
32
+ }
33
+ axiosConfig: AxiosRequestConfig //Axios请求配置
34
+ isExist?: boolean // 是否选中关闭,单选默认true,多选默认false
35
+ searchKey?: string // 模糊搜索字段,默认search,
36
+ onChange?: (value: string, row: AnyO) => void
37
+ // selectConfig?:Props<ISelectV2Props>
38
+ getData?: (params: any) => any[] // 获取数据的方法::getData="(data: any) => data.data"
38
39
  }
39
40
  export interface Basic {
40
- page: number
41
- limit: number
42
- count: number
43
- is_dialogTable: boolean
44
- loading: boolean
45
- search: string
41
+ page: number
42
+ limit: number
43
+ count: number
44
+ s_page: number
45
+ s_count: number
46
+ is_dialogTable: boolean
47
+ loading: boolean
48
+ footerShow: boolean
49
+ search: string
50
+ }
51
+ type FormListBase = {
52
+ name: string
53
+ label: string
54
+ col?: number
55
+ type?: string
56
+ hide?: { judgment: string, value: any }[]
57
+ mul?: boolean
58
+ range?: boolean
59
+ sub?: string[]
60
+ listen?: (val: any) => any
61
+ }
62
+ type no_select = { sign: 1 | 4 }
63
+ type is_select = {
64
+ sign: 3
65
+ select?: { url: string, pName: string, sign?: number, where?: object }
66
+ options?: {
67
+ label: string
68
+ value: number
69
+ [propName: string]: any
70
+ }[]
71
+ }
72
+ type is_suffix = {
73
+ sign: 2,
74
+ whereKey?: string
75
+ suffixConfig: SelectSuffix
46
76
  }
77
+
78
+ export type FormList = FormListBase & (no_select | is_select | is_suffix)
@@ -10,6 +10,7 @@
10
10
  @clear="clear"
11
11
  @close="close"
12
12
  @open="open"
13
+ @getFocus="getFocus"
13
14
  >
14
15
  <template #reference="{ toggle }">
15
16
  <div style="width: 40px; height: 30px; line-height: 30px; display: flex">
@@ -49,12 +50,16 @@
49
50
  :colorh="'#2C93FF'"
50
51
  @click="toggle"
51
52
  />
53
+ <!-- <filter-icon-vue
54
+ @click="toggle"
55
+ :color="hasValue ? '#2C93FF' : ''"
56
+ /> -->
52
57
  </div>
53
58
  </div>
54
59
  </template>
55
60
  <template #default="{ closeF }">
56
61
  <el-select
57
- v-if="props.type !== 'select'"
62
+ v-if="props.type !== 'select' && props.showConnector"
58
63
  v-model="operator"
59
64
  class="m-2 input-select"
60
65
  placeholder="请选择查询类型"
@@ -76,6 +81,8 @@
76
81
  :placeholder="placeholder"
77
82
  @keydown.enter="confirm(closeF)"
78
83
  clearable
84
+ ref="numberInputRef"
85
+ type="number"
79
86
  />
80
87
  <el-input
81
88
  v-else-if="!props.type || props.type === 'text'"
@@ -83,22 +90,46 @@
83
90
  :placeholder="placeholder"
84
91
  @keydown.enter="confirm(closeF)"
85
92
  clearable
93
+ ref="textInputRef"
86
94
  />
87
95
  <el-select-v2
88
96
  v-else-if="props.type === 'select'"
89
97
  v-model="selectValue"
90
98
  :placeholder="placeholder || _selectConfig.placeholder"
91
99
  :size="_selectConfig.selectSize || 'default'"
92
- :options="_selectConfig.options"
100
+ :options="OptiosSelect"
93
101
  :clearable="_selectConfig.clearable"
94
- :filterable="_selectConfig.filterable"
95
102
  :multiple="_selectConfig.selectMultiple"
96
103
  :collapse-tags-tooltip="_selectConfig.collapseTagsTooltip"
97
104
  :collapse-tags="_selectConfig.collapseTags"
98
105
  :allow-create="_selectConfig.allowCreate"
99
106
  :default-first-option="_selectConfig.defaultFirstOption"
100
107
  :popper-class="_selectConfig.popperClass"
101
- />
108
+ :props="_selectConfig.props"
109
+ :filterable="_selectConfig.filterable"
110
+ :remote="myRemote"
111
+ :remote-method="myRemote ? remoteMethod : () => {}"
112
+ :loading="loading"
113
+ >
114
+ <template #footer v-if="props.selectConfig?.getOptions">
115
+ <el-pagination
116
+ v-model:current-page="currentPage"
117
+ v-model:page-size="pageSize"
118
+ :page-sizes="[20, 30, 50, 100, 500]"
119
+ small
120
+ :background="background"
121
+ layout=" prev, pager, next, jumper,total"
122
+ :total="selectOptionTotal"
123
+ @size-change="handleSizeChange"
124
+ @current-change="handleCurrentChange"
125
+ />
126
+ </template>
127
+ <template #loading v-if="props.selectConfig?.getOptions">
128
+ <svg class="circular" viewBox="0 0 50 50">
129
+ <circle class="path" cx="25" cy="25" r="20" fill="none" />
130
+ </svg>
131
+ </template>
132
+ </el-select-v2>
102
133
  <div class="date-picker" v-if="props.type === 'date'">
103
134
  <el-date-picker
104
135
  v-if="props.type === 'date' && operator === 'between'"
@@ -134,11 +165,11 @@
134
165
 
135
166
  <script setup lang="ts">
136
167
  defineOptions({ name: 'ci-headerInput' })
137
- // import SvgIcon from '@/components/SvgIcon.vue'
138
168
  import SvgIcon from '../svgIcon/svgicon.vue'
139
- import { computed, ref, watch } from 'vue'
140
- import lodash from 'lodash'
169
+ import { computed, ref, watch, PropType, onMounted } from 'vue'
170
+ import lodash, { debounce } from 'lodash'
141
171
  import headerPopover from './utils/headerPopover.vue'
172
+ import filterIconVue from './utils/filterIcon.vue'
142
173
  import { TooltipTriggerType } from 'element-plus'
143
174
 
144
175
  // 定义 props 的类型
@@ -161,6 +192,10 @@ interface SelectConfig {
161
192
  selectAllPlaceholder?: string
162
193
  optionValue?: string
163
194
  optionLabel?: string
195
+ props?: { label: string; value: string }
196
+ getOptions: (val: { page: number; limit: number; search?: string | string[] }) => Promise<any[]>
197
+ page?: number // 分页
198
+ limit?: number // 分页每页大小
164
199
  }
165
200
  // 定义排序的类型
166
201
  interface OrdersConfig {
@@ -181,34 +216,97 @@ interface Props {
181
216
  ordersConfig?: OrdersConfig // 排序的配置项
182
217
  }
183
218
 
219
+ interface PopperStyle {
220
+ [key: string]: string
221
+ }
222
+
223
+ type SType = 'text' | 'number' | 'select' | 'date' // 输入框类型
224
+
184
225
  // 使用 defineProps 和 withDefaults 来声明 props 并设置默认值
185
226
 
186
- const props = withDefaults(defineProps<Props>(), {
187
- type: 'text',
188
- initValue: '',
189
- disableFilter: false,
190
- // storePar: () => {},
191
- popperStyle: () => ({ width: '240px', height: '100px' }),
192
- selectConfig: (): SelectConfig => ({
193
- placeholder: '请选择', // 输入框的placeholder提示
194
- selectSize: 'default', // 输入框的大小
195
- selectDisabled: false, // 输入框的disabled属性
196
- clearable: true, // 是否有清除按钮
197
- filterable: true, // 是否可搜索
198
- collapseTags: true, // 是否折叠tag
199
- collapseTagsTooltip: true, // 是否显示tag的tooltip提示
200
- selectMultiple: false, // 是否多选
201
- allowCreate: false, // 是否允许创建新条目
202
- defaultFirstOption: true, // 是否默认高亮第一个选项
203
- popperClass: '', // popper的class类名
204
- selectStyle: '', // 输入框的style样式
205
- selectAll: false, // 是否显示全选按钮
206
- selectAllLabel: '全选', // 全选按钮的文本
207
- selectAllPlaceholder: '请选择', // 全选按钮的placeholder提示
208
- options: [], //select下拉选项时的 列表数据
209
- optionValue: 'value', // 选项的默认value值
210
- optionLabel: 'label' // 选项的默认label值
211
- })
227
+ const props = defineProps({
228
+ column: {
229
+ type: String,
230
+ // required: true,
231
+ default: ''
232
+ },
233
+ type: {
234
+ type: String as PropType<SType>,
235
+ default: 'text'
236
+ },
237
+ text: {
238
+ type: String,
239
+ required: true,
240
+ default: ''
241
+ },
242
+ storePar: {
243
+ type: Object,
244
+ // required: true,
245
+ default: () => {}
246
+ },
247
+
248
+ placeholder: {
249
+ type: String,
250
+ default: ''
251
+ },
252
+ initValue: {
253
+ type: [String, Number],
254
+ default: ''
255
+ },
256
+ disableFilter: {
257
+ type: Boolean,
258
+ default: false
259
+ },
260
+ popperStyle: {
261
+ type: Object as PropType<PopperStyle>,
262
+ default: () => ({ width: '240px', height: '100px' })
263
+ },
264
+ trigger: {
265
+ type: String as PropType<TooltipTriggerType>,
266
+ default: 'hover'
267
+ },
268
+ selectConfig: {
269
+ type: Object as PropType<SelectConfig>,
270
+ default: () => ({
271
+ placeholder: '请选择', // 输入框的placeholder提示
272
+ selectSize: 'default', // 输入框的大小
273
+ selectDisabled: false, // 输入框的disabled属性
274
+ clearable: true, // 是否有清除按钮
275
+ filterable: true, // 是否可搜索
276
+ collapseTags: true, // 是否折叠tag
277
+ collapseTagsTooltip: true, // 是否显示tag的tooltip提示
278
+ selectMultiple: false, // 是否多选
279
+ allowCreate: false, // 是否允许创建新条目
280
+ defaultFirstOption: true, // 是否默认高亮第一个选项
281
+ popperClass: '', // popper的class类名
282
+ selectStyle: '', // 输入框的style样式
283
+ selectAll: false, // 是否显示全选按钮
284
+ selectAllLabel: '全选', // 全选按钮的文本
285
+ selectAllPlaceholder: '请选择', // 全选按钮的placeholder提示
286
+ options: [], //select下拉选项时的 列表数据
287
+ optionValue: 'value', // 选项的默认value值
288
+ optionLabel: 'label', // 选项的默认label值
289
+ props: { label: 'label', value: 'value' },
290
+ page: 1, // 分页
291
+ limit: 8 // 分页每页大小
292
+ // getOptions: {
293
+ // type: Function,
294
+ // default: null,
295
+ // }, // 如果使用内置获取数据方法 () => Promise<any[]>
296
+ })
297
+ },
298
+ ordersConfig: {
299
+ type: Object as PropType<OrdersConfig>,
300
+ default: () => ({
301
+ enableOrder: false, // 是否开启排序 默认false 关闭的
302
+ initOrder: '' // 默认是否升序排序 默认''
303
+ })
304
+ },
305
+ // 是否使用连接符输入框
306
+ showConnector: {
307
+ type: Boolean,
308
+ default: true
309
+ }
212
310
  })
213
311
 
214
312
  // console.log('props表头', props)
@@ -232,11 +330,19 @@ const _selectConfig = computed((): SelectConfig => {
232
330
  selectAllPlaceholder: '请选择', // 全选按钮的placeholder提示
233
331
  options: [], //select下拉选项时的 列表数据
234
332
  optionValue: 'value', // 选项的默认value值
235
- optionLabel: 'label' // 选项的默认label值
333
+ optionLabel: 'label', // 选项的默认label值
334
+ props: { label: 'label', value: 'value' }, // 指定显示字段和值字段
335
+ page: 1, // 分页
336
+ limit: 8 // 分页每页大小
236
337
  }
237
338
  return lodash.assign(obj, props.selectConfig || {})
238
339
  })
239
340
 
341
+ // 根据是否传递远程获取下拉列表函数,判断是否需要开启远程搜索功能
342
+ const myRemote = computed(() => {
343
+ return props.selectConfig?.getOptions ? true : false
344
+ })
345
+
240
346
  // 根据传参重置排序配置参数的默认值
241
347
  const _ordersConfig = computed((): OrdersConfig => {
242
348
  let obj = {
@@ -283,6 +389,7 @@ const operatorOptions = ref<
283
389
  label: '不等于'
284
390
  },
285
391
  {
392
+ // 数组的第8个元素必须是介于,后面再日期的时候会禁用第8个
286
393
  value: 'between',
287
394
  label: '介于'
288
395
  }
@@ -328,7 +435,7 @@ if (props.type === 'select') {
328
435
  // 将面板宽度调整宽一些
329
436
  // 判断props.popperStyle的宽度是否为小于300px,如果是就修改为300px
330
437
  if (props.popperStyle.width && parseInt(props.popperStyle.width.replace('px', '')) < 300) {
331
- updatePopperStyle({ width: '300px' })
438
+ updatePopperStyle({ width: '460px' })
332
439
  }
333
440
  }
334
441
 
@@ -427,9 +534,14 @@ const confirm = (closeF?: Function) => {
427
534
  }
428
535
 
429
536
  // 判断input输入框中的值是否为空
430
-
431
- emits('change', obj)
432
- closeF && closeF()
537
+ if (props.showConnector) {
538
+ emits('change', obj)
539
+ closeF && closeF()
540
+ } else {
541
+ // 如果是隐藏了条件连接符下拉选择框,就只返回输入的值
542
+ emits('change', value.value)
543
+ closeF && closeF()
544
+ }
433
545
  }
434
546
 
435
547
  // 清除按钮:清空输入框和发送请求
@@ -444,13 +556,66 @@ const clear = () => {
444
556
  value.value = void 0
445
557
  confirm()
446
558
  }
447
-
559
+ const loading = ref(false)
448
560
  // 关闭面板
449
561
  const close = () => {}
450
562
  const open = () => {
563
+ if (props.selectConfig?.getOptions) {
564
+ console.log('打开', props)
565
+ // getOptins()
566
+ }
567
+ // if (props.type === 'select' && props.initValue) {
568
+ // search.value = props.initValue
569
+ // value.value = props.initValue
570
+ // getOptins()
571
+ // }
451
572
  emits('open')
452
573
  }
453
574
 
575
+ // 请求下拉列表函数
576
+ const getOptins = () => {
577
+ loading.value = true
578
+ props.selectConfig
579
+ ?.getOptions({
580
+ page: currentPage.value,
581
+ limit: pageSize.value,
582
+ search: search.value
583
+ })
584
+ .then((val: any) => {
585
+ console.log('val: ', val)
586
+ if (val.code === 200 && val.data.length > 0) {
587
+ OptiosSelect.value = val.data
588
+ // lodash.uniqBy( [...OptiosSelect.value, ...val.data], (item) => JSON.stringify(item), )
589
+ selectOptionTotal.value = val.count // 总数
590
+ } else {
591
+ OptiosSelect.value = []
592
+ selectOptionTotal.value = 0
593
+ console.log('列表数据获取失败或者为空', val.msg)
594
+ }
595
+ })
596
+ .catch((err) => {
597
+ console.log('err: ', err)
598
+ loading.value = false
599
+ })
600
+ .finally(() => {
601
+ loading.value = false
602
+ })
603
+ }
604
+
605
+ // 开启远程搜索函数
606
+ const remoteMethod = (query: string) => {
607
+ console.log('query: ', query, OptiosSelect.value.length)
608
+ if (OptiosSelect.value.length < 1 || query) {
609
+ let setQuery = (q: string) => {
610
+ search.value = q
611
+ getOptins()
612
+ }
613
+ // 防抖
614
+ let myDebounce = debounce(() => setQuery(query), 1000)
615
+ myDebounce()
616
+ }
617
+ }
618
+
454
619
  // 排序
455
620
  const orderChangtop = (val: string) => {
456
621
  console.log('升序', ordersVal.value)
@@ -492,17 +657,30 @@ const orderChangbot = (val: string) => {
492
657
  }
493
658
 
494
659
  // 监听 props.storePar 的filters 和 orders属性 然对应按钮颜色是否改变
660
+ // 如果props.showConnector为true,就监听 props.storePar 变化,如果为false就监听props.initValue 的变化
495
661
  watch(
496
- () => props.storePar,
662
+ () => {
663
+ if (props.showConnector) {
664
+ return props.storePar
665
+ } else {
666
+ return props.initValue
667
+ }
668
+ },
497
669
  (newVal, oldVal) => {
498
- // console.log('监听props.storePar', newVal, oldVal)
499
- if (newVal.filters) {
670
+ // console.log('监听输入框中值(store.params.value)变化', newVal, oldVal)
671
+ // 判断newVal是否为字符串还是对象
672
+ if (newVal && typeof newVal == 'string') {
673
+ hasValue.value = true
674
+ } else {
675
+ hasValue.value = false
676
+ }
677
+ if (newVal?.filters) {
500
678
  // 判断是否是当前列的筛选条件
501
679
  const filter = newVal.filters.find((item: any) => item.column == props.column)
502
680
  if (filter) {
503
681
  // console.log('filter: ', filter.value)
504
682
  // 判断是否是当前列的筛选条件
505
- if (filter.value) {
683
+ if (filter.value || filter) {
506
684
  hasValue.value = true
507
685
  } else {
508
686
  hasValue.value = false
@@ -511,7 +689,7 @@ watch(
511
689
  hasValue.value = false
512
690
  }
513
691
  }
514
- if (newVal.orders) {
692
+ if (newVal?.orders) {
515
693
  // 判断是否是当前列的筛选条件
516
694
  const order = newVal.orders.find((item: any) => item.column == props.column)
517
695
  if (order) {
@@ -535,6 +713,75 @@ watch(
535
713
  immediate: true
536
714
  }
537
715
  )
716
+ watch(
717
+ () => props.initValue,
718
+ (newVal, oldVal) => {
719
+ // console.log('监听props.initValue变化', newVal, oldVal)
720
+ // 判断newVal是否为字符串还是对象
721
+ if (newVal && typeof newVal == 'string') {
722
+ hasValue.value = true
723
+ } else {
724
+ hasValue.value = false
725
+ }
726
+ },
727
+ {
728
+ deep: true,
729
+ immediate: true
730
+ }
731
+ )
732
+
733
+ // 获取焦点相关代码
734
+ const textInputRef = ref()
735
+ const numberInputRef = ref()
736
+ let getFocus = () => void 0
737
+
738
+ onMounted(() => {
739
+ if (textInputRef.value) {
740
+ getFocus = () => {
741
+ textInputRef.value.focus()
742
+ }
743
+ }
744
+ if (numberInputRef.value) {
745
+ getFocus = () => {
746
+ numberInputRef.value.focus()
747
+ }
748
+ }
749
+ })
750
+ const currentPage = computed(() => {
751
+ return props.selectConfig.page || 1
752
+ })
753
+ const pageSize = computed(() => {
754
+ return props.selectConfig.limit || 8
755
+ })
756
+ const search = ref('')
757
+ const small = ref(false)
758
+ const background = ref(false) // 是否为圆角
759
+ const selectOptionTotal = ref(0)
760
+
761
+ const OptiosSelect = ref<any[]>([])
762
+ watch(
763
+ () => _selectConfig.value.options,
764
+ (newVal, oldVal) => {
765
+ OptiosSelect.value = newVal
766
+ }
767
+ )
768
+ watch(
769
+ () => props.selectConfig?.options,
770
+ (newVal, oldVal) => {
771
+ if (newVal) {
772
+ OptiosSelect.value = newVal
773
+ }
774
+ },
775
+ { deep: true, immediate: true }
776
+ )
777
+
778
+ const handleSizeChange = (val: number) => {
779
+ console.log(`${val} items per page`)
780
+ }
781
+ const handleCurrentChange = (val: number) => {
782
+ console.log(`current page: ${val}`)
783
+ getOptins()
784
+ }
538
785
  </script>
539
786
 
540
787
  <style scoped lang="scss">
@@ -1,5 +1,3 @@
1
- <!-- @format -->
2
-
3
1
  <template>
4
2
  <svg
5
3
  t="1702537913405"
@@ -16,11 +14,7 @@
16
14
  :fill="color || '#b3b3b3'"
17
15
  p-id="1521"
18
16
  ></path>
19
- <path
20
- d="M614.4 409.6h409.6v102.4h-409.6z"
21
- :fill="color || '#b3b3b3'"
22
- p-id="1522"
23
- ></path>
17
+ <path d="M614.4 409.6h409.6v102.4h-409.6z" :fill="color || '#b3b3b3'" p-id="1522"></path>
24
18
  </svg>
25
19
  </template>
26
20
  <script lang="ts" setup>
@@ -1,5 +1,3 @@
1
- <!-- @format -->
2
-
3
1
  <template>
4
2
  <filterVue style="cursor: pointer" />
5
3
  </template>
@@ -1,5 +1,3 @@
1
- <!-- @format -->
2
-
3
1
  <template>
4
2
  <el-popover
5
3
  ref="popoverRef"