ts-glitter 14.2.4 → 14.2.6

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 (107) hide show
  1. package/lowcode/Entry.js +1 -1
  2. package/lowcode/Entry.ts +1 -1
  3. package/lowcode/backend-manager/bg-product.js +2 -1
  4. package/lowcode/backend-manager/bg-product.ts +2 -1
  5. package/lowcode/cms-plugin/filter-options.js +1 -3
  6. package/lowcode/cms-plugin/filter-options.ts +1 -3
  7. package/lowcode/cms-plugin/module/product-excel.js +537 -0
  8. package/lowcode/cms-plugin/module/product-excel.ts +652 -0
  9. package/lowcode/cms-plugin/shopping-allowance-manager.js +12 -5
  10. package/lowcode/cms-plugin/shopping-allowance-manager.ts +12 -5
  11. package/lowcode/cms-plugin/shopping-discount-setting.js +1 -1
  12. package/lowcode/cms-plugin/shopping-discount-setting.ts +1 -1
  13. package/lowcode/cms-plugin/shopping-finance-setting.js +0 -7
  14. package/lowcode/cms-plugin/shopping-finance-setting.ts +8 -8
  15. package/lowcode/cms-plugin/shopping-invoice-manager.js +5 -1
  16. package/lowcode/cms-plugin/shopping-invoice-manager.ts +5 -2
  17. package/lowcode/cms-plugin/shopping-order-manager.js +8 -0
  18. package/lowcode/cms-plugin/shopping-order-manager.ts +8 -0
  19. package/lowcode/cms-plugin/shopping-product-setting.js +61 -638
  20. package/lowcode/cms-plugin/shopping-product-setting.ts +67 -790
  21. package/lowcode/jspage/main.ts +0 -1
  22. package/lowcode/public-components/blogs/blogs-01.js +4 -0
  23. package/lowcode/public-components/checkout/index.js +967 -209
  24. package/lowcode/public-components/checkout/index.ts +977 -214
  25. package/lowcode/public-components/checkout/index_.js +1724 -412
  26. package/lowcode/public-components/checkout/index_.ts +2032 -704
  27. package/lowcode/public-components/product/pd-class.js +68 -13
  28. package/lowcode/public-components/product/pd-class.ts +74 -14
  29. package/lowcode/public-components/product/product-detail.js +1 -1
  30. package/lowcode/public-components/product/product-detail.ts +7 -3
  31. package/lowcode/public-components/product/product-list.js +55 -0
  32. package/lowcode/public-components/product/product-list.ts +62 -1
  33. package/lowcode/public-components/public/ad.js +14 -0
  34. package/lowcode/public-components/public/ad.ts +15 -0
  35. package/package.json +7 -4
  36. package/src/api-public/controllers/ai-chat.js.map +1 -1
  37. package/src/api-public/controllers/app-release.js.map +1 -1
  38. package/src/api-public/controllers/article.js.map +1 -1
  39. package/src/api-public/controllers/fcm.js.map +1 -1
  40. package/src/api-public/controllers/post.js.map +1 -1
  41. package/src/api-public/controllers/rebate.js.map +1 -1
  42. package/src/api-public/controllers/shop.js +16 -0
  43. package/src/api-public/controllers/shop.js.map +1 -1
  44. package/src/api-public/controllers/shop.ts +27 -3
  45. package/src/api-public/controllers/user.js.map +1 -1
  46. package/src/api-public/services/EcInvoice.js +18 -12
  47. package/src/api-public/services/EcInvoice.js.map +1 -1
  48. package/src/api-public/services/EcInvoice.ts +19 -14
  49. package/src/api-public/services/ai-robot.d.ts +0 -1
  50. package/src/api-public/services/ai-robot.js.map +1 -1
  51. package/src/api-public/services/auto-send-email.js.map +1 -1
  52. package/src/api-public/services/chat.js.map +1 -1
  53. package/src/api-public/services/custom-code.js.map +1 -1
  54. package/src/api-public/services/delivery.js.map +1 -1
  55. package/src/api-public/services/ezpay/tool.d.ts +1 -0
  56. package/src/api-public/services/fb-message.js.map +1 -1
  57. package/src/api-public/services/financial-service.d.ts +49 -1
  58. package/src/api-public/services/financial-service.js +226 -1
  59. package/src/api-public/services/financial-service.js.map +1 -1
  60. package/src/api-public/services/financial-service.ts +282 -1
  61. package/src/api-public/services/line-message.js.map +1 -1
  62. package/src/api-public/services/monitor.d.ts +1 -0
  63. package/src/api-public/services/post.js.map +1 -1
  64. package/src/api-public/services/rebate.js.map +1 -1
  65. package/src/api-public/services/schedule.js.map +1 -1
  66. package/src/api-public/services/share-permission.js.map +1 -1
  67. package/src/api-public/services/shopping.d.ts +3 -1
  68. package/src/api-public/services/shopping.js +57 -58
  69. package/src/api-public/services/shopping.js.map +1 -1
  70. package/src/api-public/services/shopping.ts +77 -76
  71. package/src/api-public/services/sms.js.map +1 -1
  72. package/src/api-public/services/user.js.map +1 -1
  73. package/src/api-public/utils/ut-permission.d.ts +1 -0
  74. package/src/app-project/serverless/src/modules/database.d.ts +1 -1
  75. package/src/app-project/serverless/src/modules/redis.d.ts +1 -1
  76. package/src/config.d.ts +1 -1
  77. package/src/config.js.map +1 -1
  78. package/src/controllers/ai.js.map +1 -1
  79. package/src/controllers/filemanager.js.map +1 -1
  80. package/src/firebase/message.js +2 -1
  81. package/src/firebase/message.js.map +1 -1
  82. package/src/helper/app_creater.js +2 -1
  83. package/src/helper/app_creater.js.map +1 -1
  84. package/src/helper/glitter-util.js.map +3 -3
  85. package/src/index.js +111 -92
  86. package/src/index.js.map +1 -5
  87. package/src/index.ts +424 -397
  88. package/src/lambda/interface.d.ts +1 -1
  89. package/src/lambda/interface.js +2 -2
  90. package/src/lambda/interface.js.map +1 -1
  91. package/src/modules/AWSLib.js +3 -2
  92. package/src/modules/AWSLib.js.map +1 -1
  93. package/src/modules/database.d.ts +1 -1
  94. package/src/modules/redis.d.ts +1 -1
  95. package/src/modules/tool.js +2 -1
  96. package/src/modules/tool.js.map +1 -1
  97. package/src/run.js +2 -1
  98. package/src/run.js.map +1 -1
  99. package/src/services/backend-service.js.map +1 -1
  100. package/src/services/create-instance.js +4 -3
  101. package/src/services/create-instance.js.map +1 -1
  102. package/src/services/saas-table-check.js +2 -2
  103. package/src/services/saas-table-check.js.map +1 -1
  104. package/src/services/ses.js +2 -1
  105. package/src/services/ses.js.map +1 -1
  106. package/src/services/tool.js +3 -2
  107. package/src/services/tool.js.map +1 -1
