ts-glitter 14.3.9 → 14.4.2

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 (51) hide show
  1. package/lowcode/Entry.js +1 -1
  2. package/lowcode/Entry.ts +1 -1
  3. package/lowcode/backend-manager/bg-product.js +22 -20
  4. package/lowcode/backend-manager/bg-product.ts +85 -73
  5. package/lowcode/backend-manager/bg-recommend.js +31 -28
  6. package/lowcode/backend-manager/bg-recommend.ts +31 -28
  7. package/lowcode/cms-plugin/ai-message.ts +2 -1
  8. package/lowcode/cms-plugin/filter-options.js +6 -4
  9. package/lowcode/cms-plugin/filter-options.ts +8 -6
  10. package/lowcode/cms-plugin/module/product-excel.js +35 -14
  11. package/lowcode/cms-plugin/module/product-excel.ts +40 -15
  12. package/lowcode/cms-plugin/shopping-discount-setting.js +1 -1
  13. package/lowcode/cms-plugin/shopping-discount-setting.ts +5 -2
  14. package/lowcode/cms-plugin/shopping-invoice-manager.js +0 -1
  15. package/lowcode/cms-plugin/shopping-invoice-manager.ts +0 -1
  16. package/lowcode/cms-plugin/shopping-product-setting.js +265 -160
  17. package/lowcode/cms-plugin/shopping-product-setting.ts +295 -297
  18. package/lowcode/cms-plugin/shopping-product-stock.js +12 -16
  19. package/lowcode/cms-plugin/shopping-product-stock.ts +29 -35
  20. package/lowcode/glitter-base/route/shopping.js +25 -4
  21. package/lowcode/glitter-base/route/shopping.ts +52 -44
  22. package/lowcode/glitterBundle/html-component/widget.js +0 -3
  23. package/lowcode/glitterBundle/html-component/widget.ts +3 -3
  24. package/lowcode/public-components/blogs/blogs-01.js +138 -1
  25. package/lowcode/public-components/blogs/blogs-01.ts +142 -2
  26. package/lowcode/public-components/checkout/index.js +3 -2
  27. package/lowcode/public-components/checkout/index.ts +16 -3
  28. package/lowcode/public-components/product/product-detail.js +1 -0
  29. package/lowcode/public-components/product/product-detail.ts +1 -0
  30. package/lowcode/public-components/product/product-list.js +1 -0
  31. package/lowcode/public-components/product/product-list.ts +1 -0
  32. package/lowcode/public-components/user-manager/um-class.js +2 -2
  33. package/lowcode/public-components/user-manager/um-class.ts +2 -2
  34. package/lowcode/public-components/user-manager/um-rebate.js +18 -18
  35. package/lowcode/public-components/user-manager/um-rebate.ts +39 -38
  36. package/package.json +1 -1
  37. package/src/api-public/controllers/shop.js +18 -0
  38. package/src/api-public/controllers/shop.js.map +1 -1
  39. package/src/api-public/controllers/shop.ts +17 -1
  40. package/src/api-public/services/financial-service.d.ts +16 -0
  41. package/src/api-public/services/financial-service.js +70 -3
  42. package/src/api-public/services/financial-service.js.map +1 -1
  43. package/src/api-public/services/financial-service.ts +89 -4
  44. package/src/api-public/services/recommend.js +14 -0
  45. package/src/api-public/services/recommend.js.map +1 -1
  46. package/src/api-public/services/recommend.ts +15 -0
  47. package/src/api-public/services/shopping.d.ts +35 -0
  48. package/src/api-public/services/shopping.js +97 -9
  49. package/src/api-public/services/shopping.js.map +1 -1
  50. package/src/api-public/services/shopping.ts +136 -20
  51. package/src/services/template.js.map +1 -1
@@ -12,7 +12,7 @@ import { Tool } from '../modules/tool.js';
12
12
  import { CheckInput } from '../modules/checkInput.js';
13
13
  import { imageLibrary } from '../modules/image-library.js';
14
14
  import { ProductAi } from './ai-generator/product-ai.js';
15
- import { ProductExcel, Variant as variant, RowInitData } from './module/product-excel.js';
15
+ import { ProductExcel, Variant, RowInitData } from './module/product-excel.js';
16
16
 
17
17
  export class ShoppingProductSetting {
18
18
  public static main(gvc: GVC, type: 'product' | 'addProduct' | 'giveaway' | 'hidden' = 'product') {
@@ -120,9 +120,7 @@ export class ShoppingProductSetting {
120
120
  product_type: type,
121
121
  });
122
122
  case 'list':
123
- (window.parent as any).glitter.share.checkData = () => {
124
- return true;
125
- };
123
+ (window.parent as any).glitter.share.checkData = () => true;
126
124
  vm.tableId = gvc.glitter.getUUID();
127
125
  vm.dataList = [];
128
126
  const vmlist = {
@@ -143,7 +141,10 @@ export class ShoppingProductSetting {
143
141
  type: 'multi_checkbox',
144
142
  name: '商品分類',
145
143
  data: vmlist.collections.map((item) => {
146
- return { key: `${item.key}`, name: item.value };
144
+ return {
145
+ key: `${item.key}`,
146
+ name: item.value,
147
+ };
147
148
  }),
148
149
  });
149
150
  }
