ts-glitter 18.2.6 → 18.2.8

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.
Files changed (57) hide show
  1. package/lowcode/Entry.js +30 -1
  2. package/lowcode/Entry.ts +36 -1
  3. package/lowcode/cms-plugin/customer-message-user.js +503 -8
  4. package/lowcode/cms-plugin/customer-message-user.ts +549 -12
  5. package/lowcode/cms-plugin/shopping-finance-setting.js +4 -4
  6. package/lowcode/cms-plugin/shopping-finance-setting.ts +4 -4
  7. package/lowcode/cms-plugin/shopping-information.js +16 -0
  8. package/lowcode/cms-plugin/shopping-information.ts +16 -0
  9. package/lowcode/cms-plugin/shopping-order-manager.js +138 -77
  10. package/lowcode/cms-plugin/shopping-order-manager.ts +177 -102
  11. package/lowcode/glitter-base/global/language.js +6 -0
  12. package/lowcode/glitter-base/global/language.ts +6 -0
  13. package/lowcode/glitterBundle/GVController.js +2 -2
  14. package/lowcode/glitterBundle/GVController.ts +2 -2
  15. package/lowcode/glitterBundle/dialog/dialog_inner.js +5 -2
  16. package/lowcode/glitterBundle/dialog/dialog_inner.ts +5 -2
  17. package/lowcode/glitterBundle/module/Animation.js +59 -0
  18. package/lowcode/glitterBundle/module/Animation.ts +62 -0
  19. package/lowcode/glitterBundle/module/PageManager.js +3 -3
  20. package/lowcode/glitterBundle/module/PageManager.ts +1 -1
  21. package/lowcode/index.html +1 -0
  22. package/lowcode/public-components/checkout/index.js +77 -117
  23. package/lowcode/public-components/checkout/index.ts +174 -221
  24. package/lowcode/public-components/footer/footer-01.js +3 -0
  25. package/lowcode/public-components/footer/footer-01.ts +3 -0
  26. package/lowcode/public-components/footer/footer-02.js +3 -0
  27. package/lowcode/public-components/footer/footer-02.ts +3 -0
  28. package/lowcode/public-components/footer/footer-03.js +3 -0
  29. package/lowcode/public-components/footer/footer-03.ts +3 -0
  30. package/lowcode/public-components/product/pd-class.js +868 -355
  31. package/lowcode/public-components/product/pd-class.ts +1005 -438
  32. package/lowcode/public-components/product/product-detail.js +1 -1
  33. package/lowcode/public-components/product/product-detail.ts +3 -1
  34. package/package.json +1 -1
  35. package/src/api-public/controllers/article.js.map +1 -1
  36. package/src/api-public/controllers/delivery.js.map +1 -1
  37. package/src/api-public/controllers/delivery.ts +2 -0
  38. package/src/api-public/controllers/shop.js +3 -2
  39. package/src/api-public/controllers/shop.js.map +1 -1
  40. package/src/api-public/controllers/shop.ts +4 -3
  41. package/src/api-public/controllers/user.js.map +1 -1
  42. package/src/api-public/services/ai-robot.js.map +1 -1
  43. package/src/api-public/services/fb-api.js.map +1 -1
  44. package/src/api-public/services/financial-service.d.ts +4 -0
  45. package/src/api-public/services/financial-service.js +48 -23
  46. package/src/api-public/services/financial-service.js.map +1 -1
  47. package/src/api-public/services/financial-service.ts +57 -26
  48. package/src/api-public/services/public-table-check.js.map +1 -1
  49. package/src/api-public/services/shopping.js +7 -0
  50. package/src/api-public/services/shopping.js.map +1 -1
  51. package/src/api-public/services/shopping.ts +9 -0
  52. package/src/api-public/services/user.d.ts +2 -2
  53. package/src/api-public/services/user.js +8 -2
  54. package/src/api-public/services/user.js.map +1 -1
  55. package/src/api-public/services/user.ts +8 -2
  56. package/src/index.js +3 -3
  57. package/src/index.js.map +1 -1
@@ -1,15 +1,16 @@
1
- import { GVC } from '../../glitterBundle/GVController.js';
2
- import { Tool } from '../../modules/tool.js';
3
- import { ApiShop } from '../../glitter-base/route/shopping.js';
4
- import { ApiCart } from '../../glitter-base/route/api-cart.js';
5
- import { GlobalUser } from '../../glitter-base/global/global-user.js';
6
- import { CheckInput } from '../../modules/checkInput.js';
7
- import { Ad } from '../public/ad.js';
8
- import { Language } from '../../glitter-base/global/language.js';
9
- import { Currency } from '../../glitter-base/global/currency.js';
10
- import { Product, ProductInitial } from '../../public-models/product.js';
11
- import { VoucherContent } from '../user-manager/um-voucher.js';
1
+ import {GVC} from '../../glitterBundle/GVController.js';
2
+ import {Tool} from '../../modules/tool.js';
3
+ import {ApiShop} from '../../glitter-base/route/shopping.js';
4
+ import {ApiCart} from '../../glitter-base/route/api-cart.js';
5
+ import {GlobalUser} from '../../glitter-base/global/global-user.js';
6
+ import {CheckInput} from '../../modules/checkInput.js';
7
+ import {Ad} from '../public/ad.js';
8
+ import {Language} from '../../glitter-base/global/language.js';
9
+ import {Currency} from '../../glitter-base/global/currency.js';
10
+ import {Product, ProductInitial} from '../../public-models/product.js';
12
11
  import {ApiTrack} from "../../glitter-base/route/api-track.js";
12
+ import {Animation, AnimationConfig} from "../../glitterBundle/module/Animation.js";
13
+ import {ShareDialog} from "../../glitterBundle/dialog/ShareDialog.js";
13
14
 
14
15
  const html = String.raw;
15
16
  const css = String.raw;
@@ -122,7 +123,14 @@ export type FileItem = {
122
123
  export type FileList = FileItem[];
123
124
 
124
125
  export class PdClass {
125
- static jumpAlert(obj: { gvc: GVC; text: string; justify: 'top' | 'bottom'; align: 'left' | 'center' | 'right'; timeout?: number; width?: number }) {
126
+ static jumpAlert(obj: {
127
+ gvc: GVC;
128
+ text: string;
129
+ justify: 'top' | 'bottom';
130
+ align: 'left' | 'center' | 'right';
131
+ timeout?: number;
132
+ width?: number
133
+ }) {
126
134
  const className = 'pd-class';
127
135
 
128
136
  const fixedStyle = (() => {
@@ -176,7 +184,8 @@ export class PdClass {
176
184
  }
177
185
  `);
178
186
 
179
- const htmlString = html` <div class="bounce-effect-${className}">${obj.text}</div>`;
187
+ const htmlString = html`
188
+ <div class="bounce-effect-${className}">${obj.text}</div>`;
180
189
  obj.gvc.glitter.document.body.insertAdjacentHTML('beforeend', htmlString);
181
190
  setTimeout(() => {
182
191
  const element = document.querySelector(`.bounce-effect-${className}`) as HTMLElement;
@@ -269,6 +278,7 @@ export class PdClass {
269
278
  }
270
279
 
271
280
  .add-cart-imd-btn {
281
+ border: none;
272
282
  display: inline-flex;
273
283
  align-items: center;
274
284
  justify-content: center;
@@ -332,37 +342,42 @@ export class PdClass {
332
342
 
333
343
  static addCartAction(obj: { gvc: GVC; titleFontColor: any; prod: any; vm: any }) {
334
344
  obj.gvc.glitter.innerDialog((gvc: GVC) => {
335
- return html` <div class="bg-white shadow rounded-3" style="overflow-y: auto; ${document.body.clientWidth > 768 ? `min-width: 400px; width: 1000px;` : 'width:calc(100vw - 20px);'}">
336
- <div class="bg-white shadow rounded-3" style="width: 100%; overflow-y: auto; position: relative;">
337
- <div class="w-100 d-flex align-items-center p-3 border-bottom" style="position: sticky; top: 0; background: #fff;z-index:12;">
338
- <div class="fw-bold fs-5" style="color:${obj.titleFontColor}; white-space: nowrap;text-overflow: ellipsis;max-width: calc(100% - 40px); overflow: hidden;">
339
- ${obj.prod.title}
340
- </div>
341
- <div class="flex-fill"></div>
342
- <i
343
- class="fa-regular fa-circle-xmark fs-5 text-dark"
344
- style="cursor: pointer"
345
- onclick="${gvc.event(() => {
346
- gvc.closeDialog();
347
- })}"
348
- ></i>
349
- </div>
350
- <div class="c_dialog">
351
- <div class="c_dialog_body">
352
- <div class="c_dialog_main" style="gap: 24px; max-height: calc(100vh - 100px); ${document.body.clientWidth < 800 ? `padding: 12px 20px;` : `padding: 30px;`}">
353
- ${PdClass.selectSpec({
354
- gvc,
355
- titleFontColor: obj.titleFontColor,
356
- prod: obj.prod,
357
- vm: obj.vm,
358
- preview: true,
359
- })}
345
+ return html`
346
+ <div class=" bg-white shadow ${document.body.clientWidth > 768 ? `rounded-3` : ` position-absolute bottom-0`}"
347
+ style=" ${document.body.clientWidth > 768 ? `min-width: 400px; width: 1000px;max-height:calc(100% - 150px);overflow-y: auto;` : 'width:calc(100vw);height:100%;'}">
348
+ <div class="bg-white shadow ${document.body.clientWidth > 768 ? `rounded-3` : `h-100`}" style="
349
+ width: 100%; position: relative;${document.body.clientWidth > 768 ? `` : `overflow-y: auto;`}">
350
+ <div class="w-100 d-flex align-items-center p-3 border-bottom"
351
+ style="position: sticky; top: 0; background: #fff;z-index:12;">
352
+ <div class="fw-bold fs-5"
353
+ style="color:${obj.titleFontColor}; white-space: nowrap;text-overflow: ellipsis;max-width: calc(100% - 40px); overflow: hidden;">
354
+ ${obj.prod.title}
360
355
  </div>
356
+ <div class="flex-fill"></div>
357
+ <i
358
+ class="fa-regular fa-circle-xmark fs-5 text-dark"
359
+ style="cursor: pointer"
360
+ onclick="${gvc.event(() => {
361
+ gvc.closeDialog();
362
+ })}"
363
+ ></i>
364
+ </div>
365
+ <div class="c_dialog_main"
366
+ style="gap: 24px; max-height: calc(100% - 100px); ${document.body.clientWidth < 800 ? `padding: 12px 20px;` : `padding: 30px;`}">
367
+ ${PdClass.selectSpec({
368
+ gvc,
369
+ titleFontColor: obj.titleFontColor,
370
+ prod: obj.prod,
371
+ vm: obj.vm,
372
+ preview: true,
373
+ })}
374
+ <div class="d-sm-none" style="height:100px;"></div>
361
375
  </div>
362
376
  </div>
363
- </div>
364
- </div>`;
365
- }, Tool.randomString(7));
377
+ </div>`;
378
+ }, Tool.randomString(7), {
379
+ animation: (document.body.clientWidth < 768) ? Animation.popup : Animation.fade
380
+ });
366
381
  }
367
382
 
368
383
  static showSwiper(obj: { gvc: GVC; prod: Product; vm: any }) {
@@ -377,11 +392,12 @@ export class PdClass {
377
392
  src: `https://cdn.jsdelivr.net/npm/swiper@11/swiper-bundle.min.js`,
378
393
  },