@@ -12,440 +12,14 @@ 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 * as url from 'node:url';
16
-
17
- interface variant {
18
- save_stock?: string;
19
- sale_price: number;
20
- compare_price: number;
21
- cost: number;
22
- spec: string[];
23
- profit: number;
24
- v_length: number;
25
- v_width: number;
26
- v_height: number;
27
- weight: number;
28
- shipment_type: 'weight' | 'none' | 'volume';
29
- sku: string;
30
- barcode: string;
31
- stock: number;
32
- preview_image: string;
33
- show_understocking: string;
34
- type: string;
35
- }
36
-
37
- class Excel {
38
- private workbook: any;
39
- private worksheet: any;
40
- private ExcelJS: any;
41
- private gvc: GVC;
42
- public headers: string[];
43
- public lineName: string[];
44
-
45
- constructor(gvc: GVC, headers: string[], lineName: string[]) {
46
- this.gvc = gvc;
47
- this.headers = headers;
48
- this.lineName = lineName;
49
- }
50
-
51
- loadScript() {
52
- return new Promise((resolve) => {
53
- if ((window as any).ExcelJS) {
54
- this.initExcel();
55
- resolve(true);
56
- } else {
57
- this.gvc.addMtScript(
58
- [{ src: 'https://cdnjs.cloudflare.com/ajax/libs/exceljs/4.3.0/exceljs.min.js' }],
59
- () => {
60
- if ((window as any).XLSX) {
61
- this.initExcel();
62
- resolve(true);
63
- }
64
- },
65
- () => {}
66
- );
67
- }
68
- });
69
- }
70
-
71
- private initExcel() {
72
- this.ExcelJS = (window as any).ExcelJS;
73
- this.workbook = new this.ExcelJS.Workbook();
74
- this.worksheet = this.workbook.addWorksheet('Sheet1');
75
- }
76
-
77
- // 匯入excel
78
- async importData(notifyId: string, file: any) {
79
- await this.loadScript();
80
- const reader = new FileReader();
81
- const dialog = new ShareDialog(this.gvc.glitter);
82
- dialog.dataLoading({ visible: true, text: '資料處理中' });
83
-
84
- reader.onload = async (e) => {
85
- const arrayBuffer = e.target!.result;
86
- const workbook = new this.ExcelJS.Workbook();
87
- await workbook.xlsx.load(arrayBuffer);
88
- const worksheet = workbook.getWorksheet(1);
89
-
90
- const data: any = [];
91
- worksheet.eachRow({ includeEmpty: true }, (row: any, rowNumber: any) => {
92
- const rowData: any = [];
93
- row.eachCell({ includeEmpty: true }, (cell: any, colNumber: any) => {
94
- rowData.push(cell.value);
95
- });
96
- const isEmptyRow = rowData.every((cellValue: any) => cellValue === null || cellValue === '');
97
- if (!isEmptyRow) {
98
- data.push(rowData);
99
- }
100
- });
101
- let error = false;
102
- let addCollection: any = [];
103
- let postMD: {
104
- title: string;
105
- productType: {
106
- product: boolean;
107
- addProduct: boolean;
108
- giveaway: boolean;
109
- };
110
- content: string;
111
- preview_image: string;
112
- hideIndex: string;
113
- collection: string[];
114
- status: 'active' | 'draft';
115
- specs: { title: string; option: any }[];
116
- variants: variant[];
117
- seo: {
118
- title: string;
119
- content: string;
120
- keywords: string;
121
- };
122
- template: string;
123
- }[] = [];
124
- let productData: any = {};
125
- let variantData: variant = {
126
- barcode: '',
127
- compare_price: 0,
128
- cost: 0,
129
- preview_image: '',
130
- profit: 0,
131
- sale_price: 0,
132
- shipment_type: 'weight',
133
- show_understocking: '',
134
- sku: '',
135
- spec: [],
136
- stock: 0,
137
- type: '',
138
- v_height: 0,
139
- v_length: 0,
140
- v_width: 0,
141
- weight: 0,
142
- };
143
- data.forEach((row: any, index: number) => {
144
- variantData = {
145
- barcode: '',
146
- compare_price: 0,
147
- cost: 0,
148
- preview_image: '',
149
- profit: 0,
150
- sale_price: 0,
151
- shipment_type: 'weight',
152
- show_understocking: '',
153
- sku: '',
154
- spec: [],
155
- stock: 0,
156
- type: '',
157
- v_height: 0,
158
- v_length: 0,
159
- v_width: 0,
160
- weight: 0,
161
- };
162
- if (index != 0) {
163
- if (row[1]) {
164
- if (Object.keys(productData).length != 0) {
165
- postMD.push(productData);
166
- }
167
- addCollection = [];
168
- productData = {
169
- title: '',
170
- productType: {
171
- product: true,
172
- addProduct: false,
173
- giveaway: false,
174
- },
175
- content: '',
176
- status: 'active',
177
- collection: [],
178
- hideIndex: 'false',
179
- preview_image: '',
180
- specs: [],
181
- variants: [],
182
- seo: {
183
- title: '',
184
- content: '',
185
- keywords: '',
186
- },
187
- template: '',
188
- };
189
- productData.title = row[0] ?? '';
190
- productData.status = row[1] == '上架' ? 'active' : 'draft';
191
- productData.collection = row[2].split(',') ?? [];
192
- const regex = /[\s\/\\]+/g;
193
- // 去除多餘空白
194
- productData.collection = productData.collection.map((item: string) => item.replace(/\s+/g, ''));
195
-
196
- productData.collection.forEach((row: any) => {
197
- let collection = row.replace(/\s+/g, '');
198
- if (regex.test(collection)) {
199
- error = true;
200
- const dialog = new ShareDialog(this.gvc.glitter);
201
- dialog.infoMessage({ text: `第${index + 1}行的類別名稱不可包含空白格與以下符號:「 / 」「 \\ 」,並以「 , 」區分不同類別` });
202
- return;
203
- }
204
-
205
- // 若帶有/,要自動加上父類
206
- function splitStringIncrementally(input: string): string[] {
207
- const parts = input.split('/');
208
- const result: string[] = [];
209
-
210
- // 使用 reduce 来构建每一部分的拼接字符串
211
- parts.reduce((acc, part) => {
212
- const newAcc = acc ? `${acc}/${part}` : part;
213
- result.push(newAcc);
214
- return newAcc;
215
- }, '');
216
-
217
- return result;
218
- }
219
-
220
- if (collection.split('/').length > 1) {
221
- // 會進來代表有/的內容 需要檢查放進去的collection有沒有父類
222
- // 先取得目前分層 例如 貓/貓用品/貓砂/A品牌 會拆分成 貓/貓用品/貓砂 , 貓/貓用品, 貓
223
- // 然後把父層自動推進去
224
- let check = splitStringIncrementally(collection);
225
- const newItems = check.filter((item: string) => !productData.collection.includes(item));
226
- addCollection.push(...newItems);
227
- }
228
- addCollection.push(collection);
229
- });
230
- productData.collection = addCollection;
231
- productData.productType.addProduct = row[3].includes('加購品');
232
- productData.productType.product = row[3].includes('商品');
233
- productData.productType.giveaway = row[3].includes('贈品');
234
- productData.preview_image = row[4] ? [row[4]] : ['商品圖片'];
235
- productData.seo.title = row[5] ?? '';
236
- productData.seo.content = row[6] ?? '';
237
- productData.seo.keywords = row[7] ?? '';
238
- // spec值 merge
239
- let indices = [8, 10, 12];
240
- indices.forEach((index) => {
241
- if (row[index]) {
242
- productData.specs.push({
243
- title: row[index],
244
- option: [],
245
- });
246
- }
247
- });
248
- }
249
-
250
- let indices = [9, 11, 13];
251
- indices.forEach((rowindex, key) => {
252
- if (row[rowindex] && productData.specs.length > key) {
253
- productData.specs[key].option = productData.specs[key].option ?? [];
254
- const exists = productData.specs[key].option.some((item: any) => item.title === row[rowindex]);
255
- if (!exists) {
256
- productData.specs[key].option.push({ title: row[rowindex], expand: true });
257
- }
258
- variantData.spec.push(row[rowindex]);
259
- }
260
- });
261
- variantData.sku = row[14] ?? '';
262
- variantData.cost = row[15] ?? '';
263
- variantData.sale_price = row[16] ?? 0;
264
- variantData.compare_price = row[17] ?? 0;
265
- variantData.profit = row[18] ?? 0;
266
-
267
- const shipmentTypeMap: { [key: string]: string } = {
268
- 依材積計算: 'volume',
269
- 不計算運費: 'none',
270
- };
271
- // @ts-ignore
272
- variantData.shipment_type = shipmentTypeMap[row[19]] || 'weight';
273
-
274
- variantData.v_length = row[20] ?? 0;
275
- variantData.v_width = row[21] ?? 0;
276
- variantData.v_height = row[22] ?? 0;
277
- variantData.weight = row[23] ?? 0;
278
- variantData.show_understocking = row[25] == '追蹤' ? 'true' : 'false';
279
- variantData.stock = row[26] ?? 0;
280
- variantData.save_stock = row[27] ?? 0;
281
- variantData.barcode = row[28] ?? '';
282
-
283
- productData.variants.push(JSON.parse(JSON.stringify(variantData)));
284
- }
285
- });
286
- postMD.push(productData);
287
- productData.reverse;
288
- let passData = {
289
- data: postMD,
290
- collection: addCollection,
291
- };
292
-
293
- dialog.dataLoading({ visible: false });
294
- if (!error) {
295
- dialog.dataLoading({ visible: true, text: '上傳資料中' });
296
- await ApiShop.postMultiProduct({
297
- data: passData,
298
- token: (window.parent as any).config.token,
299
- }).then(() => {
300
- dialog.dataLoading({ visible: false });
301
- dialog.successMessage({ text: '上傳成功' });
302
- this.gvc.glitter.closeDiaLog();
303
- this.gvc.notifyDataChange(notifyId);
304
- });
305
- }
306
- };
307
- reader.readAsArrayBuffer(file);
308
- }
309
-
310
- static getFileTime() {
311
- const now = new Date();
312
- const year = now.getFullYear();
313
- const month = String(now.getMonth() + 1).padStart(2, '0');
314
- const day = String(now.getDate()).padStart(2, '0');
315
- const hours = String(now.getHours()).padStart(2, '0');
316
- const minutes = String(now.getMinutes()).padStart(2, '0');
317
- return `${year}${month}${day}${hours}${minutes}`;
318
- }
319
-
320
- async exportData(data: any, name?: string) {
321
- await this.loadScript();
322
- this.setHeader();
323
- this.insertData(data);
324
- this.setHeaderStyle();
325
- this.setRowHeight();
326
- this.setFontAndAlignmentStyle();
327
- this.adjustColumnWidths(data);
328
- const buffer = await this.workbook.xlsx.writeBuffer();
329
- let fileName = name ?? `example_${new Date().toISOString()}`;
330
- this.saveAsExcelFile(buffer, `${fileName}.xlsx`);
331
- }
332
-
333
- private insertData(data: any): void {
334
- data.forEach((row: any) => {
335
- this.worksheet.addRow(Object.values(row));
336
- });
337
- }
338
-
339
- private setHeader(): void {
340
- this.worksheet.addRow(this.headers);
341
- }
342
-
343
- // 設定標頭粗體
344
- private setHeaderStyle(): void {
345
- this.worksheet.getRow(1).eachCell((cell: any) => {
346
- cell.font = { name: 'Microsoft JhengHei', bold: true };
347
- cell.alignment = { vertical: 'middle', horizontal: 'center' };
348
- cell.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFE1E1E1' } };
349
- });
350
- }
351
-
352
- // 設定行高1.2
353
- private setRowHeight(): void {
354
- this.worksheet.eachRow((row: any) => {
355
- row.height = 18;
356
- });
357
- }
358
-
359
- private setFontAndAlignmentStyle(): void {
360
- this.worksheet.eachRow((row: any) => {
361
- row.eachCell((cell: any) => {
362
- cell.font = { name: 'Microsoft JhengHei' };
363
- cell.alignment = { vertical: 'middle', horizontal: 'center' };
364
- });
365
- });
366
- }
367
-
368
- // 將內容匯出成excel檔
369
- public async exportToExcel(): Promise<void> {
370
- const buffer = await this.workbook.xlsx.writeBuffer();
371
- this.saveAsExcelFile(buffer, `example_${new Date().toISOString()}.xlsx`);
372
- }
373
-
374
- private saveAsExcelFile(buffer: any, fileName: string): void {
375
- const saasConfig: { config: any; api: any } = (window as any).saasConfig;
376
- const dialog = new ShareDialog(this.gvc.glitter);
377
- saasConfig.api.uploadFile(fileName).then((data: any) => {
378
- const EXCEL_TYPE = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8';
379
- const blobData: Blob = new Blob([buffer], { type: EXCEL_TYPE });
380
- const data1 = data.response;
381
- dialog.dataLoading({ visible: true });
382
- $.ajax({
383
- url: data1.url,
384
- type: 'put',
385
- data: blobData,
386
- processData: false,
387
- headers: {
388
- 'Content-Type': data1.type,
389
- },
390
- crossDomain: true,
391
- success: () => {
392
- dialog.dataLoading({ visible: false });
393
- const link = document.createElement('a');
394
- link.href = data1.fullUrl;
395
- link.download = fileName;
396
- link.click();
397
- },
398
- error: () => {
399
- dialog.dataLoading({ visible: false });
400
- dialog.errorMessage({ text: '上傳失敗' });
401
- },
402
- });
403
- });
404
- }
405
-
406
- // 透過位元組的大小,判斷內容文字的適合寬度計算
407
- private getByteLength(str: string): number {
408
- let byteLength = 0;
409
- for (let i = 0; i < str.length; i++) {
410
- const charCode = str.charCodeAt(i);
411
- if (charCode <= 0x007f) {
412
- // ASCII 字符
413
- byteLength += 1;
414
- } else if (charCode <= 0x07ff) {
415
- // 扩展拉丁字符
416
- byteLength += 2;
417
- } else if (charCode <= 0xffff) {
418
- // 大部分语言字符
419
- byteLength += 3;
420
- } else {
421
- // 补充字符
422
- byteLength += 4;
423
- }
424
- }
425
- return byteLength;
426
- }
427
-
428
- // 調整excel內容的寬度
429
- private adjustColumnWidths(sheetData: any): void {
430
- const maxLengths = this.headers.map((header) => this.getByteLength(header));
431
- sheetData.forEach((row: any) => {
432
- Object.values(row).forEach((value, index) => {
433
- const valueLength = this.getByteLength(value as string);
434
- if (valueLength > maxLengths[index]) {
435
- maxLengths[index] = valueLength;
436
- }
437
- });
438
- });
439
- this.worksheet.columns = this.headers.map((header, index) => {
440
- return { header, width: maxLengths[index] + 2 };
441
- });
442
- }
443
- }
15
+ import { ProductExcel, Variant as variant, RowInitData } from './module/product-excel.js';
444
16
 
