ci-plus 1.3.7 → 1.3.9

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/README.md CHANGED
@@ -46,6 +46,24 @@ npm publish
46
46
 
47
47
  ```
48
48
 
49
+ ## 如果用pnpm安装组件后出现组件中某个依赖报错说没有默认导出
50
+
51
+ ```sh
52
+ # 清楚pnpm缓存,删除项目目录的node_modules文件夹
53
+ pnpm store prune
54
+ # 重新安装
55
+ pnpm install
56
+ ```
57
+
58
+ ## 组件库使用说明
59
+
60
+ ```sh
61
+ # 安装组件
62
+ pnpm install ci-plus -S
63
+ # 安装element-plus 和引入
64
+ pnpm install element-plus@2.5.1 @element-plus/icons-vue@2.3.1 -S
65
+ ```
66
+
49
67
  ## svg图标组件使用说明
50
68
 
51
69
  ```ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ci-plus",
3
- "version": "1.3.7",
3
+ "version": "1.3.9",
4
4
  "description": "ci组件库",
5
5
  "main": "./index.ts",
6
6
  "scripts": {
@@ -27,7 +27,9 @@
27
27
  "qrcode": "^1.5.3",
28
28
  "jsbarcode": "^3.11.6"
29
29
  },
30
- "devDependencies": {},
30
+ "devDependencies": {
31
+ "@vueuse/core": "^9.13.0"
32
+ },
31
33
  "peerDependencies": {},
32
34
  "peerDependenciesMeta": {}
33
35
  }
@@ -25,6 +25,10 @@ declare module '@vue/runtime-core' {
25
25
  CiSeeFile: typeof components.SeeFile
26
26
  CiUpload: typeof components.Upload
27
27
  CiUploadV2: typeof components.UploadV2
28
+
29
+ CiSelect: typeof components.Select
30
+ CiSelectTable: typeof components.SelectTable
31
+ CiQueryCondition: typeof components.QueryCondition
28
32
  }
29
33
  }
30
34
  export { };
package/src/index.ts CHANGED
@@ -16,4 +16,8 @@ export * from './identificationCard/qrcode'; // 导出标识卡二维码模板
16
16
 
17
17
  export * from './fileRelated/index/ciseeFile'; // 导出附件查看组件
18
18
  export * from './fileRelated/index/ciupload'; // 导出附件上传组件
