@mixd-id/web-scaffold 0.1.2301231337 → 0.1.2301231339

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.2301231337",
4
+ "version": "0.1.2301231339",
5
5
  "scripts": {
6
6
  "dev": "vite serve",
7
7
  "build": "vite build",
@@ -15,13 +15,15 @@
15
15
  "require": "./src/utils/helpers.js",
16
16
  "import": "./src/utils/helpers.mjs"
17
17
  },
18
- "./importer": "./src/utils/importer.js"
18
+ "./importer": "./src/utils/importer.js",
19
+ "./listpage1": "./src/utils/listpage1.js"
19
20
  },
20
21
  "dependencies": {
21
22
  "@faker-js/faker": "^7.3.0",
22
23
  "@tailwindcss/line-clamp": "^0.4.0",
23
24
  "@vueuse/core": "^9.0.2",
24
25
  "adm-zip": "^0.5.10",
26
+ "axios": "^1.3.4",
25
27
  "compression": "^1.7.4",
26
28
  "cookie-parser": "^1.4.6",
27
29
  "cors": "^2.8.5",
@@ -36,6 +38,7 @@
36
38
  "nprogress": "^0.2.0",
37
39
  "pinia": "^2.0.14",
38
40
  "prismjs": "^1.28.0",
41
+ "sequelize": "^6.29.0",
39
42
  "serve-static": "^1.15.0",
40
43
  "tailwindcss": "^3.2.4",
41
44
  "vue": "^3.2.25",
@@ -5,7 +5,7 @@
5
5
  <img :class="computedClass" :src="actualSrc" ref="img" :style="imageStyle"/>
6
6
  <input v-if="Boolean(editable)" class="hidden" type="file" accept="image/*" ref="file" @change="onChange"/>
7
7
  <slot></slot>
8
- <div :class="$style.loading" v-if="loading">
8
+ <div :class="$style.loading" v-if="loading && spinnerType === 'spinner'">
9
9
  <svg class="animate-spin aspect-square w-[15%] text-primary" 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>
10
10
  </div>
11
11
  </div>
@@ -48,7 +48,12 @@ export default{
48
48
  defaultSrc: {
49
49
  type: String,
50
50
  default: "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0yMS4xNTkyIDIxLjA4MjhDMjEuNjc5OCAyMC41NDMyIDIyIDE5LjgwOSAyMiAxOVY1QzIyIDMuMzQzMTUgMjAuNjU2OSAyIDE5IDJINUMzLjM0MzE1IDIgMiAzLjM0MzE1IDIgNVYxOUMyIDIwLjY1NjkgMy4zNDMxNSAyMiA1IDIySDE5QzE5LjI5NjIgMjIgMTkuNTgyMyAyMS45NTcxIDE5Ljg1MjUgMjEuODc3MUMxOS44NjU4IDIxLjg3MzIgMTkuODc5IDIxLjg2OTIgMTkuODkyMSAyMS44NjUxQzIwLjI1ODYgMjEuNzUxMSAyMC41OTUgMjEuNTY4NyAyMC44ODYzIDIxLjMzMjlDMjAuODkzNyAyMS4zMjY5IDIwLjkwMSAyMS4zMjEgMjAuOTA4MyAyMS4zMTQ5QzIwLjk4MjQgMjEuMjUzOCAyMS4wNTM1IDIxLjE4OTIgMjEuMTIxMyAyMS4xMjEzQzIxLjEzNDEgMjEuMTA4NiAyMS4xNDY3IDIxLjA5NTcgMjEuMTU5MiAyMS4wODI4Wk0xOSAzLjVINUM0LjE3MTU3IDMuNSAzLjUgNC4xNzE1NyAzLjUgNVYxMi43TDYuMDUyOTIgOS42MzY0OUM3LjIxNTY2IDguMjQxMjEgOS4zNDE3NyA4LjE5MTAyIDEwLjU2OSA5LjUyOTg3TDIwLjE0MTggMTkuOTcyOEMyMC4zNjUyIDE5LjcxMDkgMjAuNSAxOS4zNzEyIDIwLjUgMTlWNUMyMC41IDQuMTcxNTcgMTkuODI4NCAzLjUgMTkgMy41Wk01IDIwLjVDNC4xNzE1NyAyMC41IDMuNSAxOS44Mjg0IDMuNSAxOVYxNS4wNDMxTDcuMjA1MjYgMTAuNTk2OEM3LjcxMzk1IDkuOTg2MzMgOC41OTE0NCA5Ljg5MDgxIDkuMjEzOTUgMTAuMzI0OUM5LjIxOTUxIDEwLjMyODggOS4yMjUwNSAxMC4zMzI3IDkuMjMwNTcgMTAuMzM2N0M5LjMxMzMyIDEwLjM5NjEgOS4zOTE0MSAxMC40NjUgOS40NjMzMiAxMC41NDM1TDE4LjU5MDEgMjAuNUg1WiIgZmlsbD0iYmxhY2siIGZpbGwtb3BhY2l0eT0iLjA4Ii8+CjxjaXJjbGUgY3g9IjE3IiBjeT0iNyIgcj0iMS4yNSIgc3Ryb2tlPSJibGFjayIgc3Ryb2tlLW9wYWNpdHk9Ii4wOCIgc3Ryb2tlLXdpZHRoPSIxLjUiLz4KPC9zdmc+Cg=="
51
- }
51
+ },
52
+
53
+ spinnerType: {
54
+ type: String,
55
+ default: "shimmer" // spinner | shimmer
56
+ }
52
57
 
53
58
  },