@@ -348,13 +349,8 @@ export class ShoppingProductSetting {
348
349
  searchType: vm.queryType ?? '',
349
350
  orderBy: vm.orderString ?? '',
350
351
  status: (() => {
351
- if (vm.filter.status && vm.filter.status.length === 1) {
352
- switch (vm.filter.status[0]) {
353
- case 'active':
354
- return 'active';
355
- case 'draft':
356
- return 'draft';
357
- }
352
+ if (vm.filter.status && vm.filter.status.length > 0) {
353
+ return vm.filter.status.join(',');
358
354
  }
359
355
  return undefined;
360
356
  })(),
@@ -390,7 +386,19 @@ export class ShoppingProductSetting {
390
386
  const baseRowData = (index: number): RowInitData => ({
391
387
  id: index === 0 ? productData.content.id || '' : '',
392
388
  name: index === 0 ? productData.content.title || '未命名商品' : '',
393
- status: index === 0 ? (productData.content?.status === 'active' ? '啟用' : '草稿') : '',
389
+ status:
390
+ index === 0
391
+ ? (() => {
392
+ switch (productData.content?.status) {
393
+ case 'draft':
394
+ return '草稿';
395
+ case 'schedule':
396
+ return '期間限定';
397
+ default:
398
+ return '啟用';
399
+ }
400
+ })()
401
+ : '',
394
402
  category: index === 0 ? expo.checkString(productData.content.collection.join(' , ')) : '',
395
403
  productType:
396
404
  index === 0 ? expo.checkString(this.getProductTypeString(productData.content)) : '',
@@ -451,42 +459,6 @@ export class ShoppingProductSetting {
451
459
  return;
452
460
  })
453
461
  ),
454
- // BgWidget.grayButton(
455
- // "AI 生成",
456
- // gvc.event(() => {
457
- // vm.ai_initial={
458
- // title: '',
459
- // productType: {
460
- // product: true,
461
- // addProduct: false,
462
- // giveaway: false,
463
- // },
464
- // content: '',
465
- // visible: 'true',
466
- // status: 'active',
467
- // collection: [],
468
- // hideIndex: 'false',
469
- // preview_image: [],
470
- // specs: [],
471
- // variants: [],
472
- // seo: {
473
- // title: '',
474
- // content: '',
475
- // keywords: '',
476
- // domain: '',
477
- // },
478
- // relative_product: [],
479
- // template: '',
480
- // content_array: [],
481
- // content_json: [],
482
- // }
483
- // ProductAi.setProduct(gvc,vm.ai_initial,()=>{
484
- // vm.type='ai-initial'
485
- //
486
- // })
487
- // }),
488
- // { }
489
- // ),
490
462
  BgWidget.darkButton(
491
463
  '新增',
492
464
  gvc.event(() => {
@@ -579,13 +551,8 @@ export class ShoppingProductSetting {
579
551
  searchType: vm.queryType || undefined,
580
552
  orderBy: vm.orderString || undefined,
581
553
  status: (() => {
582
- if (vm.filter.status && vm.filter.status.length === 1) {
583
- switch (vm.filter.status[0]) {
584
- case 'active':
585
- return 'active';
586
- case 'draft':
587
- return 'draft';
588
- }
554
+ if (vm.filter.status && vm.filter.status.length > 0) {
555
+ return vm.filter.status.join(',');
589
556
  }
590
557
  return undefined;
591
558
  })(),
@@ -644,24 +611,29 @@ export class ShoppingProductSetting {
644
611
  return {
645
612
  bind: id,
646
613
  view: () => {
647
- BgWidget.switchTextButton(
648
- gvc,
649
- dd.content.status === 'active',
650
- { left: dd.content.status === 'active' ? '啟用' : '草稿' },
651
- (bool) => {
652
- dd.content.status = bool ? 'active' : 'draft';
653
- ApiPost.put({
654
- postData: dd.content,
655
- token: (window.parent as any).config.token,
656
- type: 'manager',
657
- }).then((res) => {
658
- res.result && gvc.notifyDataChange(id);
659
- });
660
- }
661
- );
662
- return dd.content.status === 'active'
663
- ? BgWidget.successInsignia('啟用')
664
- : BgWidget.secondaryInsignia('草稿');
614
+ // BgWidget.switchTextButton(
615
+ // gvc,
616
+ // dd.content.status === 'active',
617
+ // { left: dd.content.status === 'active' ? '啟用' : '草稿' },
618
+ // (bool) => {
619
+ // dd.content.status = bool ? 'active' : 'draft';
620
+ // ApiPost.put({
621
+ // postData: dd.content,
622
+ // token: (window.parent as any).config.token,
623
+ // type: 'manager',
624
+ // }).then((res) => {
625
+ // res.result && gvc.notifyDataChange(id);
626
+ // });
627
+ // }
628
+ // );
629
+ switch (dd.content.status) {
630
+ case 'draft':
631
+ return BgWidget.secondaryInsignia('草稿');
632
+ case 'schedule':
633
+ return BgWidget.notifyInsignia('期間限定');
634
+ default:
635
+ return BgWidget.successInsignia('啟用');
636
+ }
665
637
  },
666
638
  divCreate: {
667
639
  option: [
@@ -864,7 +836,7 @@ export class ShoppingProductSetting {
864
836
  }
865
837
  });
866
838
 
867
- function checkStore(next: () => void) {
839
+ function checkStore(next: () => void, cancel?: () => void) {
868
840
  const dialog = new ShareDialog(gvc.glitter);
869
841
  if (JSON.stringify(orignData) !== JSON.stringify(variant)) {
870
842
  dialog.checkYesOrNot({
@@ -873,6 +845,10 @@ export class ShoppingProductSetting {
873
845
  if (response) {
874
846
  (postMD.variants as any)[index] = variant;
875
847
  }
848
+ if (cancel) {
849
+ cancel();
850
+ return;
851
+ }
876
852
  obj && obj.goBackEvent ? obj.goBackEvent.save(postMD) : next();
877
853
  },
878
854
  });
@@ -901,7 +877,7 @@ export class ShoppingProductSetting {
901
877
  <div class="flex-fill"></div>
902
878
  </div>
903
879
  <div class="d-flex flex-column ${obj.single ? `flex-column-reverse` : `flex-sm-row mt-4`} w-100 p-0" style="gap: 24px;">
904
- <div class="leftBigArea d-flex flex-column flex-fill" style="gap: 24px;">
880
+ <div class="leftBigArea d-flex flex-column flex-fill" style="gap: 18px;">
905
881
  ${!obj.single
906
882
  ? BgWidget.mainCard(
907
883
  gvc.bindView(() => {
@@ -1105,7 +1081,6 @@ export class ShoppingProductSetting {
1105
1081
  .join('')}
1106
1082
  </div>
1107
1083
  </div>
1108
-
1109
1084
  <div style="font-weight: 700;">商品重量</div>
1110
1085
  <div class="w-100 row m-0" style="color:#393939;">
1111
1086
  <input
@@ -1297,13 +1272,16 @@ export class ShoppingProductSetting {
1297
1272
  e.style.background = '#FFFFFF';
1298
1273
  })}"
1299
1274
  onclick="${gvc.event(() => {
1300
- checkStore(() => {
1301
- postMD.variants.map((dd: any) => {
1302
- dd.editable = false;
1303
- });
1304
- data.editable = true;
1305
- obj.vm.type = 'editSpec';
1306
- });
1275
+ checkStore(
1276
+ () => {
1277
+ postMD.variants.map((dd: any) => {
1278
+ dd.editable = false;
1279
+ });
1280
+ data.editable = true;
1281
+ obj.vm.type = 'editSpec';
1282
+ },
1283
+ () => {}
1284
+ );
1307
1285
  })}"
1308
1286
  >
1309
1287
  ${BgWidget.validImageBox({
@@ -1331,7 +1309,10 @@ export class ShoppingProductSetting {
1331
1309
  </div>
1332
1310
  ${obj.single ? '' : BgWidget.mbContainer(240)}
1333
1311
  </div>
1334
- `
1312
+ `,
1313
+ {
1314
+ style: obj.vm.type === 'editSpec' ? '' : 'margin-top: 0 !important;',
1315
+ }
1335
1316
  )}
1336
1317
  <div class="update-bar-container ${obj.single ? `d-none` : ``}">
1337
1318
  ${BgWidget.cancel(
@@ -1348,53 +1329,7 @@ export class ShoppingProductSetting {
1348
1329
  )}
1349
1330
  ${BgWidget.save(
1350
1331
  obj.gvc.event(() => {
1351
- function checkEmpty(variant: any, alert: boolean = false) {
1352
- const checkList = ['sale_price'];
1353
- for (const checkItem of checkList) {
1354
- if (!variant[checkItem]) {
1355
- dialog.infoMessage({
1356
- text: '價格輸入錯誤',
1357
- });
1358
- return false;
1359
- }
1360
- }
1361
- if (variant.shipment_type == 'weight') {
1362
- if (!variant.weight) {
1363
- dialog.infoMessage({
1364
- text: '商品重量未填',
1365
- });
1366
- return false;
1367
- }
1368
- }
1369
- if (variant.shipment_type == 'volume') {
1370
- if (!variant.v_height || !variant.v_length || !variant.v_width) {
1371
- dialog.infoMessage({
1372
- text: '商品材積未填',
1373
- });
1374
- return false;
1375
- }
1376
- }
1377
-
1378
- return true;
1379
- }
1380
-
1381
- const dialog = new ShareDialog(gvc.glitter);
1382
1332
  let checkPass = true;
1383
- // postMD.variants.map((data: any, index: number) => {
1384
- // if (data.editable) {
1385
- // postMD.variants[index] = variant;
1386
- // if (!checkEmpty(data, true)) {
1387
- // checkPass = false;
1388
- // }
1389
- // } else {
1390
- // if (!checkEmpty(data)) {
1391
- // checkPass = false;
1392
- // dialog.infoMessage({
1393
- // text: `規格 ${data.spec.join('')} 的欄位輸入錯誤`,
1394
- // });
1395
- // }
1396
- // }
1397
- // });
1398
1333
  if (checkPass) {
1399
1334
  postMD.variants[index] = variant;
1400
1335
  if (obj && obj.goBackEvent) {
@@ -1409,6 +1344,18 @@ export class ShoppingProductSetting {
1409
1344
  </div>`;
1410
1345
  }
1411
1346
 
1347
+ static getDateTime = (n = 0) => {
1348
+ const now = new Date();
1349
+ now.setDate(now.getDate() + n);
1350
+ const year = now.getFullYear();
1351
+ const month = (now.getMonth() + 1).toString().padStart(2, '0');
1352
+ const day = now.getDate().toString().padStart(2, '0');
1353
+ const hours = now.getHours().toString().padStart(2, '0');
1354
+ const dateStr = `${year}-${month}-${day}`;
1355
+ const timeStr = `${hours}:00`;
1356
+ return { date: dateStr, time: timeStr };
1357
+ };
1358
+
1412
1359
  public static async editProduct(obj: { vm: any; gvc: GVC; type?: 'add' | 'replace'; defData?: any; initial_data?: any; product_type?: 'product' | 'addProduct' | 'giveaway' | 'hidden' }) {
1413
1360
  let postMD: {
1414
1361
  shipment_type?: string;
@@ -1426,9 +1373,9 @@ export class ShoppingProductSetting {
1426
1373
  relative_product: string[];
1427
1374
  hideIndex: string;
1428
1375
  collection: string[];
1429
- status: 'active' | 'draft';
1376
+ status: 'active' | 'draft' | 'schedule';
1430
1377
  specs: { title: string; option: any }[];
1431
- variants: variant[];
1378
+ variants: Variant[];
1432
1379
  seo: {
1433
1380
  domain: string;
1434
1381
  title: string;
@@ -1441,6 +1388,12 @@ export class ShoppingProductSetting {
1441
1388
  id: string;
1442
1389
  list: { key: string; value: string }[];
1443
1390
  }[];
1391
+ active_schedule: {
1392
+ startDate: string;
1393
+ startTime: string;
1394
+ endDate?: string;
1395
+ endTime?: string;
1396
+ };
1444
1397
  } = obj.initial_data || {
1445
1398
  title: '',
1446
1399
  ai_description: '',
@@ -1467,6 +1420,12 @@ export class ShoppingProductSetting {
1467
1420
  template: '',
1468
1421
  content_array: [],
1469
1422
  content_json: [],
1423
+ active_schedule: {
1424
+ startDate: this.getDateTime().date,
1425
+ startTime: this.getDateTime().time,
1426
+ endDate: this.getDateTime(7).date,
1427
+ endTime: this.getDateTime(7).time,
1428
+ },
1470
1429
  };
1471
1430
  function setProductType() {
1472
1431
  switch (obj.product_type) {
@@ -1492,33 +1451,29 @@ export class ShoppingProductSetting {
1492
1451
  postMD.content_array = postMD.content_array ?? [];
1493
1452
  postMD.content_json = postMD.content_json ?? [];
1494
1453
  if (obj.type === 'replace') {
1495
- postMD = obj.defData;
1454
+ postMD = {
1455
+ ...postMD,
1456
+ ...obj.defData,
1457
+ };
1496
1458
  } else {
1497
1459
  obj.vm.replaceData = postMD;
1498
1460
  }
1499
1461
  const origin_data = JSON.stringify(postMD);
1500
- (window.parent as any).glitter.share.checkData = () => {
1501
- return origin_data === JSON.stringify(postMD);
1502
- };
1462
+ (window.parent as any).glitter.share.checkData = () => origin_data === JSON.stringify(postMD);
1503
1463
  const html = String.raw;
1504
1464
  const gvc = obj.gvc;
1505
- const seoID = gvc.glitter.getUUID();
1506
1465
  const variantsViewID = gvc.glitter.getUUID();
1507
- let createPage: any = {
1508
- page: 'add',
1509
- };
1466
+ const saasConfig: { config: any; api: any } = (window.parent as any).saasConfig;
1510
1467
  let selectFunRow = false;
1511
-
1512
- const saasConfig: {
1513
- config: any;
1514
- api: any;
1515
- } = (window.parent as any).saasConfig;
1516
1468
  let shipment_config: any = await saasConfig.api.getPrivateConfig(saasConfig.config.appName, `glitter_shipment`);
1517
1469
  if (shipment_config.response.result[0]) {
1518
1470
  shipment_config = shipment_config.response.result[0].value || {};
1519
1471
  } else {
1520
1472
  shipment_config = {};
1521
1473
  }
1474
+ let createPage: any = {
1475
+ page: 'add',
1476
+ };
1522
1477
 
1523
1478
  function updateVariants() {
1524
1479
  const remove_indexs: number[] = [];
@@ -1651,6 +1606,8 @@ export class ShoppingProductSetting {
1651
1606
  preview_image: '',
1652
1607
  });
1653
1608
  }
1609
+
1610
+ obj.vm.replaceData = postMD;
1654
1611
  obj.gvc.notifyDataChange(variantsViewID);
1655
1612
  }
1656
1613
 
@@ -1687,11 +1644,11 @@ export class ShoppingProductSetting {
1687
1644
  id: gvc.glitter.getUUID(),
1688
1645
  };
1689
1646
 
1690
- updateVariants();
1691
1647
  return gvc.bindView(() => {
1692
1648
  return {
1693
1649
  bind: vm.id,
1694
1650
  view: () => {
1651
+ updateVariants();
1695
1652
  return [
1696
1653
  BgWidget.container(
1697
1654
  html`
@@ -1742,7 +1699,10 @@ export class ShoppingProductSetting {
1742
1699
  }).then((data) => {
1743
1700
  dialog.dataLoading({ visible: false });
1744
1701
  if (data.result && data.response.data && data.response.data.content) {
1745
- postMD = data.response.data.content;
1702
+ postMD = {
1703
+ ...postMD,
1704
+ ...data.response.data.content,
1705
+ };
1746
1706
  postMD.id = undefined;
1747
1707
  setProductType();
1748
1708
  gvc.notifyDataChange(vm.id);
@@ -1763,15 +1723,19 @@ export class ShoppingProductSetting {
1763
1723
  }),
1764
1724
  {}
1765
1725
  ),
1766
- BgWidget.grayButton(
1767
- document.body.clientWidth > 768 ? '預覽商品' : '預覽',
1768
- gvc.event(() => {
1769
- const href = `https://${(window.parent as any).glitter.share.editorViewModel.domain}/products/${postMD.seo.domain}`;
1770
- (window.parent as any).glitter.openNewTab(href);
1771
- }),
1772
- { icon: document.body.clientWidth > 768 ? 'fa-regular fa-eye' : undefined }
1773
- ),
1774
- ].join(html`<div class="mx-1"></div>`)}
1726
+ postMD.id
1727
+ ? BgWidget.grayButton(
1728
+ document.body.clientWidth > 768 ? '預覽商品' : '預覽',
1729
+ gvc.event(() => {
1730
+ const href = `https://${(window.parent as any).glitter.share.editorViewModel.domain}/products/${postMD.seo.domain}`;
1731
+ (window.parent as any).glitter.openNewTab(href);
1732
+ }),
1733
+ { icon: document.body.clientWidth > 768 ? 'fa-regular fa-eye' : undefined }
1734
+ )
1735
+ : '',
1736
+ ]
1737
+ .filter((str) => str.length > 0)
1738
+ .join(html`<div class="mx-1"></div>`)}
1775
1739
  </div>
1776
1740
  </div>
1777
1741
  ${BgWidget.container1x2(
@@ -1780,18 +1744,20 @@ export class ShoppingProductSetting {
1780
1744
  BgWidget.mainCard(html`
1781
1745
  <div class="d-flex flex-column guide5-4">
1782
1746
  <div style="font-weight: 700;">商品名稱</div>
1783
- <input
1784
- class="w-100 mt-2"
1785
- value="${postMD.title ?? ''}"
1786
- style="border-radius: 10px;border: 1px solid #DDD;display: flex;padding: 9px 18px 9px 18px;align-items: center;align-self: stretch;"
1787
- onchange="${gvc.event((e) => {
1747
+ ${BgWidget.editeInput({
1748
+ gvc: gvc,
1749
+ title: '',
1750
+ type: 'text',
1751
+ default: postMD.title ?? '',
1752
+ placeHolder: '請輸入商品名稱',
1753
+ callback: (text) => {
1788
1754
  if (postMD.seo.domain === postMD.title) {
1789
- postMD.seo.domain = e.value;
1755
+ postMD.seo.domain = text;
1790
1756
  }
1791
- postMD.title = e.value;
1757
+ postMD.title = text;
1792
1758
  gvc.notifyDataChange('seo');
1793
- })}"
1794
- />
1759
+ },
1760
+ })}
1795
1761
  </div>
1796
1762
  `),
1797
1763
  BgWidget.mainCard(
@@ -1857,10 +1823,6 @@ export class ShoppingProductSetting {
1857
1823
  return html` <div class="d-flex align-items-center justify-content-end mb-3">
1858
1824
  <div class="d-flex align-items-center gap-2">
1859
1825
  <div style="color: #393939; font-weight: 700;">商品描述</div>
1860
- ${BgWidget.aiChatButton({
1861
- gvc,
1862
- select: 'writer',
1863
- })}
1864
1826
  </div>
1865
1827
  <div class="flex-fill"></div>
1866
1828
  <div
@@ -2004,7 +1966,19 @@ export class ShoppingProductSetting {
2004
1966
  const originContent = `${postMD.content}`;
2005
1967
  BgWidget.fullDialog({
2006
1968
  gvc: gvc,
2007
- title: '商品描述',
1969
+ title: (gvc2)=>{
1970
+ return `<div class="d-flex align-items-center me-2" style="gap:10px;">商品描述${BgWidget.aiChatButton({
1971
+ gvc:gvc2,
1972
+ select: 'writer',
1973
+ click:()=>{
1974
+ ProductAi.generateRichText(gvc,(text)=>{
1975
+ postMD.content+=text;
1976
+ gvc.notifyDataChange(vm.id)
1977
+ gvc2.recreateView()
1978
+ })
1979
+ }
1980
+ })}</div>`
1981
+ },
2008
1982
  innerHTML: (gvc2) => {
2009
1983
  return html` <div>
2010
1984
  ${EditorElem.richText({
@@ -2380,13 +2354,13 @@ export class ShoppingProductSetting {
2380
2354
  view: () => {
2381
2355
  if (editSpectPage[specIndex].type == 'show') {
2382
2356
  gvc.addStyle(`
2383
- .option {
2384
- background-color: #f7f7f7;
2385
- }
2386
- .pen {
2387
- display: none;
2388
- }
2389
- `);
2357
+ .option {
2358
+ background-color: #f7f7f7;
2359
+ }
2360
+ .pen {
2361
+ display: none;
2362
+ }
2363
+ `);
2390
2364
  return html` <div class="d-flex flex-column" style="gap:6px;align-items: flex-start;padding: 12px 0;">
2391
2365
  <div style="font-size: 16px;">${dd.title}</div>
2392
2366
  ${(() => {
@@ -2526,7 +2500,6 @@ export class ShoppingProductSetting {
2526
2500
  </div>
2527
2501
  `;
2528
2502
  }
2529
-
2530
2503
  return returnHTML;
2531
2504
  },
2532
2505
  divCreate: {
@@ -2553,10 +2526,8 @@ export class ShoppingProductSetting {
2553
2526
  }
2554
2527
  return '';
2555
2528
  })(),
2556
-
2557
- postMD.specs.length == 0
2558
- ? ''
2559
- : BgWidget.mainCard(
2529
+ postMD.variants.length > 1
2530
+ ? BgWidget.mainCard(
2560
2531
  html` <div style="font-size: 16px;font-weight: 700;color:#393939;margin-bottom: 18px;">規格設定</div>` +
2561
2532
  obj.gvc.bindView(() => {
2562
2533
  function getPreviewImage(img?: string) {
@@ -3166,7 +3137,19 @@ export class ShoppingProductSetting {
3166
3137
  <div
3167
3138
  style="display: flex;height: 40px;padding: 8px 17px 8px 18px;align-items: center;justify-content: space-between;gap: 4px;align-self: stretch;border-radius: 10px;background: #F7F7F7;"
3168
3139
  >
3169
- 已選取 ${selected.length}
3140
+ <div style="display: flex; gap: 12px;align-items: center;">
3141
+ <i
3142
+ class="fa-solid fa-square-check"
3143
+ style="width: 16px;height: 16px; margin-left: 3px; cursor: pointer;color: #393939;font-size: 18px;"
3144
+ onclick="${gvc.event(() => {
3145
+ postMD.variants.map((dd) => {
3146
+ (dd as any).checked = false;
3147
+ });
3148
+ gvc.notifyDataChange(variantsViewID);
3149
+ })}"
3150
+ ></i>
3151
+ 已選取 ${selected.length} 項
3152
+ </div>
3170
3153
  <div
3171
3154
  style="position: relative"
3172
3155
  onclick="${gvc.event(() => {
@@ -3294,9 +3277,9 @@ export class ShoppingProductSetting {
3294
3277
  >
3295
3278
  <i
3296
3279
  class="${selected.length ? `fa-solid fa-square-check` : `fa-regular fa-square`}"
3297
- style="width: 16px;height: 16px;margin-left:2px;margin-right:18px;cursor: pointer;
3298
- color: ${selected.length ? `#393939` : `#DDD`};font-size: 18px;
3299
- "
3280
+ style="width: 16px;height: 16px;margin-left:2px;margin-right:18px;cursor: pointer; color: ${selected.length
3281
+ ? `#393939`
3282
+ : `#DDD`};font-size: 18px;"
3300
3283
  onclick="${gvc.event(() => {
3301
3284
  postMD.variants.map((dd) => {
3302
3285
  (dd as any).checked = !selected.length;
@@ -3333,17 +3316,14 @@ export class ShoppingProductSetting {
3333
3316
  if (index === arrays.length) {
3334
3317
  return [[]];
3335
3318
  }
3336
-
3337
3319
  const currentArray = arrays[index];
3338
3320
  const nextCombinations = getCombinations(arrays, index + 1);
3339
-
3340
3321
  const currentCombinations: string[][] = [];
3341
3322
  for (const value of currentArray) {
3342
3323
  for (const combination of nextCombinations) {
3343
3324
  currentCombinations.push([value, ...combination]);
3344
3325
  }
3345
3326
  }
3346
-
3347
3327
  return currentCombinations;
3348
3328
  };
3349
3329
 
@@ -3601,7 +3581,7 @@ export class ShoppingProductSetting {
3601
3581
  return compareArrays(variant.spec, item);
3602
3582
  });
3603
3583
  })
3604
- .filter((item) => item !== undefined) as variant[];
3584
+ .filter((item) => item !== undefined) as Variant[];
3605
3585
 
3606
3586
  viewList.push(
3607
3587
  postMD.variants
@@ -3627,7 +3607,6 @@ export class ShoppingProductSetting {
3627
3607
  dd.editable = false;
3628
3608
  });
3629
3609
  (data as any).editable = true;
3630
- obj.vm.from = 'add';
3631
3610
  obj.vm.type = 'editSpec';
3632
3611
  })}"
3633
3612
  >
@@ -3768,7 +3747,8 @@ export class ShoppingProductSetting {
3768
3747
  },
3769
3748
  };
3770
3749
  })
3771
- ),
3750
+ )
3751
+ : '',
3772
3752
  BgWidget.mainCard(
3773
3753
  obj.gvc.bindView(() => {
3774
3754
  const id = gvc.glitter.getUUID();
@@ -3861,7 +3841,6 @@ export class ShoppingProductSetting {
3861
3841
  title: '',
3862
3842
  content: '',
3863
3843
  };
3864
-
3865
3844
  return {
3866
3845
  bind: 'seo',
3867
3846
  view: () => {
@@ -3947,9 +3926,112 @@ ${postMD.seo.content ?? ''}</textarea
3947
3926
  };
3948
3927
  })
3949
3928
  ),
3929
+ BgWidget.mainCard(
3930
+ html` <div class="mb-2" style="font-weight: 700;">商品狀態</div>
3931
+ ${gvc.bindView(
3932
+ (() => {
3933
+ const id = gvc.glitter.getUUID();
3934
+ const inputStyle = 'display: block; width: 200px;';
3935
+ return {
3936
+ bind: id,
3937
+ view: () => {
3938
+ return [
3939
+ postMD.status === 'schedule'
3940
+ ? html` <div class="tx_700">啟用期間</div>
3941
+ <div class="d-flex mb-3 ${document.body.clientWidth < 768 ? 'flex-column' : ''}" style="gap: 12px">
3942
+ <div class="d-flex align-items-center">
3943
+ <span class="tx_normal me-2">開始日期</span>
3944
+ ${BgWidget.editeInput({
3945
+ gvc: gvc,
3946
+ title: '',
3947
+ type: 'date',
3948
+ style: inputStyle,
3949
+ default: `${postMD.active_schedule.startDate}`,
3950
+ placeHolder: '',
3951
+ callback: (text) => {
3952
+ postMD.active_schedule.startDate = text;
3953
+ },
3954
+ })}
3955
+ </div>
3956
+ <div class="d-flex align-items-center">
3957
+ <span class="tx_normal me-2">開始時間</span>
3958
+ ${BgWidget.editeInput({
3959
+ gvc: gvc,
3960
+ title: '',
3961
+ type: 'time',
3962
+ style: inputStyle,
3963
+ default: `${postMD.active_schedule.startTime}`,
3964
+ placeHolder: '',
3965
+ callback: (text) => {
3966
+ postMD.active_schedule.startTime = text;
3967
+ },
3968
+ })}
3969
+ </div>
3970
+ </div>
3971
+ ${BgWidget.multiCheckboxContainer(
3972
+ gvc,
3973
+ [
3974
+ {
3975
+ key: 'noEnd',
3976
+ name: '無期限',
3977
+ },
3978
+ {
3979
+ key: 'withEnd',
3980
+ name: '結束時間',
3981
+ innerHtml: html` <div
3982
+ class="d-flex mt-0 mt-md-1 ${document.body.clientWidth < 768 ? 'flex-column' : ''}"
3983
+ style="gap: 12px"
3984
+ >
3985
+ <div class="d-flex align-items-center">
3986
+ <span class="tx_normal me-2">結束日期</span>
3987
+ ${BgWidget.editeInput({
3988
+ gvc: gvc,
3989
+ title: '',
3990
+ type: 'date',
3991
+ style: inputStyle,
3992
+ default: `${postMD.active_schedule.endDate}`,
3993
+ placeHolder: '',
3994
+ callback: (text) => {
3995
+ postMD.active_schedule.endDate = text;
3996
+ },
3997
+ })}
3998
+ </div>
3999
+ <div class="d-flex align-items-center">
4000
+ <span class="tx_normal me-2">結束時間</span>
4001
+ ${BgWidget.editeInput({
4002
+ gvc: gvc,
4003
+ title: '',
4004
+ type: 'time',
4005
+ style: inputStyle,
4006
+ default: `${postMD.active_schedule.endTime}`,
4007
+ placeHolder: '',
4008
+ callback: (text) => {
4009
+ postMD.active_schedule.endTime = text;
4010
+ },
4011
+ })}
4012
+ </div>
4013
+ </div>`,
4014
+ },
4015
+ ],
4016
+ [postMD.active_schedule.endDate ? `withEnd` : `noEnd`],
4017
+ (text) => {
4018
+ if (text[0] === 'noEnd') {
4019
+ postMD.active_schedule.endDate = undefined;
4020
+ postMD.active_schedule.endTime = undefined;
4021
+ }
4022
+ },
4023
+ { single: true }
4024
+ )}`
4025
+ : '',
4026
+ ].join(BgWidget.mbContainer(12));
4027
+ },
4028
+ };
4029
+ })()
4030
+ )}`
4031
+ ),
3950
4032
  ]
3951
4033
  .filter((str) => str.length > 0)
3952
- .join(BgWidget.mbContainer(12)),
4034
+ .join(BgWidget.mbContainer(18)),
3953
4035
  ratio: 77,
3954
4036
  },
3955
4037
  {
@@ -3961,76 +4043,18 @@ ${postMD.seo.content ?? ''}</textarea
3961
4043
  <div style="font-weight: 400;" class="mb-2">${this.getProductTypeString(postMD)}</div>
3962
4044
  `
3963
4045
  ),
3964
- BgWidget.mainCard(
3965
- html` <div style="font-weight: 700;" class="mb-2">商品狀態</div>` +
3966
- EditorElem.select({
3967
- gvc: obj.gvc,
3968
- title: '',
3969
- def: postMD.status,
3970
- array: [
3971
- { title: '啟用', value: 'active' },
3972
- { title: '草稿', value: 'draft' },
3973
- ],
3974
- callback: (text: any) => {
3975
- postMD.status = text;
3976
- },
3977
- })
3978
- ),
3979
- // BgWidget.mainCard(
3980
- // html` <div style="font-weight: 700;" class="mb-2">商品顯示</div>` +
3981
- // BgWidget.grayNote('當商品設定為隱藏時,僅能顯示於隱形賣場與一頁商店當中') +
3982
- // html` <div class="my-2"></div>` +
3983
- // EditorElem.select({
3984
- // gvc: obj.gvc,
3985
- // title: '',
3986
- // def: postMD.visible || 'true',
3987
- // array: [
3988
- // { title: '顯示', value: 'true' },
3989
- // { title: '隱藏', value: 'false' },
3990
- // ],
3991
- // callback: (text: any) => {
3992
- // postMD.visible = text;
3993
- // },
3994
- // })
3995
- // ),
3996
- // BgWidget.mainCard(
3997
- // html` <div style="font-weight: 700;" class="mb-2">商品類型</div>` +
3998
- // gvc.bindView({
3999
- // bind: 'productType',
4000
- // view: () => {
4001
- // postMD.productType = postMD.productType ?? {
4002
- // product: true,
4003
- // addProduct: false,
4004
- // giveaway: false,
4005
- // };
4006
- // return ['product', 'addProduct', 'giveaway']
4007
- // .map((dd, index) => {
4008
- // return html` <div
4009
- // class="d-flex align-items-center"
4010
- // style="gap:6px;cursor: pointer;"
4011
- // onclick="${gvc.event(() => {
4012
- // (postMD!.productType as any)[dd] = !(postMD!.productType as any)[dd];
4013
- // gvc.notifyDataChange('productType');
4014
- // })}"
4015
- // >
4016
- // ${(postMD!.productType as any)[dd]
4017
- // ? html` <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none">
4018
- // <rect width="16" height="16" rx="3" fill="#393939" />
4019
- // <path d="M4.5 8.5L7 11L11.5 5" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
4020
- // </svg>`
4021
- // : html` <div style="width: 16px;height: 16px;border-radius: 3px;border: 1px solid #DDD;"></div> `}
4022
- // ${['商品', '加購品', '贈品'][index]}
4023
- // </div>`;
4024
- // })
4025
- // .join('');
4026
- // },
4027
- // divCreate: {
4028
- // class: `d-flex flex-column `,
4029
- // style: 'gap:12px;',
4030
- // },
4031
- // }),
4032
- // ''
4033
- // ),
4046
+ BgWidget.mainCard(`<div style="font-weight: 700;" class="mb-2">商品狀態</div>`+BgWidget.select({
4047
+ gvc: obj.gvc,
4048
+ default: postMD.status,
4049
+ options: [
4050
+ { key: 'active', value: '啟用' },
4051
+ { key: 'draft', value: '草稿' },
4052
+ // { key: 'schedule', value: '期間限定' },
4053
+ ],
4054
+ callback: (text: any) => {
4055
+ postMD.status = text;
4056
+ },
4057
+ })),
4034
4058
  BgWidget.mainCard(
4035
4059
  obj.gvc.bindView(() => {
4036
4060
  const id = obj.gvc.glitter.getUUID();
@@ -4040,10 +4064,10 @@ ${postMD.seo.content ?? ''}</textarea
4040
4064
  return [
4041
4065
  html` <div style="font-weight: 700;" class="mb-2">商品分類</div>`,
4042
4066
  postMD.collection
4043
- .map((dd, index) => {
4044
- return `<span style="font-size: 14px;">${dd}</span>`;
4067
+ .map((dd) => {
4068
+ return html`<span style="font-size: 14px;">${dd}</span>`;
4045
4069
  })
4046
- .join(`<div class="my-1"></div>`),
4070
+ .join(html`<div class="my-1"></div>`),
4047
4071
  html` <div class="w-100 mt-3">
4048
4072
  ${BgWidget.darkButton(
4049
4073
  `設定商品分類`,
@@ -4077,9 +4101,9 @@ ${postMD.seo.content ?? ''}</textarea
4077
4101
  bind: id,
4078
4102
  view: () => {
4079
4103
  return [
4080
- `<div style="font-weight: 700;" class="mb-2">AI 選品</div>`,
4104
+ html`<div style="font-weight: 700;" class="mb-2">AI 選品</div>`,
4081
4105
  BgWidget.grayNote(postMD.ai_description || '尚未設定描述語句,透過設定描述語句,可以幫助AI更準確的定位產品。'),
4082
- `<div class="my-2"></div>`,
4106
+ html`<div class="my-2"></div>`,
4083
4107
  BgWidget.darkButton(
4084
4108
  `設定描述語句`,
4085
4109
  gvc.event(() => {
@@ -4127,7 +4151,7 @@ ${postMD.seo.content ?? ''}</textarea
4127
4151
  ),
4128
4152
  ]
4129
4153
  .filter((str) => str.length > 0)
4130
- .join(BgWidget.mbContainer(24))}
4154
+ .join(BgWidget.mbContainer(18))}
4131
4155
  </div>`,
4132
4156
  ratio: 23,
4133
4157
  }
@@ -4221,32 +4245,6 @@ ${postMD.seo.content ?? ''}</textarea
4221
4245
  }
4222
4246
  }
4223
4247
  }
4224
- // if (postMD['variants'][0]['shipment_type'] == 'volume') {
4225
- // if (
4226
- // postMD['variants'][0]['v_height'] == undefined ||
4227
- // postMD['variants'][0]['v_height'] == 0 ||
4228
- // postMD['variants'][0]['v_width'] == undefined ||
4229
- // postMD['variants'][0]['v_width'] == 0 ||
4230
- // postMD['variants'][0]['v_length'] == undefined ||
4231
- // postMD['variants'][0]['v_length'] == 0
4232
- // ) {
4233
- // dialog.infoMessage({
4234
- // text: '商品材積資訊未填',
4235
- // });
4236
- // return false;
4237
- // }
4238
- // }
4239
- // if (postMD['variants'][0]['shipment_type'] != 'none') {
4240
- // if (postMD['variants'][0]['shipment_type'] == 'weight') {
4241
- // if (postMD['variants'][0]['weight'] == undefined || postMD['variants'][0]['weight'] == 0) {
4242
- // dialog.infoMessage({
4243
- // text: '商品重量未填',
4244
- // });
4245
- // return false;
4246
- // }
4247
- // }
4248
- //
4249
- // }
4250
4248
  return true;
4251
4249
  }
4252
4250