379
394
  ],
380
- () => {},
381
- () => {}
395
+ () => {
396
+ },
397
+ () => {
398
+ }
382
399
  );
383
400
 
384
- console.log(`obj.prod.preview_image=>`,JSON.stringify(obj.prod.preview_image))
385
401
  obj.prod.variants.forEach((variant) => {
386
402
  variant.preview_image = (variant as any)[`preview_image_${Language.getLanguage()}`] || variant.preview_image;
387
403
  if (variant.preview_image && !obj.prod.preview_image.includes(variant.preview_image)) {
@@ -400,8 +416,8 @@ export class PdClass {
400
416
  return image !== 'https://d3jnmi1tfjgtti.cloudfront.net/file/234285319/1722936949034-default_image.jpg';
401
417
  });
402
418
 
403
- if(obj.prod.preview_image.length===0){
404
- obj.prod.preview_image=['https://d3jnmi1tfjgtti.cloudfront.net/file/234285319/1722936949034-default_image.jpg']
419
+ if (obj.prod.preview_image.length === 0) {
420
+ obj.prod.preview_image = ['https://d3jnmi1tfjgtti.cloudfront.net/file/234285319/1722936949034-default_image.jpg']
405
421
  }
406
422
  return obj.gvc.bindView(() => {
407
423
  const id = obj.gvc.glitter.getUUID();
@@ -409,37 +425,44 @@ export class PdClass {
409
425
  bind: id,
410
426
  view: () => {
411
427
  return html`
412
- <div class="swiper${id}" id="dynamic-swiper${id}" style="width: 500px;position:relative;overflow: hidden;max-width: 100%;">
428
+ <div class="swiper${id}" id="dynamic-swiper${id}"
429
+ style="width: 500px;position:relative;overflow: hidden;max-width: 100%;">
413
430
  <div class="swiper-wrapper">
414
431
  ${obj.prod.preview_image
415
- .map((image, index) => {
416
- return html` <div class="swiper-slide swiper-slide-def">
417
- <img src="${image}" alt="${obj.prod.title}-${index}" />
418
- </div>`;
419
- })
420
- .join('')}
432
+ .map((image, index) => {
433
+ return html`
434
+ <div class="swiper-slide swiper-slide-def">
435
+ <img src="${image}" alt="${obj.prod.title}-${index}"/>
436
+ </div>`;
437
+ })
438
+ .join('')}
421
439
  </div>
422
440
  <div class="swiper-button-prev"></div>
423
441
  <div class="swiper-button-next"></div>
424
442
  </div>
425
443
  ${obj.prod.preview_image.length > 1
426
- ? html` <div class="swiper-sm${id} mt-2" style="height: ${isPhone ? 75 : 100}px; overflow: hidden;">
427
- <div class="swiper-wrapper">
428
- ${obj.prod.preview_image
429
- .map((image, index) => {
430
- return html` <div class="swiper-slide swiper-slide-sm" data-image-index="${index}">
431
- <img src="${image}" alt="${obj.prod.title}-${index}-sm" style="height: ${isPhone ? 75 : 100}px;width: auto !important;" />
432
- </div>`;
433
- })
434
- .join('')}
435
- </div>
436
- </div>`
437
- : ``}
444
+ ? html`
445
+ <div class="swiper-sm${id} mt-2"
446
+ style="height: ${isPhone ? 75 : 100}px; overflow: hidden;">
447
+ <div class="swiper-wrapper">
448
+ ${obj.prod.preview_image
449
+ .map((image, index) => {
450
+ return html`
451
+ <div class="swiper-slide swiper-slide-sm"
452
+ data-image-index="${index}">
453
+ <img src="${image}" alt="${obj.prod.title}-${index}-sm"
454
+ style="height: ${isPhone ? 75 : 100}px;width: auto !important;"/>
455
+ </div>`;
456
+ })
457
+ .join('')}
458
+ </div>
459
+ </div>`
460
+ : ``}
438
461
  `;
439
462
  },
440
463
  divCreate: {
441
464
  class: ``,
442
- option: [{ key: 'id', value: id }],
465
+ option: [{key: 'id', value: id}],
443
466
  style: `overflow:hidden;position:relative;${document.body.clientWidth > 800 ? `width:500px;` : `width:100%:`}`,
444
467
  },
445
468
  onCreate: () => {
@@ -547,7 +570,7 @@ export class PdClass {
547
570
  callback?: () => void;
548
571
  preview?: boolean;
549
572
  only_select?: (data: any) => void;
550
- is_gift?:boolean;
573
+ is_gift?: boolean;
551
574
  }) {
552
575
  const gvc = obj.gvc;
553
576
  const glitter = gvc.glitter;
@@ -560,6 +583,7 @@ export class PdClass {
560
583
  addCartButton: glitter.getUUID(),
561
584
  stock_count: glitter.getUUID(),
562
585
  qty_count: glitter.getUUID(),
586
+ ids_spec: glitter.getUUID()
563
587
  };
564
588
  obj.gvc.addStyle(`
565
589
  .insignia {
@@ -581,12 +605,12 @@ export class PdClass {
581
605
  justify-content: center;
582
606
  align-items: center;
583
607
  gap: 4px;
584
- border-radius: 7px;
585
- background: #FFE9B2;
608
+ border-radius: 2px;
586
609
  font-size: 14px;
587
610
  }
588
611
  `);
589
- let changePage = (index: string, type: 'page' | 'home', subData: any) => {};
612
+ let changePage = (index: string, type: 'page' | 'home', subData: any) => {
613
+ };
590
614
  gvc.glitter.getModule(new URL('./official_event/page/change-page.js', gvc.glitter.root_path).href, (cl) => {
591
615
  changePage = cl.changePage;
592
616
  });
@@ -608,157 +632,190 @@ export class PdClass {
608
632
  }
609
633
  }
610
634
 
635
+ function refreshAll(){
636
+ gvc.notifyDataChange([ids.price, ids.addCartButton, ids.stock_count, ids.qty_count,ids.ids_spec])
637
+ }
638
+ const solidButtonBgr = glitter.share.globalValue['theme_color.0.solid-button-bg'] ?? '#dddddd';
639
+ const solidButtonText = glitter.share.globalValue['theme_color.0.solid-button-text'] ?? '#000000';
611
640
  const aboutVoucherHTML =
612
641
  vm.data && vm.data.content.about_vouchers && vm.data.content.about_vouchers.length > 0
613
- ? html`<div class="d-flex flex-column gap-2 mt-3">
614
- ${vm.data.content.about_vouchers
615
- .map((v) => {
616
- return html`
617
- <div class="d-flex gap-2 align-items-center">
618
- <div class="insignia insignia-voucher">${eventName(v.reBackType)}</div>
619
- <div style="font-size: 14px; font-weight: 500;">${v.title}</div>
620
- </div>
621
- `;
622
- })
623
- .join('')}
624
- </div>`
642
+ ? html`
643
+ <div class="d-flex flex-column gap-2 mt-3">
644
+ ${vm.data.content.about_vouchers
645
+ .map((v) => {
646
+ return html`
647
+ <div class="d-flex gap-2 align-items-center">
648
+ <div class="insignia insignia-voucher"
649
+ style="background:${solidButtonBgr};color:${solidButtonText};font-size:12px;">
650
+ ${eventName(v.reBackType)}
651
+ </div>
652
+ <div class="fs-sm" style="font-weight: 500;color:${titleFontColor};">
653
+ ${v.title}
654
+ </div>
655
+ </div>
656
+ `;
657
+ })
658
+ .join('')}
659
+ </div>`
625
660
  : '';
626
- return html`
627
- <div class="d-flex flex-column flex-lg-row w-100" style="gap:${this.isPhone() ? 20 : 40}px;">
628
- <div class="w-100">
661
+ let viewMap = [
662
+ ` <div class="w-100">
629
663
  <div class="w-100">
630
664
  ${obj.preview
631
- ? PdClass.showSwiper({
632
- gvc: gvc,
633
- prod: obj.prod,
634
- vm: obj.vm,
635
- })
636
- : ``}
665
+ ? PdClass.showSwiper({
666
+ gvc: gvc,
667
+ prod: obj.prod,
668
+ vm: obj.vm,
669
+ })
670
+ : ``}
637
671
  </div>
638
- <div class="w-100">${aboutVoucherHTML}</div>
639
- </div>
640
- <div class="w-100">
641
- <h1 style="color: ${titleFontColor};font-size:${document.body.clientWidth > 991 ? `36` : `24`}px;">${prod.title}</h1>
672
+ </div>`,
673
+ ` <div class="w-100">
674
+ <h1 style="color: ${titleFontColor};font-size:${document.body.clientWidth > 991 ? `28` : `20`}px;">
675
+ ${prod.title}</h1>
642
676
  <div class="d-flex flex-wrap" style="gap:10px;">
643
677
  ${(prod.product_tag as any).language[Language.getLanguage()]
644
- .map((tag: any) => {
645
- return html`<div
646
- class="mb-3 rounded-1 text-white d-flex align-items-center justify-content-center px-2 "
647
- style="background: ${glitter.share.globalValue['theme_color.0.solid-button-bg']};font-size: 13px;"
648
- >
649
- ${tag}
650
- </div>`;
651
- })
652
- .join('')}
678
+ .map((tag: any) => {
679
+ return html`
680
+ <div
681
+ class="mb-3 rounded-1 text-white d-flex align-items-center justify-content-center px-2 "
682
+ style="background: ${glitter.share.globalValue['theme_color.0.solid-button-bg']};font-size: 12px;"
683
+ >
684
+ ${tag}
685
+ </div>`;
686
+ })
687
+ .join('')}
653
688
  </div>
654
689
  ${prod.min_qty && `${prod.min_qty}` > `1`
655
- ? html` <div class="insignia mx-0 w-auto mt-0 mb-3 fw-500 py-2 me-1" style="background: #ffe9b2;margin-left:5px;">
656
- ${Language.text('min_p_count').replace('_c_', `<span class="fw-bold mx-1">${prod.min_qty}</span>`)}
657
- </div>`
658
- : ``}
690
+ ? html`
691
+ <div class="insignia mx-0 w-auto mt-0 mb-3 fw-500 py-2 me-1"
692
+ style="background: #ffe9b2;margin-left:5px;">
693
+ ${Language.text('min_p_count').replace('_c_', `<span class="fw-bold mx-1">${prod.min_qty}</span>`)}
694
+ </div>`
695
+ : ``}
659
696
  ${prod.max_qty && `${prod.max_qty}` > `1`
660
- ? html` <div class="insignia mx-0 w-auto mt-0 mb-3 fw-500 py-2" style="background: #ffe9b2;margin-left:5px;">
661
- ${Language.text('max_p_count').replace('_c_', `<span class="fw-bold mx-1">${prod.max_qty}</span>`)}
662
- </div>`
663
- : ``}
664
- ${language_data && language_data.sub_title ? html` <div class="mb-3">${language_data.sub_title}</div> ` : ``}
697
+ ? html`
698
+ <div class="insignia mx-0 w-auto mt-0 mb-3 fw-500 py-2"
699
+ style="background: #ffe9b2;margin-left:5px;">
700
+ ${Language.text('max_p_count').replace('_c_', `<span class="fw-bold mx-1">${prod.max_qty}</span>`)}
701
+ </div>`
702
+ : ``}
703
+ ${language_data && language_data.sub_title ? html`
704
+ <div class="mb-3">${language_data.sub_title}</div> ` : ``}
665
705
  ${gvc.bindView({
666
- bind: ids.price,
667
- view: () => {
668
- const v = prod.variants.find((variant) => PdClass.ObjCompare(variant.spec, vm.specs, true));
706
+ bind: ids.price,
707
+ view: () => {
708
+ const v = prod.variants.find((variant) => PdClass.ObjCompare(variant.spec, vm.specs, true));
669
709
 
670
- if (!v) return '錯誤';
710
+ if (!v) return '錯誤';
671
711
 
672
- const comparePrice = parseInt(`${v.compare_price ?? 0}`, 10);
673
- const originPrice = parseInt(`${v.origin_price ?? 0}`, 10);
674
- const lineThroughPrice = comparePrice > originPrice ? originPrice : comparePrice;
712
+ const comparePrice = parseInt(`${v.compare_price ?? 0}`, 10);
713
+ const originPrice = parseInt(`${v.origin_price ?? 0}`, 10);
714
+ const lineThroughPrice = comparePrice > originPrice ? originPrice : comparePrice;
675
715
 
716
+ return html`
717
+ <div class="d-flex align-items-end" style="font-family: 'Noto Sans'; gap: 8px;">
718
+ <div style="color: ${(lineThroughPrice > 0 && lineThroughPrice > v.sale_price) ? '#ff5353':titleFontColor}; font-size: 24px; font-weight: 700; line-height: normal">
719
+ ${Currency.convertCurrencyText(v.sale_price)}
720
+ </div>
721
+ ${lineThroughPrice > 0 && lineThroughPrice > v.sale_price
722
+ ? html`
723
+ <div style="color: #8D8D8D; font-size: 16px; text-decoration: line-through;">
724
+ ${Currency.convertCurrencyText(lineThroughPrice)}
725
+ </div> `
726
+ : ''}
727
+ </div>
728
+ `;
729
+ },
730
+ divCreate: {
731
+ style: 'margin-bottom: 12px;'
732
+ }
733
+ })}
734
+ ${gvc.bindView(() => {
735
+
736
+ return {
737
+ bind: ids.ids_spec,
738
+ view: () => {
739
+ return prod.specs.map((spec, index1) => {
676
740
  return html`
677
- <div class="d-flex align-items-end" style="font-family: 'Noto Sans'; gap: 8px;">
678
- <div style="color: ${titleFontColor}; font-size: 26px; font-weight: 700; line-height: normal">${Currency.convertCurrencyText(v.sale_price)}</div>
679
- ${lineThroughPrice > 0 && lineThroughPrice > v.sale_price
680
- ? html`<div style="color: #8D8D8D; font-size: 18px; text-decoration: line-through;">${Currency.convertCurrencyText(lineThroughPrice)}</div> `
681
- : ''}
682
- </div>
683
- `;
684
- },
685
- divCreate: {
686
- style: 'margin-bottom: 12px;'
687
- }
688
- })}
689
- ${gvc.map(
690
- prod.specs.map((spec, index1) => {
691
- return html` <div>
741
+ <div>
692
742
  <h5 class="mb-2" style="color: ${titleFontColor};font-size:14px;">
693
743
  ${(spec.language_title && (spec.language_title as any)[Language.getLanguage()]) || spec.title}
694
744
  </h5>
695
745
  <div class="d-flex gap-2 flex-wrap">
696
746
  ${gvc.map(
697
- spec.option.map((opt: any) => {
698
- return html` <div
699
- gvc-option="spec-option-${index1}"
700
- class="spec-option ${vm.specs[index1] === opt.title ? 'selected-option' : ''}"
701
- onclick="${gvc.event((e) => {
702
- const allOptions = document.querySelectorAll(`div[gvc-option=spec-option-${index1}]`);
703
- allOptions.forEach((option: any) => {
704
- option.classList.remove('selected-option');
705
- });
706
- e.classList.toggle('selected-option');
707
- vm.specs[index1] = opt.title;
708
- const v = prod.variants.find((variant) => {
709
- return PdClass.ObjCompare(variant.spec, vm.specs, true);
710
- });
711
- if (v?.preview_image) {
712
- let index = prod.preview_image.findIndex((src) => {
713
- return src == v.preview_image;
714
- });
715
- if (index >= 0) {
716
- vm.swiper.slideTo(index);
717
- }
718
- }
719
- gvc.notifyDataChange([ids.price, ids.addCartButton, ids.stock_count, ids.qty_count]);
720
- })}"
721
- >
747
+ spec.option.map((opt: any) => {
748
+ return html`
749
+ <div
750
+ gvc-option="spec-option-${index1}"
751
+ class="spec-option ${vm.specs[index1] === opt.title ? 'selected-option' : ''}"
752
+ onclick="${gvc.event((e) => {
753
+ const allOptions = document.querySelectorAll(`div[gvc-option=spec-option-${index1}]`);
754
+ allOptions.forEach((option: any) => {
755
+ option.classList.remove('selected-option');
756
+ });
757
+ e.classList.toggle('selected-option');
758
+ vm.specs[index1] = opt.title;
759
+ const v = prod.variants.find((variant) => {
760
+ return PdClass.ObjCompare(variant.spec, vm.specs, true);
761
+ });
762
+ if (v?.preview_image) {
763
+ let index = prod.preview_image.findIndex((src) => {
764
+ return src == v.preview_image;
765
+ });
766
+ if (index >= 0) {
767
+ vm.swiper.slideTo(index);
768
+ }
769
+ }
770
+ refreshAll()
771
+ })}"
772
+ >
722
773
  <span style="font-size: 15px; font-weight: 500; letter-spacing: 1.76px;"
723
- >${(opt.language_title && (opt.language_title as any)[Language.getLanguage()]) || opt.title}</span
774
+ >${(opt.language_title && (opt.language_title as any)[Language.getLanguage()]) || opt.title}</span
724
775
  >
725
- </div>`;
726
- })
776
+ </div>`;
777
+ })
727
778
  )}
728
779
  </div>
729
780
  </div>
730
781
  <div class="mt-3"></div>`;
731
- })
732
- )}
782
+ }).join('')
783
+ },
784
+ divCreate: {
785
+ class: `w-100`
786
+ }
787
+ }
788
+ })}
733
789
  ${[
734
- //數量按鈕
735
- gvc.bindView(() => {
736
- return {
737
- bind: ids.qty_count,
738
- view: () => {
739
- const variant = prod.variants.find((item) => PdClass.ObjCompare(item.spec, vm.specs, true));
740
- const cartItem = new ApiCart().cart.line_items.find((item) => PdClass.ObjCompare(item.spec, vm.specs, true));
741
- if (
742
- variant &&
743
- (variant.stock < parseInt(vm.quantity, 10) || (cartItem && variant.stock < cartItem.count + parseInt(vm.quantity, 10))) &&
744
- `${variant.show_understocking}` !== 'false'
745
- ) {
746
- return '';
747
- }
748
- return html`
749
- <h5 class="mb-0" style="color: ${titleFontColor};font-size:14px;">${Language.text('quantity')}</h5>
750
- <div class="d-flex align-items-center" style="color:${titleFontColor};">
751
- <select
752
- class="form-select custom-select me-2"
753
- style="border-radius: 5px; color: #575757; width: 100px;height:38px;"
754
- onchange="${gvc.event((e) => {
755
- vm.quantity = e.value;
756
- gvc.notifyDataChange([ids.addCartButton, ids.stock_count]);
757
- })}"
758
- >
759
- ${gvc.map(
760
- [
761
- ...new Array(
790
+ //數量按鈕
791
+ gvc.bindView(() => {
792
+ return {
793
+ bind: ids.qty_count,
794
+ view: () => {
795
+ const variant = prod.variants.find((item) => PdClass.ObjCompare(item.spec, vm.specs, true));
796
+ const cartItem = new ApiCart().cart.line_items.find((item) => PdClass.ObjCompare(item.spec, vm.specs, true));
797
+ if (
798
+ variant &&
799
+ (variant.stock < parseInt(vm.quantity, 10) || (cartItem && variant.stock < cartItem.count + parseInt(vm.quantity, 10))) &&
800
+ `${variant.show_understocking}` !== 'false'
801
+ ) {
802
+ return '';
803
+ }
804
+ return html`
805
+ <h5 class="mb-0" style="color: ${titleFontColor};font-size:14px;">
806
+ ${Language.text('quantity')}</h5>
807
+ <div class="d-flex align-items-center" style="color:${titleFontColor};">
808
+ <select
809
+ class="form-select custom-select me-2"
810
+ style="border-radius: 5px; color: #575757; width: 100px;height:38px;"
811
+ onchange="${gvc.event((e) => {
812
+ vm.quantity = e.value;
813
+ gvc.notifyDataChange([ids.addCartButton, ids.stock_count]);
814
+ })}"
815
+ >
816
+ ${gvc.map(
817
+ [
818
+ ...new Array(
762
819
  (() => {
763
820
  const variant = prod.variants.find((item) => PdClass.ObjCompare(item.spec, vm.specs, true));
764
821
  if (!variant || variant.show_understocking === 'false') {
@@ -766,270 +823,780 @@ export class PdClass {
766
823
  }
767
824
  return variant.stock < 50 ? variant.stock : 50;
768
825
  })()
769
- ),
770
- ].map((item, index) => {
771
- return html` <option value="${index + 1}">${index + 1}</option>`;
772
- })
773
- )}
774
- </select>
775
- ${(prod.unit as any)[Language.getLanguage()] || Language.text('pieces')}
776
- </div>
777
- `;
778
- },
779
- divCreate: {
780
- class: `flex-column gap-2 ${obj.with_qty === false ? `d-none` : `d-flex`} `,
781
- },
782
- };
783
- }),
784
- //庫存顯示
785
- gvc.bindView(() => {
786
- return {
787
- bind: ids.stock_count,
788
- view: () => {
789
- return [
790
- (() => {
791
- const variant = prod.variants.find((item) => PdClass.ObjCompare(item.spec, vm.specs, true));
792
-
793
- if (variant && variant.show_understocking !== 'false') {
794
- const stockClass = `${variant.stock}` === '0' ? 'text-danger' : '';
795
- return html`
796
- <div class="${stockClass} fw-500 mt-2" style="font-size: 14px; color: ${titleFontColor};">${Language.text('stock_count')}:${variant.stock}</div>
797
- `;
798
- }
799
-
800
- return '';
801
- })(),
802
- ].join('');
826
+ ),
827
+ ].map((item, index) => {
828
+ return html`
829
+ <option value="${index + 1}">${index + 1}</option>`;
830
+ })
831
+ )}
832
+ </select>
833
+ ${(prod.unit as any)[Language.getLanguage()] || Language.text('pieces')}
834
+ </div>
835
+ `;
836
+ },
837
+ divCreate: {
838
+ class: `flex-column gap-2 ${obj.with_qty === false ? `d-none` : `d-none d-sm-flex`} `,
839
+ },
840
+ };
841
+ }),
842
+ //庫存顯示
843
+ gvc.bindView(() => {
844
+ return {
845
+ bind: ids.stock_count,
846
+ view: () => {
847
+ return [
848
+ (() => {
849
+ const variant = prod.variants.find((item) => PdClass.ObjCompare(item.spec, vm.specs, true));
850
+
851
+ if (variant && variant.show_understocking !== 'false') {
852
+ const stockClass = `${variant.stock}` === '0' ? 'text-danger' : '';
853
+ return html`
854
+ <div class="${stockClass} fw-500 mt-2"
855
+ style="font-size: 14px; color: ${titleFontColor};">
856
+ ${Language.text('can_buy')}:${variant.stock}
857
+ </div>
858
+ `;
859
+ }
860
+
861
+ return '';
862
+ })(),
863
+ ].join('');
864
+ },
865
+ divCreate: {},
866
+ };
867
+ }),
868
+ //購物車按鈕
869
+ gvc.bindView({
870
+ bind: ids.addCartButton,
871
+ view: () => {
872
+ const variant = prod.variants.find((item) => {
873
+ return PdClass.ObjCompare(item.spec, vm.specs, true);
874
+ });
875
+ const cartItem = new ApiCart().cart.line_items.find((item) => {
876
+ return PdClass.ObjCompare(item.spec, vm.specs, true);
877
+ });
878
+ if (!variant) {
879
+ return html`
880
+ <button class="no-stock w-100" disabled>發生錯誤</button>`;
881
+ }
882
+
883
+ Ad.gtagEvent('view_item', {
884
+ currency: 'TWD',
885
+ value: variant.sale_price,
886
+ items: [
887
+ {
888
+ item_id: prod.id,
889
+ item_name: prod.title,
890
+ item_variant: variant.spec.length > 0 ? variant.spec.join('-') : '',
891
+ price: variant.sale_price,
803
892
  },
804
- divCreate: {},
805
- };
806
- }),
807
- //購物車按鈕
808
- gvc.bindView({
809
- bind: ids.addCartButton,
810
- view: () => {
811
- const variant = prod.variants.find((item) => {
812
- return PdClass.ObjCompare(item.spec, vm.specs, true);
813
- });
814
- const cartItem = new ApiCart().cart.line_items.find((item) => {
815
- return PdClass.ObjCompare(item.spec, vm.specs, true);
816
- });
817
- if (!variant) {
818
- return html` <button class="no-stock w-100" disabled>發生錯誤</button>`;
819
- }
893
+ ],
894
+ });
895
+ Ad.fbqEvent('ViewContent', {
896
+ content_ids: [variant.sku || prod.id],
897
+ content_type: 'product',
898
+ value: variant.sale_price,
899
+ currency: 'TWD',
900
+ });
901
+
902
+ if (
903
+ ((variant.stock < parseInt(vm.quantity, 10)) &&
904
+ `${variant.show_understocking}` !== 'false') && (document.body.clientWidth > 800)
905
+ ) {
906
+ return html`
907
+ <button class="no-stock w-100" disabled>${Language.text('out_of_stock')}
908
+ </button>`;
909
+ }
820
910
 
821
- Ad.gtagEvent('view_item', {
822
- currency: 'TWD',
823
- value: variant.sale_price,
824
- items: [
825
- {
826
- item_id: prod.id,
827
- item_name: prod.title,
828
- item_variant: variant.spec.length > 0 ? variant.spec.join('-') : '',
829
- price: variant.sale_price,
911
+ //當是贈品一個按鈕就好
912
+ if (obj.is_gift) {
913
+ return `<button
914
+ class="add-cart-imd-btn fw-bold"
915
+ style="width:calc(100% - 10px);cursor: pointer;height:48px;"
916
+ onclick="${gvc.event(() => {
917
+ if (obj.only_select) {
918
+ obj.only_select({id: prod.id, specs: vm.specs});
919
+ } else {
920
+ new ApiCart(ApiCart.checkoutCart).addToCart(`${prod.id}`, vm.specs, vm.quantity);
921
+ gvc.glitter.recreateView('.js-cart-count');
922
+ gvc.glitter.recreateView('.shopping-cart');
923
+ PdClass.jumpAlert({
924
+ gvc,
925
+ text: html`${Language.text('add_to_cart_success')}`,
926
+ justify: 'top',
927
+ align: 'center',
928
+ width: 300,
929
+ });
930
+ ApiTrack.track({
931
+ event_name: "AddToCart",
932
+ custom_data: {
933
+ currency: "TWD",
934
+ value: variant.sale_price,
935
+ content_ids: [variant.sku || `${prod.id}-${vm.specs.join('-')}`],
936
+ content_name: prod.title,
937
+ content_type: "product"
938
+ }
939
+ })
940
+ obj.callback && obj.callback();
941
+ }
942
+ })}"
943
+ >
944
+ ${Language.text('confirm_select')}
945
+ </button>`
946
+ }
947
+ let viewMap = []
948
+ if (document.body.clientWidth < 800 && (window as any).store_info.chat_toggle) {
949
+ viewMap.push(`<div class="rounded-3 d-flex flex-column align-items-center justify-content-center fs-6 add-cart-btn fw-bold "
950
+ style="height:44px;width:44px;" onclick="${gvc.event(() => {
951
+ const userID = (() => {
952
+ if (GlobalUser.token) {
953
+ return GlobalUser.parseJWT(GlobalUser.token).payload.userID
954
+ } else {
955
+ return gvc.glitter.macAddress
956
+ }
957
+ })()
958
+ gvc.glitter.getModule(new URL('./cms-plugin/customer-message-user.js', gvc.glitter.root_path).href, (cl) => {
959
+ cl.mobileChat({
960
+ gvc: gvc,
961
+ chat: {
962
+ chat_id: [`${userID}`, 'manager'].sort().join('-'),
963
+ type: 'user',
830
964
  },
831
- ],
965
+ user_id: `${userID}`
966
+ })
967
+ })
968
+ // gvc.glitter.getModule('',(module)=>{
969
+ })
970
+ }">
971
+ <i class="fa-brands fa-rocketchat"></i>
972
+ <div style="font-size:10px;">${Language.text('chat')}</div>
973
+ </div>`)
974
+ }
975
+ viewMap.push(`<div class="rounded-3 d-flex flex-column align-items-center justify-content-center fs-6 add-cart-btn fw-bold "
976
+ style="height:44px;width:44px;cursor: pointer;" onclick="${gvc.event(() => {
977
+ navigator.clipboard.writeText(`${window.location.href}`);
978
+ const dialog = new ShareDialog(gvc.glitter)
979
+ dialog.successMessage({text: Language.text('copy_link_success')})
980
+ })
981
+ }">
982
+ <i class="fa-solid fa-share"></i>
983
+ <div style="font-size:10px;">${Language.text('share')}</div>
984
+ </div>`)
985
+ if ((window as any).store_info.wishlist) {
986
+ viewMap.push(gvc.bindView(() => {
987
+ return {
988
+ bind: ids.wishStatus,
989
+ view: () => {
990
+ return html`${(vm.wishStatus) ? ` <i class="fa-solid fa-heart" style="color:white;"></i>` : ` <i class="fa-regular fa-heart"></i>`}
991
+ <div style="font-size:10px; ${(vm.wishStatus) ? `color:white;` : ``}">
992
+ ${(vm.wishStatus) ? Language.text('h_collect') : Language.text('collect')}
993
+ </div>`
994
+ },
995
+ divCreate: () => {
996
+ return {
997
+ option: [
998
+ {
999
+ key: 'onclick',
1000
+ value: gvc.event(() => {
1001
+ if (CheckInput.isEmpty(GlobalUser.token)) {
1002
+ changePage('login', 'page', {});
1003
+ GlobalUser.loginRedirect = location.href
1004
+ return;
1005
+ }
1006
+ const dialog = new ShareDialog(gvc.glitter)
1007
+ dialog.dataLoading({visible: true})
1008
+ ApiShop.getWishList().then((getRes) => {
1009
+ if (getRes.result && getRes.response.data) {
1010
+ if (getRes.response.data.find((item: Product_l) => `${item.id}` === `${prod.id}`)) {
1011
+ ApiShop.deleteWishList(`${prod.id}`).then(async () => {
1012
+ PdClass.jumpAlert({
1013
+ gvc,
1014
+ text: '刪除成功',
1015
+ justify: 'top',
1016
+ align: 'center',
1017
+ });
1018
+ vm.wishStatus = false;
1019
+ gvc.notifyDataChange(ids.wishStatus);
1020
+ dialog.dataLoading({visible: false})
1021
+ });
1022
+ } else {
1023
+ const variant = prod.variants.find((item) => PdClass.ObjCompare(item.spec, vm.specs, true)) ?? prod.variants[0];
1024
+ Ad.gtagEvent('add_to_wishlist', {
1025
+ currency: 'TWD',
1026
+ value: variant.sale_price,
1027
+ items: [
1028
+ {
1029
+ item_id: prod.id,
1030
+ item_name: prod.title,
1031
+ item_variant: variant.spec.length > 0 ? variant.spec.join('-') : '',
1032
+ price: variant.sale_price,
1033
+ },
1034
+ ],
1035
+ });
1036
+ Ad.fbqEvent('AddToWishlist', {
1037
+ content_ids: [prod.id],
1038
+ contents: [
1039
+ {
1040
+ id: prod.id,
1041
+ quantity: 1,
1042
+ },
1043
+ ],
1044
+ value: variant.sale_price,
1045
+ currency: 'TWD',
1046
+ });
1047
+
1048
+ ApiShop.postWishList(`${prod.id}`).then(async () => {
1049
+ PdClass.jumpAlert({
1050
+ gvc,
1051
+ text: '新增成功',
1052
+ justify: 'top',
1053
+ align: 'center',
1054
+ });
1055
+ vm.wishStatus = true;
1056
+ gvc.notifyDataChange(ids.wishStatus);
1057
+ dialog.dataLoading({visible: false})
1058
+ });
1059
+ }
1060
+ }
1061
+ });
1062
+ })
1063
+ }
1064
+ ],
1065
+ class: `rounded-3 d-flex flex-column align-items-center justify-content-center fs-6 add-cart-btn fw-bold`,
1066
+ style: `height:44px;width:44px;cursor:pointer; ${(vm.wishStatus) ? `background: #ff5353;border:1px solid white;` : ``}`
1067
+ }
1068
+ }
1069
+ }
1070
+ }))
1071
+ }
1072
+ viewMap.push(`<button
1073
+ class="add-cart-btn fw-bold fs-sm"
1074
+ style=" flex: 1;height:44px;"
1075
+ onclick="${gvc.event(() => {
1076
+ if (document.body.clientWidth < 800) {
1077
+ this.addProductPopUp(obj, 'addCart', () => {
1078
+ refreshAll()
1079
+ })
1080
+ return
1081
+ }
1082
+ if (obj.only_select) {
1083
+ obj.only_select({id: prod.id, specs: vm.specs});
1084
+ } else {
1085
+ new ApiCart().addToCart(`${prod.id}`, vm.specs, vm.quantity);
1086
+ gvc.glitter.recreateView('.js-cart-count');
1087
+ gvc.glitter.recreateView('.shopping-cart');
1088
+ PdClass.jumpAlert({
1089
+ gvc,
1090
+ text: html`${Language.text('add_to_cart_success')}`,
1091
+ justify: 'top',
1092
+ align: 'center',
1093
+ width: 300,
832
1094
  });
833
- Ad.fbqEvent('ViewContent', {
834
- content_ids: [variant.sku || prod.id ],
835
- content_type: 'product',
1095
+ ApiTrack.track({
1096
+ event_name: "AddToCart",
1097
+ custom_data: {
1098
+ currency: "TWD",
1099
+ value: variant.sale_price,
1100
+ content_ids: [variant.sku || `${prod.id}-${vm.specs.join('-')}`],
1101
+ content_name: prod.title,
1102
+ content_type: "product"
1103
+ }
1104
+ })
1105
+ obj.callback && obj.callback();
1106
+ }
1107
+ })}"
1108
+ >
1109
+ ${Language.text('add_to_cart')}
1110
+ </button>`)
1111
+ viewMap.push(`<button
1112
+ class="add-cart-imd-btn fw-bold fs-sm"
1113
+ style="cursor: pointer; flex: 1;height:44px;"
1114
+ onclick="${gvc.event(() => {
1115
+ if (document.body.clientWidth < 800) {
1116
+ this.addProductPopUp(obj, 'buyNow', () => {
1117
+ refreshAll()
1118
+ })
1119
+ return
1120
+ }
1121
+ const buy_it = new ApiCart(ApiCart.buyItNow);
1122
+ buy_it.clearCart();
1123
+ buy_it.addToCart(`${prod.id}`, vm.specs, vm.quantity);
1124
+ ApiCart.toCheckOutPage(ApiCart.buyItNow);
1125
+ gvc.closeDialog();
1126
+ ApiTrack.track({
1127
+ event_name: "AddToCart",
1128
+ custom_data: {
1129
+ currency: "TWD",
836
1130
  value: variant.sale_price,
837
- currency: 'TWD',
838
- });
839
-
840
- if (
841
- (variant.stock < parseInt(vm.quantity, 10) || (cartItem && variant.stock < cartItem.count + parseInt(vm.quantity, 10))) &&
842
- `${variant.show_understocking}` !== 'false'
843
- ) {
844
- return html` <button class="no-stock w-100" disabled>${Language.text('out_of_stock')}</button>`;
1131
+ content_ids: [variant.sku || `${prod.id}-${vm.specs.join('-')}`],
1132
+ content_name: prod.title,
1133
+ content_type: "product"
845
1134
  }
1135
+ })
1136
+ })}"
1137
+ >
1138
+ ${Language.text('buy_it_now')}
1139
+ </button>`)
1140
+ return viewMap.join('')
1141
+ },
1142
+ divCreate: {
1143
+ style: `${document.body.clientWidth > 800 ? `width:100%;height: 38px;` : `width:100%;z-index:10;`}gap:6px;`,
1144
+ class: `d-flex ${(document.body.clientWidth < 800) ? `position-fixed bottom-0 start-0 px-2 py-2 pb-4 bg-white shadow border-top` : `mt-3`}`,
1145
+ },
1146
+ }),
1147
+ (aboutVoucherHTML) ? `
1148
+ <div class="w-100 border-top" style="margin-top:${this.isPhone() ? 10 : 20}px;margin-bottom:${this.isPhone() ? 10 : 10}px;"></div>
1149
+ <div class="w-100">
1150
+ <h1 style="color: ${titleFontColor};font-size:16px;">本商品適用活動</h1>
1151
+ ${aboutVoucherHTML}
1152
+ </div>` : ``,
1153
+ ].join('')}
1154
+ </div>`
1155
+ ]
1156
+ return html`
1157
+ <div class="d-flex flex-column flex-lg-row w-100" style="gap:${this.isPhone() ? 20 : 40}px">
1158
+ ${viewMap.join(``)}
1159
+ </div>
1160
+ `;
1161
+ }
846
1162
 
847
- //當是贈品一個按鈕就好
848
- if(obj.is_gift ){
849
- return `<button
1163
+ static addProductPopUp(obj: {
1164
+ gvc: GVC;
1165
+ titleFontColor: string;
1166
+ prod: Product;
1167
+ vm: {
1168
+ data?: Product_l;
1169
+ specs: string[];
1170
+ quantity: string;
1171
+ wishStatus: boolean;
1172
+ swiper?: any;
1173
+ };
1174
+ with_qty?: boolean;
1175
+ callback?: () => void;
1176
+ preview?: boolean;
1177
+ only_select?: (data: any) => void;
1178
+ is_gift?: boolean;
1179
+ }, type: 'addCart' | 'buyNow', close_event: () => void) {
1180
+ const gvc = obj.gvc;
1181
+ const glitter = gvc.glitter;
1182
+ const titleFontColor = obj.titleFontColor;
1183
+ const prod = obj.prod;
1184
+ const vm = obj.vm;
1185
+ const ids = {
1186
+ price: glitter.getUUID(),
1187
+ wishStatus: glitter.getUUID(),
1188
+ addCartButton: glitter.getUUID(),
1189
+ stock_count: glitter.getUUID(),
1190
+ qty_count: glitter.getUUID(),
1191
+ };
1192
+ obj.gvc.addStyle(`
1193
+ .insignia {
1194
+ border-radius: 0.5rem;
1195
+ padding: 6px 8px;
1196
+ font-size: 0.875rem;
1197
+ display: inline-block;
1198
+ font-weight: 500;
1199
+ line-height: 1.5;
1200
+ text-align: center;
1201
+ white-space: normal;
1202
+ vertical-align: baseline;
1203
+ }
1204
+
1205
+ .insignia-voucher {
1206
+ display: flex;
1207
+ height: 22px;
1208
+ padding: 4px 6px;
1209
+ justify-content: center;
1210
+ align-items: center;
1211
+ gap: 4px;
1212
+ border-radius: 2px;
1213
+ font-size: 14px;
1214
+ }
1215
+ `);
1216
+ let changePage = (index: string, type: 'page' | 'home', subData: any) => {
1217
+ };
1218
+ gvc.glitter.getModule(new URL('./official_event/page/change-page.js', gvc.glitter.root_path).href, (cl) => {
1219
+ changePage = cl.changePage;
1220
+ });
1221
+ const language_data = (prod as any).language_data && (prod as any).language_data[Language.getLanguage()];
1222
+ ProductInitial.initial(prod);
1223
+
1224
+ const solidButtonBgr = glitter.share.globalValue['theme_color.0.solid-button-bg'] ?? '#dddddd';
1225
+ const solidButtonText = glitter.share.globalValue['theme_color.0.solid-button-text'] ?? '#000000';
1226
+ obj.gvc.glitter.innerDialog((gvc: GVC) => {
1227
+ const variant = prod.variants.find((item) => {
1228
+ return PdClass.ObjCompare(item.spec, vm.specs, true);
1229
+ });
1230
+ return `<div class="w-100 h-100 position-absolute bottom-0 left-0" onclick="${gvc.event(() => {
1231
+ gvc.closeDialog()
1232
+ })}"></div>
1233
+ <div class="rounded-top bg-white w-100 position-absolute bottom-0 left-0 px-3 pt-3" style="padding-bottom:100px;">
1234
+
1235
+ <div class="d-flex align-items-center mb-3 " style="margin-top:20px;gap:10px;">
1236
+ <div style="width: 88px;height: 88px;border-radius: 10px;background: 50%/cover url('${variant?.preview_image}');"></div>
1237
+ <div class="d-flex flex-column" style="gap:5px;">
1238
+ <div class="fw-bold" style="color: ${titleFontColor};font-size:14px;">${prod.title}</div>
1239
+ ${gvc.bindView({
1240
+ bind: ids.price,
1241
+ view: () => {
1242
+ const v = prod.variants.find((variant) => PdClass.ObjCompare(variant.spec, vm.specs, true));
1243
+
1244
+ if (!v) return '錯誤';
1245
+
1246
+ const comparePrice = parseInt(`${v.compare_price ?? 0}`, 10);
1247
+ const originPrice = parseInt(`${v.origin_price ?? 0}`, 10);
1248
+ const lineThroughPrice = comparePrice > originPrice ? originPrice : comparePrice;
1249
+
1250
+ return html`
1251
+ <div class="d-flex align-items-end" style=" gap: 8px;">
1252
+ <div style="color: ${(lineThroughPrice > 0 && lineThroughPrice > v.sale_price) ? '#ff5353':titleFontColor}; font-size: 16px; font-weight: 700; ">
1253
+ ${Currency.convertCurrencyText(v.sale_price)}
1254
+ </div>
1255
+ ${lineThroughPrice > 0 && lineThroughPrice > v.sale_price
1256
+ ? html`
1257
+ <div style="color: #8D8D8D; font-size: 14px; text-decoration: line-through;">
1258
+ ${Currency.convertCurrencyText(lineThroughPrice)}
1259
+ </div> `
1260
+ : ''}
1261
+ </div>
1262
+ `;
1263
+ },
1264
+ divCreate: {
1265
+ style: ''
1266
+ }
1267
+ })}
1268
+ </div>
1269
+ </div>
1270
+ ${[
1271
+ //規格選擇
1272
+ prod.specs.map((spec, index1) => {
1273
+ return html`
1274
+ <div>
1275
+ <h5 class="mb-2" style="color: ${titleFontColor};font-size:14px;">
1276
+ ${(spec.language_title && (spec.language_title as any)[Language.getLanguage()]) || spec.title}
1277
+ </h5>
1278
+ <div class="d-flex gap-2 flex-wrap">
1279
+ ${gvc.map(
1280
+ spec.option.map((opt: any) => {
1281
+ return html`
1282
+ <div
1283
+ gvc-option="spec-option-${index1}"
1284
+ class="spec-option ${vm.specs[index1] === opt.title ? 'selected-option' : ''}"
1285
+ onclick="${gvc.event((e) => {
1286
+ const allOptions = document.querySelectorAll(`div[gvc-option=spec-option-${index1}]`);
1287
+ allOptions.forEach((option: any) => {
1288
+ option.classList.remove('selected-option');
1289
+ });
1290
+ e.classList.toggle('selected-option');
1291
+ vm.specs[index1] = opt.title;
1292
+ const v = prod.variants.find((variant) => {
1293
+ return PdClass.ObjCompare(variant.spec, vm.specs, true);
1294
+ });
1295
+ if (v?.preview_image) {
1296
+ let index = prod.preview_image.findIndex((src) => {
1297
+ return src == v.preview_image;
1298
+ });
1299
+ if (index >= 0) {
1300
+ vm.swiper.slideTo(index);
1301
+ }
1302
+ }
1303
+ gvc.recreateView();
1304
+ })}"
1305
+ >
1306
+ <span style="font-size: 15px; font-weight: 500; letter-spacing: 1.76px;"
1307
+ >${(opt.language_title && (opt.language_title as any)[Language.getLanguage()]) || opt.title}</span
1308
+ >
1309
+ </div>`;
1310
+ })
1311
+ )}
1312
+ </div>
1313
+ </div>
1314
+ <div class="mt-3"></div>`;
1315
+ }).join(''),
1316
+
1317
+ //庫存顯示
1318
+ gvc.bindView(() => {
1319
+ return {
1320
+ bind: ids.stock_count,
1321
+ view: () => {
1322
+ return [
1323
+ (() => {
1324
+ const variant = prod.variants.find((item) => PdClass.ObjCompare(item.spec, vm.specs, true));
1325
+
1326
+ if (variant && variant.show_understocking !== 'false') {
1327
+ const stockClass = `${variant.stock}` === '0' ? 'text-danger' : '';
1328
+ return html`
1329
+ <div class="${stockClass} fw-500 mt-2"
1330
+ style="font-size: 14px; color: ${titleFontColor};">
1331
+ ${Language.text('can_buy')}:${variant.stock}
1332
+ </div>
1333
+ `;
1334
+ }
1335
+
1336
+ return '';
1337
+ })(),
1338
+ ].join('');
1339
+ },
1340
+ divCreate: {},
1341
+ };
1342
+ }),
1343
+ //購物車按鈕
1344
+ gvc.bindView({
1345
+ bind: ids.addCartButton,
1346
+ view: () => {
1347
+ const variant = prod.variants.find((item) => {
1348
+ return PdClass.ObjCompare(item.spec, vm.specs, true);
1349
+ });
1350
+ const cartItem = new ApiCart().cart.line_items.find((item) => {
1351
+ return PdClass.ObjCompare(item.spec, vm.specs, true);
1352
+ });
1353
+ if (!variant) {
1354
+ return html`
1355
+ <button class="no-stock w-100" disabled>發生錯誤</button>`;
1356
+ }
1357
+
1358
+ Ad.gtagEvent('view_item', {
1359
+ currency: 'TWD',
1360
+ value: variant.sale_price,
1361
+ items: [
1362
+ {
1363
+ item_id: prod.id,
1364
+ item_name: prod.title,
1365
+ item_variant: variant.spec.length > 0 ? variant.spec.join('-') : '',
1366
+ price: variant.sale_price,
1367
+ },
1368
+ ],
1369
+ });
1370
+ Ad.fbqEvent('ViewContent', {
1371
+ content_ids: [variant.sku || prod.id],
1372
+ content_type: 'product',
1373
+ value: variant.sale_price,
1374
+ currency: 'TWD',
1375
+ });
1376
+
1377
+
1378
+ //當是贈品一個按鈕就好
1379
+ if (obj.is_gift) {
1380
+ return `<button
850
1381
  class="add-cart-imd-btn fw-bold h-100"
851
1382
  style="width:calc(100% - 10px);cursor: pointer;"
852
1383
  onclick="${gvc.event(() => {
853
- if (obj.only_select) {
854
- obj.only_select({ id: prod.id, specs: vm.specs });
855
- } else {
856
- new ApiCart(ApiCart.checkoutCart).addToCart(`${prod.id}`, vm.specs, vm.quantity);
857
- gvc.glitter.recreateView('.js-cart-count');
858
- gvc.glitter.recreateView('.shopping-cart');
859
- PdClass.jumpAlert({
860
- gvc,
861
- text: html`${Language.text('add_to_cart_success')}`,
862
- justify: 'top',
863
- align: 'center',
864
- width: 300,
865
- });
866
- ApiTrack.track({
867
- event_name: "AddToCart",
868
- custom_data: {
869
- currency: "TWD",
870
- value: variant.sale_price,
871
- content_ids: [variant.sku || `${prod.id}-${vm.specs.join('-')}`],
872
- content_name: prod.title,
873
- content_type: "product"
874
- }
875
- })
876
- obj.callback && obj.callback();
1384
+ if (obj.only_select) {
1385
+ obj.only_select({id: prod.id, specs: vm.specs});
1386
+ } else {
1387
+ new ApiCart(ApiCart.checkoutCart).addToCart(`${prod.id}`, vm.specs, vm.quantity);
1388
+ gvc.glitter.recreateView('.js-cart-count');
1389
+ gvc.glitter.recreateView('.shopping-cart');
1390
+ PdClass.jumpAlert({
1391
+ gvc,
1392
+ text: html`${Language.text('add_to_cart_success')}`,
1393
+ justify: 'top',
1394
+ align: 'center',
1395
+ width: 300,
1396
+ });
1397
+ ApiTrack.track({
1398
+ event_name: "AddToCart",
1399
+ custom_data: {
1400
+ currency: "TWD",
1401
+ value: variant.sale_price,
1402
+ content_ids: [variant.sku || `${prod.id}-${vm.specs.join('-')}`],
1403
+ content_name: prod.title,
1404
+ content_type: "product"
877
1405
  }
878
- })}"
1406
+ })
1407
+ obj.callback && obj.callback();
1408
+ }
1409
+ })}"
879
1410
  >