54
59
 
@@ -57,7 +62,8 @@ export default{
57
62
  computedOuterClass(){
58
63
  return [
59
64
  this.$style.img,
60
- this.outerClass
65
+ this.outerClass,
66
+ this.loading && this.spinnerType === 'shimmer' ? this.$style.shimmer : ''
61
67
  ]
62
68
  .join(' ')
63
69
  },
@@ -135,13 +141,13 @@ export default{
135
141
  var img = new Image()
136
142
  img.addEventListener('load', () => {
137
143
  this.loaded = true
138
- this.actualSrc = img.src
139
- this.loading = false
144
+ //this.actualSrc = img.src
145
+ //this.loading = false
140
146
  })
141
147
  img.addEventListener('error', () => {
142
148
  this.loaded = true
143
149
  this.actualSrc = this.defaultSrc
144
- this.loading = false
150
+ //this.loading = false
145
151
  })
146
152
  img.src = src[screens[b]]
147
153
  this.loading = true
@@ -202,5 +208,9 @@ export default{
202
208
  @apply flex items-center justify-center;
203
209
  }
204
210
 
211
+ .shimmer{
212
+ @apply bg-text-100 animate-pulse;
213
+ }
214
+
205
215
 
206
216
  </style>
@@ -97,6 +97,8 @@ import axios from "axios";
97
97
 
98
98
  export default{
99
99
 
100
+ emit: [ 'complete' ],
101
+
100
102
  inject: [ 'socketEmit', 'socket', 'toast' ],
101
103
 
102
104
  props: {
@@ -195,6 +197,9 @@ export default{
195
197
  close(){
196
198
  this.isOpen = false
197
199
  this.$emit('dismiss')
200
+ if(this.step === 3){
201
+ this.$emit('complete')
202
+ }
198
203
  },
199
204
 
200
205
  reset(){
@@ -394,7 +394,7 @@ export default{
394
394
 
395
395
  onHooks(module, event, items){
396
396
 
397
- //console.log('onHooks', module, event, items)
397
+ console.log('onHooks', module, event, items)
398
398
 
399
399
  if(!Array.isArray(items)) return
400
400
  items = items.filter((_) => _).map((_) => {
@@ -423,8 +423,10 @@ export default{
423
423
  break
424
424
 
425
425
  case 'remove':
426
+ case 'destroy':
426
427
  items.forEach((item) => {
427
428
  const idx = this.items.findIndex((_) => _.id === item.id)
429
+ console.log(idx, item)
428
430
  if(idx >= 0){
429
431
  this.items.splice(idx, 1)
430
432
  }
@@ -0,0 +1,434 @@
1
+ const { Op } = require('sequelize')
2
+
3
+ let ListPage1 = {
4
+
5
+ presetName: 'listpage1',
6
+ itemsPerPage: 24,
7
+ model: '',
8
+ channel: '',
9
+
10
+ async patch(){
11
+
12
+ let currentPreset
13
+ if(this.user && this.socket && this.socket.auth){
14
+ const { userId } = this.socket.auth
15
+ const user = await this.user.withId(userId)
16
+ const preset = await user.loadPreset(this.presetName)
17
+ currentPreset = {
18
+ ...this.getDefaultPresets(),
19
+ ...preset
20
+ }
21
+ }
22
+ else{
23
+ currentPreset = {
24
+ ...this.getDefaultPresets()
25
+ }
26
+ }
27
+
28
+ const data = await this.load({ preset:currentPreset.presets[currentPreset.presetIdx] })
29
+
30
+ if(this.channel && this.socket){
31
+ if(this.socket.joinWithArgs){
32
+ this.socket.joinWithArgs(this.channel, { preset:currentPreset.presets[currentPreset.presetIdx] })
33
+ }
34
+ else{
35
+ this.socket.join(this.channel)
36
+ }
37
+ }
38
+
39
+ return {
40
+ ...currentPreset,
41
+ ...data
42
+ }
43
+ },
44
+
45
+ async load(params){
46
+
47
+ /*const listAcl = socket.auth.user.getAclv('customer', 'list')
48
+ if(listAcl === false){
49
+ throw new Error('Insufficient privilege')
50
+ }
51
+ else if(Array.isArray(listAcl.filters) && listAcl.filters.includes('user-customers')){
52
+ where = {
53
+ ...where,
54
+ referralType: {
55
+ [Op.in]: [ "App\\Models\\User", "user" ]
56
+ },
57
+ referralId: socket.auth.userId
58
+ }
59
+ }*/
60
+
61
+ const { afterItem, itemsPerPage = this.itemsPerPage } = params
62
+ const { preset = {} } = params
63
+ let where = {}
64
+ let replacements = []
65
+ let order = [
66
+ [ 'updatedAt', 'desc' ],
67
+ [ 'id', 'desc' ],
68
+ ]
69
+
70
+ let attributes = { id:1, updatedAt:1 }
71
+ let modelAttributes = this.model.getAttributes()
72
+ preset.columns.forEach((column) => {
73
+ if(column.visible && modelAttributes[column.key]){
74
+ switch(column.key){
75
+
76
+ case 'item':
77
+ case 'option':
78
+ // Ignored
79
+ break
80
+
81
+ default:
82
+ attributes[column.key] = 1
83
+ break
84
+ }
85
+ }
86
+ })
87
+ attributes = Object.keys(attributes)
88
+
89
+ if(preset.filters){
90
+ const { where:presetWhere } = this.getPresetFilterParams(preset)
91
+ where = {
92
+ ...where,
93
+ ...presetWhere
94
+ }
95
+ }
96
+
97
+ if(preset.sorts){
98
+ const { order:presetOrder } = this.getPresetSortParams(preset)
99
+ if(presetOrder){
100
+ order = presetOrder
101
+ }
102
+ }
103
+
104
+ if(preset.search){
105
+ where = {
106
+ ...where,
107
+ [Op.and]: Sequelize.literal('MATCH(tag) AGAINST (? IN BOOLEAN MODE)')
108
+ }
109
+ replacements.push(ftW)
110
+ }
111
+
112
+ if(afterItem){
113
+ const sortWhere = this.getPresetSortWhereParams(order, afterItem)
114
+ where = {
115
+ ...where,
116
+ ...sortWhere
117
+ }
118
+ }
119
+
120
+ const items = await this.model.findAll({
121
+ where,
122
+ attributes,
123
+ order,
124
+ limit: itemsPerPage + 1,
125
+ replacements,
126
+ })
127
+
128
+ const hasNext = items.length > itemsPerPage
129
+ if(hasNext){
130
+ items.splice(items.length - 1, 1)
131
+ }
132
+
133
+ if(this.socket){
134
+ this.socket.joinWithArgs(this.channel, { preset })
135
+ }
136
+
137
+ return {
138
+ items,
139
+ hasNext
140
+ }
141
+ },
142
+
143
+ getPresetFilterParams(preset){
144
+
145
+ let where = {}
146
+ let replacements = []
147
+
148
+ if(preset.filters){
149
+
150
+ //console.log(util.inspect(preset.filters, false, null, true /* enable colors */))
151
+
152
+ preset.filters.forEach((filter) => {
153
+
154
+ const key = filter.key
155
+ const type = filter.type
156
+ const items = filter.filters ?? []
157
+ const operand = items[0] && items[0].operand && items[0].operand === 'or' && items.length > 1 ?
158
+ 'or' : 'and'
159
+
160
+ let whereValue = {}
161
+ switch(type){
162
+
163
+ case 'date':
164
+ items.forEach((item) => {
165
+ const operator = item.operator
166
+ const value = item.value
167
+
168
+ switch(operator){
169
+
170
+ case 'today':
171
+ whereValue = {
172
+ ...whereValue,
173
+ [Op.eq]: dayjs().format('YYYY-MM-DD'),
174
+ }
175
+ break
176
+
177
+ case 'thisWeek':
178
+ whereValue = {
179
+ ...whereValue,
180
+ [Op.gte]: dayjs().startOf('week').format('YYYY-MM-DD 00:00:00'),
181
+ [Op.lt]: dayjs().endOf('week').format('YYYY-MM-DD 23:59:59'),
182
+ }
183
+ break
184
+
185
+ case 'thisMonth':
186
+ whereValue = {
187
+ ...whereValue,
188
+ [Op.gte]: dayjs().format('YYYY-MM-01 00:00:00'),
189
+ [Op.lt]: dayjs().endOf('month').format('YYYY-MM-DD 23:59:59'),
190
+ }
191
+ break
192
+
193
+ case 'lastMonth':
194
+ whereValue = {
195
+ [Op.gte]: dayjs().add(-1, 'month').format('YYYY-MM-01 00:00:00'),
196
+ [Op.lte]: dayjs().add(-1, 'month').endOf('month').format('YYYY-MM-DD 23:59:59'),
197
+ }
198
+ break
199
+
200
+ case 'thisYear':
201
+ whereValue = {
202
+ ...whereValue,
203
+ [Op.gte]: dayjs().startOf('year').format('YYYY-MM-DD 00:00:00'),
204
+ [Op.lt]: dayjs().endOf('year').format('YYYY-MM-DD 23:59:59'),
205
+ }
206
+ break
207
+
208
+ case 'lastYear':
209
+ whereValue = {
210
+ ...whereValue,
211
+ [Op.gte]: dayjs().add(-1, 'year').startOf('year').format('YYYY-MM-DD 00:00:00'),
212
+ [Op.lt]: dayjs().add(-1, 'year').endOf('year').format('YYYY-MM-DD 23:59:59'),
213
+ }
214
+ break
215
+
216
+ case 'between':
217
+ whereValue = {
218
+ ...whereValue,
219
+ [Op.gte]: dayjs(value[0]).format('YYYY-MM-DD 00:00:00'),
220
+ [Op.lt]: dayjs(value[1]).format('YYYY-MM-DD 23:59:59'),
221
+ }
222
+ break
223
+ }
224
+ })
225
+ break
226
+
227
+ case 'enum':
228
+ items.forEach((item) => {
229
+ const value = item.value ?? []
230
+ whereValue = {
231
+ ...whereValue,
232
+ [Op.in]: value
233
+ }
234
+ })
235
+ break
236
+
237
+ case 'currency':
238
+ items.forEach((item) => {
239
+
240
+ const operator = item.operator
241
+ const value = item.value
242
+
243
+ switch(operator){
244
+
245
+ case '>':
246
+ whereValue = {
247
+ ...whereValue,
248
+ [Op.gt]: parseFloat(value)
249
+ }
250
+ break
251
+
252
+ case '>=':
253
+ whereValue = {
254
+ ...whereValue,
255
+ [Op.gte]: parseFloat(value)
256
+ }
257
+ break
258
+
259
+ case '=':
260
+ whereValue = {
261
+ ...whereValue,
262
+ [Op.eq]: parseFloat(value)
263
+ }
264
+ break
265
+
266
+ case '<':
267
+ whereValue = {
268
+ ...whereValue,
269
+ [Op.lt]: parseFloat(value)
270
+ }
271
+ break
272
+
273
+ case '<=':
274
+ whereValue = {
275
+ ...whereValue,
276
+ [Op.lte]: parseFloat(value)
277
+ }
278
+ break
279
+ }
280
+ })
281
+ break
282
+
283
+ default:
284
+ items.forEach((item) => {
285
+
286
+ const operator = item.operator
287
+ const value = item.value
288
+
289
+ switch(operator){
290
+
291
+ case 'startsWith':
292
+ whereValue = {
293
+ ...whereValue,
294
+ [Op.like]: `${value}%`
295
+ }
296
+ break
297
+
298
+ case 'endsWith':
299
+ whereValue = {
300
+ ...whereValue,
301
+ [Op.like]: `%${value}`
302
+ }
303
+ break
304
+
305
+ case 'contains':
306
+ whereValue = {
307
+ ...whereValue,
308
+ [Op.like]: `%${value}%`
309
+ }
310
+ break
311
+
312
+ case '=':
313
+ whereValue = {
314
+ ...whereValue,
315
+ [Op.eq]: value
316
+ }
317
+ break
318
+ }
319
+ })
320
+ break
321
+ }
322
+
323
+ switch(operand){
324
+
325
+ case 'or':
326
+ where = {
327
+ ...where,
328
+ [key]: {
329
+ [Op.or]: whereValue
330
+ }
331
+ }
332
+ break
333
+
334
+ default:
335
+ where = {
336
+ ...where,
337
+ [key]: {
338
+ [Op.and]: whereValue
339
+ }
340
+ }
341
+ break
342
+ }
343
+ })
344
+ }
345
+
346
+ //console.log('where#1', util.inspect(where, false, null, true /* enable colors */))
347
+
348
+ return {
349
+ where,
350
+ replacements
351
+ }
352
+ },
353
+
354
+ getPresetSortParams(preset){
355
+
356
+ if(preset.sorts && preset.sorts.length > 0){
357
+ let order = []
358
+ preset.sorts.forEach((sort) => {
359
+ const key = sort.key
360
+ const type = sort.type === 'desc' ? 'desc' : 'asc'
361
+ order.push([ key, type ])
362
+ })
363
+ order.push([ 'id', 'desc' ])
364
+
365
+ return {
366
+ order
367
+ }
368
+ }
369
+ return {}
370
+ },
371
+
372
+ getPresetSortWhereParams(order, afterItem){
373
+
374
+ if(order.filter((_) => _[0] === 'id').length <= 0){
375
+ order.push([ 'id', 'desc' ])
376
+ }
377
+
378
+ const opOr = []
379
+ for(let i = 0 ; i < order.length ; i++){
380
+
381
+ const obj = order[i]
382
+
383
+ const exp = {}
384
+ for(let j = 0 ; j < i ; j++){
385
+ exp[order[j][0]] = afterItem[order[j][0]]
386
+ }
387
+ exp[obj[0]] = obj[1] === 'desc' ? { [Op.lt]:afterItem[obj[0]] } : { [Op.gt]:afterItem[obj[0]] }
388
+
389
+ if(Object.keys(exp).length === 1){
390
+ opOr.push(exp)
391
+ }
392
+ else{
393
+ opOr.push({
394
+ [Op.and]: exp
395
+ })
396
+ }
397
+ }
398
+
399
+ let sortWhere = {}
400
+ if(opOr.length > 0){
401
+ sortWhere = {
402
+ [Op.or]: opOr
403
+ }
404
+ }
405
+ return sortWhere
406
+ },
407
+
408
+ async onHooks(model, event, items, io){
409
+
410
+ switch(event){
411
+
412
+ case 'destroy':
413
+ case 'remove':
414
+ io.to(model).emit(model, event, items)
415
+ break
416
+
417
+ default:
418
+ const instances = await this.model.findAll({
419
+ where: {
420
+ id: {
421
+ [Op.in]: items.map((_) => _.id)
422
+ }
423
+ }
424
+ })
425
+ io.to(model).emit(`${model}${event}`, instances)
426
+ break
427
+
428
+ }
429
+
430
+ }
431
+
432
+ }
433
+
434
+ module.exports = ListPage1