@mixd-id/web-scaffold 0.1.2301231353 → 0.1.2301231354
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/ListPage1.vue +119 -32
- package/src/components/VirtualTable.vue +4 -3
- package/src/utils/listpage1.js +151 -2
package/package.json
CHANGED
|
@@ -44,10 +44,9 @@
|
|
|
44
44
|
</div>
|
|
45
45
|
|
|
46
46
|
<div class="flex-1 mb-4 flex flex-col bg-base-500 border-text-50 border-[1px]" v-if="summary">
|
|
47
|
-
<VirtualTable v-if="preset.summary.mode === 'table'" :items="
|
|
48
|
-
|
|
47
|
+
<VirtualTable v-if="preset.summary.mode === 'table'" :items="summaryItems" :columns="summaryColumns" class="flex-1"></VirtualTable>
|
|
49
48
|
<Bar v-else-if="preset.summary.mode === 'bar'" :data="chartData" :options="chartOptions" class="flex-1 w-full p-2"/>
|
|
50
|
-
|
|
49
|
+
<Line v-else-if="preset.summary.mode === 'line'" :data="chartData" :options="chartOptions" class="flex-1 w-full p-2"/>
|
|
51
50
|
</div>
|
|
52
51
|
|
|
53
52
|
<VirtualTable v-if="!hideDetails" class="flex-1" :columns="presetColumns" :items="items"
|
|
@@ -255,7 +254,18 @@
|
|
|
255
254
|
</div>
|
|
256
255
|
|
|
257
256
|
<div class="p-3">
|
|
258
|
-
<label class="text-text-400 flex-1">
|
|
257
|
+
<label class="text-text-400 flex-1">Type</label>
|
|
258
|
+
<div class="mt-2">
|
|
259
|
+
<Dropdown v-model="preset.summary.mode" class="flex-1" @change="load">
|
|
260
|
+
<option value="table">{{ $t('Table') }}</option>
|
|
261
|
+
<option value="bar">{{ $t('Bar Chart') }}</option>
|
|
262
|
+
<option value="line">{{ $t('Line Chart') }}</option>
|
|
263
|
+
</Dropdown>
|
|
264
|
+
</div>
|
|
265
|
+
</div>
|
|
266
|
+
|
|
267
|
+
<div class="p-3">
|
|
268
|
+
<label class="text-text-400 flex-1">{{ preset.summary.mode === 'table' ? $t('Row') : $t('X-axis') }}</label>
|
|
259
269
|
<div class="flex flex-row mt-2 gap-2">
|
|
260
270
|
<Dropdown v-model="preset.summary.rows[0].key" class="flex-1" @change="load">
|
|
261
271
|
<option value="" disabled selected>{{ $t('Add Column') }}</option>
|
|
@@ -264,15 +274,21 @@
|
|
|
264
274
|
<Dropdown v-model="preset.summary.rows[0].format" class="w-[100px]" @change="load">
|
|
265
275
|
<option value="">{{ $t('Default') }}</option>
|
|
266
276
|
<option value="date">{{ $t('Date') }}</option>
|
|
277
|
+
<option value="month">{{ $t('Month') }}</option>
|
|
278
|
+
<option value="year">{{ $t('Year') }}</option>
|
|
267
279
|
</Dropdown>
|
|
268
280
|
</div>
|
|
281
|
+
<Checkbox class="mt-2" v-if="preset.summary.mode === 'table'" v-model="preset.summary.showRowTotal">
|
|
282
|
+
Row Total
|
|
283
|
+
</Checkbox>
|
|
269
284
|
</div>
|
|
270
285
|
|
|
271
286
|
<div class="p-3">
|
|
272
|
-
<label class="text-text-400 flex-1">Column</label>
|
|
287
|
+
<label class="text-text-400 flex-1">{{ preset.summary.mode === 'table' ? $t('Column') : $t('Dimension') }}</label>
|
|
273
288
|
<div class="flex flex-row mt-2 gap-2">
|
|
274
289
|
<Dropdown v-model="preset.summary.columns[0].key" class="flex-1" @change="load">
|
|
275
290
|
<option value="" disabled selected>{{ $t('Add Column') }}</option>
|
|
291
|
+
<option value="(none)">{{ $t('None') }}</option>
|
|
276
292
|
<option v-for="column in filterableColumns" :value="column.key">{{ column.label }}</option>
|
|
277
293
|
</Dropdown>
|
|
278
294
|
<Dropdown v-model="preset.summary.columns[0].format" class="w-[100px]" @change="load">
|
|
@@ -280,28 +296,23 @@
|
|
|
280
296
|
<option value="date">{{ $t('Date') }}</option>
|
|
281
297
|
</Dropdown>
|
|
282
298
|
</div>
|
|
299
|
+
<Checkbox class="mt-2" v-if="preset.summary.mode === 'table'" v-model="preset.summary.showColumnTotal">
|
|
300
|
+
Column Total
|
|
301
|
+
</Checkbox>
|
|
302
|
+
<Checkbox class="mt-2" v-else-if="preset.summary.mode === 'bar'" v-model="preset.summary.stacked">
|
|
303
|
+
Stacked
|
|
304
|
+
</Checkbox>
|
|
283
305
|
</div>
|
|
284
306
|
|
|
285
307
|
<div class="p-3">
|
|
286
308
|
<label class="text-text-400 flex-1">Values</label>
|
|
287
309
|
<div class="flex flex-row mt-2 gap-2">
|
|
288
|
-
<Dropdown v-model="preset.summary.values[0].
|
|
289
|
-
<option value="" disabled selected>{{ $t('
|
|
290
|
-
<option v-for="column in filterableColumns" :value="column.key">{{ column.label }}</option>
|
|
291
|
-
</Dropdown>
|
|
292
|
-
<Dropdown v-model="preset.summary.values[0].aggregrate" class="w-[100px]" @change="load">
|
|
293
|
-
<option value="">{{ $t('Default') }}</option>
|
|
310
|
+
<Dropdown v-model="preset.summary.values[0].aggregrate" class="flex-1" @change="load">
|
|
311
|
+
<option value="" disabled selected>{{ $t('Select') }}</option>
|
|
294
312
|
<option value="count">{{ $t('Count') }}</option>
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
<div class="p-3">
|
|
300
|
-
<label class="text-text-400 flex-1">Type</label>
|
|
301
|
-
<div class="mt-2">
|
|
302
|
-
<Dropdown v-model="preset.summary.mode" class="flex-1" @change="load">
|
|
303
|
-
<option value="table">{{ $t('Table') }}</option>
|
|
304
|
-
<option value="bar">{{ $t('Bar Chart') }}</option>
|
|
313
|
+
<option value="max">{{ $t('Max') }}</option>
|
|
314
|
+
<option value="min">{{ $t('Min') }}</option>
|
|
315
|
+
<option value="avg">{{ $t('Avg') }}</option>
|
|
305
316
|
</Dropdown>
|
|
306
317
|
</div>
|
|
307
318
|
</div>
|
|
@@ -310,8 +321,6 @@
|
|
|
310
321
|
|
|
311
322
|
</div>
|
|
312
323
|
|
|
313
|
-
<div class="px-6 py-3 flex flex-row gap-2"></div>
|
|
314
|
-
|
|
315
324
|
</div>
|
|
316
325
|
|
|
317
326
|
</div>
|
|
@@ -325,14 +334,13 @@
|
|
|
325
334
|
|
|
326
335
|
import throttle from "lodash/throttle";
|
|
327
336
|
import {urlQuery} from "../utils/helpers.mjs";
|
|
328
|
-
import { Bar } from 'vue-chartjs'
|
|
329
|
-
import
|
|
330
|
-
|
|
331
|
-
ChartJS.register(Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale)
|
|
337
|
+
import { Bar, Line } from 'vue-chartjs'
|
|
338
|
+
import Chart from 'chart.js/auto'
|
|
339
|
+
import dayjs from "dayjs";
|
|
332
340
|
|
|
333
341
|
export default{
|
|
334
342
|
|
|
335
|
-
components: { Bar },
|
|
343
|
+
components: { Bar, Line },
|
|
336
344
|
|
|
337
345
|
inject: [ 'socket', 'confirm', 'alert', 'socketEmit', 'toast' ],
|
|
338
346
|
|
|
@@ -421,6 +429,19 @@ export default{
|
|
|
421
429
|
|
|
422
430
|
var style = getComputedStyle(document.body)
|
|
423
431
|
var gridColor = style.getPropertyValue('--text-50')
|
|
432
|
+
var gridColor2 = style.getPropertyValue('--text-200')
|
|
433
|
+
|
|
434
|
+
const baseColumn = this.summary.columns[0]
|
|
435
|
+
const baseColumnType = baseColumn.type
|
|
436
|
+
|
|
437
|
+
let highGrids = []
|
|
438
|
+
if(baseColumnType === 'date'){
|
|
439
|
+
this.summary.items.forEach((item) => {
|
|
440
|
+
if(dayjs(item.dfDate).day() === 1){
|
|
441
|
+
highGrids.push(dayjs(item.dfDate).format('D MMM'))
|
|
442
|
+
}
|
|
443
|
+
})
|
|
444
|
+
}
|
|
424
445
|
|
|
425
446
|
return {
|
|
426
447
|
responsive: true,
|
|
@@ -431,12 +452,20 @@ export default{
|
|
|
431
452
|
scales: {
|
|
432
453
|
x: {
|
|
433
454
|
grid: {
|
|
434
|
-
color:
|
|
435
|
-
|
|
455
|
+
color: function(context){
|
|
456
|
+
if(baseColumnType === 'date' && context.tick && highGrids.includes(context.tick.label)){
|
|
457
|
+
return `rgb(${gridColor2})`
|
|
458
|
+
}
|
|
459
|
+
return `rgb(${gridColor})`
|
|
460
|
+
}
|
|
461
|
+
},
|
|
462
|
+
stacked: this.preset.summary.stacked
|
|
436
463
|
},
|
|
437
464
|
y: {
|
|
438
465
|
grid: {
|
|
439
|
-
color:
|
|
466
|
+
color: function(context){
|
|
467
|
+
return `rgb(${gridColor})`
|
|
468
|
+
}
|
|
440
469
|
}
|
|
441
470
|
}
|
|
442
471
|
}
|
|
@@ -447,9 +476,21 @@ export default{
|
|
|
447
476
|
|
|
448
477
|
//console.log(this.summary)
|
|
449
478
|
|
|
479
|
+
const column = this.summary.columns.filter((_) => _.key === 'dfDate').pop()
|
|
480
|
+
|
|
450
481
|
const labels = []
|
|
451
482
|
this.summary.items.forEach((item) => {
|
|
452
|
-
|
|
483
|
+
|
|
484
|
+
let label = item.dfDate
|
|
485
|
+
switch(column.type){
|
|
486
|
+
|
|
487
|
+
case 'date':
|
|
488
|
+
const dateFormat = column.format ?? 'D MMM YY HH:mm:ss'
|
|
489
|
+
const djs = dayjs(item.dfDate)
|
|
490
|
+
label = djs.isValid() ? djs.format(dateFormat) : item.dfDate
|
|
491
|
+
break
|
|
492
|
+
}
|
|
493
|
+
labels.push(label)
|
|
453
494
|
})
|
|
454
495
|
|
|
455
496
|
const datasets = []
|
|
@@ -489,6 +530,52 @@ export default{
|
|
|
489
530
|
if(this.preset && this.preset.summary && this.preset.summary.hideDetails)
|
|
490
531
|
return this.preset.summary.hideDetails
|
|
491
532
|
return false;
|
|
533
|
+
},
|
|
534
|
+
|
|
535
|
+
summaryColumns(){
|
|
536
|
+
|
|
537
|
+
const columns = [ ...this.summary.columns ]
|
|
538
|
+
|
|
539
|
+
if(this.preset.summary.showColumnTotal){
|
|
540
|
+
columns.push({ key:"_total", label:"Total", visible:true, type:"number" })
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
return columns
|
|
544
|
+
},
|
|
545
|
+
|
|
546
|
+
summaryItems(){
|
|
547
|
+
|
|
548
|
+
const items = [ ...this.summary.items ]
|
|
549
|
+
|
|
550
|
+
//console.log('#1', this.preset.summary.showColumnTotal, this.preset.summary.showRowTotal, items.length)
|
|
551
|
+
|
|
552
|
+
if(this.preset.summary.showColumnTotal){
|
|
553
|
+
items.forEach((item) => {
|
|
554
|
+
let total = 0
|
|
555
|
+
for(let key in item){
|
|
556
|
+
if([ 'dfDate', '_total' ].includes(key)) continue
|
|
557
|
+
total += parseInt(item[key])
|
|
558
|
+
}
|
|
559
|
+
item._total = total
|
|
560
|
+
})
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
if(this.preset.summary.showRowTotal){
|
|
564
|
+
const totalItem = { dfDate:"Total" }
|
|
565
|
+
this.summary.items.forEach((item) => {
|
|
566
|
+
|
|
567
|
+
for(let key in item){
|
|
568
|
+
if([ 'dfDate' ].includes(key)) continue
|
|
569
|
+
|
|
570
|
+
if(!(key in totalItem))
|
|
571
|
+
totalItem[key] = 0
|
|
572
|
+
totalItem[key] += parseInt(item[key])
|
|
573
|
+
}
|
|
574
|
+
})
|
|
575
|
+
items.push(totalItem)
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
return items
|
|
492
579
|
}
|
|
493
580
|
|
|
494
581
|
},
|
|
@@ -331,12 +331,13 @@ export default{
|
|
|
331
331
|
}
|
|
332
332
|
|
|
333
333
|
let text = value
|
|
334
|
+
let dateFormat, val
|
|
334
335
|
switch(column.type){
|
|
335
336
|
|
|
336
337
|
case 'date':
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
text = val.isValid() ? val.format(dateFormat) :
|
|
338
|
+
dateFormat = column.format ?? 'D MMM YY HH:mm:ss'
|
|
339
|
+
val = dayjs(value)
|
|
340
|
+
text = val.isValid() ? val.format(dateFormat) : value
|
|
340
341
|
break
|
|
341
342
|
|
|
342
343
|
case 'currency':
|
package/src/utils/listpage1.js
CHANGED
|
@@ -107,11 +107,12 @@ let ListPage1 = {
|
|
|
107
107
|
}
|
|
108
108
|
|
|
109
109
|
if(preset.search){
|
|
110
|
+
const tableName = this.model.tableName
|
|
110
111
|
where = {
|
|
111
112
|
...where,
|
|
112
|
-
[Op.and]: Sequelize.literal(
|
|
113
|
+
[Op.and]: Sequelize.literal(`MATCH(\`${tableName}\`.tag) AGAINST (? IN BOOLEAN MODE)`)
|
|
113
114
|
}
|
|
114
|
-
replacements.push(
|
|
115
|
+
replacements.push(preset.search)
|
|
115
116
|
}
|
|
116
117
|
|
|
117
118
|
if(afterItem){
|
|
@@ -164,6 +165,154 @@ let ListPage1 = {
|
|
|
164
165
|
}
|
|
165
166
|
},
|
|
166
167
|
|
|
168
|
+
async loadSummary(preset, modelParams){
|
|
169
|
+
|
|
170
|
+
const { columns, rows, values } = preset.summary
|
|
171
|
+
|
|
172
|
+
if(!Array.isArray(columns) || columns.length !== 1) return
|
|
173
|
+
if(!Array.isArray(rows) || rows.length !== 1) return
|
|
174
|
+
if(!Array.isArray(values) || values.length !== 1) return
|
|
175
|
+
|
|
176
|
+
const col = columns[0]
|
|
177
|
+
let columnValues = []
|
|
178
|
+
let colKey
|
|
179
|
+
if(col.key !== '(none)'){
|
|
180
|
+
colKey = this.model.rawAttributes[col.key].field
|
|
181
|
+
columnValues = await this.model.findAll({
|
|
182
|
+
attributes: [
|
|
183
|
+
[ Sequelize.fn("DISTINCT", Sequelize.col(colKey)), 'cols' ]
|
|
184
|
+
],
|
|
185
|
+
order: [
|
|
186
|
+
[ colKey, 'asc' ]
|
|
187
|
+
],
|
|
188
|
+
...modelParams
|
|
189
|
+
})
|
|
190
|
+
//console.log(columnValues)
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const attributes = []
|
|
194
|
+
const group = []
|
|
195
|
+
const summaryColumns = [
|
|
196
|
+
/*{ key:"dfDate", label:"Date", width:"200px", visible:true },
|
|
197
|
+
{ key:"type-1", label:"Type 1", type:"number", visible:true },
|
|
198
|
+
{ key:"type-2", label:"Type 2", type:"number", visible:true },
|
|
199
|
+
{ key:"type-3", label:"Type 3", type:"number", visible:true },
|
|
200
|
+
{ key:"type-4", label:"Type 4", type:"number", visible:true },
|
|
201
|
+
{ key:"type-8", label:"Type 8", type:"number", visible:true },*/
|
|
202
|
+
]
|
|
203
|
+
|
|
204
|
+
const row = rows[0]
|
|
205
|
+
const rowKey = this.model.rawAttributes[row.key].field
|
|
206
|
+
const rowLabel = this.columns[row.key].label
|
|
207
|
+
switch(row.format){
|
|
208
|
+
case 'date':
|
|
209
|
+
attributes.push([Sequelize.fn("DATE_FORMAT", Sequelize.col(rowKey), '%Y-%m-%d'), "dfDate"])
|
|
210
|
+
group.push([Sequelize.fn("DATE_FORMAT", Sequelize.col(rowKey), '%Y-%m-%d'), "dfDate"])
|
|
211
|
+
summaryColumns.push({ key:"dfDate", label:rowLabel, width:"200px", visible:true, type:"date", format:"D MMM" })
|
|
212
|
+
break
|
|
213
|
+
|
|
214
|
+
case 'month':
|
|
215
|
+
attributes.push([Sequelize.fn("DATE_FORMAT", Sequelize.col(rowKey), '%Y-%m'), "dfDate"])
|
|
216
|
+
group.push([Sequelize.fn("DATE_FORMAT", Sequelize.col(rowKey), '%Y-%m'), "dfDate"])
|
|
217
|
+
summaryColumns.push({ key:"dfDate", label:rowLabel, width:"200px", visible:true, type:"date", format:"MMM YYYY" })
|
|
218
|
+
break
|
|
219
|
+
|
|
220
|
+
case 'year':
|
|
221
|
+
attributes.push([Sequelize.fn("DATE_FORMAT", Sequelize.col(rowKey), '%Y'), "dfDate"])
|
|
222
|
+
group.push([Sequelize.fn("DATE_FORMAT", Sequelize.col(rowKey), '%Y'), "dfDate"])
|
|
223
|
+
summaryColumns.push({ key:"dfDate", label:rowLabel, width:"200px", visible:true, type:"date", format:"YYYY" })
|
|
224
|
+
break
|
|
225
|
+
|
|
226
|
+
default:
|
|
227
|
+
attributes.push([Sequelize.col(rowKey), "dfDate"])
|
|
228
|
+
group.push([Sequelize.col(rowKey), "dfDate"])
|
|
229
|
+
summaryColumns.push({ key:"dfDate", label:rowLabel, width:"200px", visible:true })
|
|
230
|
+
break
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const value = values[0]
|
|
234
|
+
if(columnValues.length > 0){
|
|
235
|
+
columnValues.forEach((obj) => {
|
|
236
|
+
const columnValue = obj.dataValues['cols']
|
|
237
|
+
|
|
238
|
+
switch(value.aggregrate){
|
|
239
|
+
case 'count':
|
|
240
|
+
attributes.push([Sequelize.fn("SUM", Sequelize.fn("IF", Sequelize.literal(`${colKey} = '${columnValue}'`), 1, 0)), colKey + "-" + columnValue])
|
|
241
|
+
summaryColumns.push({ key:colKey + "-" + columnValue, label:(columnValue ?? '').toString(), visible:true, aggregrate:"count" })
|
|
242
|
+
break
|
|
243
|
+
|
|
244
|
+
case 'min':
|
|
245
|
+
attributes.push([Sequelize.fn("MIN", colKey), colKey + "-" + columnValue])
|
|
246
|
+
summaryColumns.push({ key:colKey + "-" + columnValue, label:(columnValue ?? '').toString(), visible:true, aggregrate:"count" })
|
|
247
|
+
break
|
|
248
|
+
|
|
249
|
+
case 'max':
|
|
250
|
+
attributes.push([Sequelize.fn("MAX", colKey), colKey + "-" + columnValue])
|
|
251
|
+
summaryColumns.push({ key:colKey + "-" + columnValue, label:(columnValue ?? '').toString(), visible:true, aggregrate:"count" })
|
|
252
|
+
break
|
|
253
|
+
|
|
254
|
+
case 'avg':
|
|
255
|
+
attributes.push([Sequelize.fn("AVG", colKey), colKey + "-" + columnValue])
|
|
256
|
+
summaryColumns.push({ key:colKey + "-" + columnValue, label:(columnValue ?? '').toString(), visible:true, aggregrate:"count" })
|
|
257
|
+
break
|
|
258
|
+
}
|
|
259
|
+
})
|
|
260
|
+
}
|
|
261
|
+
else{
|
|
262
|
+
switch(value.aggregrate) {
|
|
263
|
+
case 'count':
|
|
264
|
+
default:
|
|
265
|
+
attributes.push([Sequelize.fn('count', '*'), 'Count'])
|
|
266
|
+
summaryColumns.push({ key:'Count', label:'Count', type:"number", visible:true, aggregrate:"count" })
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
//console.log(attributes)
|
|
271
|
+
|
|
272
|
+
const summaryItems = await this.model.findAll({
|
|
273
|
+
attributes,
|
|
274
|
+
group,
|
|
275
|
+
order: [
|
|
276
|
+
[ 'dfDate', 'asc' ]
|
|
277
|
+
],
|
|
278
|
+
...modelParams
|
|
279
|
+
})
|
|
280
|
+
/*const summaryItems = await this.model.findAll({
|
|
281
|
+
attributes: [
|
|
282
|
+
[Sequelize.fn("DATE_FORMAT", Sequelize.col("created_at"), '%Y-%m-%d'), "dfDate"],
|
|
283
|
+
[Sequelize.fn("SUM", Sequelize.fn("IF", Sequelize.literal("type = 1"), 1, 0)), "type-1"],
|
|
284
|
+
[Sequelize.literal("SUM(IF(type = 2, 1, 0))"), "type-2"],
|
|
285
|
+
[Sequelize.literal("SUM(IF(type = 3, 1, 0))"), "type-3"],
|
|
286
|
+
[Sequelize.literal("SUM(IF(type = 4, 1, 0))"), "type-4"],
|
|
287
|
+
[Sequelize.literal("SUM(IF(type = 8, 1, 0))"), "type-8"],
|
|
288
|
+
],
|
|
289
|
+
group: [
|
|
290
|
+
[Sequelize.fn("DATE_FORMAT", Sequelize.col("created_at"), '%Y-%m-%d')]
|
|
291
|
+
],
|
|
292
|
+
order: [
|
|
293
|
+
[ 'dfDate', 'asc' ]
|
|
294
|
+
],
|
|
295
|
+
...modelParams
|
|
296
|
+
})*/
|
|
297
|
+
//console.log(summaryItems)
|
|
298
|
+
|
|
299
|
+
const summary = {
|
|
300
|
+
type: "table",
|
|
301
|
+
columns: summaryColumns,
|
|
302
|
+
items: summaryItems
|
|
303
|
+
/*items: [
|
|
304
|
+
{ date:"21 Jan 23", "type-1":12, "type-2":11, "type-3":16, "type-4":2, "type-8":8 },
|
|
305
|
+
{ date:"22 Jan 23", "type-1":51, "type-2":87, "type-3":86, "type-4":3, "type-8":9 },
|
|
306
|
+
{ date:"23 Jan 23", "type-1":14, "type-2":66, "type-3":77, "type-4":4, "type-8":18 },
|
|
307
|
+
{ date:"24 Jan 23", "type-1":7, "type-2":3, "type-3":63, "type-4":5, "type-8":28 },
|
|
308
|
+
{ date:"25 Jan 23", "type-1":88, "type-2":55, "type-3":68, "type-4":6, "type-8":38 },
|
|
309
|
+
{ date:"26 Jan 23", "type-1":172, "type-2":13, "type-3":6, "type-4":7, "type-8":48 }
|
|
310
|
+
]*/
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
return summary
|
|
314
|
+
},
|
|
315
|
+
|
|
167
316
|
async subscribe(params, socket){
|
|
168
317
|
const { name } = params
|
|
169
318
|
if(name){
|