880
1411
  ${Language.text('confirm_select')}
881
1412
  </button>`
1413
+ }
1414
+ let viewMap = []
1415
+
1416
+ viewMap.push(gvc.bindView(() => {
1417
+ return {
1418
+ bind: ids.qty_count,
1419
+ view: () => {
1420
+ vm.quantity = vm.quantity || '1'
1421
+ const supportMinus = parseInt(vm.quantity, 10) > 1;
1422
+
1423
+ function getSupportAds() {
1424
+ return !((variant!!.stock < (parseInt(vm.quantity, 10) + 1)) &&
1425
+ `${variant!!.show_understocking}` !== 'false')
1426
+ }
1427
+
1428
+ function hasStock() {
1429
+ return !(((variant!!.stock < (parseInt(vm.quantity, 10))) || (variant!!.stock < 1)) &&
1430
+ `${variant!!.show_understocking}` !== 'false')
1431
+ }
1432
+
1433
+ let supportAdds = getSupportAds()
1434
+ if (
1435
+ !hasStock()
1436
+ ) {
1437
+ vm.quantity = `${variant.stock}`;
1438
+ }
1439
+
1440
+ if (!hasStock()) {
1441
+ return ``
1442
+ }
1443
+
1444
+ return html`
1445
+ <div class="d-flex align-items-center" style="color:${titleFontColor};">
1446
+ <div class="d-flex align-items-center justify-content-center"
1447
+ style="width:44px;height: 44px;cursor: pointer;" onclick="${
1448
+ gvc.event(() => {
1449
+ if (supportMinus) {
1450
+ vm.quantity = `${parseInt(vm.quantity, 10) - 1}`;
1451
+ gvc.recreateView()
1452
+ }
1453
+ })
1454
+ }">
1455
+ <i class="fa-solid fa-minus"
1456
+ style="color:${(supportMinus) ? `#ff5353` : `#999`};"></i>
1457
+ </div>
1458
+ <select
1459
+ class="form-select custom-select mx-0 p-0 "
1460
+ style="border-radius: 5px; color: #575757; width: 100px;height:38px;background-image:none;${parseInt(vm.quantity,10) < 10 ? `text-indent: 43%;`:`text-indent: 40%;`}"
1461
+ onchange="${gvc.event((e) => {
1462
+ vm.quantity = e.value;
1463
+ gvc.notifyDataChange([ids.addCartButton, ids.stock_count]);
1464
+ })}"
1465
+ >
1466
+ ${gvc.map(
1467
+ [
1468
+ ...new Array(
1469
+ (() => {
1470
+ const variant = prod.variants.find((item) => PdClass.ObjCompare(item.spec, vm.specs, true));
1471
+ if (!variant || variant.show_understocking === 'false') {
1472
+ return 50;
1473
+ }
1474
+ return variant.stock < 50 ? variant.stock : 50;
1475
+ })()
1476
+ ),
1477
+ ].map((item, index) => {
1478
+ return html`
1479
+ <option value="${index + 1}"
1480
+ ${(`${vm.quantity}` === `${index + 1}`) ? `selected` : ``}>
1481
+ ${index + 1}
1482
+ </option>`;
1483
+ })
1484
+ )}
1485
+ </select>
1486
+ <div class="d-flex align-items-center justify-content-center"
1487
+ style="width:44px;height: 44px;cursor: pointer;" onclick="${
1488
+ gvc.event(() => {
1489
+ if (supportAdds) {
1490
+ vm.quantity = `${parseInt(vm.quantity, 10) + 1}`;
1491
+ gvc.recreateView()
1492
+ }
1493
+ })
1494
+ }">
1495
+ <i class="fa-solid fa-plus"
1496
+ style="color:${(supportAdds) ? `#ff5353` : `#999`};"></i>
1497
+ </div>
1498
+ </div>
1499
+ `;
1500
+ },
1501
+ divCreate: {
1502
+ class: `flex-column gap-2 d-flex `,
1503
+ },
1504
+ };
1505
+ }),)
1506
+
1507
+ if (
1508
+ ((variant.stock < 1) &&
1509
+ `${variant.show_understocking}` !== 'false')
1510
+ ) {
1511
+ viewMap.push(`
1512
+ <button class="no-stock w-100 " style="height:44px;" disabled>${Language.text('out_of_stock')}
1513
+ </button>`);
1514
+ } else if (type === 'addCart') {
1515
+ viewMap.push(`<button
1516
+ class="add-cart-imd-btn fw-bold fs-sm"
1517
+ style=" flex: 1;height:44px;"
1518
+ onclick="${gvc.event(() => {
1519
+ if (obj.only_select) {
1520
+ obj.only_select({id: prod.id, specs: vm.specs});
1521
+ } else {
1522
+ new ApiCart().addToCart(`${prod.id}`, vm.specs, vm.quantity);
1523
+ gvc.glitter.recreateView('.js-cart-count');
1524
+ gvc.glitter.recreateView('.shopping-cart');
1525
+ PdClass.jumpAlert({
1526
+ gvc,
1527
+ text: html`${Language.text('add_to_cart_success')}`,
1528
+ justify: 'top',
1529
+ align: 'center',
1530
+ width: 300,
1531
+ });
1532
+ ApiTrack.track({
1533
+ event_name: "AddToCart",
1534
+ custom_data: {
1535
+ currency: "TWD",
1536
+ value: variant.sale_price,
1537
+ content_ids: [variant.sku || `${prod.id}-${vm.specs.join('-')}`],
1538
+ content_name: prod.title,
1539
+ content_type: "product"
1540
+ }
1541
+ })
1542
+ obj.callback && obj.callback();
882
1543
  }