445
17
  export class ShoppingProductSetting {
446
18
  public static main(gvc: GVC, type: 'product' | 'addProduct' | 'giveaway' | 'hidden' = 'product') {
447
19
  const html = String.raw;
448
20
  const glitter = gvc.glitter;
21
+ const dialog = new ShareDialog(glitter);
22
+ const excelHeader = ProductExcel.exampleHeader();
449
23
 
450
24
  const vm: {
451
25
  id: string;
@@ -472,45 +46,16 @@ export class ShoppingProductSetting {
472
46
  replaceData: '',
473
47
  ai_initial: {},
474
48
  };
475
- const rowInitData: {
476
- name: string;
477
- status: string;
478
- category: string;
479
- productType: string;
480
- img: string;
481
- SEO_title: string;
482
- SEO_desc: string;
483
- SEO_keyword: string;
484
- spec1: string;
485
- spec1Value: string;
486
- spec2: string;
487
- spec2Value: string;
488
- spec3: string;
489
- spec3Value: string;
490
- sku: string;
491
- cost: string;
492
- sale_price: string;
493
- compare_price: string;
494
- benefit: string;
495
- shipment_type: string;
496
- length: string;
497
- width: string;
498
- height: string;
499
- weight: string;
500
- weightUnit: string;
501
- stockPolicy: string;
502
- stock: string;
503
- save_stock: string;
504
- barcode: string;
505
- } = {
49
+
50
+ const rowInitData: RowInitData = {
506
51
  name: '',
507
52
  status: '',
508
53
  category: '',
509
54
  productType: ``,
510
55
  img: '',
56
+ SEO_domain: '',
511
57
  SEO_title: '',
512
58
  SEO_desc: '',
513
- SEO_keyword: '',
514
59
  spec1: '',
515
60
  spec1Value: '',
516
61
  spec2: '',
@@ -533,50 +78,14 @@ export class ShoppingProductSetting {
533
78
  save_stock: '',
534
79
  barcode: '',
535
80
  };
536
- const excel = new Excel(
81
+
82
+ const excel = new ProductExcel(
537
83
  gvc,
538
- [
539
- '商品ID',
540
- '商品名稱',
541
- '啟用狀態',
542
- '商品類別',
543
- '商品類型',
544
- '商品圖片',
545
- 'SEO標題',
546
- 'SEO內文',
547
- 'SEO關鍵字',
548
- '規格1',
549
- '規格詳細',
550
- '規格2',
551
- '規格詳細',
552
- '規格3',
553
- '規格詳細',
554
- 'sku',
555
- '成本',
556
- '售價',
557
- '原價',
558
- '利潤',
559
- '運費計算方式',
560
- '長度',
561
- '寬度',
562
- '高度',
563
- '商品重量',
564
- '重量單位',
565
- '庫存政策',
566
- '庫存',
567
- '安全庫存',
568
- '商品條碼',
569
- ],
84
+ excelHeader.filter((item) => item !== '商品ID'),
570
85
  Object.keys(rowInitData)
571
86
  );
572
- let dialog = new ShareDialog(glitter);
573
87
 
574
88
  const ListComp = new BgListComponent(gvc, vm, FilterOptions.productFilterFrame);
575
- gvc.addMtScript(
576
- [{ src: 'https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.16.9/xlsx.full.min.js' }],
577
- () => {},
578
- () => {}
579
- );
580
89
  vm.filter = ListComp.getFilterObject();
581
90
 
582
91
  return gvc.bindView(() => {
@@ -614,7 +123,6 @@ export class ShoppingProductSetting {
614
123
  (window.parent as any).glitter.share.checkData = () => {
615
124
  return true;
616
125
  };
617
- const filterID = gvc.glitter.getUUID();
618
126
  vm.tableId = gvc.glitter.getUUID();
619
127
  vm.dataList = [];
620
128
  const vmlist = {
@@ -679,157 +187,7 @@ export class ShoppingProductSetting {
679
187
  class="cursor_pointer"
680
188
  style="color: #36B; font-size: 14px; font-style: normal; font-weight: 400; line-height: normal; text-decoration-line: underline;"
681
189
  onclick="${gvc.event(() => {
682
- let sample = [
683
- [
684
- '產品1',
685
- '啟用',
686
- '商品',
687
- '精品/手套',
688
- 'image1',
689
- 'SEO標題',
690
- 'SEO內文',
691
- 'SEO關鍵字',
692
- '大小',
693
- 'S',
694
- '形狀',
695
- '長方形',
696
- '顏色',
697
- '白色',
698
- 'product-1-variant-1',
699
- '5000',
700
- '13000',
701
- '12000',
702
- '7000',
703
- '依重量計算',
704
- '10',
705
- '15',
706
- '10',
707
- '7',
708
- 'KG',
709
- '追蹤商品庫存',
710
- '13',
711
- '35',
712
- '001001001',
713
- ],
714
- [
715
- '產品1',
716
- '',
717
- '',
718
- '',
719
- 'image2',
720
- '',
721
- 'S',
722
- '',
723
- '長方形',
724
- '',
725
- '黑色',
726
- 'product-1-variant-2',
727
- '5000',
728
- '13000',
729
- '12000',
730
- '7000',
731
- '依重量計算',
732
- '10',
733
- '15',
734
- '10',
735
- '7',
736
- 'KG',
737
- '追蹤商品庫存',
738
- '13',
739
- '35',
740
- '001001002',
741
- ],
742
- [
743
- '產品1',
744
- '',
745
- '',
746
- '',
747
- 'image3',
748
- '',
749
- 'L',
750
- '',
751
- '正方形',
752
- '',
753
- '黑色',
754
- 'product-1-variant-3',
755
- '4300',
756
- '12000',
757
- '11000',
758
- '7000',
759
- '依重量計算',
760
- '10',
761
- '10',
762
- '10',
763
- '6',
764
- 'KG',
765
- '追蹤商品庫存',
766
- '13',
767
- '35',
768
- '001001003',
769
- ],
770
- [
771
- '產品2',
772
- '啟用',
773
- '商品',
774
- '工具/餐具',
775
- 'image1-1',
776
- 'SEO標題',
777
- 'SEO內文',
778
- 'SEO關鍵字',
779
- '材質',
780
- '木頭',
781
- '形狀',
782
- '長方形',
783
- '',
784
- '',
785
- 'product-2-variant-1',
786
- '700',
787
- '1300',
788
- '1200',
789
- '700',
790
- '依體積計算',
791
- '5',
792
- '5',
793
- '6',
794
- '2',
795
- 'KG',
796
- '不追蹤',
797
- '5',
798
- '35',
799
- '001002001',
800
- ],
801
- [
802
- '產品2',
803
- '',
804
- '',
805
- '工具/',
806
- 'image1-2',
807
- '',
808
- '金屬',
809
- '',
810
- '長方形',
811
- '',
812
- '',
813
- 'product-2-variant-2',
814
- '700',
815
- '1300',
816
- '1200',
817
- '700',
818
- '依體積計算',
819
- '5',
820
- '5',
821
- '6',
822
- '3',
823
- 'KG',
824
- '不追蹤',
825
- '5',
826
- '35',
827
- '001002002',
828
- ],
829
- ];
830
- excel.exportData(sample, '商品詳細列表_範例').then(() => {
831
- dialog.successMessage({ text: '匯出成功' });
832
- });
190
+ excel.exportData(ProductExcel.exampleSheet(), `範例_商品詳細列表_${ProductExcel.getFileTime()}`);
833
191
  })}"
834
192
  >
835
193
  下載範例
@@ -1025,143 +383,63 @@ export class ShoppingProductSetting {
1025
383
 
1026
384
  ApiShop.getProduct(getFormData).then((response) => {
1027
385
  dialog.dataLoading({ visible: false });
1028
- let exportData: any = [];
1029
- response.response.data.map((productData: any) => {
1030
- let rowData: {
1031
- id: string;
1032
- name: string;
1033
- status: string;
1034
- category: string;
1035
- productType: string;
1036
- img: string;
1037
- SEO_title: string;
1038
- SEO_desc: string;
1039
- SEO_keyword: string;
1040
- spec1: string;
1041
- spec1Value: string;
1042
- spec2: string;
1043
- spec2Value: string;
1044
- spec3: string;
1045
- spec3Value: string;
1046
- sku: string;
1047
- cost: string;
1048
- sale_price: string;
1049
- compare_price: string;
1050
- benefit: string;
1051
- shipment_type: string;
1052
- length: string;
1053
- width: string;
1054
- height: string;
1055
- weight: string;
1056
- weightUnit: string;
1057
- stockPolicy: string;
1058
- stock: string;
1059
- save_stock: string;
1060
- barcode: string;
1061
- } = {
1062
- id: '',
1063
- name: productData.content.title ?? '未命名商品',
1064
- status: '',
1065
- category: '',
1066
- productType: ``,
1067
- img: '',
1068
- SEO_title: '',
1069
- SEO_desc: '',
1070
- SEO_keyword: '',
1071
- spec1: '',
1072
- spec1Value: '',
1073
- spec2: '',
1074
- spec2Value: '',
1075
- spec3: '',
1076
- spec3Value: '',
1077
- sku: '',
1078
- cost: '',
1079
- sale_price: '',
1080
- compare_price: '',
1081
- benefit: '',
1082
- shipment_type: '',
1083
- length: '',
1084
- width: '',
1085
- height: '',
1086
- weight: '',
1087
- weightUnit: '',
1088
- stockPolicy: '',
1089
- stock: '',
1090
- save_stock: '',
1091
- barcode: '',
1092
- };
386
+ const expo = new ProductExcel(gvc, excelHeader, Object.keys(rowInitData));
387
+ let exportData: any[] = [];
1093
388
 
1094
- productData.content.variants.map((variant: any, index: number) => {
1095
- if (index == 0) {
1096
- rowData.SEO_title = productData.content?.seo?.title ?? '';
1097
- rowData.SEO_desc = productData.content?.seo?.content ?? '';
1098
- rowData.SEO_keyword = productData.content?.seo?.keyword ?? '';
1099
- rowData.category = productData.content.collection.join(' , ') ?? '';
1100
- rowData.productType = `${productData.content?.productType?.product ? '商品' : ''} ${
1101
- productData.content?.productType?.addProduct ? '加購品' : ''
1102
- } ${productData.content?.productType?.giveaway ? '贈品' : ''}`;
1103
- rowData.status = productData.content?.status == 'active' ? '上架' : '下架';
1104
- rowData.spec1 = productData.content?.specs[0]?.title ?? '';
1105
- rowData.spec2 = productData.content?.specs[1]?.title ?? '';
1106
- rowData.spec3 = productData.content?.specs[2]?.title ?? '';
1107
- rowData.img = productData.content.preview_image[0];
1108
- } else {
1109
- rowData.category = ``;
1110
- rowData.productType = ``;
1111
- rowData.status = ``;
1112
- rowData.spec1 = '';
1113
- rowData.spec2 = '';
1114
- rowData.spec3 = '';
1115
- rowData.img = '';
1116
- rowData.SEO_title = '';
1117
- rowData.SEO_desc = '';
1118
- rowData.SEO_keyword = '';
1119
- }
1120
- rowData.img = rowData.img ?? variant.preview_image ?? '';
1121
- rowData.spec1Value = variant.spec[0] ?? '';
1122
- rowData.spec2Value = variant.spec[1] ?? '';
1123
- rowData.spec3Value = variant.spec[2] ?? '';
1124
- rowData.sku = variant.sku ?? '';
1125
- rowData.cost = variant.cost ?? '';
1126
- rowData.sale_price = variant.sale_price ?? '';
1127
- rowData.benefit = variant.profit ?? '';
1128
- rowData.compare_price = variant.compare_price ?? '';
1129
- rowData.width = variant?.v_width ?? '0';
1130
- rowData.height = variant?.v_height ?? '0';
1131
- rowData.length = variant?.v_length ?? '0';
1132
- rowData.weight = variant.weight ?? '0';
1133
- rowData.weightUnit = variant.weightUnit ?? 'KG';
1134
- rowData.stockPolicy = variant.show_understocking ? '追蹤' : '不追蹤';
1135
- rowData.stock = variant.stock ?? '0';
1136
- rowData.save_stock = variant.save_stock ?? '0';
1137
- rowData.barcode = variant.barcode ?? '';
1138
- rowData.id = productData.content.id;
1139
- if (variant.shipment_type) {
1140
- switch (variant.shipment_type) {
1141
- case 'volume': {
1142
- rowData.shipment_type = '依材積計算';
1143
- break;
1144
- }
1145
- case 'none': {
1146
- rowData.shipment_type = '不計算運費';
1147
- break;
1148
- }
1149
- default: {
1150
- rowData.shipment_type = '依重量計算';
1151
- }
1152
- }
1153
- } else {
1154
- rowData.shipment_type = '依重量計算';
389
+ response.response.data.forEach((productData: any) => {
390
+ const baseRowData = (index: number): RowInitData => ({
391
+ id: index === 0 ? productData.content.id || '' : '',
392
+ name: index === 0 ? productData.content.title || '未命名商品' : '',
393
+ status: index === 0 ? (productData.content?.status === 'active' ? '啟用' : '草稿') : '',
394
+ category: index === 0 ? expo.checkString(productData.content.collection.join(' , ')) : '',
395
+ productType:
396
+ index === 0 ? expo.checkString(this.getProductTypeString(productData.content)) : '',
397
+ img: index === 0 ? expo.checkString(productData.content.preview_image[0]) : '',
398
+ SEO_domain: index === 0 ? expo.checkString(productData.content?.seo?.domain) : '',
399
+ SEO_title: index === 0 ? expo.checkString(productData.content?.seo?.title) : '',
400
+ SEO_desc: index === 0 ? expo.checkString(productData.content?.seo?.content) : '',
401
+ spec1: index === 0 ? expo.checkString(productData.content?.specs[0]?.title) : '',
402
+ spec1Value: expo.checkString(productData.content.variants[index]?.spec[0]),
403
+ spec2: index === 0 ? expo.checkString(productData.content?.specs[1]?.title) : '',
404
+ spec2Value: expo.checkString(productData.content.variants[index]?.spec[1]),
405
+ spec3: index === 0 ? expo.checkString(productData.content?.specs[2]?.title) : '',
406
+ spec3Value: expo.checkString(productData.content.variants[index]?.spec[2]),
407
+ sku: expo.checkString(productData.content.variants[index]?.sku),
408
+ cost: expo.checkNumber(productData.content.variants[index]?.cost),
409
+ sale_price: expo.checkNumber(productData.content.variants[index]?.sale_price),
410
+ compare_price: expo.checkNumber(productData.content.variants[index]?.compare_price),
411
+ benefit: expo.checkNumber(productData.content.variants[index]?.profit),
412
+ shipment_type: getShipmentType(productData.content.variants[index]?.shipment_type),
413
+ length: expo.checkNumber(productData.content.variants[index]?.v_length || 0),
414
+ width: expo.checkNumber(productData.content.variants[index]?.v_width || 0),
415
+ height: expo.checkNumber(productData.content.variants[index]?.v_height || 0),
416
+ weight: expo.checkNumber(productData.content.variants[index]?.weight || 0),
417
+ weightUnit: expo.checkString(productData.content.variants[index]?.weightUnit || 'KG'),
418
+ stockPolicy:
419
+ productData.content.variants[index]?.show_understocking === 'true' ? '追蹤' : '不追蹤',
420
+ stock: expo.checkNumber(productData.content.variants[index]?.stock),
421
+ save_stock: expo.checkNumber(productData.content.variants[index]?.save_stock),
422
+ barcode: expo.checkString(productData.content.variants[index]?.barcode),
423
+ });
424
+
425
+ const getShipmentType = (type: string) => {
426
+ switch (type) {
427
+ case 'volume':
428
+ return '依材積計算';
429
+ case 'none':
430
+ return '不計算運費';
431
+ default:
432
+ return '依重量計算';
1155
433
  }
434
+ };
1156
435
 
1157
- exportData.push(JSON.parse(JSON.stringify(rowData)));
436
+ productData.content.variants.forEach((variant: any, index: number) => {
437
+ const rowData = baseRowData(index);
438
+ exportData.push(rowData);
1158
439
  });
1159
440
  });
1160
- ``;
1161
441
 
1162
- excel.exportData(exportData, `商品詳細列表_${Excel.getFileTime()}`).then(() => {
1163
- dialog.successMessage({ text: '匯出成功' });
1164
- });
442
+ expo.exportData(exportData, `商品詳細列表_${ProductExcel.getFileTime()}`);
1165
443
  });
1166
444
  }),
1167
445
  '匯出'
@@ -1369,7 +647,7 @@ export class ShoppingProductSetting {
1369
647
  BgWidget.switchTextButton(
1370
648
  gvc,
1371
649
  dd.content.status === 'active',
1372
- { left: dd.content.status === 'active' ? '上架' : '下架' },
650
+ { left: dd.content.status === 'active' ? '啟用' : '草稿' },
1373
651
  (bool) => {
1374
652
  dd.content.status = bool ? 'active' : 'draft';
1375
653
  ApiPost.put({
@@ -1382,8 +660,8 @@ export class ShoppingProductSetting {
1382
660
  }
1383
661
  );
1384
662
  return dd.content.status === 'active'
1385
- ? BgWidget.successInsignia('上架')
1386
- : BgWidget.secondaryInsignia('下架');
663
+ ? BgWidget.successInsignia('啟用')
664
+ : BgWidget.secondaryInsignia('草稿');
1387
665
  },
1388
666
  divCreate: {
1389
667
  option: [
@@ -1419,7 +697,7 @@ export class ShoppingProductSetting {
1419
697
  },
1420
698
  filter: [
1421
699
  {
1422
- name: '上架',
700
+ name: '啟用',
1423
701
  event: (checkedData) => {
1424
702
  const selCount = checkedData.length;
1425
703
  dialog.dataLoading({ visible: true });
@@ -1451,7 +729,7 @@ export class ShoppingProductSetting {
1451
729
  option: true,
1452
730
  },
1453
731
  {
1454
- name: '下架',
732
+ name: '草稿',
1455
733
  event: (checkedData) => {
1456
734
  const selCount = checkedData.length;
1457
735
  dialog.dataLoading({ visible: true });
@@ -1557,6 +835,7 @@ export class ShoppingProductSetting {
1557
835
  divCreate: {
1558
836
  class: `w-100 h-100`,
1559
837
  },
838
+ onCreate: () => {},
1560
839
  };
1561
840
  });
1562
841
  }
@@ -4977,8 +4256,6 @@ ${postMD.seo.content ?? ''}</textarea
4977
4256
  } else {
4978
4257
  ShoppingProductSetting.postEvent(postMD, obj.gvc, obj.vm);
4979
4258
  }
4980
- } else {
4981
- // const dialog = new ShareDialog(gvc.glitter)
4982
4259
  }
4983
4260
  }, 500);
4984
4261
  }),