@mixd-id/web-scaffold 0.1.230406060 → 0.1.230406062

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": "@mixd-id/web-scaffold",
3
3
  "private": false,
4
- "version": "0.1.230406060",
4
+ "version": "0.1.230406062",
5
5
  "scripts": {
6
6
  "dev": "vite serve",
7
7
  "build": "vite build",
@@ -16,7 +16,8 @@
16
16
  "import": "./src/utils/helpers.mjs"
17
17
  },
18
18
  "./importer": "./src/utils/importer.js",
19
- "./listpage1": "./src/utils/listpage1.js"
19
+ "./listpage1": "./src/utils/listpage1.js",
20
+ "./listview": "./src/utils/listview.js"
20
21
  },
21
22
  "dependencies": {
22
23
  "@faker-js/faker": "^7.3.0",
@@ -43,9 +43,12 @@ export default {
43
43
  if(Array.isArray(this.modelValue)){
44
44
  return this.modelValue.includes(this.value)
45
45
  }
46
- else{
46
+ else if(this.modelValue){
47
47
  return this.value === this.modelValue
48
48
  }
49
+ else{
50
+ return !!this.value
51
+ }
49
52
  }
50
53
  else if(this.trueValue && this.falseValue) {
51
54
  return this.modelValue === this.trueValue
@@ -0,0 +1,84 @@
1
+ <template>
2
+ <div :class="$style.comp">
3
+ <div :class="$style.circle" @click="$refs.contextMenu.open($refs.btn)"
4
+ ref="btn" :style="{ backgroundColor:this.modelValue }"></div>
5
+ <input type="color" :class="$style.inputColor" ref="inputColor"
6
+ @change="select($refs.inputColor.value)"/>
7
+
8
+ <ContextMenu ref="contextMenu" :dismiss="false">
9
+ <div class="p-4 flex flex-col gap-4">
10
+ <div class="grid grid-cols-6 gap-4">
11
+ <div v-for="color in colors">
12
+ <div :class="$style.circle" :style="{ backgroundColor:color }"
13
+ @click="select(color)"></div>
14
+ </div>
15
+ </div>
16
+ <button type="button" v-if="Boolean(customColor)"
17
+ class="w-full p-1 border-text-100 border-[1px] rounded-lg"
18
+ @click="$refs.inputColor.click()">Custom</button>
19
+ </div>
20
+ </ContextMenu>
21
+
22
+ </div>
23
+ </template>
24
+
25
+ <script>
26
+
27
+ export default{
28
+
29
+ props: {
30
+
31
+ colors: Array,
32
+
33
+ customColor: undefined,
34
+
35
+ modelValue: String
36
+
37
+ },
38
+
39
+ methods: {
40
+
41
+ select(color){
42
+ this.$emit('update:modelValue', color)
43
+ this.$refs.contextMenu.close()
44
+ }
45
+
46
+ },
47
+
48
+ computed:{
49
+
50
+ customColorCount(){
51
+ const count = parseInt(this.customColor)
52
+ return isNaN(count) ? 0 : count
53
+ }
54
+
55
+ },
56
+
57
+ data(){
58
+ return {
59
+ customColors: []
60
+ }
61
+ }
62
+
63
+ }
64
+
65
+ </script>
66
+
67
+ <style module>
68
+
69
+ .comp{
70
+ @apply p-[2px] border-[1px] border-text-200 rounded-full relative;
71
+ }
72
+
73
+ .circle{
74
+ @apply w-[19px] h-[19px] rounded-full cursor-pointer;
75
+ }
76
+
77
+ .inputColor{
78
+ @apply absolute top-0 left-0;
79
+ width: 0;
80
+ height: 0;
81
+ opacity: 0;
82
+ }
83
+
84
+ </style>
@@ -71,7 +71,7 @@ export default{
71
71
  }
72
72
 
73
73
  .previewModal{
74
- @apply !w-screen !h-screen !bg-base-300 top-0;
74
+ @apply !w-screen !h-screen !bg-base-300 !rounded-none top-0;
75
75
  z-index: 21 !important;
76
76
  max-width: unset !important;
77
77
  max-height: unset !important;
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div :class="$style.comp" v-if="configLoaded">
2
+ <div :class="$style.comp">
3
3
 
4
4
  <slot v-if="$slots.head" name="head"></slot>
5
5
  <div v-else class="flex flex-row items-center gap-4 px-6 md:px-0 py-4 md:py-0 bg-base-400 dark:bg-base-300 md:bg-transparent">
@@ -8,7 +8,7 @@
8
8
  class="flex-1 md:flex-none flex flex-row gap-1 items-center text-left md:ml-2"
9
9
  @click="$refs.presetSelector.toggle($refs.presetSelectorBtn)">
10
10
  <h2 class="overflow-hidden whitespace-nowrap text-ellipsis">{{ preset.name }}</h2>
11
- <svg width="16" height="16" class="fill-text hover:fill-primary" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><path d="M31.3 192h257.3c17.8 0 26.7 21.5 14.1 34.1L174.1 354.8c-7.8 7.8-20.5 7.8-28.3 0L17.2 226.1C4.6 213.5 13.5 192 31.3 192z"/></svg>
11
+ <svg width="13" height="13" class="ml-1 relative top-[2px] fill-text hover:fill-primary" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><path d="M31.3 192h257.3c17.8 0 26.7 21.5 14.1 34.1L174.1 354.8c-7.8 7.8-20.5 7.8-28.3 0L17.2 226.1C4.6 213.5 13.5 192 31.3 192z"/></svg>
12
12
  </button>
13
13
 
14
14
  <ContextMenu ref="presetSelector">
@@ -53,8 +53,9 @@
53
53
 
54
54
  <slot name="headerOpt"></slot>
55
55
 
56
- <Textbox :placeholder="$t('Search...')" :clearable="true" @clear="clearSearch" v-model="preset.search"
57
- @keyup.enter="load" :class="$style.searchBox" v-if="mediaPrefix !== 'sm'">
56
+ <Textbox v-if="mediaPrefix && mediaPrefix !== 'sm'" :placeholder="$t('Search...')" :clearable="true"
57
+ @clear="clearSearch" v-model="preset.search"
58
+ @keyup.enter="load" :class="$style.searchBox">
58
59
  <template #start>
59
60
  <div class="pl-2">
60
61
  <svg width="14" height="14" class="fill-text-300" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M508.5 481.6l-129-129c-2.3-2.3-5.3-3.5-8.5-3.5h-10.3C395 312 416 262.5 416 208 416 93.1 322.9 0 208 0S0 93.1 0 208s93.1 208 208 208c54.5 0 104-21 141.1-55.2V371c0 3.2 1.3 6.2 3.5 8.5l129 129c4.7 4.7 12.3 4.7 17 0l9.9-9.9c4.7-4.7 4.7-12.3 0-17zM208 384c-97.3 0-176-78.7-176-176S110.7 32 208 32s176 78.7 176 176-78.7 176-176 176z"/></svg>
@@ -63,9 +64,9 @@
63
64
  </Textbox>
64
65
  </div>
65
66
 
66
- <div v-if="mediaPrefix === 'sm'" class="px-6 pb-4 border-b-[1px] border-text-50 bg-base-400 dark:bg-base-300">
67
+ <div v-if="mediaPrefix && mediaPrefix === 'sm'" class="px-6 pb-4 border-b-[1px] border-text-50 bg-base-400 dark:bg-base-300">
67
68
  <Textbox :placeholder="$t('Search...')" :clearable="true" @clear="clearSearch" v-model="preset.search"
68
- @keyup.enter="load" :class="$style.searchBox">
69
+ @keyup.enter="load" :class="$style.searchBox2">
69
70
  <template #start>
70
71
  <div class="pl-2">
71
72
  <svg width="14" height="14" class="fill-text-300" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M508.5 481.6l-129-129c-2.3-2.3-5.3-3.5-8.5-3.5h-10.3C395 312 416 262.5 416 208 416 93.1 322.9 0 208 0S0 93.1 0 208s93.1 208 208 208c54.5 0 104-21 141.1-55.2V371c0 3.2 1.3 6.2 3.5 8.5l129 129c4.7 4.7 12.3 4.7 17 0l9.9-9.9c4.7-4.7 4.7-12.3 0-17zM208 384c-97.3 0-176-78.7-176-176S110.7 32 208 32s176 78.7 176 176-78.7 176-176 176z"/></svg>
@@ -74,8 +75,23 @@
74
75
  </Textbox>
75
76
  </div>
76
77
 
78
+ <div v-if="presetSummary && summary" class="h-[300px] max-h-[30vh] flex">
79
+ <Bar v-if="presetSummary.mode === 'bar'" :data="chartData" :options="chartOptions" class="flex-1 w-full p-2"/>
80
+ <Line v-else-if="presetSummary.mode === 'line'" :data="chartData" :options="chartOptions" class="flex-1 w-full p-2"/>
81
+ <VirtualTable v-else-if="presetSummary.mode === 'table'" :items="summaryItems" :columns="summaryColumns" class="flex-1"></VirtualTable>
82
+ <Gmaps v-else-if="presetSummary.mode === 'map'" :data="summary.items" :config="presetSummary.map"
83
+ class="flex-1 w-full p-2" :apiKey="mapApiKey" />
84
+ </div>
85
+
77
86
  <div class="flex-1 flex" v-if="mediaPrefix">
78
- <VirtualTable v-if="mediaPrefix !== 'sm'" ref="table1" :columns="presetColumns" :items="items"
87
+ <VirtualScroll v-if="mediaPrefix === 'sm'" :items="items" ref="table2"
88
+ class="flex-1 bg-base-400 dark:bg-base-300" @scroll-end="loadNext">
89
+ <template #item="{ item }">
90
+ <slot name="mobileItem" :item="item"></slot>
91
+ </template>
92
+ </VirtualScroll>
93
+
94
+ <VirtualTable v-else ref="table1" :columns="presetColumns" :items="items"
79
95
  class="flex-1 bg-base-400"
80
96
  @scroll-end="loadNext">
81
97
  <template v-for="column in presetColumns" #[colOf(column.key)]="{}">
@@ -110,11 +126,6 @@
110
126
  <slot :name="slot" :item="item" :index="index"></slot>
111
127
  </template>
112
128
  </VirtualTable>
113
- <VirtualScroll v-else :items="items" ref="table2" class="flex-1 bg-base-400 dark:bg-base-300" @scroll-end="loadNext">
114
- <template #item="{ item }">
115
- <slot name="mobileItem" :item="item"></slot>
116
- </template>
117
- </VirtualScroll>
118
129
  </div>
119
130
 
120
131
  <ContextMenu ref="columnMenu" :dismiss="false">
@@ -156,8 +167,12 @@
156
167
  <script>
157
168
 
158
169
  import throttle from "lodash/throttle";
170
+ import { Bar, Line } from 'vue-chartjs'
171
+ import Chart from 'chart.js/auto'
172
+ import dayjs from "dayjs";
159
173
 
160
174
  export default{
175
+ components: {Line, Bar},
161
176
 
162
177
  emits: [ ],
163
178
 
@@ -214,7 +229,7 @@ export default{
214
229
  this.presetFilterSelector = null
215
230
  },
216
231
 
217
- calcMediaPrefix: throttle(function(){
232
+ calcMediaPrefix() {
218
233
  if(!this.$el) return
219
234
 
220
235
  const w = this.$el.clientWidth
@@ -238,7 +253,7 @@ export default{
238
253
  }
239
254
 
240
255
  this.mediaPrefix = prefix
241
- }, 100, { leading:true }),
256
+ },
242
257
 
243
258
  clearSearch(){
244
259
  this.preset.search = ''
@@ -268,10 +283,14 @@ export default{
268
283
  load(){
269
284
  if(!this.src) return
270
285
 
271
- this.socketEmit2(this.src, { preset: this.preset })
286
+ this.$refs.table1 ? this.$refs.table1.setState(2) : this.$refs.table2.setState(3)
287
+ this.socketEmit2(this.src, { columns:this.config.columns, preset:this.preset })
272
288
  .then((res) => {
273
289
  Object.assign(this.$data, res)
274
290
  })
291
+ .finally(() => {
292
+ this.$refs.table1 ? this.$refs.table1.setState(1) : this.$refs.table2.setState(1)
293
+ })
275
294
  },
276
295
 
277
296
  loadNext(){
@@ -293,8 +312,13 @@ export default{
293
312
  },
294
313
 
295
314
  async loadConfig(){
315
+
296
316
  if(!this.configStoreObj || 'reset' in ((this.$route ?? {}).query ?? {})){
297
317
  this.configLoaded = true
318
+
319
+ if('reset' in ((this.$route ?? {}).query ?? {}))
320
+ await this.saveConfig()
321
+
298
322
  return
299
323
  }
300
324
 
@@ -308,7 +332,6 @@ export default{
308
332
  }
309
333
 
310
334
  this.configLoaded = true
311
- this.$nextTick(() => this.calcMediaPrefix())
312
335
  })
313
336
  }
314
337
  },
@@ -321,8 +344,9 @@ export default{
321
344
  preset: this.preset
322
345
  })
323
346
  .then((res) => {
324
- const data = res && res.data ? res.data : res
325
- this.summary = data
347
+ console.log('res', res)
348
+ /*const data = res && res.data ? res.data : res
349
+ this.summary = data*/
326
350
  })
327
351
  .catch((err) => {
328
352
  this.toast(err)
@@ -330,20 +354,46 @@ export default{
330
354
  },
331
355
 
332
356
  onHooks(model, event, items){
357
+
333
358
  if(model === this.subscriptionObj.model){
334
359
  switch(event){
335
360
 
336
361
  case 'create':
337
362
  case 'update':
338
- items.forEach((item) => {
339
- this.$util.unshift(this.items, item)
340
- })
363
+ if(Object.keys(items[0]).length <= 1 && Object.keys(items[0])[0] === 'uid'){
364
+ this.socketEmit2(this.src, {
365
+ columns:this.config.columns,
366
+ preset:{
367
+ ...this.preset,
368
+ filters: [{
369
+ enabled: true,
370
+ key: "uid",
371
+ filters: [
372
+ {
373
+ operator: "in",
374
+ value: items.map((_) => _.uid)
375
+ }
376
+ ]
377
+ }
378
+ ]
379
+ }
380
+ })
381
+ .then(({ items }) => {
382
+ this.$util.unshift(this.items, ...items)
383
+ })
384
+ }
385
+ else{
386
+ this.$util.unshift(this.items, ...items)
387
+ }
341
388
  break
342
389
 
343
390
  case 'remove':
344
391
  case 'destroy':
345
392
  items.forEach((item) => {
346
- const idx = this.items.findIndex((_) => _.id === item.id)
393
+ const idx = this.items.findIndex((_) => {
394
+ return item.uid ? _.uid === item.uid :
395
+ (item.id ? _.id === item.id : false)
396
+ })
347
397
  if(idx >= 0){
348
398
  this.items.splice(idx, 1)
349
399
  }
@@ -421,7 +471,54 @@ export default{
421
471
  this.socketEmit2(method, { name:model }).then()
422
472
  break
423
473
  }
424
- }
474
+ },
475
+
476
+ summaryColumns(){
477
+
478
+ const columns = [ ...this.summary.columns ]
479
+
480
+ if(this.presetSummary.mode === 'table' && this.presetSummary.table.showColumnTotal){
481
+ columns.push({ key:"_total", label:"Total", visible:true, type:"number" })
482
+ }
483
+
484
+ return columns
485
+ },
486
+
487
+ summaryItems(){
488
+
489
+ const items = [ ...this.summary.items ]
490
+
491
+ //console.log('#1', this.presetSummary.showColumnTotal, this.presetSummary.showRowTotal, items.length)
492
+
493
+ if(this.presetSummary.mode === 'table' && this.presetSummary.table.showColumnTotal){
494
+ items.forEach((item) => {
495
+ let total = 0
496
+ for(let key in item){
497
+ if([ 'dfDate', '_total' ].includes(key)) continue
498
+ total += parseInt(item[key])
499
+ }
500
+ item._total = total
501
+ })
502
+ }
503
+
504
+
505
+ if(this.presetSummary.mode === 'table' && this.presetSummary.table.showRowTotal){
506
+ const totalItem = { dfDate:"Total" }
507
+ this.summary.items.forEach((item) => {
508
+
509
+ for(let key in item){
510
+ if([ 'dfDate' ].includes(key)) continue
511
+
512
+ if(!(key in totalItem))
513
+ totalItem[key] = 0
514
+ totalItem[key] += parseInt(item[key])
515
+ }
516
+ })
517
+ items.push(totalItem)
518
+ }
519
+
520
+ return items
521
+ },
425
522
 
426
523
  },
427
524
 
@@ -429,6 +526,128 @@ export default{
429
526
 
430
527
  computed: {
431
528
 
529
+
530
+ chartOptions(){
531
+
532
+ var style = getComputedStyle(document.body)
533
+ var gridColor = style.getPropertyValue('--text-50')
534
+ var gridColor2 = style.getPropertyValue('--text-200')
535
+
536
+ const baseColumn = this.summary.columns[0] ?? {}
537
+ const baseColumnType = baseColumn.type
538
+
539
+ let highGrids = []
540
+ if(baseColumnType === 'date'){
541
+ this.summary.items.forEach((item) => {
542
+ if(dayjs(item.dfDate).day() === 1){
543
+ highGrids.push(dayjs(item.dfDate).format('D MMM'))
544
+ }
545
+ })
546
+ }
547
+
548
+ return {
549
+ responsive: true,
550
+ maintainAspectRatio: false,
551
+ plugins: {
552
+ legend: !this.presetSummary.hideLegends,
553
+ tooltip: {
554
+ callbacks: {
555
+ label: function(context) {
556
+
557
+ const labels = []
558
+
559
+ labels.push(context.dataset.label + ': ' + context.parsed.y)
560
+
561
+ if(context.parsed._stacks){
562
+ let total = 0
563
+ let percent = 0
564
+ for(let key in context.parsed._stacks.y){
565
+ if(!isNaN(parseInt(key))){
566
+ total += parseInt(context.parsed._stacks.y[key])
567
+ }
568
+ }
569
+ percent = Math.round(parseInt(context.parsed.y) / total * 100)
570
+ labels.push(`Total: ${total} (${percent}%)`)
571
+ }
572
+
573
+ return labels;
574
+ }
575
+ }
576
+ }
577
+ },
578
+ scales: {
579
+ x: {
580
+ grid: {
581
+ color: function(context){
582
+ if(baseColumnType === 'date' && context.tick && highGrids.includes(context.tick.label)){
583
+ return `rgb(${gridColor2})`
584
+ }
585
+ return `rgb(${gridColor})`
586
+ }
587
+ },
588
+ stacked: this.presetSummary.mode === 'bar' ? this.presetSummary[this.presetSummary.mode].stacked : undefined
589
+ },
590
+ y: {
591
+ grid: {
592
+ color: function(context){
593
+ return `rgb(${gridColor})`
594
+ }
595
+ },
596
+ stacked: this.presetSummary.mode === 'bar' ? this.presetSummary[this.presetSummary.mode].stacked : undefined
597
+ }
598
+ }
599
+ }
600
+ },
601
+
602
+ chartData(){
603
+
604
+ const column = this.summary.columns.filter((_) => _.key === 'dfDate').pop() ?? {}
605
+
606
+ const labels = []
607
+ this.summary.items.forEach((item) => {
608
+
609
+ let label = item.dfDate
610
+ switch(column.type){
611
+
612
+ case 'date':
613
+ const dateFormat = column.format ?? 'D MMM YY HH:mm:ss'
614
+ const djs = dayjs(item.dfDate)
615
+ label = djs.isValid() ? djs.format(dateFormat) : item.dfDate
616
+ break
617
+ }
618
+ labels.push(label)
619
+ })
620
+
621
+ const datasets = []
622
+ this.summary.columns.forEach((column) => {
623
+ if(column.key === 'dfDate') return
624
+
625
+ const data = []
626
+ this.summary.items.forEach((item) => {
627
+ data.push(parseInt(item[column.key]))
628
+ })
629
+
630
+ const dataset = {
631
+ label: column.label,
632
+ data,
633
+ backgroundColor: this.chartOpt.backgroundColors[datasets.length % 9],
634
+ borderColor: this.chartOpt.borderColors[datasets.length % 9]
635
+ }
636
+
637
+ datasets.push(dataset)
638
+ })
639
+
640
+ return {
641
+ labels,
642
+ datasets
643
+ }
644
+
645
+ /*return {
646
+ labels: [ 'January', 'February', 'March' ],
647
+ datasets: [ { data: [40, 20, 12] } ]
648
+ }*/
649
+ },
650
+
432
651
  subscriptionObj(){
433
652
  const splitted = ((this.subscription ?? '').toString()).split(':')
434
653
  const splitted2 = (splitted[1] ?? '').split(',')
@@ -521,6 +740,10 @@ export default{
521
740
  return c
522
741
  },
523
742
 
743
+ presetSummary(){
744
+ return ((this.preset ?? {}).summaries ?? []).filter((_) => _.enabled).pop()
745
+ },
746
+
524
747
  },
525
748
 
526
749
  data(){
@@ -531,20 +754,50 @@ export default{
531
754
  configLoaded: false,
532
755
  selectedColumn: null,
533
756
  copiedConfig: null,
534
- mediaPrefix: 'md'
757
+ mediaPrefix: null,
758
+ summary: null,
759
+ mapApiKey: null,
760
+ chartOpt: {
761
+ backgroundColors: [
762
+ '#5D9CEC',
763
+ '#A0D468',
764
+ '#FFCE54',
765
+ '#FC6E51',
766
+ '#48CFAD',
767
+ '#AC92EC',
768
+ '#4FC1E9',
769
+ '#FFCE54',
770
+ '#ED5565',
771
+ '#EC87C0'
772
+ ],
773
+ borderColors: [
774
+ '#4A89DC',
775
+ '#8CC152',
776
+ '#F6BB42',
777
+ '#E9573F',
778
+ '#37BC9B',
779
+ '#967ADC',
780
+ '#3BAFDA',
781
+ '#F6BB42',
782
+ '#DA4453',
783
+ '#D770AD'
784
+ ],
785
+ },
535
786
  }
536
787
  },
537
788
 
538
789
 
539
790
  mounted() {
540
- window.addEventListener('resize', () => this.calcMediaPrefix())
791
+ window.addEventListener('resize', throttle(() => this.calcMediaPrefix(), 100, { leading:true }))
541
792
  this.calcMediaPrefix()
793
+
542
794
  this.socket.onAny(this.onHooks)
543
795
 
544
796
  window.setTimeout(() => {
545
797
  this.loadConfig().then(() => {
546
- this.load()
547
- })
798
+ window.setTimeout(() => {})
799
+ this.load()
800
+ }, 1000)
548
801
  }, 201)
549
802
 
550
803
  this.subscribe()
@@ -579,6 +832,10 @@ export default{
579
832
  @apply !bg-base-400 md:w-[300px];
580
833
  }
581
834
 
835
+ .searchBox2{
836
+ @apply bg-text-50;
837
+ }
838
+
582
839
  .header{
583
840
  @apply p-2 cursor-pointer border-b-[2px] border-transparent overflow-hidden;
584
841
  }
@@ -0,0 +1,80 @@
1
+ <template>
2
+ <div :class="$style.comp">
3
+
4
+ <div class="p-3">
5
+ <label class="text-text-400 flex-1">{{ $t('X-axis') }}</label>
6
+ <div class="flex flex-row mt-2 gap-2">
7
+ <Dropdown v-model="summary.bar.rows[0].key" class="flex-1">
8
+ <option value="" disabled selected>{{ $t('Add Column') }}</option>
9
+ <option v-for="column in columns" :value="column.key">{{ column.label ?? column.key }}</option>
10
+ </Dropdown>
11
+ <Dropdown v-model="summary.bar.rows[0].format" class="w-[100px]">
12
+ <option value="">{{ $t('Default') }}</option>
13
+ <option value="date">{{ $t('Date') }}</option>
14
+ <option value="month">{{ $t('Month') }}</option>
15
+ <option value="quarter">{{ $t('Quarterly') }}</option>
16
+ <option value="year">{{ $t('Year') }}</option>
17
+ </Dropdown>
18
+ </div>
19
+ </div>
20
+
21
+ <div class="p-3">
22
+ <label class="text-text-400 flex-1">{{ $t('Column') }}</label>
23
+ <div class="flex flex-row mt-2 gap-2">
24
+ <Dropdown v-model="summary.bar.columns[0].key" class="flex-1">
25
+ <option value="" disabled selected>{{ $t('Add Column') }}</option>
26
+ <option value="(none)">{{ $t('None') }}</option>
27
+ <option v-for="column in columns" :value="column.key">{{ column.label ?? column.key }}</option>
28
+ </Dropdown>
29
+ <Dropdown v-model="summary.bar.columns[0].format" class="w-[100px]">
30
+ <option value="">{{ $t('Default') }}</option>
31
+ <option value="date">{{ $t('Date') }}</option>
32
+ </Dropdown>
33
+ </div>
34
+ <Checkbox class="mt-2" v-model="summary.bar.stacked">
35
+ Stacked
36
+ </Checkbox>
37
+ </div>
38
+
39
+ <div class="p-3">
40
+ <label class="text-text-400 flex-1">Values</label>
41
+ <div class="flex flex-row mt-2 gap-2">
42
+ <Dropdown v-model="summary.bar.values[0].aggregrate" class="flex-1">
43
+ <option value="" disabled selected>{{ $t('Select') }}</option>
44
+ <option value="count">{{ $t('Count') }}</option>
45
+ <option value="max">{{ $t('Max') }}</option>
46
+ <option value="min">{{ $t('Min') }}</option>
47
+ <option value="avg">{{ $t('Avg') }}</option>
48
+ </Dropdown>
49
+ </div>
50
+ </div>
51
+
52
+ </div>
53
+ </template>
54
+
55
+ <script>
56
+
57
+ export default{
58
+
59
+ props: {
60
+
61
+ columns: Array,
62
+
63
+ summary: {
64
+ type: Object,
65
+ required: true
66
+ }
67
+
68
+ }
69
+
70
+ }
71
+
72
+ </script>
73
+
74
+ <style module>
75
+
76
+ .comp{
77
+
78
+ }
79
+
80
+ </style>