883
- return html`
884
- <div
885
- class="add-cart-imd-btn fw-bold h-100 "
886
- style="width:calc(50% - 5px);cursor: pointer;"
887
- onclick="${gvc.event(() => {
888
- const buy_it = new ApiCart(ApiCart.buyItNow);
889
- buy_it.clearCart();
890
- buy_it.addToCart(`${prod.id}`, vm.specs, vm.quantity);
891
- ApiCart.toCheckOutPage(ApiCart.buyItNow);
892
- gvc.closeDialog();
893
- ApiTrack.track({
894
- event_name: "AddToCart",
895
- custom_data: {
896
- currency: "TWD",
897
- value: variant.sale_price,
898
- content_ids: [variant.sku || `${prod.id}-${vm.specs.join('-')}`],
899
- content_name: prod.title,
900
- content_type: "product"
901
- }
902
- })
903
- })}"
904
- >
905
- ${Language.text('buy_it_now')}
906
- </div>
907
- <div class="flex-fill"></div>
908
- <button
909
- class="add-cart-btn fw-bold "
910
- style="width:calc(50% - 5px);"
911
- onclick="${gvc.event(() => {
912
- if (obj.only_select) {
913
- obj.only_select({ id: prod.id, specs: vm.specs });
914
- } else {
915
- new ApiCart().addToCart(`${prod.id}`, vm.specs, vm.quantity);
916
- gvc.glitter.recreateView('.js-cart-count');
917
- gvc.glitter.recreateView('.shopping-cart');
918
- PdClass.jumpAlert({
919
- gvc,
920
- text: html`${Language.text('add_to_cart_success')}`,
921
- justify: 'top',
922
- align: 'center',
923
- width: 300,
924
- });
925
- ApiTrack.track({
926
- event_name: "AddToCart",
927
- custom_data: {
928
- currency: "TWD",
929
- value: variant.sale_price,
930
- content_ids: [variant.sku || `${prod.id}-${vm.specs.join('-')}`],
931
- content_name: prod.title,
932
- content_type: "product"
933
- }
934
- })
935
- obj.callback && obj.callback();
936
- }
937
- })}"
1544
+ gvc.closeDialog()
1545
+ })}"
938
1546
  >
939
1547
  ${Language.text('add_to_cart')}
940
- </button>
941
- `;
942
- },
943
- divCreate: {
944
- style: `height: 38px;width:${document.body.clientWidth > 800 ? `400px` : `100%`};`,
945
- class: `d-flex mt-3`,
946
- },
947
- }),
948
- ].join('')}
949
- <div class="d-flex py-3" style="color: #554233">
950
- <span
951
- class="d-flex nav-link p-0 add-wish-container"
952
- onclick="${gvc.event(() => {
953
- if (CheckInput.isEmpty(GlobalUser.token)) {
954
- changePage('login', 'page', {});
955
- return;
956
- }
957
-
958
- ApiShop.getWishList().then((getRes) => {
959
- if (getRes.result && getRes.response.data) {
960
- if (getRes.response.data.find((item: Product_l) => `${item.id}` === `${prod.id}`)) {
961
- ApiShop.deleteWishList(`${prod.id}`).then(async () => {
962
- PdClass.jumpAlert({
963
- gvc,
964
- text: '刪除成功',
965
- justify: 'top',
966
- align: 'center',
967
- });
968
- vm.wishStatus = false;
969
- gvc.notifyDataChange(ids.wishStatus);
970
- });
971
- } else {
972
- const variant = prod.variants.find((item) => PdClass.ObjCompare(item.spec, vm.specs, true)) ?? prod.variants[0];
973
- Ad.gtagEvent('add_to_wishlist', {
974
- currency: 'TWD',
975
- value: variant.sale_price,
976
- items: [
977
- {
978
- item_id: prod.id,
979
- item_name: prod.title,
980
- item_variant: variant.spec.length > 0 ? variant.spec.join('-') : '',
981
- price: variant.sale_price,
982
- },
983
- ],
984
- });
985
- Ad.fbqEvent('AddToWishlist', {
986
- content_ids: [prod.id],
987
- contents: [
988
- {
989
- id: prod.id,
990
- quantity: 1,
991
- },
992
- ],
993
- value: variant.sale_price,
994
- currency: 'TWD',
995
- });
996
-
997
- ApiShop.postWishList(`${prod.id}`).then(async () => {
998
- PdClass.jumpAlert({
999
- gvc,
1000
- text: '新增成功',
1001
- justify: 'top',
1002
- align: 'center',
1003
- });
1004
- vm.wishStatus = true;
1005
- gvc.notifyDataChange(ids.wishStatus);
1006
- });
1007
- }
1548
+ </button>`)
1549
+ } else if (type === 'buyNow') {
1550
+ viewMap.push(`<button
1551
+ class="add-cart-imd-btn fw-bold fs-sm"
1552
+ style="cursor: pointer; flex: 1;height:44px;"
1553
+ onclick="${gvc.event(() => {
1554
+ const buy_it = new ApiCart(ApiCart.buyItNow);
1555
+ buy_it.clearCart();
1556
+ buy_it.addToCart(`${prod.id}`, vm.specs, vm.quantity);
1557
+ gvc.glitter.closeDiaLog()
1558
+ setTimeout(() => {
1559
+ ApiCart.toCheckOutPage(ApiCart.buyItNow);
1560
+ }, 100)
1561
+ ApiTrack.track({
1562
+ event_name: "AddToCart",
1563
+ custom_data: {
1564
+ currency: "TWD",
1565
+ value: variant.sale_price,
1566
+ content_ids: [variant.sku || `${prod.id}-${vm.specs.join('-')}`],
1567
+ content_name: prod.title,
1568
+ content_type: "product"
1008
1569
  }
1009
- });
1570
+ })
1010
1571
  })}"
