ts-glitter 20.6.8 → 20.6.9

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 (160) hide show
  1. package/lowcode/Entry.js +2 -2
  2. package/lowcode/Entry.ts +2 -2
  3. package/lowcode/backend-manager/bg-blog.js +617 -621
  4. package/lowcode/backend-manager/bg-blog.ts +2323 -2325
  5. package/lowcode/backend-manager/bg-line.js +5 -4
  6. package/lowcode/backend-manager/bg-line.ts +5 -4
  7. package/lowcode/backend-manager/bg-list-component.js +9 -0
  8. package/lowcode/backend-manager/bg-list-component.ts +15 -1
  9. package/lowcode/backend-manager/bg-notify.js +6 -4
  10. package/lowcode/backend-manager/bg-notify.ts +6 -4
  11. package/lowcode/backend-manager/bg-product.js +145 -0
  12. package/lowcode/backend-manager/bg-product.ts +153 -0
  13. package/lowcode/backend-manager/bg-sns.js +5 -3
  14. package/lowcode/backend-manager/bg-sns.ts +5 -3
  15. package/lowcode/backend-manager/bg-widget.js +92 -4
  16. package/lowcode/backend-manager/bg-widget.ts +122 -6
  17. package/lowcode/backend-manager/splitPage.js +0 -39
  18. package/lowcode/backend-manager/splitPage.ts +0 -40
  19. package/lowcode/cms-plugin/auto-fcm-advertise.js +17 -5
  20. package/lowcode/cms-plugin/auto-fcm-advertise.ts +19 -6
  21. package/lowcode/cms-plugin/auto-fcm-history.js +2732 -0
  22. package/lowcode/cms-plugin/auto-fcm-history.ts +2995 -0
  23. package/lowcode/cms-plugin/cms-router.js +5 -0
  24. package/lowcode/cms-plugin/cms-router.ts +6 -0
  25. package/lowcode/cms-plugin/filter-options.js +80 -27
  26. package/lowcode/cms-plugin/filter-options.ts +83 -27
  27. package/lowcode/cms-plugin/language-backend.js +50 -39
  28. package/lowcode/cms-plugin/language-backend.ts +109 -95
  29. package/lowcode/cms-plugin/menus-setting.js +175 -151
  30. package/lowcode/cms-plugin/menus-setting.ts +620 -591
  31. package/lowcode/cms-plugin/model/order.d.ts +1 -0
  32. package/lowcode/cms-plugin/module/data.js +7 -7
  33. package/lowcode/cms-plugin/module/data.ts +262 -233
  34. package/lowcode/cms-plugin/module/delivery-html.js +18 -10
  35. package/lowcode/cms-plugin/module/delivery-html.ts +26 -10
  36. package/lowcode/cms-plugin/module/order-setting.js +458 -328
  37. package/lowcode/cms-plugin/module/order-setting.ts +622 -351
  38. package/lowcode/cms-plugin/module/product-excel.js +1 -1
  39. package/lowcode/cms-plugin/module/product-excel.ts +2 -1
  40. package/lowcode/cms-plugin/order/order-module.js +90 -1
  41. package/lowcode/cms-plugin/order/order-module.ts +106 -1
  42. package/lowcode/cms-plugin/pos-pages/payment-page.js +11 -8
  43. package/lowcode/cms-plugin/pos-pages/payment-page.ts +28 -15
  44. package/lowcode/cms-plugin/pos-pages/products-page.js +0 -39
  45. package/lowcode/cms-plugin/pos-pages/products-page.ts +0 -40
  46. package/lowcode/cms-plugin/shopping-collections.ts +1 -3
  47. package/lowcode/cms-plugin/shopping-finance-setting.js +19 -80
  48. package/lowcode/cms-plugin/shopping-finance-setting.ts +19 -87
  49. package/lowcode/cms-plugin/shopping-order-manager.js +122 -38
  50. package/lowcode/cms-plugin/shopping-order-manager.ts +160 -58
  51. package/lowcode/cms-plugin/shopping-product-setting.js +364 -376
  52. package/lowcode/cms-plugin/shopping-product-setting.ts +406 -415
  53. package/lowcode/cms-plugin/shopping-setting-advance.js +57 -16
  54. package/lowcode/cms-plugin/shopping-setting-advance.ts +69 -18
  55. package/lowcode/cms-plugin/user/user-module.js +2 -43
  56. package/lowcode/cms-plugin/user/user-module.ts +2 -46
  57. package/lowcode/cms-plugin/user-list.js +4 -6
  58. package/lowcode/cms-plugin/user-list.ts +35 -38
  59. package/lowcode/css/editor.css +42 -3
  60. package/lowcode/glitter-base/global/language.js +6 -1
  61. package/lowcode/glitter-base/global/language.ts +10 -4
  62. package/lowcode/glitter-base/global/payment-config.js +19 -16
  63. package/lowcode/glitter-base/global/payment-config.ts +22 -16
  64. package/lowcode/glitter-base/global/shipment-config.js +6 -5
  65. package/lowcode/glitter-base/global/shipment-config.ts +12 -10
  66. package/lowcode/glitter-base/route/fcm.js +21 -1
  67. package/lowcode/glitter-base/route/fcm.ts +22 -2
  68. package/lowcode/glitter-base/route/shopping.js +8 -32
  69. package/lowcode/glitter-base/route/shopping.ts +10 -33
  70. package/lowcode/glitter-base/route/user.js +11 -2
  71. package/lowcode/glitter-base/route/user.ts +23 -12
  72. package/lowcode/jspage/function-page/setting_editor.js +9 -0
  73. package/lowcode/jspage/function-page/setting_editor.ts +9 -0
  74. package/lowcode/public-components/blogs/list.js +223 -195
  75. package/lowcode/public-components/blogs/list.ts +383 -352
  76. package/lowcode/public-components/product/product-list.js +8 -4
  77. package/lowcode/public-components/product/product-list.ts +9 -4
  78. package/lowcode/public-components/terms-related/index.js +1 -1
  79. package/lowcode/public-components/terms-related/index.ts +1 -1
  80. package/lowcode/public-components/user-manager/um-login.js +1 -1
  81. package/lowcode/public-components/user-manager/um-login.ts +2 -2
  82. package/lowcode/public-components/user-manager/um-order.js +41 -5
  83. package/lowcode/public-components/user-manager/um-order.ts +58 -20
  84. package/lowcode/public-components/user-manager/um-voucher.ts +2 -2
  85. package/nhi4veq3gk.json +1 -0
  86. package/package.json +1 -1
  87. package/src/Language.d.ts +2 -0
  88. package/src/Language.js +66 -65
  89. package/src/Language.js.map +1 -1
  90. package/src/Language.ts +719 -715
  91. package/src/api-public/config/shipment-config.js +3 -2
  92. package/src/api-public/config/shipment-config.js.map +1 -1
  93. package/src/api-public/config/shipment-config.ts +3 -2
  94. package/src/api-public/controllers/ai-chat.js.map +1 -1
  95. package/src/api-public/controllers/ai-chat.ts +1 -2
  96. package/src/api-public/controllers/fcm.js +23 -58
  97. package/src/api-public/controllers/fcm.js.map +1 -1
  98. package/src/api-public/controllers/fcm.ts +28 -56
  99. package/src/api-public/controllers/shop.js +7 -1
  100. package/src/api-public/controllers/shop.js.map +1 -1
  101. package/src/api-public/controllers/shop.ts +17 -10
  102. package/src/api-public/controllers/user.js +1 -0
  103. package/src/api-public/controllers/user.js.map +1 -1
  104. package/src/api-public/controllers/user.ts +2 -0
  105. package/src/api-public/services/auto-send-email.js +247 -187
  106. package/src/api-public/services/auto-send-email.js.map +1 -1
  107. package/src/api-public/services/auto-send-email.ts +568 -505
  108. package/src/api-public/services/delivery.js +1 -1
  109. package/src/api-public/services/delivery.js.map +1 -1
  110. package/src/api-public/services/delivery.ts +6 -5
  111. package/src/api-public/services/financial-service.js +1 -2
  112. package/src/api-public/services/financial-service.js.map +1 -1
  113. package/src/api-public/services/financial-service.ts +4 -6
  114. package/src/api-public/services/manager.d.ts +4 -3
  115. package/src/api-public/services/manager.js +8 -12
  116. package/src/api-public/services/manager.js.map +1 -1
  117. package/src/api-public/services/manager.ts +57 -59
  118. package/src/api-public/services/model/handlePaymentTransaction.d.ts +1 -1
  119. package/src/api-public/services/model/handlePaymentTransaction.js +23 -3
  120. package/src/api-public/services/model/handlePaymentTransaction.js.map +1 -1
  121. package/src/api-public/services/model/handlePaymentTransaction.ts +25 -36
  122. package/src/api-public/services/schedule.d.ts +1 -0
  123. package/src/api-public/services/schedule.js +27 -0
  124. package/src/api-public/services/schedule.js.map +1 -1
  125. package/src/api-public/services/schedule.ts +30 -0
  126. package/src/api-public/services/shopping.d.ts +22 -2
  127. package/src/api-public/services/shopping.js +362 -90
  128. package/src/api-public/services/shopping.js.map +1 -1
  129. package/src/api-public/services/shopping.ts +481 -134
  130. package/src/api-public/services/user.d.ts +1 -0
  131. package/src/api-public/services/user.js +32 -12
  132. package/src/api-public/services/user.js.map +1 -1
  133. package/src/api-public/services/user.ts +38 -19
  134. package/src/api-public/services/workers.js +3 -3
  135. package/src/api-public/services/workers.js.map +1 -1
  136. package/src/api-public/services/workers.ts +103 -103
  137. package/src/app-project/serverless/src/modules/database.js +1 -1
  138. package/src/app-project/serverless/src/modules/database.js.map +1 -1
  139. package/src/app-project/serverless/src/modules/database.ts +171 -171
  140. package/src/controllers/template.d.ts +1 -1
  141. package/src/controllers/template.js +16 -16
  142. package/src/controllers/template.js.map +1 -1
  143. package/src/controllers/template.ts +98 -84
  144. package/src/modules/database.js +3 -1
  145. package/src/modules/database.js.map +1 -1
  146. package/src/modules/database.ts +185 -181
  147. package/src/modules/firebase.d.ts +17 -0
  148. package/src/modules/firebase.js +126 -0
  149. package/src/modules/firebase.js.map +1 -1
  150. package/src/modules/firebase.ts +169 -0
  151. package/src/public-config-initial/auto-fcm.js +8 -2
  152. package/src/public-config-initial/auto-fcm.js.map +1 -1
  153. package/src/public-config-initial/auto-fcm.ts +15 -6
  154. package/src/services/app.d.ts +2 -1
  155. package/src/services/app.js.map +1 -1
  156. package/src/services/app.ts +2 -1
  157. package/src/services/template.d.ts +3 -2
  158. package/src/services/template.js +2 -1
  159. package/src/services/template.js.map +1 -1
  160. package/src/services/template.ts +13 -20
