@mixd-id/web-scaffold 0.1.230406289 → 0.1.230406291
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/Button.vue +5 -5
- package/src/components/Image.vue +1 -1
- package/src/components/List.vue +39 -107
- package/src/components/VirtualTable.vue +109 -7
- package/src/index.js +2 -1
- package/src/mixin/component.js +4 -1
- package/src/utils/preset-selector.js +24 -9
- package/src/utils/preset-selector.mjs +104 -1
- package/src/widgets/PresetBar.vue +48 -5
- package/src/widgets/PresetBarPivotColumnEdit.vue +172 -0
package/package.json
CHANGED
|
@@ -146,7 +146,7 @@ export default{
|
|
|
146
146
|
@apply flex items-center justify-center
|
|
147
147
|
}
|
|
148
148
|
.button:disabled{
|
|
149
|
-
|
|
149
|
+
@apply text-opacity-50;
|
|
150
150
|
}
|
|
151
151
|
.button:active{
|
|
152
152
|
@apply top-[1px] left-[1px] relative;
|
|
@@ -164,7 +164,7 @@ export default{
|
|
|
164
164
|
@apply bg-primary-600;
|
|
165
165
|
}
|
|
166
166
|
.button-primary:disabled{
|
|
167
|
-
@apply bg-primary-500
|
|
167
|
+
@apply bg-primary-500 top-0 left-0 cursor-not-allowed;
|
|
168
168
|
@apply top-0 left-0;
|
|
169
169
|
}
|
|
170
170
|
.button-primary *{
|
|
@@ -188,7 +188,7 @@ export default{
|
|
|
188
188
|
.button-outline:hover{
|
|
189
189
|
}
|
|
190
190
|
.button-outline:disabled{
|
|
191
|
-
@apply
|
|
191
|
+
@apply top-0 left-0 cursor-not-allowed;
|
|
192
192
|
@apply text-text border-primary-500;
|
|
193
193
|
}
|
|
194
194
|
.button-outline *{
|
|
@@ -214,7 +214,7 @@ export default{
|
|
|
214
214
|
@apply bg-primary-200 border-primary-200;
|
|
215
215
|
}
|
|
216
216
|
.button-secondary:disabled{
|
|
217
|
-
@apply bg-primary-100
|
|
217
|
+
@apply bg-primary-100 top-0 left-0 cursor-not-allowed;
|
|
218
218
|
}
|
|
219
219
|
.button-secondary *{
|
|
220
220
|
@apply text-text-500 fill-white;
|
|
@@ -238,7 +238,7 @@ export default{
|
|
|
238
238
|
@apply bg-red-600 border-red-600;
|
|
239
239
|
}
|
|
240
240
|
.button-red:disabled{
|
|
241
|
-
@apply bg-red-500 border-red-500
|
|
241
|
+
@apply bg-red-500 border-red-500 top-0 left-0 cursor-not-allowed;
|
|
242
242
|
}
|
|
243
243
|
.button-red *{
|
|
244
244
|
@apply text-white fill-white;
|
package/src/components/Image.vue
CHANGED
package/src/components/List.vue
CHANGED
|
@@ -120,7 +120,11 @@
|
|
|
120
120
|
</div>
|
|
121
121
|
</slot>
|
|
122
122
|
|
|
123
|
-
<
|
|
123
|
+
<div v-if="readyState === 3" class="flex-1 flex items-center justify-center">
|
|
124
|
+
<svg class="animate-spin" width="36" height="36" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path></svg>
|
|
125
|
+
</div>
|
|
126
|
+
|
|
127
|
+
<VirtualTable v-else-if="presetView === 'table' || pivotEnabled"
|
|
124
128
|
ref="table"
|
|
125
129
|
:columns="columns"
|
|
126
130
|
class="flex-1 rounded-lg panel-400"
|
|
@@ -244,7 +248,7 @@ import VirtualGrid from "./VirtualGrid.vue";
|
|
|
244
248
|
import throttle from "lodash/throttle";
|
|
245
249
|
import PresetSelector from "../widgets/PresetSelector.vue";
|
|
246
250
|
import groupBy from "lodash/groupBy";
|
|
247
|
-
import {sortsFn} from "../utils/preset-selector.mjs";
|
|
251
|
+
import { generatePivotColumns, sortsFn } from "../utils/preset-selector.mjs";
|
|
248
252
|
import PresetBar from "../widgets/PresetBar.vue";
|
|
249
253
|
|
|
250
254
|
export default{
|
|
@@ -304,114 +308,20 @@ export default{
|
|
|
304
308
|
.join(' ')
|
|
305
309
|
},
|
|
306
310
|
|
|
307
|
-
generatePivotColumns(items){
|
|
308
|
-
if(!this.preset.pivot || !this.preset.pivot.enabled) return
|
|
309
|
-
if(!Array.isArray(items) && items.length < 1) return
|
|
310
|
-
|
|
311
|
-
const tableColumns = (this.preset.columns ?? this.config.columns)
|
|
312
|
-
.reduce((cur, obj) => {
|
|
313
|
-
cur[obj.key] = obj
|
|
314
|
-
return cur
|
|
315
|
-
}, {})
|
|
316
|
-
|
|
317
|
-
const currentPivotColumns = [ ...(this.preset.pivot.columns ?? []) ]
|
|
318
|
-
.reduce((cur, obj) => {
|
|
319
|
-
cur[obj.key] = obj
|
|
320
|
-
return cur
|
|
321
|
-
}, {})
|
|
322
|
-
|
|
323
|
-
const pivotColumns = []
|
|
324
|
-
|
|
325
|
-
for(let row of this.preset.pivot.rows){
|
|
326
|
-
|
|
327
|
-
let format
|
|
328
|
-
switch(row.aggregrate){
|
|
329
|
-
case 'year':
|
|
330
|
-
format = 'YYYY'
|
|
331
|
-
break
|
|
332
|
-
|
|
333
|
-
case 'month':
|
|
334
|
-
format = 'MMM YYYY'
|
|
335
|
-
break
|
|
336
|
-
|
|
337
|
-
case 'date':
|
|
338
|
-
format = 'D MMM YYYY'
|
|
339
|
-
break
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
if(currentPivotColumns[row.key]){
|
|
343
|
-
Object.assign(currentPivotColumns[row.key], {
|
|
344
|
-
format,
|
|
345
|
-
visible: true
|
|
346
|
-
})
|
|
347
|
-
|
|
348
|
-
pivotColumns.push(currentPivotColumns[row.key])
|
|
349
|
-
}
|
|
350
|
-
else{
|
|
351
|
-
pivotColumns.push({
|
|
352
|
-
...tableColumns[row.key],
|
|
353
|
-
format,
|
|
354
|
-
visible: true
|
|
355
|
-
})
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
for(let key in items[0]){
|
|
360
|
-
if(key.startsWith('_')){
|
|
361
|
-
let [ k1, ...k2 ] = key.substring(1).split('-')
|
|
362
|
-
k2 = k2.join('-')
|
|
363
|
-
|
|
364
|
-
let label = k2.replace(/_/gi, ' ')
|
|
365
|
-
const column = tableColumns[k1]
|
|
366
|
-
if(column){
|
|
367
|
-
switch(column.type){
|
|
368
|
-
case 'enum':
|
|
369
|
-
label = (column.typeParams ?? []).find(_ => `${_.value}` === `${k2}`)?.text ?? label
|
|
370
|
-
break
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
if(currentPivotColumns[key]){
|
|
375
|
-
Object.assign(currentPivotColumns[key], {
|
|
376
|
-
visible: true
|
|
377
|
-
})
|
|
378
|
-
|
|
379
|
-
pivotColumns.push(currentPivotColumns[key])
|
|
380
|
-
}
|
|
381
|
-
else{
|
|
382
|
-
pivotColumns.push({
|
|
383
|
-
key,
|
|
384
|
-
label,
|
|
385
|
-
label2: (((tableColumns[k1] ?? {}).label ?? '') + ': ' + label).trim(),
|
|
386
|
-
type: 'number',
|
|
387
|
-
})
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
(this.preset.pivot.columns ?? []).filter(_ => !pivotColumns.find(i => i.key === _.key))
|
|
393
|
-
.forEach(_ => {
|
|
394
|
-
_.visible = false
|
|
395
|
-
pivotColumns.push(_)
|
|
396
|
-
})
|
|
397
|
-
|
|
398
|
-
this.preset.pivot.columns = pivotColumns
|
|
399
|
-
|
|
400
|
-
},
|
|
401
|
-
|
|
402
311
|
load(){
|
|
403
312
|
if(this.src){
|
|
404
313
|
if(!this.preset.columns){
|
|
405
314
|
this.preset.columns = JSON.parse(JSON.stringify(this.config.columns))
|
|
406
315
|
}
|
|
407
316
|
|
|
317
|
+
this.readyState = 3
|
|
408
318
|
return this.socket.send(this.src, {
|
|
409
319
|
...this.preset,
|
|
410
320
|
itemsPerPage: this.data.itemsPerPage,
|
|
411
321
|
})
|
|
412
322
|
.then(data => {
|
|
413
323
|
|
|
414
|
-
this.
|
|
324
|
+
generatePivotColumns(this.preset, data.items)
|
|
415
325
|
this.loadEnums(data.items)
|
|
416
326
|
Object.assign(this.data, data ?? {})
|
|
417
327
|
this.$emit('after-load')
|
|
@@ -420,6 +330,7 @@ export default{
|
|
|
420
330
|
.catch(err => {
|
|
421
331
|
this.toast(err)
|
|
422
332
|
})
|
|
333
|
+
.finally(_ => this.readyState = 1)
|
|
423
334
|
}
|
|
424
335
|
return new Promise(resolve => resolve())
|
|
425
336
|
},
|
|
@@ -529,7 +440,7 @@ export default{
|
|
|
529
440
|
},
|
|
530
441
|
|
|
531
442
|
loadExt(){
|
|
532
|
-
if(!this.
|
|
443
|
+
if(!this.extBar.open) return
|
|
533
444
|
|
|
534
445
|
this.readyState = 3
|
|
535
446
|
return this.socket.send(this.src, {
|
|
@@ -620,7 +531,6 @@ export default{
|
|
|
620
531
|
|
|
621
532
|
onSignal(event, items){
|
|
622
533
|
if(this.pivotEnabled){
|
|
623
|
-
console.log('no background update due ti pivot')
|
|
624
534
|
return
|
|
625
535
|
}
|
|
626
536
|
|
|
@@ -654,11 +564,22 @@ export default{
|
|
|
654
564
|
const filters = []
|
|
655
565
|
|
|
656
566
|
for(let idx in this.preset.pivot.rows){
|
|
567
|
+
const key = this.preset.pivot.rows[idx].key
|
|
568
|
+
const presetColumn = this.preset.columns.find(_ => _.key === key)
|
|
569
|
+
let value = item[this.preset.pivot.rows[idx].key]
|
|
570
|
+
switch(presetColumn.type){
|
|
571
|
+
|
|
572
|
+
case 'bool':
|
|
573
|
+
case 'boolean':
|
|
574
|
+
value = value === 'true'
|
|
575
|
+
break
|
|
576
|
+
}
|
|
577
|
+
|
|
657
578
|
filters.push({
|
|
658
|
-
key
|
|
579
|
+
key,
|
|
659
580
|
value: [{
|
|
660
581
|
operator: '=',
|
|
661
|
-
value
|
|
582
|
+
value
|
|
662
583
|
}]
|
|
663
584
|
})
|
|
664
585
|
}
|
|
@@ -666,12 +587,24 @@ export default{
|
|
|
666
587
|
let [ kk, ...vv ] = column.key.split('-')
|
|
667
588
|
vv = vv.join('-')
|
|
668
589
|
|
|
669
|
-
if(![ 'count' ].includes(vv)){
|
|
590
|
+
if(![ 'count', 'countDistinct' ].includes(vv)){
|
|
591
|
+
|
|
592
|
+
const key = kk.substring(1)
|
|
593
|
+
const presetColumn = this.preset.columns.find(_ => _.key === key)
|
|
594
|
+
let value = vv
|
|
595
|
+
switch(presetColumn.type){
|
|
596
|
+
|
|
597
|
+
case 'bool':
|
|
598
|
+
case 'boolean':
|
|
599
|
+
value = value === 'true'
|
|
600
|
+
break
|
|
601
|
+
}
|
|
602
|
+
|
|
670
603
|
filters.push({
|
|
671
|
-
key
|
|
604
|
+
key,
|
|
672
605
|
value: [{
|
|
673
606
|
operator: '=',
|
|
674
|
-
value
|
|
607
|
+
value
|
|
675
608
|
}]
|
|
676
609
|
})
|
|
677
610
|
}
|
|
@@ -700,7 +633,7 @@ export default{
|
|
|
700
633
|
switch(e.code){
|
|
701
634
|
|
|
702
635
|
case 'Backquote':
|
|
703
|
-
this
|
|
636
|
+
this.togglePreset()
|
|
704
637
|
break
|
|
705
638
|
|
|
706
639
|
default:
|
|
@@ -923,7 +856,6 @@ export default{
|
|
|
923
856
|
|
|
924
857
|
.resize2{
|
|
925
858
|
@apply h-[5px] hover:bg-primary bg-text-50 cursor-n-resize absolute top-0 left-0 right-0 flex items-center justify-center;
|
|
926
|
-
@apply z-20;
|
|
927
859
|
}
|
|
928
860
|
|
|
929
861
|
.extClose{
|
|
@@ -4,10 +4,11 @@
|
|
|
4
4
|
<table :class="$style.table" ref="tableHead" :style="tableHeadStyle">
|
|
5
5
|
<thead>
|
|
6
6
|
<tr>
|
|
7
|
-
<th v-for="column in visibleColumns" :style="thStyle(column)"
|
|
7
|
+
<th v-for="column in visibleColumns" :style="thStyle(column)"
|
|
8
|
+
v-tooltip="`${column.label ? column.label : column.key}`">
|
|
8
9
|
<slot v-if="$slots['col-' + column.key]" :name="'col-' + column.key" :column="column"></slot>
|
|
9
10
|
<div v-else :class="headerColumnClass(column)">
|
|
10
|
-
<span>{{ column.label ?? column.key }}</span>
|
|
11
|
+
<span>{{ column.label2 ? column.label2 : (column.label ?? column.key) }}</span>
|
|
11
12
|
</div>
|
|
12
13
|
<div :class="$style.separator" @mousedown="startResize($event, column)"></div>
|
|
13
14
|
</th>
|
|
@@ -39,7 +40,7 @@
|
|
|
39
40
|
@click="$emit('item-click', item, column)">
|
|
40
41
|
<slot v-if="$slots[column.key]" :name="column.key" :column="column" :item="item" :index="visibleStartIndex + index"></slot>
|
|
41
42
|
<slot v-else-if="$slots.default" name="default" :column="column" :item="item" :index="visibleStartIndex + index"></slot>
|
|
42
|
-
<div v-else :class="columnClass(column)" v-html="formatColumn(item, column)"></div>
|
|
43
|
+
<div v-else :class="columnClass(column, item)" v-html="formatColumn(item, column)"></div>
|
|
43
44
|
</td>
|
|
44
45
|
<td :class="$style.spacer"></td>
|
|
45
46
|
</tr>
|
|
@@ -201,7 +202,6 @@ export default{
|
|
|
201
202
|
this.resize()
|
|
202
203
|
|
|
203
204
|
const observer = new MutationObserver((mutationsList) => {
|
|
204
|
-
console.log(mutationsList)
|
|
205
205
|
this.resize()
|
|
206
206
|
});
|
|
207
207
|
observer.observe(this.$el, { attributes: true });
|
|
@@ -254,7 +254,7 @@ export default{
|
|
|
254
254
|
this.itemHeight = parseInt(window.getComputedStyle(this.$refs.calc).height)
|
|
255
255
|
this.maxVisibleItems = elHeight > 0 ? Math.ceil(elHeight / this.itemHeight) + 1 : this.items.length
|
|
256
256
|
|
|
257
|
-
if(this.itemHeight <= 0){
|
|
257
|
+
if(this.itemHeight <= 0 && import.meta.env.DEV){
|
|
258
258
|
console.error('[VirtualTable] Unable to calculate item height, make sure not async component.')
|
|
259
259
|
}
|
|
260
260
|
}
|
|
@@ -323,7 +323,7 @@ export default{
|
|
|
323
323
|
window.addEventListener('mouseup', onMouseUp)
|
|
324
324
|
},
|
|
325
325
|
|
|
326
|
-
columnClass(column){
|
|
326
|
+
columnClass(column, item){
|
|
327
327
|
|
|
328
328
|
let align
|
|
329
329
|
if(!column.align){
|
|
@@ -334,9 +334,111 @@ export default{
|
|
|
334
334
|
}
|
|
335
335
|
}
|
|
336
336
|
|
|
337
|
+
let appearanceClass = ''
|
|
338
|
+
if(item && Array.isArray(column.appearances)){
|
|
339
|
+
|
|
340
|
+
let value
|
|
341
|
+
switch(column.type){
|
|
342
|
+
|
|
343
|
+
case 'number':
|
|
344
|
+
value = parseInt(item[column.key])
|
|
345
|
+
break
|
|
346
|
+
|
|
347
|
+
default:
|
|
348
|
+
value = (item[column.key] ?? '').toString()
|
|
349
|
+
break
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
for(let appearance of column.appearances){
|
|
353
|
+
|
|
354
|
+
let conditionMatched = true
|
|
355
|
+
for(let condition of appearance.conditions ?? []){
|
|
356
|
+
switch(condition.operator){
|
|
357
|
+
|
|
358
|
+
case '>':
|
|
359
|
+
if(value <= condition.value){
|
|
360
|
+
conditionMatched = false
|
|
361
|
+
}
|
|
362
|
+
break
|
|
363
|
+
|
|
364
|
+
case '>=':
|
|
365
|
+
if(value < condition.value){
|
|
366
|
+
conditionMatched = false
|
|
367
|
+
}
|
|
368
|
+
break
|
|
369
|
+
|
|
370
|
+
case '=':
|
|
371
|
+
if(value !== condition.value){
|
|
372
|
+
conditionMatched = false
|
|
373
|
+
}
|
|
374
|
+
break
|
|
375
|
+
|
|
376
|
+
case '<':
|
|
377
|
+
if(value >= condition.value){
|
|
378
|
+
conditionMatched = false
|
|
379
|
+
}
|
|
380
|
+
break
|
|
381
|
+
|
|
382
|
+
case '<=':
|
|
383
|
+
if(value > condition.value){
|
|
384
|
+
conditionMatched = false
|
|
385
|
+
}
|
|
386
|
+
break
|
|
387
|
+
|
|
388
|
+
case 'startsWith':
|
|
389
|
+
if(!value.startsWith(condition.value)){
|
|
390
|
+
conditionMatched = false
|
|
391
|
+
}
|
|
392
|
+
break
|
|
393
|
+
|
|
394
|
+
case 'notStartsWith':
|
|
395
|
+
if(value.startsWith(condition.value)){
|
|
396
|
+
conditionMatched = false
|
|
397
|
+
}
|
|
398
|
+
break
|
|
399
|
+
|
|
400
|
+
case 'contains':
|
|
401
|
+
if(value.indexOf(condition.value) < 0){
|
|
402
|
+
conditionMatched = false
|
|
403
|
+
}
|
|
404
|
+
break
|
|
405
|
+
|
|
406
|
+
case 'notContains':
|
|
407
|
+
if(value.indexOf(condition.value) >= 0){
|
|
408
|
+
conditionMatched = false
|
|
409
|
+
}
|
|
410
|
+
break
|
|
411
|
+
|
|
412
|
+
case 'endsWith':
|
|
413
|
+
if(!value.endsWith(condition.value)){
|
|
414
|
+
conditionMatched = false
|
|
415
|
+
}
|
|
416
|
+
break
|
|
417
|
+
|
|
418
|
+
case 'notEndsWith':
|
|
419
|
+
if(value.endsWith(condition.value)){
|
|
420
|
+
conditionMatched = false
|
|
421
|
+
}
|
|
422
|
+
break
|
|
423
|
+
|
|
424
|
+
case 'regex':
|
|
425
|
+
break
|
|
426
|
+
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
if(!conditionMatched) break
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
if(conditionMatched){
|
|
433
|
+
appearanceClass = appearance.class
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
|
|
337
438
|
return [
|
|
338
439
|
this.$style.tdDiv,
|
|
339
|
-
this.$style['align-' + align]
|
|
440
|
+
this.$style['align-' + align],
|
|
441
|
+
appearanceClass
|
|
340
442
|
]
|
|
341
443
|
.join(' ')
|
|
342
444
|
},
|
package/src/index.js
CHANGED
|
@@ -332,7 +332,7 @@ export default{
|
|
|
332
332
|
tooltip.classList.add('active')
|
|
333
333
|
}
|
|
334
334
|
}
|
|
335
|
-
},
|
|
335
|
+
}, 1000)
|
|
336
336
|
el.setAttribute('data-tooltip-open', true)
|
|
337
337
|
})
|
|
338
338
|
|
|
@@ -565,6 +565,7 @@ export default{
|
|
|
565
565
|
app.component('SvgSetting', defineAsyncComponent(() => import("./widgets/SvgSetting.vue")))
|
|
566
566
|
app.component('PresetBar', defineAsyncComponent(() => import("./widgets/PresetBar.vue")))
|
|
567
567
|
app.component('PresetSelector', defineAsyncComponent(() => import("./widgets/PresetSelector.vue")))
|
|
568
|
+
app.component('PresetBarPivotColumnEdit', defineAsyncComponent(() => import("./widgets/PresetBarPivotColumnEdit.vue")))
|
|
568
569
|
app.component('LogViewer', defineAsyncComponent(() => import("./widgets/LogViewer.vue")))
|
|
569
570
|
app.component('ColumnSelector', defineAsyncComponent(() => import("./widgets/ColumnSelector.vue")))
|
|
570
571
|
},
|
package/src/mixin/component.js
CHANGED
|
@@ -4,7 +4,7 @@ const {inspect} = require("util");
|
|
|
4
4
|
const {ftWildcard} = require("./helpers");
|
|
5
5
|
const util = require("util");
|
|
6
6
|
const {snakeCase} = require("lodash");
|
|
7
|
-
const {Op, literal, fn} = module.parent.require("sequelize");
|
|
7
|
+
const {Op, literal, fn, DataTypes} = module.parent.require("sequelize");
|
|
8
8
|
|
|
9
9
|
const getValue = (filter, opt) => {
|
|
10
10
|
|
|
@@ -737,28 +737,34 @@ const pivotToSequelizeWhere = async (pivot, opt) => {
|
|
|
737
737
|
|
|
738
738
|
const sortKeyToOrders = {} // Helper to determine group ordering
|
|
739
739
|
for(let value of pivot.values){
|
|
740
|
+
const valueKey = model.rawAttributes[value.key].field
|
|
740
741
|
|
|
741
742
|
switch(value.aggregrate){
|
|
742
743
|
|
|
743
744
|
case 'sum':
|
|
744
|
-
attributes.push([ fn('SUM', literal(`${model.name}.${
|
|
745
|
+
attributes.push([ fn('SUM', literal(`${model.name}.${valueKey}`)), `_${value.key}-${value.aggregrate}` ])
|
|
745
746
|
break
|
|
746
747
|
|
|
747
748
|
case 'avg':
|
|
748
|
-
attributes.push([ fn('AVG', literal(`${model.name}.${
|
|
749
|
+
attributes.push([ fn('AVG', literal(`${model.name}.${valueKey}`)), `_${value.key}-${value.aggregrate}` ])
|
|
749
750
|
break
|
|
750
751
|
|
|
751
752
|
case 'min':
|
|
752
|
-
attributes.push([ fn('MIN', literal(`${model.name}.${
|
|
753
|
+
attributes.push([ fn('MIN', literal(`${model.name}.${valueKey}`)), `_${value.key}-${value.aggregrate}` ])
|
|
753
754
|
break
|
|
754
755
|
|
|
755
756
|
case 'max':
|
|
756
|
-
attributes.push([ fn('MAX', literal(`${model.name}.${
|
|
757
|
+
attributes.push([ fn('MAX', literal(`${model.name}.${valueKey}`)), `_${value.key}-${value.aggregrate}` ])
|
|
758
|
+
break
|
|
759
|
+
|
|
760
|
+
case 'countDistinct':
|
|
761
|
+
attributes.push([ literal(`COUNT(DISTINCT ${model.name}.${valueKey})`), `_${value.key}-${value.aggregrate}` ])
|
|
762
|
+
sortKeyToOrders[`_${value.key}-${value.aggregrate}`] = literal(`COUNT(DISTINCT ${model.name}.${valueKey})`)
|
|
757
763
|
break
|
|
758
764
|
|
|
759
765
|
case 'count':
|
|
760
|
-
attributes.push([ fn('COUNT', literal(`${model.name}.${
|
|
761
|
-
sortKeyToOrders[`_${value.key}-${value.aggregrate}`] = fn('COUNT', literal(`${model.name}.${
|
|
766
|
+
attributes.push([ fn('COUNT', literal(`${model.name}.${valueKey}`)), `_${value.key}-${value.aggregrate}` ])
|
|
767
|
+
sortKeyToOrders[`_${value.key}-${value.aggregrate}`] = fn('COUNT', literal(`${model.name}.${valueKey}`))
|
|
762
768
|
break
|
|
763
769
|
|
|
764
770
|
default:
|
|
@@ -780,7 +786,10 @@ const pivotToSequelizeWhere = async (pivot, opt) => {
|
|
|
780
786
|
|
|
781
787
|
const field = model.rawAttributes[value.key].field
|
|
782
788
|
|
|
789
|
+
|
|
783
790
|
groups.forEach(group => {
|
|
791
|
+
|
|
792
|
+
let groupValue
|
|
784
793
|
if(group[value.key] === null){
|
|
785
794
|
attributes.push([ literal(`SUM(CASE WHEN ${model.name}.${field} is null THEN 1 ELSE 0 END)`), `_${value.key}-(null)` ])
|
|
786
795
|
}
|
|
@@ -788,8 +797,14 @@ const pivotToSequelizeWhere = async (pivot, opt) => {
|
|
|
788
797
|
attributes.push([ literal(`SUM(CASE WHEN ${model.name}.${field} = '' THEN 1 ELSE 0 END)`), `_${value.key}-(empty)` ])
|
|
789
798
|
}
|
|
790
799
|
else{
|
|
791
|
-
|
|
792
|
-
|
|
800
|
+
if(model.rawAttributes[value.key].type instanceof DataTypes.BOOLEAN){
|
|
801
|
+
groupValue = group[value.key]
|
|
802
|
+
attributes.push([ literal(`SUM(CASE WHEN ${model.name}.${field} = ${groupValue === true ? 1 : 0} THEN 1 ELSE 0 END)`), `_${value.key}-${groupValue}` ])
|
|
803
|
+
}
|
|
804
|
+
else{
|
|
805
|
+
groupValue = (group[value.key] ?? '').toString().replace(/\s/g, '_')
|
|
806
|
+
attributes.push([ literal(`SUM(CASE WHEN ${model.name}.${field} = '${group[value.key]}' THEN 1 ELSE 0 END)`), `_${value.key}-${groupValue}` ])
|
|
807
|
+
}
|
|
793
808
|
}
|
|
794
809
|
})
|
|
795
810
|
|
|
@@ -55,8 +55,111 @@ const setupConfig = (config) => {
|
|
|
55
55
|
return config
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
+
const generatePivotColumns = (preset, items) => {
|
|
59
|
+
if(!preset.pivot || !preset.pivot.enabled) return
|
|
60
|
+
if(!Array.isArray(items) && items.length < 1) return
|
|
61
|
+
|
|
62
|
+
if(preset.pivot.manualColumns === true){
|
|
63
|
+
return
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const tableColumns = (preset.columns ?? [])
|
|
67
|
+
.reduce((cur, obj) => {
|
|
68
|
+
cur[obj.key] = obj
|
|
69
|
+
return cur
|
|
70
|
+
}, {})
|
|
71
|
+
|
|
72
|
+
const currentPivotColumns = [ ...(preset.pivot.columns ?? []) ]
|
|
73
|
+
.reduce((cur, obj) => {
|
|
74
|
+
cur[obj.key] = obj
|
|
75
|
+
return cur
|
|
76
|
+
}, {})
|
|
77
|
+
|
|
78
|
+
const pivotColumns = []
|
|
79
|
+
|
|
80
|
+
for(let row of preset.pivot.rows){
|
|
81
|
+
|
|
82
|
+
let format
|
|
83
|
+
switch(row.aggregrate){
|
|
84
|
+
case 'year':
|
|
85
|
+
format = 'YYYY'
|
|
86
|
+
break
|
|
87
|
+
|
|
88
|
+
case 'month':
|
|
89
|
+
format = 'MMM YYYY'
|
|
90
|
+
break
|
|
91
|
+
|
|
92
|
+
case 'date':
|
|
93
|
+
format = 'D MMM YYYY'
|
|
94
|
+
break
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if(currentPivotColumns[row.key]){
|
|
98
|
+
Object.assign(currentPivotColumns[row.key], {
|
|
99
|
+
format,
|
|
100
|
+
visible: true
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
pivotColumns.push(currentPivotColumns[row.key])
|
|
104
|
+
}
|
|
105
|
+
else{
|
|
106
|
+
pivotColumns.push({
|
|
107
|
+
...tableColumns[row.key],
|
|
108
|
+
format,
|
|
109
|
+
visible: true
|
|
110
|
+
})
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
for(let key in items[0]){
|
|
115
|
+
if(key.startsWith('_')){
|
|
116
|
+
let [ k1, ...k2 ] = key.substring(1).split('-')
|
|
117
|
+
k2 = k2.join('-')
|
|
118
|
+
|
|
119
|
+
let label = k2.replace(/_/gi, ' ')
|
|
120
|
+
const column = tableColumns[k1]
|
|
121
|
+
if(column){
|
|
122
|
+
switch(column.type){
|
|
123
|
+
case 'enum':
|
|
124
|
+
label = (column.typeParams ?? []).find(_ => `${_.value}` === `${k2}`)?.text ?? label
|
|
125
|
+
break
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if(currentPivotColumns[key]){
|
|
130
|
+
Object.assign(currentPivotColumns[key], {
|
|
131
|
+
visible: true
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
pivotColumns.push(currentPivotColumns[key])
|
|
135
|
+
}
|
|
136
|
+
else{
|
|
137
|
+
pivotColumns.push({
|
|
138
|
+
key,
|
|
139
|
+
label,
|
|
140
|
+
label2: (((tableColumns[k1] ?? {}).label ?? '') + ': ' + label).trim(),
|
|
141
|
+
type: 'number',
|
|
142
|
+
appearances: [
|
|
143
|
+
{ class:"text-primary cursor-pointer", conditions:[ { operator:'none' } ] }
|
|
144
|
+
]
|
|
145
|
+
})
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
(preset.pivot.columns ?? []).filter(_ => !pivotColumns.find(i => i.key === _.key))
|
|
151
|
+
.forEach(_ => {
|
|
152
|
+
_.visible = false
|
|
153
|
+
pivotColumns.push(_)
|
|
154
|
+
})
|
|
155
|
+
|
|
156
|
+
preset.pivot.columns = pivotColumns
|
|
157
|
+
|
|
158
|
+
}
|
|
159
|
+
|
|
58
160
|
export {
|
|
59
161
|
sortsFn,
|
|
60
162
|
pickColumns,
|
|
61
|
-
setupConfig
|
|
163
|
+
setupConfig,
|
|
164
|
+
generatePivotColumns
|
|
62
165
|
}
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
</div>
|
|
15
15
|
|
|
16
16
|
<div class="p-3">
|
|
17
|
-
<div class="
|
|
17
|
+
<div class="px-2">
|
|
18
18
|
<label class="text-text-300">Presets</label>
|
|
19
19
|
</div>
|
|
20
20
|
<div class="flex flex-col divide-y divide-text-50 bg-base-500 border-[1px] border-text-50 overflow-hidden rounded-lg">
|
|
@@ -95,7 +95,8 @@
|
|
|
95
95
|
body-class="divide-y divide-text-50 rounded-lg border-[1px] border-text-50 bg-base-300"
|
|
96
96
|
@reorder="(from, to) => { presetColumns.splice(to, 0, presetColumns.splice(from, 1)[0]); }">
|
|
97
97
|
<template v-slot="{ item }">
|
|
98
|
-
<div v-if="!item.key.startsWith('_') || (item.key.startsWith('_') && (preset.pivot && preset.pivot.enabled))"
|
|
98
|
+
<div v-if="!item.key.startsWith('_') || (item.key.startsWith('_') && (preset.pivot && preset.pivot.enabled))"
|
|
99
|
+
class="flex flex-row items-center gap-3 px-3 p-1 hover:bg-primary-100">
|
|
99
100
|
<div data-reorder>
|
|
100
101
|
<svg width="14" height="14" class="fill-text-300" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M496 288H16c-8.8 0-16 7.2-16 16v32c0 8.8 7.2 16 16 16h480c8.8 0 16-7.2 16-16v-32c0-8.8-7.2-16-16-16zm0-128H16c-8.8 0-16 7.2-16 16v32c0 8.8 7.2 16 16 16h480c8.8 0 16-7.2 16-16v-32c0-8.8-7.2-16-16-16z"/></svg>
|
|
101
102
|
</div>
|
|
@@ -103,7 +104,9 @@
|
|
|
103
104
|
<div>
|
|
104
105
|
<Checkbox v-model="item.visible" default="true" />
|
|
105
106
|
</div>
|
|
106
|
-
|
|
107
|
+
<Textbox v-model="item.label2" :placeholder="item.label"
|
|
108
|
+
class="border-none bg-transparent" :class="$style.columnTextbox"
|
|
109
|
+
item-class="p-1 px-0" />
|
|
107
110
|
</div>
|
|
108
111
|
</div>
|
|
109
112
|
</template>
|
|
@@ -509,7 +512,8 @@
|
|
|
509
512
|
</div>
|
|
510
513
|
<ListItem :items="presetPivot.values"
|
|
511
514
|
@reorder="(from, to) => { presetPivot.values.splice(to, 0, presetPivot.values.splice(from, 1)[0]); }"
|
|
512
|
-
class="mt-2 h-[25vh] overflow-y-auto border-[1px] border-text-200 bg-base-400 rounded-lg p-0.5"
|
|
515
|
+
class="mt-2 h-[25vh] overflow-y-auto border-[1px] border-text-200 bg-base-400 rounded-lg p-0.5"
|
|
516
|
+
container-class="divide-y divide-text-50">
|
|
513
517
|
<template v-slot="{ item, index }">
|
|
514
518
|
<div class="flex flex-row items-center gap-3 p-2 bg-base-500 hover:bg-primary-100 first:rounded-t-md last:rounded-b-md">
|
|
515
519
|
<div data-reorder v-if="(presetPivot.values ?? []).length > 1">
|
|
@@ -521,10 +525,11 @@
|
|
|
521
525
|
{{ item.label ? item.label : item.key }}
|
|
522
526
|
</strong>
|
|
523
527
|
<select v-model="item.aggregrate"
|
|
524
|
-
class="px-1 appearance-none bg-base-300 rounded-md border-[1px] border-text-50 outline-none"
|
|
528
|
+
class="px-1 appearance-none bg-base-300 w-[80px] rounded-md border-[1px] border-text-50 outline-none"
|
|
525
529
|
@change="apply()">
|
|
526
530
|
<option value="">Default</option>
|
|
527
531
|
<option value="count">Count</option>
|
|
532
|
+
<option value="countDistinct">Distinct Count</option>
|
|
528
533
|
<option v-if="[ 'number' ].includes(item.type)" value="sum">Sum</option>
|
|
529
534
|
<option v-if="[ 'number' ].includes(item.type)" value="avg">Average</option>
|
|
530
535
|
<option v-if="[ 'number' ].includes(item.type)" value="min">Min</option>
|
|
@@ -539,6 +544,40 @@
|
|
|
539
544
|
</ListItem>
|
|
540
545
|
</div>
|
|
541
546
|
|
|
547
|
+
<div>
|
|
548
|
+
<div class="flex flex-row items-center gap-2">
|
|
549
|
+
<label class="flex-1">Columns</label>
|
|
550
|
+
<button v-if="presetPivot.manualColumns"
|
|
551
|
+
type="button"
|
|
552
|
+
class="text-primary"
|
|
553
|
+
@click="delete presetPivot.manualColumns; apply()">Reset</button>
|
|
554
|
+
</div>
|
|
555
|
+
<ListItem :items="presetPivot.columns"
|
|
556
|
+
@reorder="(from, to) => { presetPivot.columns.splice(to, 0, presetPivot.columns.splice(from, 1)[0]); presetPivot.manualColumns = true; apply() }"
|
|
557
|
+
class="mt-2 h-[25vh] overflow-y-auto border-[1px] border-text-200 bg-base-400 rounded-lg p-0.5"
|
|
558
|
+
container-class="divide-y divide-text-50">
|
|
559
|
+
<template v-slot="{ item, index }">
|
|
560
|
+
<div class="flex flex-row gap-2 items-center px-2 bg-base-500">
|
|
561
|
+
<div data-reorder>
|
|
562
|
+
<svg width="14" height="14" class="fill-text-300" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M496 288H16c-8.8 0-16 7.2-16 16v32c0 8.8 7.2 16 16 16h480c8.8 0 16-7.2 16-16v-32c0-8.8-7.2-16-16-16zm0-128H16c-8.8 0-16 7.2-16 16v32c0 8.8 7.2 16 16 16h480c8.8 0 16-7.2 16-16v-32c0-8.8-7.2-16-16-16z"/></svg>
|
|
563
|
+
</div>
|
|
564
|
+
<Textbox class="flex-1 border-none" :class="$style.columnTextbox" v-model="item.label2" :placeholder="item.label"
|
|
565
|
+
item-class="p-1"/>
|
|
566
|
+
<button type="button" v-if="[ 'number' ].includes(item.type)" @click="">
|
|
567
|
+
<svg width="13" height="13" :class="(item.appearances ?? []).length > 0 ? 'fill-primary' : 'fill-text-300 hover:fill-primary'"
|
|
568
|
+
@click="$refs.presetBarPivotColumnEdit.open(item, next => { Object.assign(item, next); apply() })"
|
|
569
|
+
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Pro 6.0.0-alpha3 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) --><path d="M176 0h-128C21.49 0 0 21.49 0 48v128C0 202.5 21.49 224 48 224h128C202.5 224 224 202.5 224 176v-128C224 21.49 202.5 0 176 0zM176 288h-128C21.49 288 0 309.5 0 336v128C0 490.5 21.49 512 48 512h128C202.5 512 224 490.5 224 464v-128C224 309.5 202.5 288 176 288zM464 0h-128C309.5 0 288 21.49 288 48v128C288 202.5 309.5 224 336 224h128C490.5 224 512 202.5 512 176v-128C512 21.49 490.5 0 464 0zM488 376h-64v-64C424 298.8 413.3 288 400 288s-24 10.75-24 24v64h-64c-13.25 0-24 10.75-24 24s10.75 24 24 24h64v64c0 13.25 10.75 24 24 24s24-10.75 24-24v-64h64c13.25 0 24-10.75 24-24S501.3 376 488 376z"/></svg>
|
|
570
|
+
</button>
|
|
571
|
+
<button type="button" @click="presetPivot.columns.splice(index, 1); presetPivot.manualColumns = true; apply()">
|
|
572
|
+
<svg width="16" height="16" class="fill-text-300 hover:fill-red-500" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><path d="M207.6 256l107.72-107.72c6.23-6.23 6.23-16.34 0-22.58l-25.03-25.03c-6.23-6.23-16.34-6.23-22.58 0L160 208.4 52.28 100.68c-6.23-6.23-16.34-6.23-22.58 0L4.68 125.7c-6.23 6.23-6.23 16.34 0 22.58L112.4 256 4.68 363.72c-6.23 6.23-6.23 16.34 0 22.58l25.03 25.03c6.23 6.23 16.34 6.23 22.58 0L160 303.6l107.72 107.72c6.23 6.23 16.34 6.23 22.58 0l25.03-25.03c6.23-6.23 6.23-16.34 0-22.58L207.6 256z"/></svg>
|
|
573
|
+
</button>
|
|
574
|
+
</div>
|
|
575
|
+
</template>
|
|
576
|
+
</ListItem>
|
|
577
|
+
|
|
578
|
+
<PresetBarPivotColumnEdit ref="presetBarPivotColumnEdit" />
|
|
579
|
+
</div>
|
|
580
|
+
|
|
542
581
|
</div>
|
|
543
582
|
|
|
544
583
|
</div>
|
|
@@ -817,4 +856,8 @@ export default{
|
|
|
817
856
|
@apply flex flex-col relative;
|
|
818
857
|
}
|
|
819
858
|
|
|
859
|
+
.columnTextbox input::placeholder{
|
|
860
|
+
@apply text-text;
|
|
861
|
+
}
|
|
862
|
+
|
|
820
863
|
</style>
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<Modal ref="modal" :hash="hash" :state="state" width="480" height="480">
|
|
3
|
+
<template v-slot:head>
|
|
4
|
+
<div class="relative p-6">
|
|
5
|
+
<h3>{{ obj.label }}</h3>
|
|
6
|
+
<div class="absolute top-0 right-0 p-2">
|
|
7
|
+
<button type="button" class="p-2" @click="close">
|
|
8
|
+
<svg width="24" height="24" viewBox="0 0 24 24" class="fill-text-300 hover:fill-red-500" xmlns="http://www.w3.org/2000/svg">
|
|
9
|
+
<path d="M6.53034 5.46965C6.23745 5.17676 5.76257 5.17676 5.46968 5.46965C5.17679 5.76255 5.17679 6.23742 5.46968 6.53031L10.9393 12L5.46967 17.4697C5.17678 17.7626 5.17678 18.2374 5.46967 18.5303C5.76256 18.8232 6.23744 18.8232 6.53033 18.5303L12 13.0606L17.4697 18.5303C17.7626 18.8232 18.2375 18.8232 18.5303 18.5303C18.8232 18.2374 18.8232 17.7626 18.5303 17.4697L13.0607 12L18.5303 6.53032C18.8232 6.23743 18.8232 5.76256 18.5303 5.46966C18.2374 5.17677 17.7626 5.17677 17.4697 5.46966L12 10.9393L6.53034 5.46965Z"/>
|
|
10
|
+
</svg>
|
|
11
|
+
</button>
|
|
12
|
+
</div>
|
|
13
|
+
</div>
|
|
14
|
+
</template>
|
|
15
|
+
<template v-slot:foot>
|
|
16
|
+
<div class="p-6">
|
|
17
|
+
<Button class="w-[100px]" @click="apply">Apply</Button>
|
|
18
|
+
</div>
|
|
19
|
+
</template>
|
|
20
|
+
<div class="flex-1 p-6 flex flex-col gap-4">
|
|
21
|
+
|
|
22
|
+
<div class="flex flex-col gap-1">
|
|
23
|
+
<div class="flex flex-row gap-2">
|
|
24
|
+
<label class="text-text-400">Appearances</label>
|
|
25
|
+
<button type="button" class="text-primary" @click="appearances.push({ conditions:[{}], class:'' })">
|
|
26
|
+
<svg width="16" height="16" class="fill-primary" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Pro 6.0.0-alpha3 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) --><path d="M432 256c0 17.69-14.33 32.01-32 32.01H256v144c0 17.69-14.33 31.99-32 31.99s-32-14.3-32-31.99v-144H48c-17.67 0-32-14.32-32-32.01s14.33-31.99 32-31.99H192v-144c0-17.69 14.33-32.01 32-32.01s32 14.32 32 32.01v144h144C417.7 224 432 238.3 432 256z"/></svg>
|
|
27
|
+
</button>
|
|
28
|
+
</div>
|
|
29
|
+
<ListItem :items="appearances"
|
|
30
|
+
class="bg-transparent"
|
|
31
|
+
@reorder="(from, to) => { appearances.splice(to, 0, appearances.splice(from, 1)[0]); }"
|
|
32
|
+
container-class="flex flex-col gap-1">
|
|
33
|
+
<template v-slot="{ item, index }">
|
|
34
|
+
<div class="flex flex-row items-center gap-3">
|
|
35
|
+
<div class="flex-1 flex flex-col gap-1">
|
|
36
|
+
<div v-for="condition in item.conditions" class="flex flex-row gap-1">
|
|
37
|
+
<Dropdown v-model="condition.operator" :class="condition.operator === 'none' ? 'w-[200px]' : 'w-[100px]'">
|
|
38
|
+
<option v-for="op in operators" :value="op.value">{{ op.text }}</option>
|
|
39
|
+
<option value="none">No Condition</option>
|
|
40
|
+
</Dropdown>
|
|
41
|
+
<Textbox v-if="condition.operator !== 'none'" v-model.numberconditions="condition.value" class="w-[100px]"/>
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
<div :class="item.class" class="px-2">
|
|
45
|
+
Sample
|
|
46
|
+
</div>
|
|
47
|
+
<div>
|
|
48
|
+
<Dropdown class="w-[120px]" v-model="item.class">
|
|
49
|
+
<option value="text-primary cursor-pointer">Default</option>
|
|
50
|
+
<option value="bg-red-100 text-red-600">Red 1</option>
|
|
51
|
+
<option value="bg-red-200 text-red-600">Red 2</option>
|
|
52
|
+
<option value="bg-red-300 text-red-600">Red 3</option>
|
|
53
|
+
<option value="bg-red-400 text-white">Red 4</option>
|
|
54
|
+
<option value="bg-red-500 text-white">Red 5</option>
|
|
55
|
+
<option value="bg-green-100 text-green-700">Green 1</option>
|
|
56
|
+
<option value="bg-green-200 text-green-700">Green 2</option>
|
|
57
|
+
<option value="bg-green-300 text-green-700">Green 3</option>
|
|
58
|
+
<option value="bg-green-400 text-white">Green 4</option>
|
|
59
|
+
<option value="bg-green-500 border-[1px] border-green-600 text-white">Green 5</option>
|
|
60
|
+
<option value="text-primary underline cursor-pointer">Underline</option>
|
|
61
|
+
</Dropdown>
|
|
62
|
+
</div>
|
|
63
|
+
<div>
|
|
64
|
+
<button type="button" @click="appearances.splice(index, 1)">
|
|
65
|
+
<svg width="16" height="16" class="fill-text-300 hover:fill-red-500" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><path d="M207.6 256l107.72-107.72c6.23-6.23 6.23-16.34 0-22.58l-25.03-25.03c-6.23-6.23-16.34-6.23-22.58 0L160 208.4 52.28 100.68c-6.23-6.23-16.34-6.23-22.58 0L4.68 125.7c-6.23 6.23-6.23 16.34 0 22.58L112.4 256 4.68 363.72c-6.23 6.23-6.23 16.34 0 22.58l25.03 25.03c6.23 6.23 16.34 6.23 22.58 0L160 303.6l107.72 107.72c6.23 6.23 16.34 6.23 22.58 0l25.03-25.03c6.23-6.23 6.23-16.34 0-22.58L207.6 256z"/></svg>
|
|
66
|
+
</button>
|
|
67
|
+
</div>
|
|
68
|
+
</div>
|
|
69
|
+
</template>
|
|
70
|
+
</ListItem>
|
|
71
|
+
</div>
|
|
72
|
+
</div>
|
|
73
|
+
</Modal>
|
|
74
|
+
</template>
|
|
75
|
+
|
|
76
|
+
<script>
|
|
77
|
+
|
|
78
|
+
export default{
|
|
79
|
+
|
|
80
|
+
emits: [ 'apply' ],
|
|
81
|
+
|
|
82
|
+
inject: [ 'socketEmit2' ],
|
|
83
|
+
|
|
84
|
+
props: {
|
|
85
|
+
|
|
86
|
+
hash: String,
|
|
87
|
+
state: Boolean
|
|
88
|
+
|
|
89
|
+
},
|
|
90
|
+
|
|
91
|
+
computed: {
|
|
92
|
+
|
|
93
|
+
appearances(){
|
|
94
|
+
if(!Array.isArray(this.obj.appearances)){
|
|
95
|
+
this.obj.appearances = []
|
|
96
|
+
}
|
|
97
|
+
return this.obj.appearances
|
|
98
|
+
},
|
|
99
|
+
|
|
100
|
+
operators(){
|
|
101
|
+
|
|
102
|
+
let operators = []
|
|
103
|
+
|
|
104
|
+
switch(this.obj?.type){
|
|
105
|
+
|
|
106
|
+
case 'number':
|
|
107
|
+
operators = [
|
|
108
|
+
{ value:">", text:">" },
|
|
109
|
+
{ value:">=", text:">=" },
|
|
110
|
+
{ value:"=", text:"=" },
|
|
111
|
+
{ value:"<=", text:"<=" },
|
|
112
|
+
{ value:"<", text:"<" }
|
|
113
|
+
]
|
|
114
|
+
break
|
|
115
|
+
|
|
116
|
+
default:
|
|
117
|
+
operators = [
|
|
118
|
+
{ value:"contains", text:"Contains" },
|
|
119
|
+
{ value:"startsWith", text:"Starts With" },
|
|
120
|
+
{ value:"endsWith", text:"Ends With" },
|
|
121
|
+
{ value:"notContains", text:"Not Contains" },
|
|
122
|
+
{ value:"notStartsWith", text:"Not Starts With" },
|
|
123
|
+
{ value:"notEndsWith", text:"Not StartEnds With" },
|
|
124
|
+
{ value:"regex", text:"Match Pattern" }
|
|
125
|
+
]
|
|
126
|
+
break
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return operators
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
},
|
|
133
|
+
|
|
134
|
+
data(){
|
|
135
|
+
return {
|
|
136
|
+
obj: null,
|
|
137
|
+
callback: null
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
|
|
141
|
+
methods: {
|
|
142
|
+
|
|
143
|
+
apply(){
|
|
144
|
+
if(typeof this.callback === 'function')
|
|
145
|
+
this.callback(this.obj)
|
|
146
|
+
this.$emit('apply', this.obj)
|
|
147
|
+
this.close()
|
|
148
|
+
},
|
|
149
|
+
|
|
150
|
+
open(obj, callback){
|
|
151
|
+
this.obj = JSON.parse(JSON.stringify(obj))
|
|
152
|
+
this.callback = callback
|
|
153
|
+
this.$refs.modal.open()
|
|
154
|
+
},
|
|
155
|
+
|
|
156
|
+
close(){
|
|
157
|
+
this.$refs.modal.close()
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
</script>
|
|
165
|
+
|
|
166
|
+
<style module>
|
|
167
|
+
|
|
168
|
+
.comp{
|
|
169
|
+
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
</style>
|