1011
- >
1012
- ${gvc.bindView({
1013
- bind: ids.wishStatus,
1014
- view: () => {
1015
- if ((window as any).store_info.wishlist == false) {
1016
- return ``;
1017
- } else {
1018
- if (vm.wishStatus) {
1019
- return html` <i class="fa-solid fa-heart"></i>
1020
- <span>${Language.text('remove_to_wishlist')}</span>`;
1021
- } else {
1022
- return html` <i class="fa-regular fa-heart"></i>
1023
- <span>${Language.text('add_to_wishlist')}</span>`;
1024
- }
1025
- }
1026
- },
1027
- })}
1028
- </span>
1029
- </div>
1030
- </div>
1031
- </div>
1032
- `;
1572
+ >
1573
+ ${Language.text('buy_it_now')}
1574
+ </button>`)
1575
+ }
1576
+
1577
+
1578
+ return viewMap.join('')
1579
+ },
1580
+ divCreate: {
1581
+ style: `${document.body.clientWidth > 800 ? `width:100%;height: 38px;` : `width:100%;z-index:10;`}gap:6px;`,
1582
+ class: `d-flex ${(document.body.clientWidth < 800) ? `position-fixed bottom-0 start-0 px-2 py-2 pb-4 bg-white shadow border-top` : `mt-3`} align-items-center`,
1583
+ },
1584
+ })
1585
+ ].join('')}
1586
+ <div class="position-absolute d-flex align-items-center justify-content-center " style="top:10px;right:10px;width:30px;height:30px;"
1587
+ onclick="${gvc.event(() => {
1588
+ gvc.closeDialog()
1589
+ })}">
1590
+ <i class="fa-solid fa-xmark text-black fs-5"></i>
1591
+ </div>
1592
+ </div>
1593
+ `
1594
+ }, 'addProductPopUp', {
1595
+ animation: Animation.popup,
1596
+ dismiss: () => {
1597
+ close_event()
1598
+ }
1599
+ })
1033
1600
  }
1034
1601
 
1035
1602
  static isPhone() {