@@ -0,0 +1,2995 @@
1
+ import { GVC } from '../glitterBundle/GVController.js';
2
+ import { BgWidget } from '../backend-manager/bg-widget.js';
3
+ import { ApiUser } from '../glitter-base/route/user.js';
4
+ import { EditorElem } from '../glitterBundle/plugins/editor-elem.js';
5
+ import { ShareDialog } from '../glitterBundle/dialog/ShareDialog.js';
6
+ import { ApiPost } from '../glitter-base/route/post.js';
7
+ import { ApiFcm } from '../glitter-base/route/fcm.js';
8
+ import { FormWidget } from '../official_view_component/official/form.js';
9
+ import { Chat } from '../glitter-base/route/chat.js';
10
+ import { FilterOptions } from '../cms-plugin/filter-options.js';
11
+ import { ShoppingDiscountSetting } from '../cms-plugin/shopping-discount-setting.js';
12
+ import { ApiSmtp } from '../glitter-base/route/smtp.js';
13
+ import { BgListComponent } from '../backend-manager/bg-list-component.js';
14
+ import { Tool } from '../modules/tool.js';
15
+
16
+ const html = String.raw;
17
+
18
+ interface EmailObject {
19
+ id: number;
20
+ email: string;
21
+ }
22
+
23
+ export type PostData = {
24
+ type: 'notify-sns-config';
25
+ tag: string;
26
+ tagList: { tag: string; filter: any; valueString: string }[];
27
+ userList: EmailObject[];
28
+ name: string;
29
+ boolean: 'and' | 'or';
30
+ title: string;
31
+ content: string;
32
+ sendTime: { date: string; time: string } | undefined;
33
+ sendGroup: string[];
34
+ email?: string[];
35
+ phone?: string[];
36
+ typeName?: string;
37
+ };
38
+
39
+ const inputStyle = 'font-size: 16px; height:40px; width:300px;';
40
+
41
+ export class BgNotify {
42
+ public static email(gvc: GVC, type: 'list' | 'select' = 'list', callback: (select: any) => void = () => {}) {
43
+ const vm: {
44
+ type: 'list' | 'replace';
45
+ data: any;
46
+ dataList: any;
47
+ query?: string;
48
+ } = {
49
+ type: 'list',
50
+ data: {
51
+ id: 61,
52
+ userID: 549313940,
53
+ account: 'jianzhi.wang@homee.ai',
54
+ userData: { name: '王建智', email: 'jianzhi.wang@homee.ai', phone: '0978028739' },
55
+ created_time: '2023-11-26T02:14:09.000Z',
56
+ role: 0,
57
+ company: null,
58
+ status: 1,
59
+ },
60
+ dataList: undefined,
61
+ query: '',
62
+ };
63
+ const glitter = gvc.glitter;
64
+ const filterID = glitter.getUUID();
65
+ const id = glitter.getUUID();
66
+ return gvc.bindView(() => {
67
+ return {
68
+ bind: id,
69
+ view: () => {
70
+ let vmi: any = undefined;
71
+ function getDatalist() {
72
+ let interval: any = 0;
73
+ return vm.dataList.map((dd: any) => {
74
+ return [
75
+ {
76
+ key: '註冊信箱',
77
+ value: `<span class="fs-7">${dd.email}</span>`,
78
+ },
79
+ {
80
+ key: '訂閱標籤',
81
+ value: `<span class="fs-7">${dd.tag}</span>`,
82
+ },
83
+ ];
84
+ });
85
+ }
86
+
87
+ return BgWidget.container(
88
+ BgWidget.mainCard(
89
+ [
90
+ BgWidget.searchPlace(
91
+ gvc.event(e => {
92
+ vm.query = e.value;
93
+ gvc.notifyDataChange(id);
94
+ }),
95
+ vm.query || '',
96
+ '搜尋信箱或標籤'
97
+ ),
98
+ BgWidget.tableV3({
99
+ gvc: gvc,
100
+ getData: vmk => {
101
+ vmi = vmk;
102
+ const limit = 20;
103
+ ApiUser.getSubScribe({
104
+ page: vmi.page - 1,
105
+ limit: limit,
106
+ search: vm.query || undefined,
107
+ filter: { account: 'no' },
108
+ }).then(data => {
109
+ vm.dataList = data.response.data;
110
+ vmi.pageSize = Math.ceil(data.response.total / limit);
111
+ vmi.originalData = vm.dataList;
112
+ vmi.tableData = getDatalist();
113
+ vmi.loading = false;
114
+ vmi.callback();
115
+
116
+ if (type === 'select') {
117
+ callback(
118
+ vm.dataList.filter((dd: any) => {
119
+ return dd.checked;
120
+ })
121
+ );
122
+ }
123
+ });
124
+ },
125
+ rowClick: (data, index) => {
126
+ vm.dataList[index].checked = !vm.dataList[index].checked;
127
+ vmi.data = getDatalist();
128
+ vmi.callback();
129
+ gvc.notifyDataChange(filterID);
130
+ callback(
131
+ vm.dataList.filter((dd: any) => {
132
+ return dd.checked;
133
+ })
134
+ );
135
+ },
136
+ filter: [
137
+ {
138
+ name: '批量移除',
139
+ event: checkedData => {
140
+ const dialog = new ShareDialog(glitter);
141
+ dialog.checkYesOrNot({
142
+ text: '是否確認刪除所選項目?',
143
+ callback: response => {
144
+ if (response) {
145
+ dialog.dataLoading({ visible: true });
146
+ ApiUser.deleteSubscribe({
147
+ email: checkedData.map((dd: any) => dd.email).join(`,`),
148
+ }).then(res => {
149
+ dialog.dataLoading({ visible: false });
150
+ if (res.result) {
151
+ vm.dataList = undefined;
152
+ gvc.notifyDataChange(id);
153
+ } else {
154
+ dialog.errorMessage({ text: '刪除失敗' });
155
+ }
156
+ });
157
+ }
158
+ },
159
+ });
160
+ },
161
+ },
162
+ ],
163
+ }),
164
+ ].join('')
165
+ )
166
+ );
167
+ },
168
+ };
169
+ });
170
+ }
171
+
172
+ public static emailSetting(gvc: GVC) {
173
+ const glitter = gvc.glitter;
174
+ const vm: {
175
+ type: 'list' | 'add' | 'replace';
176
+ data: any;
177
+ dataList: any;
178
+ query?: string;
179
+ } = {
180
+ type: 'list',
181
+ data: undefined,
182
+ dataList: undefined,
183
+ query: undefined,
184
+ };
185
+ return gvc.bindView(() => {
186
+ const id = glitter.getUUID();
187
+ const filterID = glitter.getUUID();
188
+ return {
189
+ bind: id,
190
+ dataList: [{ obj: vm, key: 'type' }],
191
+ view: () => {
192
+ if (vm.type === 'list') {
193
+ return BgWidget.container(html`
194
+ <div class="title-container">
195
+ ${BgWidget.title('信件樣式')}
196
+ <div class="flex-fill"></div>
197
+ ${BgWidget.darkButton(
198
+ '新增',
199
+ gvc.event(() => {
200
+ vm.data = undefined;
201
+ vm.type = 'add';
202
+ })
203
+ )}
204
+ </div>
205
+ ${BgWidget.container(
206
+ BgWidget.mainCard(
207
+ [
208
+ BgWidget.searchPlace(
209
+ gvc.event(e => {
210
+ vm.query = e.value;
211
+ gvc.notifyDataChange(id);
212
+ }),
213
+ vm.query || '',
214
+ '搜尋所有信件內容'
215
+ ),
216
+ BgWidget.tableV3({
217
+ gvc: gvc,
218
+ getData: vmi => {
219
+ const limit = 20;
220
+ ApiPost.getManagerPost({
221
+ page: vmi.page - 1,
222
+ limit: limit,
223
+ search: vm.query ? [`title->${vm.query}`] : undefined,
224
+ type: 'notify-email-config',
225
+ }).then(data => {
226
+ function getDatalist() {
227
+ return data.response.data.map((dd: any) => {
228
+ return [
229
+ {
230
+ key: '標題',
231
+ value: html`<span class="fs-7">${dd.content.title}</span>`,
232
+ },
233
+ {
234
+ key: '最後更新時間',
235
+ value: dd.updated_time
236
+ ? gvc.glitter.ut.dateFormat(new Date(dd.updated_time), 'yyyy-MM-dd')
237
+ : '無',
238
+ },
239
+ ];
240
+ });
241
+ }
242
+ vm.dataList = data.response.data;
243
+ vmi.pageSize = Math.ceil(data.response.total / limit);
244
+ vmi.originalData = vm.dataList;
245
+ vmi.tableData = getDatalist();
246
+ vmi.loading = false;
247
+ vmi.callback();
248
+ });
249
+ },
250
+ rowClick: (data, index) => {
251
+ vm.data = vm.dataList[index].content;
252
+ vm.type = 'replace';
253
+ },
254
+ filter: [
255
+ {
256
+ name: '批量移除',
257
+ event: checkedData => {
258
+ const dialog = new ShareDialog(glitter);
259
+ dialog.checkYesOrNot({
260
+ text: '是否確認刪除所選項目?',
261
+ callback: response => {
262
+ if (response) {
263
+ dialog.dataLoading({ visible: true });
264
+ ApiPost.delete({
265
+ id: checkedData.map((dd: any) => dd.id).join(`,`),
266
+ }).then(res => {
267
+ dialog.dataLoading({ visible: false });
268
+ if (res.result) {
269
+ vm.dataList = undefined;
270
+ gvc.notifyDataChange(id);
271
+ } else {
272
+ dialog.errorMessage({ text: '刪除失敗' });
273
+ }
274
+ });
275
+ }
276
+ },
277
+ });
278
+ },
279
+ },
280
+ ],
281
+ }),
282
+ ].join('')
283
+ )
284
+ )}
285
+ ${BgWidget.mbContainer(120)}
286
+ `);
287
+ } else if (vm.type == 'replace') {
288
+ return this.emailEditor({
289
+ vm: vm,
290
+ gvc: gvc,
291
+ type: 'replace',
292
+ });
293
+ }
294
+ return this.emailEditor({
295
+ vm: vm,
296
+ gvc: gvc,
297
+ type: 'add',
298
+ });
299
+ },
300
+ };
301
+ });
302
+ }
303
+
304
+ public static emailHistory(gvc: GVC) {
305
+ const glitter = gvc.glitter;
306
+ const vm: {
307
+ id: string;
308
+ tableId: string;
309
+ type: 'list' | 'add' | 'replace';
310
+ data: any;
311
+ dataList: any;
312
+ query?: string;
313
+ queryType?: string;
314
+ filter?: any;
315
+ } = {
316
+ id: glitter.getUUID(),
317
+ tableId: glitter.getUUID(),
318
+ type: 'list',
319
+ data: undefined,
320
+ dataList: undefined,
321
+ query: '',
322
+ queryType: 'email',
323
+ filter: {},
324
+ };
325
+ return gvc.bindView(() => {
326
+ const ListComp = new BgListComponent(gvc, vm, FilterOptions.emailFilterFrame);
327
+ vm.filter = ListComp.getFilterObject();
328
+ return {
329
+ bind: vm.id,
330
+ dataList: [{ obj: vm, key: 'type' }],
331
+ view: () => {
332
+ if (vm.type === 'list') {
333
+ return BgWidget.container(html`
334
+ <div class="title-container">
335
+ ${BgWidget.title('推播紀錄')}
336
+ <div class="flex-fill"></div>
337
+ </div>
338
+ ${BgWidget.container(
339
+ BgWidget.mainCard(
340
+ [
341
+ (() => {
342
+ const id = glitter.getUUID();
343
+ return gvc.bindView({
344
+ bind: id,
345
+ view: () => {
346
+ const filterList = [
347
+ BgWidget.searchFilter(
348
+ gvc.event(e => {
349
+ vm.query = `${e.value}`.trim();
350
+ gvc.notifyDataChange(vm.tableId);
351
+ gvc.notifyDataChange(id);
352
+ }),
353
+ vm.query || '',
354
+ '搜尋所有信件內容'
355
+ ),
356
+ BgWidget.funnelFilter({
357
+ gvc,
358
+ callback: () => {
359
+ return ListComp.showRightMenu(FilterOptions.emailFunnel);
360
+ },
361
+ }),
362
+ ];
363
+
364
+ const filterTags = ListComp.getFilterTags(FilterOptions.emailFunnel);
365
+ return BgListComponent.listBarRWD(filterList, filterTags);
366
+ },
367
+ });
368
+ })(),
369
+ gvc.bindView({
370
+ bind: vm.tableId,
371
+ view: () => {
372
+ return BgWidget.tableV3({
373
+ gvc: gvc,
374
+ getData: vmi => {
375
+ const limit = 20;
376
+ ApiFcm.history({
377
+ page: vmi.page - 1,
378
+ limit: limit,
379
+ search: vm.query ?? '',
380
+ searchType: vm.queryType ?? 'email',
381
+ sendTime: undefined,
382
+ status: vm.filter.status,
383
+ mailType: vm.filter.mailType,
384
+ }).then(data => {
385
+ if (data.result) {
386
+ function getDatalist() {
387
+ return data.response.data.map(
388
+ (dd: { content: PostData; status: number; trigger_time: string }) => {
389
+ return [
390
+ {
391
+ key: '寄件類型',
392
+ value: html`<span class="fs-7">${dd.content.typeName}</span>`,
393
+ },
394
+ {
395
+ key: '標題',
396
+ value: html`<span class="fs-7"
397
+ >${Tool.truncateString(
398
+ `${dd.content.title}`,
399
+ 25
400
+ )}</span
401
+ >`,
402
+ },
403
+ {
404
+ key: '收件群組',
405
+ value: html`<span class="fs-7"
406
+ >${(() => {
407
+ if (!dd.content.sendGroup) {
408
+ return '沒有群組';
409
+ }
410
+ const lengthLimit = 25;
411
+ const tagList = [];
412
+ for (const group of dd.content.sendGroup) {
413
+ const tagLength = tagList.join('').length;
414
+ if (tagLength + group.length > lengthLimit) {
415
+ tagList.push(Tool.truncateString(group, tagLength));
416
+ break;
417
+ } else {
418
+ tagList.push(group);
419
+ }
420
+ }
421
+ return tagList.join(
422
+ html`<span
423
+ class="badge fs-7 mx-1 px-1"
424
+ style="color: #393939; background: #FFD5D0;"
425
+ >${dd.content.boolean === 'and' ? '且' : '或'}</span
426
+ >`
427
+ );
428
+ })()}</span
429
+ >`,
430
+ },
431
+ {
432
+ key: '寄送時間',
433
+ value: dd.trigger_time
434
+ ? gvc.glitter.ut.dateFormat(new Date(dd.trigger_time), 'yyyy-MM-dd hh:mm')
435
+ : '無',
436
+ },
437
+ {
438
+ key: '寄送狀態',
439
+ value: (() => {
440
+ switch (dd.status) {
441
+ case 0:
442
+ return BgWidget.warningInsignia('尚未寄送');
443
+ case 1:
444
+ return BgWidget.infoInsignia('已寄出');
445
+ case 2:
446
+ return BgWidget.secondaryInsignia('取消寄送');
447
+ }
448
+ })(),
449
+ },
450
+ ];
451
+ }
452
+ );
453
+ }
454
+
455
+ vm.dataList = data.response.data;
456
+ vmi.pageSize = Math.ceil(data.response.total / limit);
457
+ vmi.originalData = vm.dataList;
458
+ vmi.tableData = getDatalist();
459
+ vmi.loading = false;
460
+ vmi.callback();
461
+ }
462
+ });
463
+ },
464
+ rowClick: (data, index) => {
465
+ // vm.dataList[index].content.status = vm.dataList[index].status;
466
+ // vm.data = vm.dataList[index].content;
467
+ // vm.data.id = vm.dataList[index].id;
468
+ // vm.type = 'replace';
469
+ },
470
+ filter: [],
471
+ });
472
+ },
473
+ }),
474
+ ].join('')
475
+ )
476
+ )}
477
+ ${BgWidget.mbContainer(120)}
478
+ `);
479
+ }
480
+ return this.emailEditor({
481
+ vm: vm,
482
+ gvc: gvc,
483
+ type: 'replace',
484
+ readonly: true,
485
+ });
486
+ },
487
+ };
488
+ });
489
+ }
490
+
491
+ public static emailEditor(obj: { vm: any; gvc: GVC; type?: 'add' | 'replace'; defData?: any; readonly?: boolean }) {
492
+ const gvc = obj.gvc;
493
+ const vm = obj.vm;
494
+ const dialog = new ShareDialog(gvc.glitter);
495
+ const postData: {
496
+ id: string;
497
+ content: string;
498
+ title: string;
499
+ type: 'notify-email-config';
500
+ name: string;
501
+ status?: number;
502
+ } = vm.data ?? {
503
+ content: '',
504
+ title: '',
505
+ type: 'notify-email-config',
506
+ name: '',
507
+ };
508
+
509
+ return BgWidget.container(html`
510
+ <div class="title-container">
511
+ ${BgWidget.goBack(
512
+ gvc.event(() => {
513
+ vm.type = 'list';
514
+ })
515
+ )}
516
+ ${BgWidget.title(obj.readonly ? '信件詳細內容' : '編輯信件樣式')}
517
+ <div class="flex-fill"></div>
518
+ ${obj.readonly
519
+ ? html`<div class="d-flex gap-2">
520
+ ${BgWidget.secondaryInsignia(vm.data.typeName)}
521
+ ${(() => {
522
+ switch (vm.data.status) {
523
+ case 0:
524
+ return BgWidget.warningInsignia('尚未寄送');
525
+ case 1:
526
+ return BgWidget.infoInsignia('已寄出');
527
+ case 2:
528
+ return BgWidget.secondaryInsignia('取消寄送');
529
+ }
530
+ })()}
531
+ </div>`
532
+ : ''}
533
+ </div>
534
+ ${BgWidget.mbContainer(18)}
535
+ ${BgWidget.container(
536
+ obj.gvc.bindView(() => {
537
+ const bi = obj.gvc.glitter.getUUID();
538
+ return {
539
+ bind: bi,
540
+ view: () => {
541
+ let htmlList: string[] = [];
542
+ if (obj.readonly) {
543
+ const sendGroupHTML = (vm.data.sendGroup ?? []).map(
544
+ (str: string) => html`<div class="c_filter_tag">${str}</div>`
545
+ );
546
+ const emailHTML = vm.data.email.map((str: string) => html`<div class="c_filter_tag">${str}</div>`);
547
+ htmlList = htmlList.concat([
548
+ BgWidget.mainCard(html`
549
+ <div class="tx_normal fw-normal">篩選條件</div>
550
+ <div class="c_filter_container">
551
+ ${sendGroupHTML.length === 0
552
+ ? '沒有群組'
553
+ : sendGroupHTML.join(
554
+ html`<span class="badge fs-7 px-1" style="color: #393939; background: #FFD5D0;"
555
+ >${vm.data.boolean === 'and' ? '且' : '或'}</span
556
+ >`
557
+ )}
558
+ </div>
559
+ `),
560
+ BgWidget.mainCard(html`
561
+ <div class="tx_normal fw-normal">電子信箱</div>
562
+ <div class="c_filter_container">${emailHTML.join('')}</div>
563
+ `),
564
+ BgWidget.mainCard(
565
+ html`<div class="tx_700 mb-3">發送時間</div>
566
+ ${EditorElem.radio({
567
+ gvc: gvc,
568
+ title: '',
569
+ def: vm.data.sendTime === undefined ? 'now' : 'set',
570
+ array: [
571
+ {
572
+ title: '立即發送',
573
+ value: 'now',
574
+ },
575
+ {
576
+ title: '排定發送時間',
577
+ value: 'set',
578
+ innerHtml: html`<div
579
+ class="d-flex mt-3 ${document.body.clientWidth < 768 ? 'flex-column' : ''}"
580
+ style="gap: 12px"
581
+ >
582
+ ${EditorElem.editeInput({
583
+ gvc: gvc,
584
+ title: '',
585
+ type: 'date',
586
+ style: inputStyle,
587
+ default: vm.data.sendTime ? vm.data.sendTime.date : '',
588
+ placeHolder: '',
589
+ callback: () => {},
590
+ readonly: true,
591
+ })}
592
+ ${EditorElem.editeInput({
593
+ gvc: gvc,
594
+ title: '',
595
+ type: 'time',
596
+ style: inputStyle,
597
+ default: vm.data.sendTime ? vm.data.sendTime.time : '',
598
+ placeHolder: '',
599
+ callback: () => {},
600
+ readonly: true,
601
+ })}
602
+ </div>`,
603
+ },
604
+ ],
605
+ callback: () => {},
606
+ readonly: true,
607
+ })}`
608
+ ),
609
+ ]);
610
+ }
611
+ htmlList = htmlList.concat([
612
+ BgWidget.mainCard(
613
+ BgWidget.editeInput({
614
+ gvc: gvc,
615
+ title: '寄件者名稱',
616
+ default: postData.name,
617
+ placeHolder: '請輸入寄件者名稱',
618
+ callback: text => {
619
+ postData.name = text;
620
+ },
621
+ readonly: obj.readonly,
622
+ })
623
+ ),
624
+ BgWidget.mainCard(
625
+ BgWidget.editeInput({
626
+ gvc: gvc,
627
+ title: '信件主旨',
628
+ default: postData.title,
629
+ placeHolder: '請輸入信件主旨',
630
+ callback: text => {
631
+ if (text === 'default') {
632
+ const dialog = new ShareDialog(gvc.glitter);
633
+ dialog.infoMessage({ text: 'default 為系統預設值,請更改其他信件主旨' });
634
+ postData.title = '';
635
+ obj.gvc.notifyDataChange(bi);
636
+ return;
637
+ }
638
+ postData.title = text;
639
+ },
640
+ readonly: obj.readonly,
641
+ })
642
+ ),
643
+ BgWidget.mainCard(
644
+ html`<div class="d-flex w-100 align-items-center justify-content-between p-0 mb-2">
645
+ <div class="tx_normal fw-normal me-2">信件內文</div>
646
+ <div class="d-flex align-items-center gap-2">
647
+ ${obj.readonly
648
+ ? ''
649
+ : BgWidget.customButton({
650
+ button: {
651
+ color: 'snow',
652
+ size: 'md',
653
+ },
654
+ text: {
655
+ name: '範例',
656
+ },
657
+ event: obj.gvc.event(() => {
658
+ if (postData.content.length > 0) {
659
+ dialog.checkYesOrNot({
660
+ callback: bool => {
661
+ if (bool) {
662
+ postData.content = defaultEmailText();
663
+ obj.gvc.notifyDataChange(bi);
664
+ }
665
+ },
666
+ text: '此操作會覆蓋當前的內文,<br />確定要執行嗎?',
667
+ });
668
+ } else {
669
+ postData.content = defaultEmailText();
670
+ obj.gvc.notifyDataChange(bi);
671
+ }
672
+ }),
673
+ })}
674
+ ${BgWidget.aiChatButton({ gvc, select: 'writer' })}
675
+ </div>
676
+ </div>
677
+ ${obj.readonly
678
+ ? html`<div class="p-1">${postData.content}</div>`
679
+ : EditorElem.richText({
680
+ gvc: gvc,
681
+ def: postData.content,
682
+ callback: text => {
683
+ postData.content = text;
684
+ },
685
+ style: `overflow-y: auto;`,
686
+ })}`
687
+ ),
688
+ ]);
689
+ return htmlList.filter(str => str.length > 0).join(BgWidget.mbContainer(16));
690
+ },
691
+ divCreate: {},
692
+ };
693
+ })
694
+ )}
695
+ ${BgWidget.mbContainer(240)}
696
+ <div class="update-bar-container">
697
+ ${!obj.readonly && obj.type === 'replace'
698
+ ? BgWidget.danger(
699
+ obj.gvc.event(() => {
700
+ const dialog = new ShareDialog(gvc.glitter);
701
+ dialog.checkYesOrNot({
702
+ text: '是否確認刪除此信件樣式?',
703
+ callback: response => {
704
+ if (response) {
705
+ dialog.dataLoading({ visible: true });
706
+ ApiPost.delete({
707
+ id: postData.id,
708
+ }).then(res => {
709
+ dialog.dataLoading({ visible: false });
710
+ if (res.result) {
711
+ dialog.successMessage({ text: '刪除成功' });
712
+ vm.type = 'list';
713
+ } else {
714
+ dialog.errorMessage({ text: '刪除失敗' });
715
+ }
716
+ });
717
+ }
718
+ },
719
+ });
720
+ })
721
+ )
722
+ : ''}
723
+ ${obj.readonly && vm.data.status === 0
724
+ ? BgWidget.danger(
725
+ gvc.event(() => {
726
+ const dialog = new ShareDialog(gvc.glitter);
727
+ dialog.checkYesOrNot({
728
+ callback: bool => {
729
+ if (bool) {
730
+ dialog.dataLoading({ text: '取消排定中...', visible: true });
731
+ ApiSmtp.cancel(vm.data.id).then(data => {
732
+ dialog.dataLoading({ visible: false });
733
+ if (data.result) {
734
+ dialog.successMessage({ text: '取消排定發送成功' });
735
+ setTimeout(() => {
736
+ vm.type = 'list';
737
+ }, 100);
738
+ } else {
739
+ dialog.errorMessage({ text: '取消排定發送失敗' });
740
+ }
741
+ });
742
+ }
743
+ },
744
+ text: '確定取消排定發送的信件嗎?',
745
+ });
746
+ }),
747
+ '取消排定發送'
748
+ )
749
+ : ''}
750
+ ${BgWidget.cancel(
751
+ gvc.event(() => {
752
+ vm.type = 'list';
753
+ }),
754
+ obj.readonly ? '關閉' : undefined
755
+ )}
756
+ ${obj.readonly
757
+ ? ''
758
+ : BgWidget.save(
759
+ gvc.event(() => {
760
+ const dialog = new ShareDialog(gvc.glitter);
761
+ if (obj.type === 'replace') {
762
+ dialog.dataLoading({ text: '變更信件', visible: true });
763
+ ApiPost.put({
764
+ postData: postData,
765
+ token: (window.parent as any).saasConfig.config.token,
766
+ type: 'manager',
767
+ }).then(re => {
768
+ dialog.dataLoading({ visible: false });
769
+ if (re.result) {
770
+ vm.status = 'list';
771
+ dialog.successMessage({ text: '上傳成功' });
772
+ } else {
773
+ dialog.errorMessage({ text: '上傳失敗' });
774
+ }
775
+ });
776
+ } else {
777
+ dialog.dataLoading({ text: '新增信件', visible: true });
778
+ ApiPost.post({
779
+ postData: postData,
780
+ token: (window.parent as any).saasConfig.config.token,
781
+ type: 'manager',
782
+ }).then(re => {
783
+ dialog.dataLoading({ visible: false });
784
+ if (re.result) {
785
+ vm.type = 'list';
786
+ dialog.successMessage({ text: '上傳成功' });
787
+ } else {
788
+ dialog.errorMessage({ text: '上傳失敗' });
789
+ }
790
+ });
791
+ }
792
+ })
793
+ )}
794
+ </div>
795
+ `);
796
+ }
797
+
798
+ public static emailSender(gvc: any) {
799
+ const glitter = gvc.glitter;
800
+ const dialog = new ShareDialog(gvc.glitter);
801
+ const startDate = ShoppingDiscountSetting.getDateTime(1).date;
802
+ const startTime = ShoppingDiscountSetting.getDateTime(1).time;
803
+ const vm = {
804
+ id: glitter.getUUID(),
805
+ containerId: glitter.getUUID(),
806
+ emailId: glitter.getUUID(),
807
+ tagsId: glitter.getUUID(),
808
+ loading: true,
809
+ dataList: [] as { key: string; value: string }[],
810
+ };
811
+ const postData: PostData = {
812
+ type: 'notify-sns-config',
813
+ tag: '',
814
+ tagList: [],
815
+ userList: [],
816
+ boolean: 'or',
817
+ name: '',
818
+ title: '',
819
+ content: '',
820
+ sendTime: { date: startDate, time: startTime },
821
+ sendGroup: [],
822
+ };
823
+
824
+ async function getOptions(tag: string) {
825
+ if (tag === 'level') {
826
+ return await ApiUser.getPublicConfig('member_level_config', 'manager').then((res: any) => {
827
+ if (res.result && res.response.value && res.response.value.levels.length > 0) {
828
+ return res.response.value.levels.map((data: any) => {
829
+ return { key: data.id, value: data.tag_name };
830
+ });
831
+ }
832
+ return [];
833
+ });
834
+ }
835
+ if (tag === 'tags') {
836
+ return await ApiUser.getPublicConfig('user_general_tags', 'manager').then((res: any) => {
837
+ if (res.result && res.response.value && res.response.value.list.length > 0) {
838
+ return res.response.value.list.map((data: any) => {
839
+ return { key: data, value: data };
840
+ });
841
+ }
842
+ return [];
843
+ });
844
+ }
845
+ if (tag === 'group') {
846
+ return await ApiUser.getUserGroupList().then((res: any) => {
847
+ if (res.result) {
848
+ return res.response.data
849
+ .filter((data: { type: string }) => {
850
+ return data.type !== 'level';
851
+ })
852
+ .map((data: { type: string; title: string }) => {
853
+ return { key: data.type, value: data.title };
854
+ });
855
+ }
856
+ return [];
857
+ });
858
+ }
859
+ if (tag === 'birth') {
860
+ const userFunnel = await FilterOptions.getUserFunnel();
861
+ const birthData = userFunnel.find(data => data.key === 'birth');
862
+ if (birthData && Array.isArray(birthData.data)) {
863
+ return birthData.data.map((item: any) => {
864
+ item.value = item.name;
865
+ return item;
866
+ });
867
+ }
868
+ }
869
+ return [];
870
+ }
871
+
872
+ function filterEvent(filter: any) {
873
+ if (filter.length === 0) {
874
+ postData.tagList = postData.tagList.filter(data => data.tag !== postData.tag);
875
+ } else {
876
+ let valueString = '';
877
+ if (postData.tag === 'all') {
878
+ valueString = '';
879
+ } else if (Array.isArray(filter)) {
880
+ valueString = vm.dataList
881
+ .filter(data => {
882
+ return filter.includes(data.key);
883
+ })
884
+ .map(data => {
885
+ return data.value;
886
+ })
887
+ .join(', ');
888
+ } else {
889
+ const intFiltter = parseInt(`${filter}`, 10);
890
+ filter = intFiltter > 0 ? intFiltter : 0;
891
+ valueString = filter;
892
+ }
893
+
894
+ const index = postData.tagList.findIndex(data => data.tag === postData.tag);
895
+ if (index === -1) {
896
+ postData.tagList.push({ tag: postData.tag, filter: filter, valueString });
897
+ } else {
898
+ postData.tagList[index] = { tag: postData.tag, filter: filter, valueString };
899
+ }
900
+ }
901
+ setUserList();
902
+ }
903
+
904
+ function filterEmails(emails: EmailObject[], mode: 'or' | 'and', n?: number): EmailObject[] {
905
+ if (mode === 'or') {
906
+ // 使用 Set 來移除重複的 id
907
+ const uniqueIds = new Set<number>();
908
+ return emails.filter(emailObj => {
909
+ if (!uniqueIds.has(emailObj.id)) {
910
+ uniqueIds.add(emailObj.id);
911
+ return true;
912
+ }
913
+ return false;
914
+ });
915
+ } else if (mode === 'and' && n && n > 0) {
916
+ // 計算每個 id 出現的次數
917
+ const frequencyMap: { [key: number]: { count: number; emailObj: EmailObject } } = {};
918
+ emails.forEach(emailObj => {
919
+ if (frequencyMap[emailObj.id]) {
920
+ frequencyMap[emailObj.id].count += 1;
921
+ } else {
922
+ frequencyMap[emailObj.id] = { count: 1, emailObj };
923
+ }
924
+ });
925
+ // 篩選出出現次數大於或等於 n 的 id
926
+ return Object.values(frequencyMap)
927
+ .filter(entry => entry.count >= n)
928
+ .map(entry => entry.emailObj);
929
+ }
930
+ return [];
931
+ }
932
+
933
+ function setUserList() {
934
+ let n = 0;
935
+ postData.userList = [];
936
+ dialog.dataLoading({ visible: true, text: '更新預計寄件人...' });
937
+
938
+ new Promise<void>(resolve => {
939
+ const si = setInterval(() => {
940
+ if (postData.tagList.length === n) {
941
+ resolve();
942
+ clearInterval(si);
943
+ }
944
+ }, 200);
945
+ postData.tagList.map(tagData => {
946
+ if (tagData.tag === 'all') {
947
+ ApiUser.getUserList({
948
+ page: 0,
949
+ limit: 99999,
950
+ only_id:true
951
+ }).then(dd => {
952
+ dd.response.data.map((user: any) => {
953
+ if (user.userData.email && user.userData.email.length > 0) {
954
+ postData.userList.push({
955
+ id: user.userID,
956
+ email: user.userData.email,
957
+ });
958
+ }
959
+ });
960
+ n++;
961
+ });
962
+ }
963
+ if (tagData.tag === 'customers') {
964
+ ApiUser.getUserList({
965
+ page: 0,
966
+ limit: 99999,
967
+ id: tagData.filter.join(','),
968
+ }).then(dd => {
969
+ dd.response.data.map((user: any) => {
970
+ if (user.userData.email && user.userData.email.length > 0) {
971
+ postData.userList.push({
972
+ id: user.userID,
973
+ email: user.userData.email,
974
+ });
975
+ }
976
+ });
977
+ n++;
978
+ });
979
+ }
980
+ if (tagData.tag === 'level') {
981
+ let n1 = 0;
982
+ new Promise<EmailObject[]>(resolve => {
983
+ const list: EmailObject[] = [];
984
+ tagData.filter.map((id: string) => {
985
+ ApiUser.getUserListOrders({
986
+ page: 0,
987
+ limit: 99999,
988
+ group: { type: 'level', tag: id },
989
+ }).then(data => {
990
+ data.response.data.map((user: any) => {
991
+ if (user.userData.email) {
992
+ list.push({
993
+ id: user.userID,
994
+ email: user.userData.email,
995
+ });
996
+ }
997
+ });
998
+ n1++;
999
+ });
1000
+ const si = setInterval(() => {
1001
+ if (tagData.filter.length === n1) {
1002
+ resolve(filterEmails(list, 'or'));
1003
+ clearInterval(si);
1004
+ }
1005
+ }, 200);
1006
+ });
1007
+ }).then(res => {
1008
+ postData.userList = postData.userList.concat(res);
1009
+ n++;
1010
+ });
1011
+ }
1012
+ if (tagData.tag === 'group') {
1013
+ let n2 = 0;
1014
+ const list: EmailObject[] = [];
1015
+ new Promise<EmailObject[]>(resolve => {
1016
+ tagData.filter.map((type: string) => {
1017
+ ApiUser.getUserListOrders({
1018
+ page: 0,
1019
+ limit: 99999,
1020
+ group: { type: type },
1021
+ }).then(data => {
1022
+ // 加入額外的會員資料,例如有訂閱但未註冊者
1023
+ let dataArray = data.response.data;
1024
+ if (data.response.extra) {
1025
+ dataArray = dataArray.concat(data.response.extra.noRegisterUsers);
1026
+ }
1027
+ dataArray.map((user: any) => {
1028
+ if (user && user.userData.email) {
1029
+ list.push({
1030
+ id: user.userID,
1031
+ email: user.userData.email,
1032
+ });
1033
+ }
1034
+ });
1035
+ n2++;
1036
+ });
1037
+ const si = setInterval(() => {
1038
+ if (tagData.filter.length === n2) {
1039
+ resolve(filterEmails(list, 'or'));
1040
+ clearInterval(si);
1041
+ }
1042
+ }, 200);
1043
+ });
1044
+ }).then(res => {
1045
+ postData.userList = postData.userList.concat(res);
1046
+ n++;
1047
+ });
1048
+ }
1049
+ if (tagData.tag === 'birth') {
1050
+ ApiUser.getUserListOrders({
1051
+ page: 0,
1052
+ limit: 99999,
1053
+ filter: { birth: tagData.filter },
1054
+ }).then(data => {
1055
+ data.response.data.map((user: any) => {
1056
+ if (user.userData.email) {
1057
+ postData.userList.push({
1058
+ id: user.userID,
1059
+ email: user.userData.email,
1060
+ });
1061
+ }
1062
+ });
1063
+ n++;
1064
+ });
1065
+ }
1066
+ if (tagData.tag === 'tags') {
1067
+ ApiUser.getUserListOrders({
1068
+ page: 0,
1069
+ limit: 99999,
1070
+ filter: { tags: tagData.filter },
1071
+ }).then(data => {
1072
+ data.response.data.map((user: any) => {
1073
+ if (user.userData.email) {
1074
+ postData.userList.push({
1075
+ id: user.userID,
1076
+ email: user.userData.email,
1077
+ });
1078
+ }
1079
+ });
1080
+ n++;
1081
+ });
1082
+ }
1083
+ if (tagData.tag === 'expiry') {
1084
+ }
1085
+ if (tagData.tag === 'remain') {
1086
+ ApiUser.getUserListOrders({
1087
+ page: 0,
1088
+ limit: 99999,
1089
+ filter: { rebate: { key: 'moreThan', value: tagData.filter } },
1090
+ }).then(data => {
1091
+ data.response.data.map((user: any) => {
1092
+ if (user.userData.email) {
1093
+ postData.userList.push({
1094
+ id: user.userID,
1095
+ email: user.userData.email,
1096
+ });
1097
+ }
1098
+ });
1099
+ n++;
1100
+ });
1101
+ }
1102
+ if (tagData.tag === 'uncheckout') {
1103
+ }
1104
+ });
1105
+ }).then(() => {
1106
+ postData.userList = filterEmails(
1107
+ postData.userList,
1108
+ postData.boolean,
1109
+ postData.boolean === 'and' ? postData.tagList.length : undefined
1110
+ );
1111
+ dialog.dataLoading({ visible: false });
1112
+ gvc.notifyDataChange(vm.tagsId);
1113
+ });
1114
+ }
1115
+
1116
+ function tagBadge(key: string, name: string, value: string) {
1117
+ const formatName = value && value.length > 0 ? `${name}:${value}` : name;
1118
+ return {
1119
+ name: formatName,
1120
+ html: html`<div class="c_filter_tag">
1121
+ ${formatName}
1122
+ <i
1123
+ class="fa-solid fa-xmark ms-1"
1124
+ style="cursor: pointer"
1125
+ onclick="${gvc.event(() => {
1126
+ postData.tagList = postData.tagList.filter(data => data.tag !== key);
1127
+ setUserList();
1128
+ gvc.notifyDataChange(vm.tagsId);
1129
+ })}"
1130
+ ></i>
1131
+ </div>`,
1132
+ };
1133
+ }
1134
+
1135
+ function getTagsHTML() {
1136
+ const badgeList: { name: string; html: string }[] = [];
1137
+ postData.tagList.map(data => {
1138
+ const opt = FilterOptions.emailOptions.find(item => item.key === data.tag);
1139
+ if (opt) {
1140
+ if (!Array.isArray(data.filter)) {
1141
+ switch (data.tag) {
1142
+ case 'remain':
1143
+ data.valueString = `大於${data.filter}點`;
1144
+ break;
1145
+ }
1146
+ }
1147
+ badgeList.push(tagBadge(data.tag, opt.value, data.valueString));
1148
+ }
1149
+ });
1150
+ postData.sendGroup = badgeList.map(item => item.name);
1151
+ return [
1152
+ html`<div class="tx_normal fw-normal">標籤判斷</div>
1153
+ ${BgWidget.grayNote('當有多個篩選條件時,進階判斷顧客符合的交集')}
1154
+ <div style="margin: 8px 0;">
1155
+ ${BgWidget.switchTextButton(gvc, postData.boolean === 'and', { left: '或', right: '且' }, bool => {
1156
+ postData.boolean = bool ? 'and' : 'or';
1157
+ setUserList();
1158
+ gvc.notifyDataChange(vm.tagsId);
1159
+ })}
1160
+ </div>`,
1161
+ html`<div class="tx_normal fw-normal">預計寄件顧客人數</div>
1162
+ <div style="display:flex; align-items: center; gap: 18px; margin: 8px 0;">
1163
+ <div class="tx_normal">${postData.userList.length}人</div>
1164
+ ${BgWidget.grayButton(
1165
+ '查看名單',
1166
+ gvc.event(() => {
1167
+ if (postData.userList.length === 0) {
1168
+ const dialog = new ShareDialog(gvc.glitter);
1169
+ dialog.infoMessage({ text: '目前無預計寄件的顧客' });
1170
+ return;
1171
+ }
1172
+ const userVM = {
1173
+ dataList: [] as { key: string; value: string; note: string }[],
1174
+ };
1175
+ BgWidget.selectDropDialog({
1176
+ gvc: gvc,
1177
+ title: '預計寄件顧客',
1178
+ tag: 'send_users_list',
1179
+ callback: () => {},
1180
+ default: [],
1181
+ api: () => {
1182
+ return new Promise(resolve => {
1183
+ ApiUser.getUserListOrders({
1184
+ page: 0,
1185
+ limit: 99999,
1186
+ id: postData.userList.map(user => user.id ?? 0).join(','),
1187
+ }).then(dd => {
1188
+ if (dd.response.data) {
1189
+ userVM.dataList = dd.response.data.map(
1190
+ (item: { userID: number; userData: { name: string; email: string } }) => {
1191
+ return {
1192
+ key: item.userID,
1193
+ value: item.userData.name,
1194
+ note: item.userData.email,
1195
+ };
1196
+ }
1197
+ );
1198
+ if (postData.userList.length > userVM.dataList.length) {
1199
+ // 加入未註冊會員的信箱,例如有訂閱但未註冊者
1200
+ const noRegisterUser = postData.userList
1201
+ .filter(item => {
1202
+ return item.id < 0 && item.email;
1203
+ })
1204
+ .map(item => {
1205
+ return {
1206
+ key: `${item.id}`,
1207
+ value: '(未註冊的會員)',
1208
+ note: item.email,
1209
+ };
1210
+ });
1211
+ userVM.dataList = userVM.dataList.concat(noRegisterUser);
1212
+ }
1213
+ resolve(userVM.dataList);
1214
+ }
1215
+ });
1216
+ });
1217
+ },
1218
+ style: 'width: 100%;',
1219
+ readonly: true,
1220
+ });
1221
+ }),
1222
+ { textStyle: 'font-weight: 400;' }
1223
+ )}
1224
+ </div> `,
1225
+ html`
1226
+ <div class="tx_normal fw-normal">篩選條件</div>
1227
+ <div class="c_filter_container">
1228
+ ${badgeList.length === 0
1229
+ ? '無'
1230
+ : badgeList
1231
+ .map(item => {
1232
+ return item.html;
1233
+ })
1234
+ .join(postData.boolean === 'and' ? '且' : '或')}
1235
+ </div>
1236
+ `,
1237
+ ].join(BgWidget.mbContainer(18));
1238
+ }
1239
+
1240
+ return BgWidget.container(html`
1241
+ <div class="title-container">
1242
+ ${BgWidget.title('手動寄件')}
1243
+ <div class="flex-fill"></div>
1244
+ </div>
1245
+ ${BgWidget.mbContainer(18)}
1246
+ ${BgWidget.container(
1247
+ gvc.bindView(() => {
1248
+ return {
1249
+ bind: vm.containerId,
1250
+ view: () => {
1251
+ return [
1252
+ BgWidget.mainCard(
1253
+ [
1254
+ html` <div class="tx_700">選擇收件對象</div>`,
1255
+ html` <div class="tx_normal fw-normal mt-3">根據</div>`,
1256
+ html`<div
1257
+ style="display: flex; ${document.body.clientWidth > 768
1258
+ ? 'gap: 18px;'
1259
+ : 'flex-direction: column;'}"
1260
+ >
1261
+ <div style="width: ${document.body.clientWidth > 768 ? '400px' : '100%'};">
1262
+ ${BgWidget.select({
1263
+ gvc: gvc,
1264
+ default: postData.tag,
1265
+ callback: key => {
1266
+ postData.tag = key;
1267
+ vm.loading = true;
1268
+ gvc.notifyDataChange(vm.id);
1269
+ },
1270
+ options: FilterOptions.emailOptions,
1271
+ style: 'margin: 8px 0;',
1272
+ })}
1273
+ </div>
1274
+ <div style="width: 100%; display: flex; align-items: center;">
1275
+ ${gvc.bindView({
1276
+ bind: vm.id,
1277
+ view: () => {
1278
+ const getDefault = (def: any) => {
1279
+ const data = postData.tagList.find(data => data.tag === postData.tag);
1280
+ return data ? data.filter : def;
1281
+ };
1282
+ const callback = (value?: any) => {
1283
+ if (typeof value === 'string' || typeof value === 'number') {
1284
+ const intFiltter = parseInt(`${value}`, 10);
1285
+ value = intFiltter > 0 ? intFiltter : 0;
1286
+ if (isNaN(intFiltter) || intFiltter < 0) {
1287
+ const dialog = new ShareDialog(gvc.glitter);
1288
+ dialog.infoMessage({ text: '請輸入正整數或0' });
1289
+ return;
1290
+ }
1291
+ }
1292
+ filterEvent(value);
1293
+ };
1294
+ switch (postData.tag) {
1295
+ case 'all':
1296
+ dialog.dataLoading({ visible: true, text: '取得所有會員資料中...' });
1297
+ new Promise(resolve => {
1298
+ ApiUser.getUserList({
1299
+ page: 0,
1300
+ limit: 99999,
1301
+ only_id:true
1302
+ }).then(dd => {
1303
+ if (dd.response.data) {
1304
+ const ids: number[] = [];
1305
+ vm.dataList = dd.response.data
1306
+ .filter((item: { userData: { email: string } }) => {
1307
+ return item.userData.email && item.userData.email.length > 0;
1308
+ })
1309
+ .map((item: { userID: number; userData: { name: string; email: string } }) => {
1310
+ ids.push(item.userID);
1311
+ return {
1312
+ key: item.userID,
1313
+ value: item.userData.name ?? '(尚無姓名)',
1314
+ note: item.userData.email,
1315
+ };
1316
+ });
1317
+ resolve(ids);
1318
+ }
1319
+ });
1320
+ }).then(data => {
1321
+ dialog.dataLoading({ visible: false });
1322
+ callback(data);
1323
+ });
1324
+ return '';
1325
+ case 'level':
1326
+ case 'group':
1327
+ case 'birth':
1328
+ case 'tags':
1329
+ return BgWidget.selectDropList({
1330
+ gvc: gvc,
1331
+ callback: callback,
1332
+ default: getDefault([]),
1333
+ options: vm.loading ? [] : vm.dataList,
1334
+ placeholder: vm.loading ? '資料載入中...' : undefined,
1335
+ style: 'margin: 8px 0; width: 100%;',
1336
+ });
1337
+ case 'customers':
1338
+ return BgWidget.grayButton(
1339
+ '點擊選取顧客',
1340
+ gvc.event(() => {
1341
+ BgWidget.selectDropDialog({
1342
+ gvc: gvc,
1343
+ title: '搜尋特定顧客',
1344
+ tag: 'set_send_users',
1345
+ updownOptions: FilterOptions.userOrderBy,
1346
+ callback: callback,
1347
+ default: getDefault([]),
1348
+ api: (data: { query: string; orderString: string }) => {
1349
+ return new Promise(resolve => {
1350
+ ApiUser.getUserList({
1351
+ page: 0,
1352
+ limit: 99999,
1353
+ only_id:true,
1354
+ search: data.query
1355
+ }).then(dd => {
1356
+ if (dd.response.data) {
1357
+ vm.dataList = dd.response.data
1358
+ .filter((item: { userData: { email: string } }) => {
1359
+ return item.userData.email && item.userData.email.length > 0;
1360
+ })
1361
+ .map(
1362
+ (item: {
1363
+ userID: number;
1364
+ userData: { name: string; email: string };
1365
+ }) => {
1366
+ return {
1367
+ key: item.userID,
1368
+ value: item.userData.name ?? '(尚無姓名)',
1369
+ note: item.userData.email,
1370
+ };
1371
+ }
1372
+ );
1373
+ resolve(vm.dataList);
1374
+ }
1375
+ });
1376
+ });
1377
+ },
1378
+ style: 'width: 100%;',
1379
+ });
1380
+ }),
1381
+ { textStyle: 'font-weight: 400;' }
1382
+ );
1383
+ case 'expiry':
1384
+ return BgWidget.editeInput({
1385
+ gvc: gvc,
1386
+ title: '',
1387
+ default: getDefault('0'),
1388
+ placeHolder: '請輸入剩餘多少天',
1389
+ callback: callback,
1390
+ endText: '天',
1391
+ });
1392
+ case 'remain':
1393
+ return BgWidget.editeInput({
1394
+ gvc: gvc,
1395
+ title: '',
1396
+ default: getDefault('0'),
1397
+ placeHolder: '請輸入大於多少',
1398
+ callback: callback,
1399
+ startText: '大於',
1400
+ endText: '點',
1401
+ });
1402
+ case 'uncheckout':
1403
+ return BgWidget.editeInput({
1404
+ gvc: gvc,
1405
+ title: '',
1406
+ default: getDefault('0'),
1407
+ placeHolder: '請輸入超過幾天未結帳',
1408
+ callback: callback,
1409
+ endText: '天',
1410
+ });
1411
+ default:
1412
+ return '';
1413
+ }
1414
+ },
1415
+ divCreate: { class: 'w-100' },
1416
+ onCreate: () => {
1417
+ if (vm.loading) {
1418
+ getOptions(postData.tag).then(opts => {
1419
+ vm.dataList = opts as { key: string; value: string }[];
1420
+ vm.loading = false;
1421
+ gvc.notifyDataChange(vm.id);
1422
+ });
1423
+ }
1424
+ },
1425
+ })}
1426
+ </div>
1427
+ </div>`,
1428
+ gvc.bindView({
1429
+ bind: vm.tagsId,
1430
+ view: () => getTagsHTML(),
1431
+ divCreate: { style: 'margin-top: 8px;' },
1432
+ }),
1433
+ ].join('')
1434
+ ),
1435
+ BgWidget.mainCard(
1436
+ [
1437
+ html` <div class="tx_700">信件內容</div>`,
1438
+ html` <div class="tx_normal fw-normal mt-3">信件樣式</div>`,
1439
+ (() => {
1440
+ const selectVM = {
1441
+ id: glitter.getUUID(),
1442
+ loading: true,
1443
+ dataList: [] as {
1444
+ key: string;
1445
+ name: string;
1446
+ value: string;
1447
+ content: string;
1448
+ }[],
1449
+ };
1450
+ return gvc.bindView({
1451
+ bind: selectVM.id,
1452
+ view: () => {
1453
+ return BgWidget.select({
1454
+ gvc: gvc,
1455
+ default: postData.name,
1456
+ callback: key => {
1457
+ const data = selectVM.dataList.find(data => data.key === key && key !== 'def');
1458
+ postData.name = data ? data.name : '';
1459
+ postData.title = data ? data.value : '';
1460
+ postData.content = data ? data.content : '';
1461
+ gvc.notifyDataChange(vm.emailId);
1462
+ },
1463
+ options: selectVM.dataList,
1464
+ style: 'margin: 8px 0;',
1465
+ });
1466
+ },
1467
+ divCreate: {},
1468
+ onCreate: () => {
1469
+ if (selectVM.loading) {
1470
+ ApiPost.getManagerPost({
1471
+ page: 0,
1472
+ limit: 9999,
1473
+ type: 'notify-email-config',
1474
+ }).then(res => {
1475
+ if (res.result) {
1476
+ selectVM.dataList = res.response.data.map((data: any) => {
1477
+ data = data.content;
1478
+ return {
1479
+ key: `${data.id}`,
1480
+ name: data.name,
1481
+ value: data.title,
1482
+ content: data.content,
1483
+ };
1484
+ });
1485
+ selectVM.dataList.splice(0, 0, {
1486
+ key: 'default',
1487
+ name: '',
1488
+ value: '(空白樣式)',
1489
+ content: '',
1490
+ });
1491
+ }
1492
+ selectVM.loading = false;
1493
+ gvc.notifyDataChange(selectVM.id);
1494
+ });
1495
+ }
1496
+ },
1497
+ });
1498
+ })(),
1499
+ gvc.bindView({
1500
+ bind: vm.emailId,
1501
+ view: () => {
1502
+ return [
1503
+ BgWidget.editeInput({
1504
+ gvc: gvc,
1505
+ title: '寄件者名稱',
1506
+ default: postData.name,
1507
+ placeHolder: '請輸入寄件者名稱',
1508
+ callback: text => {
1509
+ postData.name = text;
1510
+ },
1511
+ }),
1512
+ BgWidget.editeInput({
1513
+ gvc: gvc,
1514
+ title: '信件主旨',
1515
+ default: postData.title,
1516
+ placeHolder: '請輸入信件主旨',
1517
+ callback: text => {
1518
+ postData.title = text;
1519
+ },
1520
+ }),
1521
+ html`<div class="d-flex w-100 align-items-center justify-content-between p-0 my-2">
1522
+ <div class="tx_normal fw-normal me-2">信件內文</div>
1523
+ <div class="d-flex align-items-center gap-2">
1524
+ ${BgWidget.customButton({
1525
+ button: {
1526
+ color: 'snow',
1527
+ size: 'md',
1528
+ },
1529
+ text: {
1530
+ name: '範例',
1531
+ },
1532
+ event: gvc.event(() => {
1533
+ if (postData.content.length > 0) {
1534
+ dialog.checkYesOrNot({
1535
+ callback: bool => {
1536
+ if (bool) {
1537
+ postData.content = defaultEmailText();
1538
+ gvc.notifyDataChange(vm.containerId);
1539
+ }
1540
+ },
1541
+ text: '此操作會覆蓋當前的內文,<br />確定要執行嗎?',
1542
+ });
1543
+ } else {
1544
+ postData.content = defaultEmailText();
1545
+ gvc.notifyDataChange(vm.containerId);
1546
+ }
1547
+ }),
1548
+ })}
1549
+ ${BgWidget.aiChatButton({ gvc, select: 'writer' })}
1550
+ </div>
1551
+ </div>
1552
+ ${EditorElem.richText({
1553
+ gvc: gvc,
1554
+ def: postData.content,
1555
+ callback: text => {
1556
+ postData.content = text;
1557
+ },
1558
+ style: `overflow-y: auto;`,
1559
+ })}`,
1560
+ ].join('');
1561
+ },
1562
+ }),
1563
+ ].join('')
1564
+ ),
1565
+ BgWidget.mainCard(
1566
+ html`<div class="tx_700 mb-3">發送時間</div>
1567
+ ${EditorElem.radio({
1568
+ gvc: gvc,
1569
+ title: '',
1570
+ def: postData.sendTime === undefined ? 'now' : 'set',
1571
+ array: [
1572
+ {
1573
+ title: '立即發送',
1574
+ value: 'now',
1575
+ },
1576
+ {
1577
+ title: '排定發送時間',
1578
+ value: 'set',
1579
+ innerHtml: html`<div
1580
+ class="d-flex mt-3 ${document.body.clientWidth < 768 ? 'flex-column' : ''}"
1581
+ style="gap: 12px"
1582
+ >
1583
+ ${EditorElem.editeInput({
1584
+ gvc: gvc,
1585
+ title: '',
1586
+ type: 'date',
1587
+ style: inputStyle,
1588
+ default: startDate,
1589
+ placeHolder: '',
1590
+ callback: date => {
1591
+ postData.sendTime = {
1592
+ date: date,
1593
+ time: postData.sendTime?.time ?? '',
1594
+ };
1595
+ },
1596
+ })}
1597
+ ${EditorElem.editeInput({
1598
+ gvc: gvc,
1599
+ title: '',
1600
+ type: 'time',
1601
+ style: inputStyle,
1602
+ default: startTime,
1603
+ placeHolder: '',
1604
+ callback: time => {
1605
+ postData.sendTime = {
1606
+ date: postData.sendTime?.date ?? '',
1607
+ time: time,
1608
+ };
1609
+ },
1610
+ })}
1611
+ </div>`,
1612
+ },
1613
+ ],
1614
+ callback: text => {
1615
+ if (text === 'now') {
1616
+ postData.sendTime = undefined;
1617
+ }
1618
+ if (text === 'set') {
1619
+ postData.sendTime = { date: startDate, time: startTime };
1620
+ }
1621
+ },
1622
+ })}`
1623
+ ),
1624
+ ].join(BgWidget.mbContainer(16));
1625
+ },
1626
+ divCreate: {},
1627
+ };
1628
+ })
1629
+ )}
1630
+ ${BgWidget.mbContainer(240)}
1631
+ <div class="update-bar-container">
1632
+ ${BgWidget.save(
1633
+ gvc.event(() => {
1634
+ function isLater(dateTimeObj: { date: string; time: string }) {
1635
+ const currentDateTime = new Date();
1636
+ const { date, time } = dateTimeObj;
1637
+ const dateTimeString = `${date}T${time}:00`;
1638
+ const providedDateTime = new Date(dateTimeString);
1639
+ return currentDateTime > providedDateTime;
1640
+ }
1641
+
1642
+ if (postData.sendTime && isLater(postData.sendTime)) {
1643
+ dialog.errorMessage({ text: '排定發送的時間需大於現在時間' });
1644
+ return;
1645
+ }
1646
+
1647
+ if (postData.userList.length == 0) {
1648
+ dialog.errorMessage({ text: '請選擇發送對象' });
1649
+ return;
1650
+ }
1651
+
1652
+ dialog.dataLoading({
1653
+ text: postData.sendTime ? '信件排定中...' : '信件發送中...',
1654
+ visible: true,
1655
+ });
1656
+ ApiSmtp.send({
1657
+ ...postData,
1658
+ email: postData.userList.map(user => user.email),
1659
+ }).then(data => {
1660
+ dialog.dataLoading({ visible: false });
1661
+ if (data.result) {
1662
+ dialog.successMessage({
1663
+ text: postData.sendTime ? '排定成功' : '發送成功',
1664
+ });
1665
+ } else {
1666
+ dialog.errorMessage({ text: '手動寄件失敗' });
1667
+ }
1668
+ });
1669
+ }),
1670
+ '送出'
1671
+ )}
1672
+ </div>
1673
+ `);
1674
+ }
1675
+
1676
+ public static fcmEditor(obj: { vm: any; gvc: GVC; type?: 'add' | 'replace'; defData?: any }) {
1677
+ const gvc = obj.gvc;
1678
+ const glitter = gvc.glitter;
1679
+ const vm = obj.vm;
1680
+ const postData: {
1681
+ id: string;
1682
+ content: string;
1683
+ title: string;
1684
+ link: string;
1685
+ type: 'notify-message-config';
1686
+ name: string;
1687
+ } = vm.data ?? {
1688
+ content: '',
1689
+ title: '',
1690
+ link: '',
1691
+ type: 'notify-message-config',
1692
+ name: '',
1693
+ };
1694
+
1695
+ return BgWidget.container(html`
1696
+ <div class="title-container">
1697
+ ${BgWidget.goBack(
1698
+ gvc.event(() => {
1699
+ vm.type = 'list';
1700
+ })
1701
+ )}
1702
+ ${BgWidget.title(`編輯推播通知`)}
1703
+ <div class="flex-fill"></div>
1704
+ </div>
1705
+ ${BgWidget.container(
1706
+ html`<div class="d-flex px-0" style="gap: 10px;">
1707
+ <div style="width: 100%">
1708
+ ${BgWidget.mainCard(
1709
+ obj.gvc.bindView(() => {
1710
+ const bi = obj.gvc.glitter.getUUID();
1711
+ return {
1712
+ bind: bi,
1713
+ view: () => {
1714
+ return [
1715
+ EditorElem.editeInput({
1716
+ gvc: gvc,
1717
+ title: '推播標題',
1718
+ default: postData.title,
1719
+ placeHolder: '請輸入推播標題',
1720
+ callback: text => {
1721
+ postData.title = text;
1722
+ },
1723
+ }),
1724
+ EditorElem.editeInput({
1725
+ gvc: gvc,
1726
+ title: '跳轉連結',
1727
+ default: postData.link,
1728
+ placeHolder: '請輸入要跳轉的連結',
1729
+ callback: text => {
1730
+ postData.link = text;
1731
+ },
1732
+ }),
1733
+ EditorElem.editeText({
1734
+ gvc: gvc,
1735
+ title: '推播主旨',
1736
+ default: postData.content,
1737
+ placeHolder: '請輸入推播內容',
1738
+ callback: text => {
1739
+ postData.content = text;
1740
+ },
1741
+ }),
1742
+ ].join('');
1743
+ },
1744
+ divCreate: {},
1745
+ };
1746
+ })
1747
+ )}
1748
+ </div>
1749
+ </div>
1750
+ ${obj.type === 'replace'
1751
+ ? html`
1752
+ <div class="d-flex w-100 mt-2">
1753
+ <div class="flex-fill"></div>
1754
+ ${BgWidget.redButton(
1755
+ '刪除樣本',
1756
+ obj.gvc.event(() => {
1757
+ const dialog = new ShareDialog(obj.gvc.glitter);
1758
+ dialog.checkYesOrNot({
1759
+ text: '是否確認刪除樣本?',
1760
+ callback: response => {
1761
+ if (response) {
1762
+ dialog.dataLoading({ visible: true });
1763
+ ApiPost.delete({
1764
+ id: postData.id,
1765
+ }).then(res => {
1766
+ dialog.dataLoading({ visible: false });
1767
+ if (res.result) {
1768
+ vm.type = 'list';
1769
+ } else {
1770
+ dialog.errorMessage({ text: '刪除失敗' });
1771
+ }
1772
+ });
1773
+ }
1774
+ },
1775
+ });
1776
+ })
1777
+ )}
1778
+ </div>
1779
+ `
1780
+ : ``}
1781
+ <div class="update-bar-container">
1782
+ ${BgWidget.cancel(
1783
+ gvc.event(() => {
1784
+ vm.type = 'list';
1785
+ })
1786
+ )}
1787
+ ${BgWidget.save(
1788
+ gvc.event(() => {
1789
+ const dialog = new ShareDialog(gvc.glitter);
1790
+ if (obj.type === 'replace') {
1791
+ dialog.dataLoading({ text: '變更信件', visible: true });
1792
+ ApiPost.put({
1793
+ postData: postData,
1794
+ token: (window.parent as any).saasConfig.config.token,
1795
+ type: 'manager',
1796
+ }).then(re => {
1797
+ dialog.dataLoading({ visible: false });
1798
+ if (re.result) {
1799
+ vm.status = 'list';
1800
+ dialog.successMessage({ text: '上傳成功' });
1801
+ } else {
1802
+ dialog.errorMessage({ text: '上傳失敗' });
1803
+ }
1804
+ });
1805
+ } else {
1806
+ dialog.dataLoading({ text: '新增信件', visible: true });
1807
+ ApiPost.post({
1808
+ postData: postData,
1809
+ token: (window.parent as any).saasConfig.config.token,
1810
+ type: 'manager',
1811
+ }).then(re => {
1812
+ dialog.dataLoading({ visible: false });
1813
+ if (re.result) {
1814
+ vm.type = 'list';
1815
+ dialog.successMessage({ text: '上傳成功' });
1816
+ } else {
1817
+ dialog.errorMessage({ text: '上傳失敗' });
1818
+ }
1819
+ });
1820
+ }
1821
+ })
1822
+ )}
1823
+ </div>`
1824
+ )}
1825
+ `);
1826
+ }
1827
+
1828
+ public static fcmDevice(gvc: GVC, type: 'list' | 'select' = 'list', callback: (select: any) => void = () => {}) {
1829
+ const vm: {
1830
+ type: 'list' | 'replace';
1831
+ data: any;
1832
+ dataList: any;
1833
+ query?: string;
1834
+ } = {
1835
+ type: 'list',
1836
+ data: {
1837
+ id: 61,
1838
+ userID: 549313940,
1839
+ account: 'jianzhi.wang@homee.ai',
1840
+ userData: { name: '王建智', email: 'jianzhi.wang@homee.ai', phone: '0978028739' },
1841
+ created_time: '2023-11-26T02:14:09.000Z',
1842
+ role: 0,
1843
+ company: null,
1844
+ status: 1,
1845
+ },
1846
+ dataList: undefined,
1847
+ query: '',
1848
+ };
1849
+ const glitter = gvc.glitter;
1850
+ const filterID = glitter.getUUID();
1851
+ const id = glitter.getUUID();
1852
+ const dialog = new ShareDialog(gvc.glitter);
1853
+ return gvc.bindView(() => {
1854
+ return {
1855
+ bind: id,
1856
+ view: () => {
1857
+ let vmi: any = undefined;
1858
+
1859
+ function getDatalist() {
1860
+ let interval: any = 0;
1861
+ return vm.dataList.map((dd: any) => {
1862
+ return [
1863
+ {
1864
+ key: '用戶ID',
1865
+ value: `<span class="fs-7">${dd.userID ?? '尚未登入'}</span>`,
1866
+ },
1867
+ {
1868
+ key: '用戶名稱',
1869
+ value: `<span class="fs-7">${dd.userData ? dd.userData.name : '尚未登入'}</span>`,
1870
+ },
1871
+ {
1872
+ key: '訂閱Token',
1873
+ value: `<span class="fs-7">${Tool.truncateString(dd.deviceToken, 40)}</span>`,
1874
+ },
1875
+ ];
1876
+ });
1877
+ }
1878
+
1879
+ return BgWidget.container(html`
1880
+ <div class="title-container ${type === 'select' ? `d-none` : ``}">
1881
+ ${BgWidget.title('已訂閱裝置')}
1882
+ <div class="flex-fill"></div>
1883
+ </div>
1884
+ ${BgWidget.container(
1885
+ BgWidget.mainCard(
1886
+ [
1887
+ BgWidget.searchPlace(
1888
+ gvc.event(e => {
1889
+ vm.query = e.value;
1890
+ gvc.notifyDataChange(id);
1891
+ }),
1892
+ vm.query || '',
1893
+ '搜尋信箱或者標籤'
1894
+ ),
1895
+ BgWidget.tableV3({
1896
+ gvc: gvc,
1897
+ getData: vmk => {
1898
+ vmi = vmk;
1899
+ const limit = 20;
1900
+ ApiUser.getFCM({
1901
+ page: vmi.page - 1,
1902
+ limit: limit,
1903
+ search: vm.query || undefined,
1904
+ }).then(data => {
1905
+ vm.dataList = data.response.data;
1906
+ vmi.pageSize = Math.ceil(data.response.total / limit);
1907
+ vmi.originalData = vm.dataList;
1908
+ vmi.tableData = getDatalist();
1909
+ vmi.loading = false;
1910
+ vmi.callback();
1911
+ if (type === 'select') {
1912
+ callback(
1913
+ vm.dataList.filter((dd: any) => {
1914
+ return dd.checked;
1915
+ })
1916
+ );
1917
+ }
1918
+ });
1919
+ },
1920
+ rowClick: (data, index) => {
1921
+ vm.dataList[index].checked = !vm.dataList[index].checked;
1922
+ vmi.data = getDatalist();
1923
+ vmi.callback();
1924
+ gvc.notifyDataChange(filterID);
1925
+ callback(
1926
+ vm.dataList.filter((dd: any) => {
1927
+ return dd.checked;
1928
+ })
1929
+ );
1930
+ },
1931
+ filter: [
1932
+ {
1933
+ name: '批量移除',
1934
+ event: checkedData => {
1935
+ dialog.checkYesOrNot({
1936
+ text: '是否確認刪除所選項目?',
1937
+ callback: response => {
1938
+ if (response) {
1939
+ dialog.dataLoading({ visible: true });
1940
+ ApiUser.deleteSubscribe({
1941
+ email: checkedData.map((dd: any) => dd.email).join(`,`),
1942
+ }).then(res => {
1943
+ dialog.dataLoading({ visible: false });
1944
+ if (res.result) {
1945
+ vm.dataList = undefined;
1946
+ gvc.notifyDataChange(id);
1947
+ } else {
1948
+ dialog.errorMessage({ text: '刪除失敗' });
1949
+ }
1950
+ });
1951
+ }
1952
+ },
1953
+ });
1954
+ },
1955
+ },
1956
+ ],
1957
+ }),
1958
+ ].join('')
1959
+ )
1960
+ )}
1961
+ `);
1962
+ },
1963
+ divCreate: {
1964
+ class: type === 'select' ? `m-n4` : ``,
1965
+ },
1966
+ };
1967
+ });
1968
+ }
1969
+
1970
+ public static fcmSetting(gvc: GVC) {
1971
+ const glitter = gvc.glitter;
1972
+ const vm: {
1973
+ type: 'list' | 'add' | 'replace';
1974
+ data: any;
1975
+ dataList: any;
1976
+ query?: string;
1977
+ } = {
1978
+ type: 'list',
1979
+ data: undefined,
1980
+ dataList: undefined,
1981
+ query: undefined,
1982
+ };
1983
+ return gvc.bindView(() => {
1984
+ const id = glitter.getUUID();
1985
+ const filterID = glitter.getUUID();
1986
+ return {
1987
+ bind: id,
1988
+ dataList: [{ obj: vm, key: 'type' }],
1989
+ view: () => {
1990
+ if (vm.type === 'list') {
1991
+ return BgWidget.container(html`
1992
+ <div class="title-container">
1993
+ ${BgWidget.title('推播訊息管理')}
1994
+ <div class="flex-fill"></div>
1995
+ ${BgWidget.darkButton(
1996
+ '新增推播',
1997
+ gvc.event(() => {
1998
+ vm.data = undefined;
1999
+ vm.type = 'add';
2000
+ })
2001
+ )}
2002
+ </div>
2003
+ ${BgWidget.container(
2004
+ BgWidget.mainCard(
2005
+ [
2006
+ BgWidget.searchPlace(
2007
+ gvc.event(e => {
2008
+ vm.query = e.value;
2009
+ gvc.notifyDataChange(id);
2010
+ }),
2011
+ vm.query || '',
2012
+ '搜尋所有信件內容'
2013
+ ),
2014
+ BgWidget.tableV3({
2015
+ gvc: gvc,
2016
+ getData: vmi => {
2017
+ const limit = 20;
2018
+ ApiPost.getManagerPost({
2019
+ page: vmi.page - 1,
2020
+ limit: limit,
2021
+ search: vm.query ? [`title->${vm.query}`] : undefined,
2022
+ type: 'notify-message-config',
2023
+ }).then(data => {
2024
+ function getDatalist() {
2025
+ return data.response.data.map((dd: any) => {
2026
+ return [
2027
+ {
2028
+ key: '推播標題',
2029
+ value: `<span class="fs-7">${dd.content.title}</span>`,
2030
+ },
2031
+ {
2032
+ key: '推播內文',
2033
+ value: `<span class="fs-7">${Tool.truncateString(dd.content.content.replace(/<[^>]*>/g, ''), 30)}</span>`,
2034
+ },
2035
+ {
2036
+ key: '發送推播',
2037
+ value: html`<button
2038
+ class="btn btn-primary-c px-4"
2039
+ style="width:20px !important;height: 30px;"
2040
+ onclick="${gvc.event((e, event) => {
2041
+ event.stopPropagation();
2042
+ gvc.glitter.innerDialog(gvc => {
2043
+ let dataList: any = [];
2044
+ return html`
2045
+ <div style="max-height: calc(100vh - 100px);overflow-y: auto;">
2046
+ ${BgWidget.container(
2047
+ BgWidget.card(
2048
+ [
2049
+ html`
2050
+ <div class="title-container">
2051
+ ${BgWidget.goBack(
2052
+ gvc.event(() => {
2053
+ gvc.closeDialog();
2054
+ })
2055
+ )}
2056
+ ${BgWidget.title(`選擇群發對象`)}
2057
+ <div class="flex-fill"></div>
2058
+ <button
2059
+ class="btn bt_c39 me-2"
2060
+ style="height:38px;font-size: 14px;"
2061
+ onclick="${gvc.event(() => {
2062
+ const dialog = new ShareDialog(gvc.glitter);
2063
+ dialog.dataLoading({
2064
+ text: '發送中...',
2065
+ visible: true,
2066
+ });
2067
+ ApiFcm.send({
2068
+ device_token: ['all'],
2069
+ title: dd.content.title,
2070
+ content: dd.content.content,
2071
+ link: dd.content.link,
2072
+ }).then(() => {
2073
+ dialog.dataLoading({ visible: false });
2074
+ dialog.successMessage({ text: `發送成功` });
2075
+ });
2076
+ })}"
2077
+ >
2078
+ 發送給所有用戶
2079
+ </button>
2080
+ <button
2081
+ class="btn bt_c39"
2082
+ style="height:38px;font-size: 14px;"
2083
+ onclick="${gvc.event(() => {
2084
+ const dialog = new ShareDialog(gvc.glitter);
2085
+ if (dataList.length > 0) {
2086
+ dialog.dataLoading({
2087
+ text: '發送中...',
2088
+ visible: true,
2089
+ });
2090
+ ApiFcm.send({
2091
+ device_token: dataList.map((dd: any) => {
2092
+ return dd.deviceToken;
2093
+ }),
2094
+ title: dd.content.title,
2095
+ content: dd.content.content,
2096
+ link: dd.content.link,
2097
+ }).then(() => {
2098
+ dialog.dataLoading({ visible: false });
2099
+ dialog.successMessage({ text: '發送成功' });
2100
+ });
2101
+ } else {
2102
+ dialog.errorMessage({ text: '請選擇發送對象' });
2103
+ }
2104
+ })}"
2105
+ >
2106
+ 確認並發送
2107
+ </button>
2108
+ </div>
2109
+ ` +
2110
+ BgNotify.fcmDevice(gvc, 'select', data => {
2111
+ dataList = data;
2112
+ }),
2113
+ ].join('')
2114
+ )
2115
+ )}
2116
+ <div></div>
2117
+ </div>
2118
+ `;
2119
+ }, 'email');
2120
+ })}"
2121
+ >
2122
+ <i class="fa-sharp fa-regular fa-paper-plane-top"></i>
2123
+ </button>`,
2124
+ },
2125
+ ];
2126
+ });
2127
+ }
2128
+
2129
+ vm.dataList = data.response.data;
2130
+ vmi.pageSize = Math.ceil(data.response.total / limit);
2131
+ vmi.originalData = vm.dataList;
2132
+ vmi.tableData = getDatalist();
2133
+ vmi.loading = false;
2134
+ vmi.callback();
2135
+ });
2136
+ },
2137
+ rowClick: (data, index) => {
2138
+ vm.data = vm.dataList[index].content;
2139
+ vm.type = 'replace';
2140
+ },
2141
+ filter: [
2142
+ {
2143
+ name: '批量移除',
2144
+ event: checkedData => {
2145
+ const dialog = new ShareDialog(glitter);
2146
+ dialog.checkYesOrNot({
2147
+ text: '是否確認刪除所選項目?',
2148
+ callback: response => {
2149
+ if (response) {
2150
+ dialog.dataLoading({ visible: true });
2151
+ ApiPost.delete({
2152
+ id: checkedData.map((dd: any) => dd.id).join(`,`),
2153
+ }).then(res => {
2154
+ dialog.dataLoading({ visible: false });
2155
+ if (res.result) {
2156
+ vm.dataList = undefined;
2157
+ gvc.notifyDataChange(id);
2158
+ } else {
2159
+ dialog.errorMessage({ text: '刪除失敗' });
2160
+ }
2161
+ });
2162
+ }
2163
+ },
2164
+ });
2165
+ },
2166
+ },
2167
+ ],
2168
+ }),
2169
+ ].join('')
2170
+ )
2171
+ )}
2172
+ `);
2173
+ } else if (vm.type == 'replace') {
2174
+ return this.fcmEditor({
2175
+ vm: vm,
2176
+ gvc: gvc,
2177
+ type: 'replace',
2178
+ });
2179
+ } else {
2180
+ return this.fcmEditor({
2181
+ vm: vm,
2182
+ gvc: gvc,
2183
+ type: 'add',
2184
+ });
2185
+ }
2186
+ },
2187
+ };
2188
+ });
2189
+ }
2190
+
2191
+ public static rebackMessage(gvc: GVC, type: 'list' | 'select' = 'list', callback: (select: any) => void = () => {}) {
2192
+ const vm: {
2193
+ type: 'list' | 'replace';
2194
+ data: any;
2195
+ dataList: any;
2196
+ query?: string;
2197
+ } = {
2198
+ type: 'list',
2199
+ data: {
2200
+ id: 61,
2201
+ userID: 549313940,
2202
+ account: 'jianzhi.wang@homee.ai',
2203
+ userData: { name: '王建智', email: 'jianzhi.wang@homee.ai', phone: '0978028739' },
2204
+ created_time: '2023-11-26T02:14:09.000Z',
2205
+ role: 0,
2206
+ company: null,
2207
+ status: 1,
2208
+ },
2209
+ dataList: undefined,
2210
+ query: '',
2211
+ };
2212
+ const glitter = gvc.glitter;
2213
+ const filterID = glitter.getUUID();
2214
+ const id = glitter.getUUID();
2215
+ return gvc.bindView(() => {
2216
+ return {
2217
+ bind: id,
2218
+ view: () => {
2219
+ let vmi: any = undefined;
2220
+
2221
+ function getDatalist() {
2222
+ let interval: any = 0;
2223
+ return vm.dataList.map((dd: any) => {
2224
+ return [
2225
+ {
2226
+ key: '名稱',
2227
+ value: `<span class="fs-7">${dd.content.name}</span>`,
2228
+ },
2229
+ {
2230
+ key: '信箱',
2231
+ value: `<span class="fs-7">${dd.content.email}</span>`,
2232
+ },
2233
+ {
2234
+ key: '標題',
2235
+ value: `<span class="fs-7">${dd.content.title}</span>`,
2236
+ },
2237
+ {
2238
+ key: '內文',
2239
+ value: `<span class="fs-7">${Tool.truncateString(dd.content.content ?? '', 30)}</span>`,
2240
+ },
2241
+ ];
2242
+ });
2243
+ }
2244
+
2245
+ if (vm.type === 'replace') {
2246
+ return BgWidget.container(html`
2247
+ <div class="title-container">
2248
+ ${BgWidget.goBack(
2249
+ gvc.event(() => {
2250
+ vm.type = 'list';
2251
+ gvc.notifyDataChange(id);
2252
+ })
2253
+ )}
2254
+ ${BgWidget.title(`用戶回饋內容`)}
2255
+ <div class="flex-fill"></div>
2256
+ </div>
2257
+ ${BgWidget.card(
2258
+ ` ${FormWidget.editorView({
2259
+ gvc: gvc,
2260
+ array: [
2261
+ {
2262
+ key: 'name',
2263
+ type: 'name',
2264
+ title: '姓名',
2265
+ require: 'true',
2266
+ readonly: 'read',
2267
+ style_data: {
2268
+ input: {
2269
+ class: '',
2270
+ style: '',
2271
+ },
2272
+ label: {
2273
+ class: 'form-label fs-base ',
2274
+ style: '',
2275
+ },
2276
+ container: {
2277
+ tag: 'aboutus-container',
2278
+ class: '',
2279
+ style: '',
2280
+ stylist: [],
2281
+ dataType: 'static',
2282
+ style_from: 'tag',
2283
+ classDataType: 'static',
2284
+ },
2285
+ },
2286
+ },
2287
+ {
2288
+ key: 'email',
2289
+ type: 'email',
2290
+ title: '信箱',
2291
+ require: 'true',
2292
+ readonly: 'read',
2293
+ style_data: {
2294
+ input: {
2295
+ class: '',
2296
+ style: '',
2297
+ },
2298
+ label: {
2299
+ class: 'form-label fs-base ',
2300
+ style: '',
2301
+ },
2302
+ container: {
2303
+ tag: 'aboutus-container',
2304
+ class: '',
2305
+ style: '',
2306
+ stylist: [],
2307
+ style_from: 'tag',
2308
+ },
2309
+ },
2310
+ },
2311
+ {
2312
+ key: 'title',
2313
+ type: 'text',
2314
+ title: '標題',
2315
+ require: 'true',
2316
+ readonly: 'read',
2317
+ style_data: {
2318
+ input: {
2319
+ class: '',
2320
+ style: '',
2321
+ },
2322
+ label: {
2323
+ class: 'form-label fs-base ',
2324
+ style: '',
2325
+ },
2326
+ container: {
2327
+ tag: 'aboutus-container',
2328
+ class: '',
2329
+ style: '',
2330
+ stylist: [],
2331
+ dataType: 'static',
2332
+ style_from: 'tag',
2333
+ classDataType: 'static',
2334
+ },
2335
+ },
2336
+ },
2337
+ {
2338
+ key: 'content',
2339
+ type: 'textArea',
2340
+ title: '訊息',
2341
+ require: 'true',
2342
+ readonly: 'read',
2343
+ style_data: {
2344
+ input: {
2345
+ class: '',
2346
+ style: '',
2347
+ },
2348
+ label: {
2349
+ class: 'form-label fs-base ',
2350
+ style: '',
2351
+ },
2352
+ container: {
2353
+ class: '',
2354
+ style: '',
2355
+ },
2356
+ },
2357
+ },
2358
+ ],
2359
+ refresh: () => {},
2360
+ formData: vm.data.content,
2361
+ })}`
2362
+ )}
2363
+ `);
2364
+ }
2365
+ return BgWidget.container(html`
2366
+ <div class="title-container ${type === 'select' ? `d-none` : ``}">
2367
+ ${BgWidget.title('回饋信件')}
2368
+ <div class="flex-fill"></div>
2369
+ </div>
2370
+ ${BgWidget.mainCard(
2371
+ [
2372
+ BgWidget.searchPlace(
2373
+ gvc.event((e, event) => {
2374
+ vm.query = e.value;
2375
+ gvc.notifyDataChange(id);
2376
+ }),
2377
+ vm.query || '',
2378
+ '搜尋標題'
2379
+ ),
2380
+ BgWidget.tableV3({
2381
+ gvc: gvc,
2382
+ getData: vmi => {
2383
+ const limit = 20;
2384
+ ApiPost.getUserPost({
2385
+ page: vmi.page - 1,
2386
+ limit: limit,
2387
+ search: vm.query || undefined,
2388
+ type: 'userQuestion',
2389
+ }).then(data => {
2390
+ vm.dataList = data.response.data;
2391
+ vmi.pageSize = Math.ceil(data.response.total / limit);
2392
+ vmi.originalData = vm.dataList;
2393
+ vmi.tableData = getDatalist();
2394
+ vmi.loading = false;
2395
+ vmi.callback();
2396
+
2397
+ if (type === 'select') {
2398
+ callback(
2399
+ vm.dataList.filter((dd: any) => {
2400
+ return dd.checked;
2401
+ })
2402
+ );
2403
+ }
2404
+ });
2405
+ },
2406
+ rowClick: (data, index) => {
2407
+ vm.type = 'replace';
2408
+ vm.data = vm.dataList[index];
2409
+ gvc.notifyDataChange(id);
2410
+ },
2411
+ filter: [
2412
+ {
2413
+ name: '批量刪除',
2414
+ event: () => {
2415
+ const dialog = new ShareDialog(gvc.glitter);
2416
+ dialog.checkYesOrNot({
2417
+ text: '是否確認刪除所選項目?',
2418
+ callback: response => {
2419
+ if (response) {
2420
+ dialog.dataLoading({ visible: true });
2421
+ ApiPost.deleteUserPost({
2422
+ id: vm.dataList
2423
+ .filter((dd: any) => {
2424
+ return dd.checked;
2425
+ })
2426
+ .map((dd: any) => {
2427
+ return dd.id;
2428
+ })
2429
+ .join(`,`),
2430
+ }).then(res => {
2431
+ dialog.dataLoading({ visible: false });
2432
+ if (res.result) {
2433
+ vm.dataList = undefined;
2434
+ gvc.notifyDataChange(id);
2435
+ } else {
2436
+ dialog.errorMessage({ text: '刪除失敗' });
2437
+ }
2438
+ });
2439
+ }
2440
+ },
2441
+ });
2442
+ },
2443
+ },
2444
+ ],
2445
+ }),
2446
+ ].join('')
2447
+ )}
2448
+ `);
2449
+ },
2450
+ divCreate: {
2451
+ class: type === 'select' ? `m-n4` : ``,
2452
+ },
2453
+ };
2454
+ });
2455
+ }
2456
+
2457
+ public static customerMessage(
2458
+ gvc: GVC,
2459
+ type: 'list' | 'select' = 'list',
2460
+ callback: (select: any) => void = () => {}
2461
+ ) {
2462
+ const vm: {
2463
+ type: 'list' | 'replace';
2464
+ data: any;
2465
+ dataList: any;
2466
+ query?: string;
2467
+ } = {
2468
+ type: 'list',
2469
+ data: {
2470
+ id: 61,
2471
+ userID: 549313940,
2472
+ account: 'jianzhi.wang@homee.ai',
2473
+ userData: { name: '王建智', email: 'jianzhi.wang@homee.ai', phone: '0978028739' },
2474
+ created_time: '2023-11-26T02:14:09.000Z',
2475
+ role: 0,
2476
+ company: null,
2477
+ status: 1,
2478
+ },
2479
+ dataList: undefined,
2480
+ query: '',
2481
+ };
2482
+ const glitter = gvc.glitter;
2483
+ const filterID = glitter.getUUID();
2484
+ const id = glitter.getUUID();
2485
+ const dialog = new ShareDialog(gvc.glitter);
2486
+ return gvc.bindView(() => {
2487
+ return {
2488
+ bind: id,
2489
+ view: () => {
2490
+ let vmi: any = undefined;
2491
+ function getDatalist() {
2492
+ let interval: any = 0;
2493
+ return vm.dataList.map((dd: any) => {
2494
+ return [
2495
+ {
2496
+ key: (() => {
2497
+ clearInterval(interval);
2498
+ if (
2499
+ !vm.dataList.find((dd: any) => {
2500
+ return !dd.checked;
2501
+ })
2502
+ ) {
2503
+ interval = setTimeout(() => {
2504
+ ApiUser.getFCM({
2505
+ page: vmi.page - 1,
2506
+ limit: 100000,
2507
+ search: vm.query || undefined,
2508
+ }).then(data => {
2509
+ callback(data.response.data);
2510
+ });
2511
+ }, 10);
2512
+ }
2513
+
2514
+ return EditorElem.checkBoxOnly({
2515
+ gvc: gvc,
2516
+ def: !vm.dataList.find((dd: any) => {
2517
+ return !dd.checked;
2518
+ }),
2519
+ callback: result => {
2520
+ vm.dataList.map((dd: any) => {
2521
+ dd.checked = result;
2522
+ });
2523
+ vmi.data = getDatalist();
2524
+ vmi.callback();
2525
+ gvc.notifyDataChange(filterID);
2526
+ callback(
2527
+ vm.dataList.filter((dd: any) => {
2528
+ return dd.checked;
2529
+ })
2530
+ );
2531
+ },
2532
+ });
2533
+ })(),
2534
+ value: EditorElem.checkBoxOnly({
2535
+ gvc: gvc,
2536
+ def: dd.checked,
2537
+ callback: result => {
2538
+ dd.checked = result;
2539
+ vmi.data = getDatalist();
2540
+ vmi.callback();
2541
+ gvc.notifyDataChange(filterID);
2542
+ callback(
2543
+ vm.dataList.filter((dd: any) => {
2544
+ return dd.checked;
2545
+ })
2546
+ );
2547
+ },
2548
+ style: 'height:25px;',
2549
+ }),
2550
+ },
2551
+ {
2552
+ key: '名稱',
2553
+ value: `<span class="fs-7">${dd.user_data ? dd.user_data.userData.name : `訪客`}</span>`,
2554
+ },
2555
+ {
2556
+ key: '信箱',
2557
+ value: `<span class="fs-7">${dd.user_data ? dd.user_data.userData.email : `...`}</span>`,
2558
+ },
2559
+ {
2560
+ key: '訊息內容',
2561
+ value: `<span class="fs-7">${dd.topMessage ? dd.topMessage.text : ``}</span>`,
2562
+ },
2563
+ ];
2564
+ });
2565
+ }
2566
+
2567
+ if (vm.type === 'replace') {
2568
+ return BgWidget.container(html`
2569
+ <div class="title-container">
2570
+ ${BgWidget.goBack(
2571
+ gvc.event(() => {
2572
+ vm.type = 'list';
2573
+ gvc.notifyDataChange(id);
2574
+ })
2575
+ )}
2576
+ ${BgWidget.title(`客服訊息`)}
2577
+ <div class="flex-fill"></div>
2578
+ </div>
2579
+ ${BgWidget.card(
2580
+ ` ${FormWidget.editorView({
2581
+ gvc: gvc,
2582
+ array: [
2583
+ {
2584
+ key: 'name',
2585
+ type: 'name',
2586
+ title: '姓名',
2587
+ require: 'true',
2588
+ readonly: 'read',
2589
+ style_data: {
2590
+ input: {
2591
+ class: '',
2592
+ style: '',
2593
+ },
2594
+ label: {
2595
+ class: 'form-label fs-base ',
2596
+ style: '',
2597
+ },
2598
+ container: {
2599
+ tag: 'aboutus-container',
2600
+ class: '',
2601
+ style: '',
2602
+ stylist: [],
2603
+ dataType: 'static',
2604
+ style_from: 'tag',
2605
+ classDataType: 'static',
2606
+ },
2607
+ },
2608
+ },
2609
+ {
2610
+ key: 'email',
2611
+ type: 'email',
2612
+ title: '信箱',
2613
+ require: 'true',
2614
+ readonly: 'read',
2615
+ style_data: {
2616
+ input: {
2617
+ class: '',
2618
+ style: '',
2619
+ },
2620
+ label: {
2621
+ class: 'form-label fs-base ',
2622
+ style: '',
2623
+ },
2624
+ container: {
2625
+ tag: 'aboutus-container',
2626
+ class: '',
2627
+ style: '',
2628
+ stylist: [],
2629
+ style_from: 'tag',
2630
+ },
2631
+ },
2632
+ },
2633
+ {
2634
+ key: 'title',
2635
+ type: 'text',
2636
+ title: '標題',
2637
+ require: 'true',
2638
+ readonly: 'read',
2639
+ style_data: {
2640
+ input: {
2641
+ class: '',
2642
+ style: '',
2643
+ },
2644
+ label: {
2645
+ class: 'form-label fs-base ',
2646
+ style: '',
2647
+ },
2648
+ container: {
2649
+ tag: 'aboutus-container',
2650
+ class: '',
2651
+ style: '',
2652
+ stylist: [],
2653
+ dataType: 'static',
2654
+ style_from: 'tag',
2655
+ classDataType: 'static',
2656
+ },
2657
+ },
2658
+ },
2659
+ {
2660
+ key: 'content',
2661
+ type: 'textArea',
2662
+ title: '訊息',
2663
+ require: 'true',
2664
+ readonly: 'read',
2665
+ style_data: {
2666
+ input: {
2667
+ class: '',
2668
+ style: '',
2669
+ },
2670
+ label: {
2671
+ class: 'form-label fs-base ',
2672
+ style: '',
2673
+ },
2674
+ container: {
2675
+ class: '',
2676
+ style: '',
2677
+ },
2678
+ },
2679
+ },
2680
+ ],
2681
+ refresh: () => {},
2682
+ formData: vm.data.content,
2683
+ })}`
2684
+ )}
2685
+ `);
2686
+ }
2687
+ return BgWidget.container(html`
2688
+ <div class="title-container ${type === 'select' ? `d-none` : ``}">
2689
+ ${BgWidget.title('客服訊息')}
2690
+ <div class="flex-fill"></div>
2691
+ <button
2692
+ class="btn hoverBtn me-2 px-3"
2693
+ style="height:35px !important;font-size: 14px;color:black;border:1px solid black;"
2694
+ onclick="${gvc.event(() => {
2695
+ EditorElem.openEditorDialog(
2696
+ gvc,
2697
+ gvc => {
2698
+ const saasConfig: {
2699
+ config: any;
2700
+ api: any;
2701
+ } = (window as any).saasConfig;
2702
+ const id = gvc.glitter.getUUID();
2703
+ let keyData = {};
2704
+ return [
2705
+ gvc.bindView(() => {
2706
+ ApiUser.getPublicConfig(`robot_auto_reply`, 'manager').then((data: any) => {
2707
+ if (data.response.value) {
2708
+ keyData = data.response.value;
2709
+ gvc.notifyDataChange(id);
2710
+ }
2711
+ });
2712
+ return {
2713
+ bind: id,
2714
+ view: () => {
2715
+ return new Promise((resolve, reject) => {
2716
+ resolve(
2717
+ FormWidget.editorView({
2718
+ gvc: gvc,
2719
+ array: [
2720
+ {
2721
+ title: '機器人問答',
2722
+ key: 'question',
2723
+ readonly: 'write',
2724
+ type: 'array',
2725
+ require: 'true',
2726
+ style_data: {
2727
+ label: {
2728
+ class: 'form-label fs-base ',
2729
+ style: '',
2730
+ },
2731
+ input: { class: '', style: '' },
2732
+ container: {
2733
+ class: '',
2734
+ style: '',
2735
+ },
2736
+ },
2737
+ referTitile: 'ask',
2738
+ plusBtn: '添加自動問答',
2739
+ formList: [
2740
+ {
2741
+ title: '問題',
2742
+ key: 'ask',
2743
+ readonly: 'write',
2744
+ type: 'text',
2745
+ require: 'true',
2746
+ style_data: {
2747
+ label: {
2748
+ class: 'form-label fs-base ',
2749
+ style: '',
2750
+ },
2751
+ input: {
2752
+ class: '',
2753
+ style: '',
2754
+ },
2755
+ container: {
2756
+ class: '',
2757
+ style: '',
2758
+ },
2759
+ },
2760
+ },
2761
+ {
2762
+ title: '回應',
2763
+ key: 'response',
2764
+ readonly: 'write',
2765
+ type: 'textArea',
2766
+ require: 'true',
2767
+ style_data: {
2768
+ label: {
2769
+ class: 'form-label fs-base ',
2770
+ style: '',
2771
+ },
2772
+ input: {
2773
+ class: '',
2774
+ style: '',
2775
+ },
2776
+ container: {
2777
+ class: '',
2778
+ style: '',
2779
+ },
2780
+ },
2781
+ },
2782
+ ],
2783
+ },
2784
+ ],
2785
+ refresh: () => {
2786
+ gvc.notifyDataChange(id);
2787
+ },
2788
+ formData: keyData,
2789
+ })
2790
+ );
2791
+ });
2792
+ },
2793
+ divCreate: {
2794
+ class: 'p-2',
2795
+ },
2796
+ };
2797
+ }),
2798
+ html`<div class="d-flex">
2799
+ <div class="flex-fill"></div>
2800
+ <div
2801
+ class=" btn-primary-c btn my-2 me-2"
2802
+ style="margin-left: 10px;height:35px;"
2803
+ onclick="${gvc.event(() => {
2804
+ dialog.dataLoading({ visible: true });
2805
+ ApiUser.setPublicConfig({
2806
+ key: `robot_auto_reply`,
2807
+ value: keyData,
2808
+ user_id: 'manager',
2809
+ }).then((data: any) => {
2810
+ dialog.dataLoading({ visible: false });
2811
+ dialog.successMessage({ text: '設定成功' });
2812
+ });
2813
+ })}"
2814
+ >
2815
+ 儲存設定
2816
+ </div>
2817
+ </div>`,
2818
+ ].join('');
2819
+ },
2820
+ () => {},
2821
+ 500,
2822
+ '自訂表單'
2823
+ );
2824
+ })}"
2825
+ >
2826
+ <i class="fa-regular fa-gear me-2 "></i>
2827
+ 機器人問答
2828
+ </button>
2829
+ </div>
2830
+ ${BgWidget.table({
2831
+ gvc: gvc,
2832
+ getData: vmk => {
2833
+ vmi = vmk;
2834
+ Chat.getChatRoom({
2835
+ page: vmi.page - 1,
2836
+ limit: 20,
2837
+ user_id: 'manager',
2838
+ }).then(data => {
2839
+ vmi.pageSize = Math.ceil(data.response.total / 20);
2840
+ vm.dataList = data.response.data;
2841
+ vmi.data = getDatalist();
2842
+ vmi.loading = false;
2843
+ vmi.callback();
2844
+ if (type === 'select') {
2845
+ callback(
2846
+ vm.dataList.filter((dd: any) => {
2847
+ return dd.checked;
2848
+ })
2849
+ );
2850
+ }
2851
+ });
2852
+ },
2853
+ rowClick: (data, index) => {
2854
+ gvc.glitter.innerDialog(() => {
2855
+ return EditorElem.iframeComponent({
2856
+ page: 'chat_page',
2857
+ width: 400,
2858
+ height: 680,
2859
+ par: [
2860
+ {
2861
+ key: 'is_manager',
2862
+ value: 'true',
2863
+ },
2864
+ {
2865
+ key: 'chat_who',
2866
+ value: vm.dataList[index].who,
2867
+ },
2868
+ ],
2869
+ });
2870
+ }, '');
2871
+ },
2872
+ filter: html`
2873
+ <div style="height:50px;" class="w-100 border-bottom ">
2874
+ <input
2875
+ class="form-control h-100 "
2876
+ style="border: none;"
2877
+ placeholder="搜尋用戶名稱"
2878
+ onchange="${gvc.event((e, event) => {
2879
+ vm.query = e.value;
2880
+ gvc.notifyDataChange(id);
2881
+ })}"
2882
+ value="${vm.query || ''}"
2883
+ />
2884
+ </div>
2885
+ ${gvc.bindView(() => {
2886
+ return {
2887
+ bind: filterID,
2888
+ view: () => {
2889
+ if (
2890
+ !vm.dataList ||
2891
+ !vm.dataList.find((dd: any) => {
2892
+ return dd.checked;
2893
+ })
2894
+ ) {
2895
+ return ``;
2896
+ } else {
2897
+ const dialog = new ShareDialog(gvc.glitter);
2898
+ const selCount = vm.dataList.filter((dd: any) => dd.checked).length;
2899
+ return BgWidget.selNavbar({
2900
+ count: selCount,
2901
+ buttonList: [
2902
+ BgWidget.selEventButton(
2903
+ '批量移除',
2904
+ gvc.event(() => {
2905
+ dialog.checkYesOrNot({
2906
+ text: '是否確認刪除所選項目?',
2907
+ callback: response => {
2908
+ if (response) {
2909
+ dialog.dataLoading({ visible: true });
2910
+ Chat.deleteChatRoom({
2911
+ id: vm.dataList
2912
+ .filter((dd: any) => {
2913
+ return dd.checked;
2914
+ })
2915
+ .map((dd: any) => {
2916
+ return dd.id;
2917
+ })
2918
+ .join(`,`),
2919
+ }).then(res => {
2920
+ dialog.dataLoading({ visible: false });
2921
+ if (res.result) {
2922
+ vm.dataList = undefined;
2923
+ gvc.notifyDataChange(id);
2924
+ } else {
2925
+ dialog.errorMessage({ text: '刪除失敗' });
2926
+ }
2927
+ });
2928
+ }
2929
+ },
2930
+ });
2931
+ })
2932
+ ),
2933
+ ],
2934
+ });
2935
+ }
2936
+ },
2937
+ divCreate: () => {
2938
+ return {
2939
+ class: `d-flex align-items-center p-2 py-3 ${
2940
+ !vm.dataList ||
2941
+ !vm.dataList.find((dd: any) => {
2942
+ return dd.checked;
2943
+ }) ||
2944
+ type === 'select'
2945
+ ? `d-none`
2946
+ : ``
2947
+ }`,
2948
+ style: ``,
2949
+ };
2950
+ },
2951
+ };
2952
+ })}
2953
+ `,
2954
+ })}
2955
+ `);
2956
+ },
2957
+ divCreate: {
2958
+ class: type === 'select' ? `m-n4` : ``,
2959
+ },
2960
+ };
2961
+ });
2962
+ }
2963
+ }
2964
+
2965
+ function defaultEmailText() {
2966
+ return `親愛的 [使用者名稱],
2967
+
2968
+ 歡迎來到 [你的公司或社群名稱]!我們很高興你選擇了我們,並成為我們社群的一員。
2969
+
2970
+ 在這裡,我們致力於提供 [描述你的服務或社群的價值]。我們的團隊一直在努力讓你有一個令人愉快和有價值的體驗。
2971
+
2972
+ 以下是一些建議的下一步:
2973
+
2974
+ 1. **完善個人資料:** 請登入您的帳戶,完善您的個人資料,這有助於我們更好地瞭解您的需求。
2975
+
2976
+ 2. **參與社群:** 加入我們的社交媒體,訂閱我們的通訊,參與我們的討論,您將有機會與其他社群成員建立聯繫。
2977
+
2978
+ 3. **探索我們的服務:** 探索我們的網站/應用程式,瞭解我們提供的所有功能和服務。
2979
+
2980
+ 如果您在使用過程中遇到任何問題,或者有任何反饋,請隨時與我們聯繫。我們的支援團隊隨時準備協助您。
2981
+
2982
+ 再次感謝您加入 [你的公司或社群名稱],我們期待與您建立長期的合作關係!
2983
+
2984
+ 祝您有美好的一天!
2985
+
2986
+ 最誠摯的問候,
2987
+
2988
+ [你的名稱]
2989
+ [你的職務]
2990
+ [你的公司或社群名稱]
2991
+ [聯絡電子郵件]
2992
+ [聯絡電話]`.replace(/\n/g, `<br>`);
2993
+ }
2994
+
2995
+ (window as any).glitter.setModule(import.meta.url, BgNotify);