19
- export * from './fileRelated/index/ciuploadV2'; // 导出附件上传v2组件
19
+ export * from './fileRelated/index/ciuploadV2'; // 导出附件上传v2组件
20
+
21
+ export * from './select/index'; // 导出select组件
22
+ export * from './selectTable/index'; // 导出selectTable组件
23
+ export * from './queryCondition/index'; // 导出queryCondition组件
@@ -0,0 +1,4 @@
1
+ import _QueryCondition from './src/index.vue'
2
+ import { withInstall } from '../utils/index';
3
+ export const QueryCondition = withInstall(_QueryCondition)
4
+ export default QueryCondition
@@ -0,0 +1,641 @@
1
+ <template>
2
+ <el-form
3
+ id="t_query_condition"
4
+ v-bind="$attrs"
5
+ :label-width="labelWidth"
6
+ :form="queryState.form"
7
+ size="default"
8
+ class="t-query-condition"
9
+ :style="{
10
+ 'grid-template-areas': gridAreas,
11
+ 'grid-template-columns': `repeat(${colLength}, minmax(0px, ${100 / colLength}%))`
12
+ }"
13
+ @submit.prevent
14
+ >
15
+ <el-form-item
16
+ v-for="(opt, i) in cOpts"
17
+ :key="i"
18
+ :label="opt.label"
19
+ :label-width="opt.labelWidth"
20
+ v-bind="$attrs"
21
+ :style="{ gridArea: i }"
22
+ :class="[opt.className, { render_label: opt.labelRender }]"
23
+ >
24
+ <!-- 自定义label -->
25
+ <template #label v-if="opt.labelRender">
26
+ <render-comp :form="queryState.form" :render="opt.labelRender" />
27
+ </template>
28
+ <!-- 自定义输入框插槽 -->
29
+ <template v-if="opt.slotName">
30
+ <slot :name="opt.slotName" :param="queryState.form" :scope="queryState.form"></slot>
31
+ </template>
32
+ <template v-if="opt.isSelfCom">
33
+ <component
34
+ :is="opt.comp"
35
+ :ref="opt.comp === 't-select-table' ? (el: any) => handleRef(el, i) : ''"
36
+ v-model="queryState.form[opt.dataIndex]"
37
+ :placeholder="opt.placeholder || getPlaceholder(opt)"
38
+ v-bind="
39
+ typeof opt.bind == 'function'
40
+ ? opt.bind(queryState.form)
41
+ : { clearable: true, filterable: true, ...$attrs, ...opt.bind }
42
+ "
43
+ :style="{ width: opt.width || '100%' }"
44
+ @change="handleEvent(opt.event, queryState.form[opt.dataIndex])"
45
+ v-on="cEvent(opt)"
46
+ />
47
+ </template>
48
+ <component
49
+ v-if="!opt.slotName && !opt.isSelfCom && opt.comp.includes('date')"
50
+ :is="opt.comp"
51
+ v-bind="
52
+ typeof opt.bind == 'function'
53
+ ? opt.bind(queryState.form)
54
+ : { clearable: true, filterable: true, ...$attrs, ...opt.bind }
55
+ "
56
+ :placeholder="opt.placeholder || getPlaceholder(opt)"
57
+ @change="handleEvent(opt.event, queryState.form[opt.dataIndex])"
58
+ v-model="queryState.form[opt.dataIndex]"
59
+ v-on="cEvent(opt)"
60
+ />
61
+ <component
62
+ v-if="!opt.slotName && !opt.isSelfCom && opt.comp.includes('tree-select')"
63
+ :is="opt.comp"
64
+ v-bind="
65
+ typeof opt.bind == 'function'
66
+ ? opt.bind(queryState.form)
67
+ : { clearable: true, filterable: true, ...$attrs, ...opt.bind }
68
+ "
69
+ :placeholder="opt.placeholder || getPlaceholder(opt)"
70
+ @change="handleEvent(opt.event, queryState.form[opt.dataIndex])"
71
+ v-model="queryState.form[opt.dataIndex]"
72
+ v-on="cEvent(opt)"
73
+ />
74
+ <component
75
+ v-if="
76
+ !opt.isSelfCom &&
77
+ !opt.slotName &&
78
+ !opt.comp.includes('date') &&
79
+ !opt.comp.includes('tree-select')
80
+ "
81
+ :is="opt.comp"
82
+ v-bind="
83
+ typeof opt.bind == 'function'
84
+ ? opt.bind(queryState.form)
85
+ : { clearable: true, filterable: true, ...$attrs, ...opt.bind }
86
+ "
87
+ :placeholder="opt.placeholder || getPlaceholder(opt)"
88
+ @change="handleEvent(opt.event, queryState.form[opt.dataIndex])"
89
+ v-on="cEvent(opt)"
90
+ v-model="queryState.form[opt.dataIndex]"
91
+ >
92
+ <component
93
+ :is="compChildName(opt)"
94
+ v-for="(value, key, index) in selectListType(opt)"
95
+ :key="index"
96
+ :disabled="value.disabled"
97
+ :label="compChildLabel(opt, value)"
98
+ :value="compChildValue(opt, value, key)"
99
+ >
100
+ {{ compChildShowLabel(opt, value) }}
101
+ </component>
102
+ </component>
103
+ </el-form-item>
104
+ <el-form-item
105
+ v-if="Object.keys(cOpts).length > 0"
106
+ label-width="0"
107
+ style="grid-area: submit_btn"
108
+ :class="[
109
+ 'btn',
110
+ { flex_end: cellLength % colLength === 0 },
111
+ { btn_flex_end: Object.keys(cOpts).length === 4 || cellLength > 3 }
112
+ ]"
113
+ >
114
+ <template v-if="footer !== null">
115
+ <slot name="footer" />
116
+ <template v-if="!slots.footer">
117
+ <el-button class="btn_check" @click="checkHandle" v-bind="queryAttrs" :loading="loading">
118
+ {{ queryAttrs.btnTxt }}
119
+ </el-button>
120
+ <el-button v-if="reset" class="btn_reset" v-bind="resetAttrs" @click="resetHandle">
121
+ {{ resetAttrs.btnTxt }}
122
+ </el-button>
123
+ <slot name="querybar"></slot>
124
+ <el-button
125
+ v-if="originCellLength > maxVisibleSpans && isShowOpen"
126
+ @click="open = !open"
127
+ link
128
+ >
129
+ {{ open ? packUpTxt : unfoldTxt }}
130
+ <el-icon v-if="open">
131
+ <ArrowUp />
132
+ </el-icon>
133
+ <el-icon v-else>
134
+ <ArrowDown />
135
+ </el-icon>
136
+ </el-button>
137
+ </template>
138
+ </template>
139
+ </el-form-item>
140
+ </el-form>
141
+ </template>
142
+
143
+ <script setup lang="ts" name="ci-query-condition">
144
+ import RenderComp from './renderComp.vue'
145
+ import { computed, ref, watch, useSlots, onMounted, reactive, toRef } from 'vue'
146
+ const props = defineProps({
147
+ opts: {
148
+ type: Object,
149
+ required: true,
150
+ default: () => ({})
151
+ },
152
+ labelWidth: {
153
+ type: String,
154
+ default: '120px'
155
+ },
156
+ // 查询按钮配置
157
+ btnCheckBind: {
158
+ type: Object,
159
+ default: () => ({})
160
+ },
161
+ // 重置按钮配置
162
+ btnResetBind: {
163
+ type: Object,
164
+ default: () => ({})
165
+ },
166
+ loading: {
167
+ type: Boolean,
168
+ default: false
169
+ },
170
+ reset: {
171
+ type: Boolean,
172
+ default: true
173
+ },
174
+ boolEnter: {
175
+ type: Boolean,
176
+ default: true
177
+ },
178
+ // 是否显示收起和展开
179
+ isShowOpen: {
180
+ type: Boolean,
181
+ default: true
182
+ },
183
+ // 是否默认展开
184
+ isExpansion: {
185
+ type: Boolean,
186
+ default: false
187
+ },
188
+ // 设置展开的最大 span 数量
189
+ maxVisibleSpans: {
190
+ type: Number,
191
+ default: 4
192
+ },
193
+ packUpTxt: {
194
+ type: String,
195
+ default: '收起'
196
+ },
197
+ unfoldTxt: {
198
+ type: String,
199
+ default: '展开'
200
+ },
201
+ // 是否显示底部操作按钮 :footer="null"
202
+ footer: Object,
203
+ configChangedReset: {
204
+ type: Boolean,
205
+ default: false
206
+ },
207
+ // 是否开启一行显示几个查询条件
208
+ isShowWidthSize: {
209
+ type: Boolean,
210
+ default: false
211
+ },
212
+ // 一行显示几个查询条件
213
+ widthSize: {
214
+ type: Number,
215
+ default: 4
216
+ }
217
+ })
218
+ const slots = useSlots()
219
+ const maxVisibleSpans = toRef(props, 'maxVisibleSpans')
220
+ // 判断是否使用了某个插槽
221
+ const isShow = (name) => {
222
+ return Object.keys(slots).includes(name)
223
+ }
224
+ // 初始化表单数据
225
+ let queryState = reactive({
226
+ form: Object.keys(props.opts).reduce((acc: any, field: any) => {
227
+ acc[field] = props.opts[field].defaultVal || null
228
+ return acc
229
+ }, {})
230
+ })
231
+ let colLength = ref(4)
232
+ let open = ref(false)
233
+ // 默认展开
234
+ if (props.isExpansion) {
235
+ open.value = true
236
+ } else {
237
+ open.value = false
238
+ }
239
+ // 查询按钮配置
240
+ const queryAttrs = computed(() => {
241
+ return {
242
+ type: 'primary',
243
+ size: 'default',
244
+ btnTxt: '查询',
245
+ ...props.btnCheckBind
246
+ }
247
+ })
248
+ // 重置按钮配置
249
+ const resetAttrs = computed(() => {
250
+ return { size: 'default', btnTxt: '重置', ...props.btnResetBind }
251
+ })
252
+ const originCellLength = computed(() => {
253
+ let length = 0
254
+ Object.keys(props.opts).forEach((key) => {
255
+ let span = props.opts[key].span || 1
256
+ if ((length % colLength.value) + span > colLength.value) {
257
+ length += colLength.value - (length % colLength.value)
258
+ }
259
+ length += span
260
+ })
261
+ return length
262
+ })
263
+ const cOpts = computed(() => {
264
+ let renderSpan = 0
265
+ return Object.keys(props.opts).reduce((acc: any, field: any) => {
266
+ let opt = {
267
+ ...props.opts[field]
268
+ }
269
+ // 收起、展开操作
270
+ if (props.isShowOpen) {
271
+ renderSpan += opt.span ?? 1
272
+ if (!open.value && renderSpan - 1 >= maxVisibleSpans.value) return acc
273
+ }
274
+ opt.dataIndex = field
275
+ acc[field] = opt
276
+ return acc
277
+ }, {})
278
+ })
279
+ const cellLength: any = computed(() => {
280
+ // 占用单元格长度
281
+ let length = 0
282
+ Object.keys(props.opts).forEach((key) => {
283
+ let span = props.opts[key].span > 4 ? 4 : props.opts[key].span || 1
284
+ length += span
285
+ })
286
+ return length
287
+ })
288
+ const gridAreas = computed(() => {
289
+ // grid布局按钮位置
290
+ const fields = Object.keys(cOpts.value)
291
+ let rowIndex = 0
292
+ let rowSpan = 0
293
+ const areas: any = [[]]
294
+ for (let fieldIndex = 0; fieldIndex < fields.length; fieldIndex++) {
295
+ const field = fields[fieldIndex]
296
+ const opt = cOpts.value[field]
297
+ const span = Math.min(opt.span ?? 1, 4) // 最大4
298
+ if (rowSpan + span > colLength.value) {
299
+ if (rowSpan < colLength.value) {
300
+ areas[rowIndex].push('.')
301
+ }
302
+ rowSpan = 0
303
+ areas[++rowIndex] = []
304
+ }
305
+ rowSpan += span
306
+ for (let index = 0; index < span; index++) {
307
+ areas[rowIndex].push(field)
308
+ }
309
+ }
310
+ if (areas[rowIndex].length === colLength.value) {
311
+ areas.push(['submit_btn', 'submit_btn', 'submit_btn', 'submit_btn'])
312
+ } else {
313
+ while (areas[rowIndex].length < colLength.value) {
314
+ areas[rowIndex].push('submit_btn')
315
+ }
316
+ }
317
+ return areas.reduce((acc, cur) => {
318
+ acc += `'${cur.join(' ')}'\n`
319
+ return acc
320
+ }, '')
321
+ })
322
+ // 引用第三方事件
323
+ const cEvent = computed(() => {
324
+ return (opt: any) => {
325
+ // console.log('opt--', opt)
326
+ let event = { ...opt.eventHandle }
327
+ let changeEvent = {}
328
+ Object.keys(event).forEach((v) => {
329
+ changeEvent[v] = (e) => {
330
+ if (
331
+ opt.comp.includes('select') ||
332
+ opt.comp.includes('picker') ||
333
+ opt.comp.includes('date')
334
+ ) {
335
+ event[v] && event[v](e, queryState.form)
336
+ } else {
337
+ if (e) {
338
+ event[v] && event[v](e, queryState.form)
339
+ } else {
340
+ event[v] && event[v](queryState.form)
341
+ }
342
+ }
343
+ }
344
+ })
345
+ return { ...changeEvent }
346
+ }
347
+ })
348
+ // 初始化表单数据
349
+ const initForm = (opts: any, keepVal = false) => {
350
+ return Object.keys(opts).reduce((acc, field) => {
351
+ if (keepVal && queryState.form) {
352
+ acc[field] = queryState.form[field] ?? opts[field].defaultVal ?? null
353
+ } else {
354
+ acc[field] = opts[field].defaultVal ?? null
355
+ }
356
+ return acc
357
+ }, {})
358
+ }
359
+ const getColLength = () => {
360
+ // 行列数
361
+ const width = window.innerWidth
362
+ let colLength = 4
363
+ if (width > 768 && width < 1280) {
364
+ colLength = 3
365
+ } else if (width <= 768) {
366
+ colLength = 2
367
+ }
368
+ return colLength
369
+ }
370
+ const emits = defineEmits(['handleEvent', 'submit', 'reset'])
371
+ // 下拉选择表格组件 ref
372
+ const tselecttableref: any = ref({})
373
+ // 下拉选择表格组件 动态ref
374
+ const handleRef = (el, key) => {
375
+ if (el) {
376
+ tselecttableref.value[`tselecttableref-${key}`] = el
377
+ }
378
+ }
379
+ // 重置
380
+ const resetHandle = () => {
381
+ queryState.form = initForm(props.opts)
382
+ // 获取所有下拉选择表格组件
383
+ const refList = Object.keys(tselecttableref.value).filter((item) =>
384
+ item.includes('tselecttableref')
385
+ )
386
+ if (refList.length > 0 && tselecttableref.value) {
387
+ refList.map((val) => {
388
+ // console.log('9999', val)
389
+ tselecttableref.value[val].clear()
390
+ })
391
+ }
392
+ emits('reset', queryState.form)
393
+ checkHandle('reset')
394
+ }
395
+ // 重置数据
396
+ const resetData = () => {
397
+ queryState.form = initForm(props.opts)
398
+ // 获取所有下拉选择表格组件
399
+ const refList = Object.keys(tselecttableref.value).filter((item) =>
400
+ item.includes('tselecttableref')
401
+ )
402
+ if (refList.length > 0 && tselecttableref.value) {
403
+ refList.map((val) => {
404
+ // console.log('9999', val)
405
+ tselecttableref.value[val].clear()
406
+ })
407
+ }
408
+ }
409
+ // 查询条件change事件
410
+ const handleEvent = (type, val) => {
411
+ emits('handleEvent', type, val, queryState.form)
412
+ }
413
+ // 查询
414
+ const checkHandle = (flagText: any = false) => {
415
+ emits('submit', queryState.form, flagText)
416
+ }
417
+ // 子组件名称
418
+ const compChildName: any = computed(() => {
419
+ return (opt: any) => {
420
+ switch (opt.type) {
421
+ case 'checkbox':
422
+ return 'el-checkbox'
423
+ case 'radio':
424
+ return 'el-radio'
425
+ case 'select-arr':
426
+ case 'select-obj':
427
+ return 'el-option'
428
+ }
429
+ }
430
+ })
431
+ // 下拉数据
432
+ const selectListType = computed(() => {
433
+ return (opt: any) => {
434
+ if (opt.listTypeInfo) {
435
+ return opt.listTypeInfo[opt.list]
436
+ } else {
437
+ return []
438
+ }
439
+ }
440
+ })
441
+ // 子子组件label
442
+ const compChildLabel = computed(() => {
443
+ return (opt: any, value) => {
444
+ switch (opt.type) {
445
+ case 'radio':
446
+ case 'checkbox':
447
+ return value.value
448
+ case 'el-select-multiple':
449
+ case 'select-arr':
450
+ return value[opt.arrLabel || 'dictLabel']
451
+ case 'select-obj':
452
+ return value
453
+ }
454
+ }
455
+ })
456
+ // 子子组件value
457
+ const compChildValue = computed(() => {
458
+ return (opt: any, value, key) => {
459
+ switch (opt.type) {
460
+ case 'radio':
461
+ case 'checkbox':
462
+ return value.value
463
+ case 'el-select-multiple':
464
+ case 'select-arr':
465
+ return value[opt.arrKey || 'dictValue']
466
+ case 'select-obj':
467
+ return key
468
+ }
469
+ }
470
+ })
471
+ // 子子组件文字展示
472
+ const compChildShowLabel = computed(() => {
473
+ return (opt: any, value) => {
474
+ switch (opt.type) {
475
+ case 'radio':
476
+ case 'checkbox':
477
+ return value.label
478
+ case 'el-select-multiple':
479
+ case 'select-arr':
480
+ return value[opt.arrLabel || 'dictLabel']
481
+ case 'select-obj':
482
+ return value
483
+ }
484
+ }
485
+ })
486
+ // placeholder的显示
487
+ const getPlaceholder = (row: any) => {
488
+ // console.log(77, row.date)
489
+ let placeholder
490
+ if (row.comp && typeof row.comp == 'string') {
491
+ if (row.comp.includes('input')) {
492
+ placeholder = '请输入' + row.label
493
+ } else if (row.comp.includes('select') || row.comp.includes('date')) {
494
+ placeholder = '请选择' + row.label
495
+ } else {
496
+ placeholder = row.label
497
+ }
498
+ }
499
+ return placeholder
500
+ }
501
+ onMounted(() => {
502
+ if (props.isShowWidthSize) {
503
+ colLength.value = props.widthSize
504
+ } else {
505
+ colLength.value = getColLength()
506
+ }
507
+ if (props.boolEnter) {
508
+ document.onkeyup = (e) => {
509
+ // console.log(7777, e)
510
+ let key = e.keyCode
511
+ let pagination = document.querySelectorAll('.el-pagination')
512
+ let isPaginationInputFocus = false
513
+ if (pagination) {
514
+ pagination.forEach((ele) => {
515
+ let paginationInputList = ele.getElementsByTagName('input')
516
+ let paginationInput = paginationInputList[paginationInputList.length - 1]
517
+ // 判断是否有分页器筛选输入框获取焦点
518
+ if (paginationInput === document.activeElement) {
519
+ isPaginationInputFocus = true
520
+ }
521
+ })
522
+ }
523
+ if (isPaginationInputFocus) {
524
+ return
525
+ }
526
+ if (key === 13) {
527
+ checkHandle()
528
+ }
529
+ }
530
+ }
531
+ // 使用自定义按钮插槽默认展开所有查询条件
532
+ if (isShow('footer')) {
533
+ open.value = true
534
+ }
535
+ })
536
+ watch(
537
+ () => props.widthSize,
538
+ (val) => {
539
+ colLength.value = val
540
+ }
541
+ )
542
+ watch(
543
+ () => props.opts,
544
+ (opts) => {
545
+ queryState.form = initForm(opts, !props.configChangedReset)
546
+ },
547
+ { deep: true }
548
+ )
549
+
550
+ // 暴露方法出去
551
+ defineExpose({
552
+ queryState,
553
+ props,
554
+ colLength,
555
+ resetData,
556
+ resetHandle,
557
+ checkHandle
558
+ })
559
+ </script>
560
+
561
+ <style lang="scss">
562
+ .t-query-condition.el-form {
563
+ position: relative;
564
+ display: grid;
565
+ gap: 2px 8px;
566
+ margin-bottom: -7px;
567
+ text-align: left;
568
+
569
+ .el-select,
570
+ .el-date-editor,
571
+ .ant-calendar-picker {
572
+ width: 100%;
573
+ }
574
+
575
+ .flex_end {
576
+ grid-area: submit_btn;
577
+ margin-top: 2px;
578
+
579
+ .el-form-item__content {
580
+ display: flex;
581
+ // justify-content: flex-end;
582
+ align-items: center;
583
+ overflow: visible !important;
584
+ }
585
+ }
586
+
587
+ .btn {
588
+ .el-form-item__content {
589
+ display: flex;
590
+ // justify-content: flex-end;
591
+ }
592
+ }
593
+
594
+ .btn_flex_end {
595
+ .el-form-item__content {
596
+ justify-content: flex-end;
597
+ }
598
+ }
599
+
600
+ .el-form-item {
601
+ display: flex;
602
+ margin-bottom: 6px;
603
+
604
+ .el-form-item__label {
605
+ flex-shrink: 0;
606
+ min-width: 60px;
607
+ padding-left: 8px;
608
+ }
609
+
610
+ .el-form-item__content {
611
+ flex-grow: 1;
612
+ // overflow: hidden;
613
+ margin-left: 0 !important;
614
+ }
615
+ }
616
+
617
+ .render_label {
618
+ .el-form-item__label {
619
+ cursor: pointer;
620
+ display: flex;
621
+ align-items: center;
622
+ justify-content: flex-end;
623
+
624
+ &::before {
625
+ margin-top: 1px;
626
+ }
627
+ }
628
+ }
629
+
630
+ .btn_check {
631
+ position: relative;
632
+ top: -1px;
633
+ }
634
+
635
+ .btn_reset {
636
+ position: relative;
637
+ top: -1px;
638
+ margin-left: 8px;
639
+ }
640
+ }
641
+ </style>