ts-glitter 21.3.0 → 21.3.3

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 (41) hide show
  1. package/lowcode/Entry.js +1 -1
  2. package/lowcode/Entry.ts +1 -1
  3. package/lowcode/backend-manager/bg-customer-message.js +662 -566
  4. package/lowcode/backend-manager/bg-customer-message.ts +1740 -1580
  5. package/lowcode/cms-plugin/customer-message-user.ts +2 -0
  6. package/lowcode/cms-plugin/module/product-excel.js +169 -129
  7. package/lowcode/cms-plugin/module/product-excel.ts +174 -130
  8. package/lowcode/cms-plugin/shopping-discount-setting.js +640 -600
  9. package/lowcode/cms-plugin/shopping-discount-setting.ts +782 -716
  10. package/lowcode/cms-plugin/shopping-finance-setting.js +372 -407
  11. package/lowcode/cms-plugin/shopping-finance-setting.ts +918 -968
  12. package/lowcode/cms-plugin/shopping-setting-advance.js +1 -1
  13. package/lowcode/cms-plugin/shopping-setting-advance.ts +1 -1
  14. package/lowcode/glitter-base/global/language.js +12 -0
  15. package/lowcode/glitter-base/global/language.ts +12 -0
  16. package/lowcode/glitter-base/route/api-track.js +2 -2
  17. package/lowcode/glitter-base/route/api-track.ts +20 -20
  18. package/lowcode/public-components/checkout/index.js +27 -5
  19. package/lowcode/public-components/checkout/index.ts +34 -6
  20. package/lowcode/public-components/headers/header-class.js +13 -18
  21. package/lowcode/public-components/headers/header-class.ts +16 -20
  22. package/lowcode/public-components/modules/cart-module.js +6 -0
  23. package/lowcode/public-components/modules/cart-module.ts +6 -0
  24. package/lowcode/public-components/product/pd-class.js +1 -3
  25. package/lowcode/public-components/product/pd-class.ts +1 -3
  26. package/omr85cp878.json +1 -0
  27. package/package.json +1 -1
  28. package/src/api-public/services/checkout-event.js +26 -12
  29. package/src/api-public/services/checkout-event.js.map +1 -1
  30. package/src/api-public/services/checkout-event.ts +34 -12
  31. package/src/api-public/services/data-analyze.d.ts +1 -1
  32. package/src/api-public/services/post.js +7 -17
  33. package/src/api-public/services/post.js.map +1 -1
  34. package/src/api-public/services/shopee.js +7 -17
  35. package/src/api-public/services/shopee.js.map +1 -1
  36. package/src/api-public/services/shopping.d.ts +44 -27
  37. package/src/api-public/services/shopping.js +56 -11
  38. package/src/api-public/services/shopping.js.map +1 -1
  39. package/src/api-public/services/shopping.ts +125 -58
  40. package/src/index.js +7 -17
  41. package/src/index.js.map +1 -1
@@ -1,52 +1,58 @@
1
- import {GVC} from '../glitterBundle/GVController.js';
2
- import {Chat} from '../glitter-base/route/chat.js';
3
- import {EditorElem} from '../glitterBundle/plugins/editor-elem.js';
4
- import {ApiUser} from '../glitter-base/route/user.js';
5
- import {FormWidget} from '../official_view_component/official/form.js';
6
- import {ShareDialog} from '../glitterBundle/dialog/ShareDialog.js';
7
- import {BgWidget} from './bg-widget.js';
8
- import {CustomerMessageUser} from '../cms-plugin/customer-message-user.js';
1
+ import { GVC } from '../glitterBundle/GVController.js';
2
+ import { Chat } from '../glitter-base/route/chat.js';
3
+ import { EditorElem } from '../glitterBundle/plugins/editor-elem.js';
4
+ import { ApiUser } from '../glitter-base/route/user.js';
5
+ import { FormWidget } from '../official_view_component/official/form.js';
6
+ import { ShareDialog } from '../glitterBundle/dialog/ShareDialog.js';
7
+ import { BgWidget } from './bg-widget.js';
8
+ import { CustomerMessageUser } from '../cms-plugin/customer-message-user.js';
9
9
 
10
10
  export class BgCustomerMessage {
11
- public static config = {
12
- color: 'rgb(254, 85, 65);',
13
- title: '',
14
- content: '',
15
- name: '',
16
- head: '',
17
- hideBar: false,
18
- };
19
- public static visible = false;
11
+ public static config = {
12
+ color: 'rgb(254, 85, 65);',
13
+ title: '',
14
+ content: '',
15
+ name: '',
16
+ head: '',
17
+ hideBar: false,
18
+ };
19
+ public static visible = false;
20
20
 
21
- public static vm: {
22
- type: 'list' | 'detail';
23
- chat_user: any;
24
- select_bt: 'list' | 'robot' | 'preview' | 'setting';
25
- } = {
26
- type: 'list',
27
- chat_user: '',
28
- select_bt: 'list',
29
- };
30
- public static id = `dsmdklweew3`;
21
+ public static vm: {
22
+ type: 'list' | 'detail';
23
+ chat_user: any;
24
+ select_bt: 'list' | 'robot' | 'preview' | 'setting';
25
+ } = {
26
+ type: 'list',
27
+ chat_user: '',
28
+ select_bt: 'list',
29
+ };
30
+ public static id = `dsmdklweew3`;
31
31
 
32
- public static leftNav(gvc: GVC) {
33
- const html = String.raw;
34
- return html`
35
- <div id="BgCustomerMessageHover" class="d-none position-fixed vw-100 vh-100"
36
- style="background: rgba(0,0,0,0.5);z-index: 99999;" onclick="${gvc.event(() => {
37
- BgCustomerMessage.toggle(false, gvc)
38
- })}"></div>
39
- <div id="BgCustomerMessage" class="position-fixed left-0 top-0 h-100 bg-white shadow-lg "
40
- style="width:480px;max-width:100vw; z-index: 99999; right: -125%;background: rgba(0,0,0,0.5);">
41
- ${BgCustomerMessage.view(gvc)}
42
- </div>`;
43
- }
32
+ public static leftNav(gvc: GVC) {
33
+ const html = String.raw;
34
+ return html` <div
35
+ id="BgCustomerMessageHover"
36
+ class="d-none position-fixed vw-100 vh-100"
37
+ style="background: rgba(0,0,0,0.5);z-index: 99999;"
38
+ onclick="${gvc.event(() => {
39
+ BgCustomerMessage.toggle(false, gvc);
40
+ })}"
41
+ ></div>
42
+ <div
43
+ id="BgCustomerMessage"
44
+ class="position-fixed left-0 top-0 h-100 bg-white shadow-lg "
45
+ style="width:480px;max-width:100vw; z-index: 99999; right: -125%;background: rgba(0,0,0,0.5);"
46
+ >
47
+ ${BgCustomerMessage.view(gvc)}
48
+ </div>`;
49
+ }
44
50
 
45
- public static view(gvc: GVC) {
46
- return gvc.bindView(() => {
47
- const html = String.raw;
48
- const vm = BgCustomerMessage.vm;
49
- gvc.addStyle(`
51
+ public static view(gvc: GVC) {
52
+ return gvc.bindView(() => {
53
+ const html = String.raw;
54
+ const vm = BgCustomerMessage.vm;
55
+ gvc.addStyle(`
50
56
 
51
57
  .btn-white-primary {
52
58
  border: 2px solid #ffb400;;
@@ -85,44 +91,40 @@ export class BgCustomerMessage {
85
91
  -webkit-text-fill-color: transparent;
86
92
  }
87
93
  `);
88
- return {
89
- bind: BgCustomerMessage.id,
90
- view: () => {
91
-
92
- if (!BgCustomerMessage.visible) {
93
-
94
- return html`
95
- <div class="d-flex align-items-center justify-content-center w-100 flex-column pt-3">
96
- <div class="spinner-border" role="status" >
97
- <span class="sr-only"></span>
98
- </div>
99
- <span class="mt-2">載入中...</span>
100
- </div>`;
101
- }
102
- if (vm.type === 'detail') {
103
- return html`
104
- <div style="padding-bottom: 70px;">
105
- ${CustomerMessageUser.detail({
106
- gvc: gvc,
107
- chat: vm.chat_user,
108
- user_id: 'manager',
109
- containerHeight: ($('body').height() as any) + 60 + 'px',
110
- document: document,
111
- goBack: () => {
112
- vm.type = 'list';
113
- vm.select_bt = 'list';
114
- gvc.notifyDataChange(BgCustomerMessage.id);
115
- },
116
- close: () => {
117
- vm.type = 'list';
118
- vm.select_bt = 'list';
119
- gvc.notifyDataChange(BgCustomerMessage.id);
120
- },
121
- })}
122
- </div>`;
123
- } else {
124
- let view = [
125
- ` <div class="navbar d-flex align-items-center justify-content-between w-100 p-3 "
94
+ return {
95
+ bind: BgCustomerMessage.id,
96
+ view: () => {
97
+ if (!BgCustomerMessage.visible) {
98
+ return html` <div class="d-flex align-items-center justify-content-center w-100 flex-column pt-3">
99
+ <div class="spinner-border" role="status">
100
+ <span class="sr-only"></span>
101
+ </div>
102
+ <span class="mt-2">載入中...</span>
103
+ </div>`;
104
+ }
105
+ if (vm.type === 'detail') {
106
+ return html` <div style="padding-bottom: 70px;">
107
+ ${CustomerMessageUser.detail({
108
+ gvc: gvc,
109
+ chat: vm.chat_user,
110
+ user_id: 'manager',
111
+ containerHeight: ($('body').height() as any) + 60 + 'px',
112
+ document: document,
113
+ goBack: () => {
114
+ vm.type = 'list';
115
+ vm.select_bt = 'list';
116
+ gvc.notifyDataChange(BgCustomerMessage.id);
117
+ },
118
+ close: () => {
119
+ vm.type = 'list';
120
+ vm.select_bt = 'list';
121
+ gvc.notifyDataChange(BgCustomerMessage.id);
122
+ },
123
+ })}
124
+ </div>`;
125
+ } else {
126
+ let view = [
127
+ ` <div class="navbar d-flex align-items-center justify-content-between w-100 p-3 "
126
128
  style="background: linear-gradient(135deg, #ffb400 0%, #ff6c02 100%);">
127
129
  <div class="d-flex align-items-center pe-3 w-100"
128
130
  style="gap:10px;display: flex;align-items: center;">
@@ -132,978 +134,1100 @@ export class BgCustomerMessage {
132
134
  alt="Albert Flores">
133
135
  <div class="d-flex px-1 text-white align-items-center" style="gap:8px;">
134
136
  <h6 class="mb-0 text-white " style="">一站式客服整合系統</h6>
135
- ${BgWidget.iconButton(
136
- {
137
- icon: 'question',
138
- event: gvc.event(() => {
139
- BgWidget.dialog({
140
- gvc,
141
- title: '提示',
142
- innerHTML: () => {
143
- return `<div class="w-100" style="white-space:normal;word-break: break-all;">${BgWidget.grayNote([`*單一後台即可管理各渠道訊息`, `*前往第三方整合設定,設定Line與Facebook官方訊息串接`, `*為確保訊息同步,請統一透過SHOPNEX後台發送訊息`].map((dd) => {
144
- return `<div style="letter-spacing: 1.2px;white-space:normal;word-break: break-all;">${dd}</div>`
145
- }).join('<div class="my-1"></div>'))}</div>`
146
- },
147
- width: 250
148
- });
149
- })
150
- }
151
- )}
137
+ ${BgWidget.iconButton({
138
+ icon: 'question',
139
+ event: gvc.event(() => {
140
+ BgWidget.dialog({
141
+ gvc,
142
+ title: '提示',
143
+ innerHTML: () => {
144
+ return `<div class="w-100" style="white-space:normal;word-break: break-all;">${BgWidget.grayNote(
145
+ [
146
+ `*單一後台即可管理各渠道訊息`,
147
+ `*前往第三方整合設定,設定Line與Facebook官方訊息串接`,
148
+ `*為確保訊息同步,請統一透過SHOPNEX後台發送訊息`,
149
+ ]
150
+ .map(dd => {
151
+ return `<div style="letter-spacing: 1.2px;white-space:normal;word-break: break-all;">${dd}</div>`;
152
+ })
153
+ .join('<div class="my-1"></div>')
154
+ )}</div>`;
155
+ },
156
+ width: 250,
157
+ });
158
+ }),
159
+ })}
152
160
  </div>
153
161
  <div class="flex-fill" style="flex: 1;"></div>
154
162
  <i class="fa-regular fa-circle-xmark text-white fs-3 " aria-hidden="true"
155
163
  onclick="${gvc.event(() => {
156
- BgCustomerMessage.toggle(false, gvc)
157
- })}"></i>
164
+ BgCustomerMessage.toggle(false, gvc);
165
+ })}"></i>
158
166
  </div>
159
167
  </div>`,
160
- html`
161
- <div class="d-flex align-items-center p-2 shadow border-bottom" style="gap:10px;">
162
- ${(() => {
163
- const list = [
164
- {
165
- key: 'list',
166
- label: '訊息列表',
167
- },
168
- {
169
- key: 'setting',
170
- label: '客服設定',
171
- },
172
- // {
173
- // key: 'preview',
174
- // label: '預覽樣式',
175
- // },
176
- ];
177
- return list
178
- .map((dd) => {
179
- if (BgCustomerMessage.vm.select_bt === dd.key) {
180
- return html`
181
- <div class="d-flex align-items-center justify-content-center fw-bold px-3 py-2 fw-500 select-label-ai-message">
182
- ${dd.label}
183
- </div>`;
184
- } else {
185
- return html`
186
- <div
187
- class="d-flex align-items-center justify-content-center fw-bold px-3 py-2 fw-500 select-btn-ai-message"
188
- onclick="${gvc.event(() => {
189
- BgCustomerMessage.vm.select_bt = dd.key as any;
190
- gvc.notifyDataChange(BgCustomerMessage.id);
191
- })}"
192
- >
193
- ${dd.label}
194
- </div>`;
195
- }
196
- })
197
- .join('');
198
- })()}
199
- </div>`
200
- ];
201
- if (BgCustomerMessage.vm.select_bt === 'list') {
202
-
203
- view.push(
204
- BgCustomerMessage.list(gvc, (user) => {
205
- vm.type = 'detail';
206
- vm.chat_user = user;
207
- gvc.notifyDataChange(BgCustomerMessage.id);
208
- })
209
- );
210
- } else if (BgCustomerMessage.vm.select_bt === 'robot') {
211
- view.push(
212
- gvc.bindView(() => {
213
- const id = gvc.glitter.getUUID();
214
- const html = String.raw;
215
- return {
216
- bind: id,
217
- view: () => {
218
- return new Promise(async (resolve, reject) => {
219
- let keyData = (await ApiUser.getPublicConfig(`robot_auto_reply`, 'manager')).response.value || {};
220
- if (Array.isArray(keyData)) {
221
- keyData = {};
222
- }
223
- const dialog = new ShareDialog(gvc.glitter);
224
- resolve(html`
225
- <div class="position-relative bgf6 d-flex align-items-center justify-content-between m-n2 p-2 border-bottom shadow">
226
- <span class="fs-6 fw-bold " style="color:black;">自動問答</span>
227
- <button
228
- class="btn btn-primary-c "
229
- style="height: 28px;width:40px;font-size:14px;"
230
- onclick="${gvc.event(() => {
231
- dialog.dataLoading({visible: true});
168
+ html` <div class="d-flex align-items-center p-2 shadow border-bottom" style="gap:10px;">
169
+ ${(() => {
170
+ const list = [
171
+ {
172
+ key: 'list',
173
+ label: '訊息列表',
174
+ },
175
+ {
176
+ key: 'setting',
177
+ label: '客服設定',
178
+ },
179
+ // {
180
+ // key: 'preview',
181
+ // label: '預覽樣式',
182
+ // },
183
+ ];
184
+ return list
185
+ .map(dd => {
186
+ if (BgCustomerMessage.vm.select_bt === dd.key) {
187
+ return html` <div
188
+ class="d-flex align-items-center justify-content-center fw-bold px-3 py-2 fw-500 select-label-ai-message"
189
+ >
190
+ ${dd.label}
191
+ </div>`;
192
+ } else {
193
+ return html` <div
194
+ class="d-flex align-items-center justify-content-center fw-bold px-3 py-2 fw-500 select-btn-ai-message"
195
+ onclick="${gvc.event(() => {
196
+ BgCustomerMessage.vm.select_bt = dd.key as any;
197
+ gvc.notifyDataChange(BgCustomerMessage.id);
198
+ })}"
199
+ >
200
+ ${dd.label}
201
+ </div>`;
202
+ }
203
+ })
204
+ .join('');
205
+ })()}
206
+ </div>`,
207
+ ];
208
+ if (BgCustomerMessage.vm.select_bt === 'list') {
209
+ view.push(
210
+ BgCustomerMessage.list(gvc, user => {
211
+ vm.type = 'detail';
212
+ vm.chat_user = user;
213
+ gvc.notifyDataChange(BgCustomerMessage.id);
214
+ })
215
+ );
216
+ } else if (BgCustomerMessage.vm.select_bt === 'robot') {
217
+ view.push(
218
+ gvc.bindView(() => {
219
+ const id = gvc.glitter.getUUID();
220
+ const html = String.raw;
221
+ return {
222
+ bind: id,
223
+ view: () => {
224
+ return new Promise(async (resolve, reject) => {
225
+ let keyData =
226
+ (await ApiUser.getPublicConfig(`robot_auto_reply`, 'manager')).response.value || {};
227
+ if (Array.isArray(keyData)) {
228
+ keyData = {};
229
+ }
230
+ const dialog = new ShareDialog(gvc.glitter);
231
+ resolve(html`
232
+ <div
233
+ class="position-relative bgf6 d-flex align-items-center justify-content-between m-n2 p-2 border-bottom shadow"
234
+ >
235
+ <span class="fs-6 fw-bold " style="color:black;">自動問答</span>
236
+ <button
237
+ class="btn btn-primary-c "
238
+ style="height: 28px;width:40px;font-size:14px;"
239
+ onclick="${gvc.event(() => {
240
+ dialog.dataLoading({ visible: true });
232
241
 
233
- ApiUser.setPublicConfig({
234
- key: `robot_auto_reply`,
235
- value: keyData,
236
- user_id: 'manager',
237
- }).then((data: any) => {
238
- dialog.dataLoading({visible: false});
239
- dialog.successMessage({text: '設定成功'});
240
- });
241
- })}"
242
- >
243
- 儲存
244
- </button>
245
- </div>
246
- <div style="margin-top: -30px;">
247
- ${FormWidget.editorView({
248
- gvc: gvc,
249
- array: [
250
- {
251
- title: '',
252
- key: 'question',
253
- readonly: 'write',
254
- type: 'array',
255
- require: 'true',
256
- style_data: {
257
- label: {
258
- class: 'form-label fs-base ',
259
- style: '',
260
- },
261
- input: {class: '', style: ''},
262
- container: {
263
- class: '',
264
- style: '',
265
- },
266
- },
267
- referTitile: 'ask',
268
- plusBtn: '添加問答項目',
269
- formList: [
270
- {
271
- title: '問題',
272
- key: 'ask',
273
- readonly: 'write',
274
- type: 'text',
275
- require: 'true',
276
- style_data: {
277
- label: {
278
- class: 'form-label fs-base ',
279
- style: '',
280
- },
281
- input: {
282
- class: '',
283
- style: '',
284
- },
285
- container: {
286
- class: '',
287
- style: '',
288
- },
289
- },
290
- },
291
- {
292
- title: '回應',
293
- key: 'response',
294
- readonly: 'write',
295
- type: 'textArea',
296
- require: 'true',
297
- style_data: {
298
- label: {
299
- class: 'form-label fs-base ',
300
- style: '',
301
- },
302
- input: {
303
- class: '',
304
- style: '',
305
- },
306
- container: {
307
- class: '',
308
- style: '',
309
- },
310
- },
311
- },
312
- ],
313
- },
314
- ],
315
- refresh: () => {
316
- },
317
- formData: keyData,
318
- })}
319
- </div>
320
- `);
321
- });
242
+ ApiUser.setPublicConfig({
243
+ key: `robot_auto_reply`,
244
+ value: keyData,
245
+ user_id: 'manager',
246
+ }).then((data: any) => {
247
+ dialog.dataLoading({ visible: false });
248
+ dialog.successMessage({ text: '設定成功' });
249
+ });
250
+ })}"
251
+ >
252
+ 儲存
253
+ </button>
254
+ </div>
255
+ <div style="margin-top: -30px;">
256
+ ${FormWidget.editorView({
257
+ gvc: gvc,
258
+ array: [
259
+ {
260
+ title: '',
261
+ key: 'question',
262
+ readonly: 'write',
263
+ type: 'array',
264
+ require: 'true',
265
+ style_data: {
266
+ label: {
267
+ class: 'form-label fs-base ',
268
+ style: '',
269
+ },
270
+ input: { class: '', style: '' },
271
+ container: {
272
+ class: '',
273
+ style: '',
274
+ },
275
+ },
276
+ referTitile: 'ask',
277
+ plusBtn: '添加問答項目',
278
+ formList: [
279
+ {
280
+ title: '問題',
281
+ key: 'ask',
282
+ readonly: 'write',
283
+ type: 'text',
284
+ require: 'true',
285
+ style_data: {
286
+ label: {
287
+ class: 'form-label fs-base ',
288
+ style: '',
322
289
  },
323
- divCreate: {
324
- class: `p-2`, style: ``
290
+ input: {
291
+ class: '',
292
+ style: '',
325
293
  },
326
- };
327
- })
328
- );
329
- } else if (BgCustomerMessage.vm.select_bt === 'preview') {
330
- return `<div class="w-100 vh-100">${
331
- CustomerMessageUser.showCustomerMessage({
332
- gvc: gvc,
333
- userID: 'preview',
334
- open: true,
335
- type: 'preview',
336
- })
337
- }</div>`
338
- } else if (BgCustomerMessage.vm.select_bt === 'setting') {
339
- view.push(
340
- gvc.bindView(() => {
341
- const html = String.raw;
342
- const vO: {
343
- id: string,
344
- loading: boolean,
345
- data: any
346
- } = {
347
- id: gvc.glitter.getUUID(),
348
- loading: false,
349
- data: {}
350
- }
351
- const keyData = (ApiUser.getPublicConfig(`message_setting`, 'manager')).then((res) => {
352
- vO.data = res.response.value;
353
- gvc.notifyDataChange(vO.id)
354
- });
355
- return {
356
- bind: vO.id,
357
- view: () => {
358
- if (vO.loading) {
359
- return BgWidget.spinner()
360
- }
361
- const keyData = vO.data
362
- keyData.color = keyData.color ?? '#FE5541';
363
- const dialog = new ShareDialog(gvc.glitter);
364
- const vm = {
365
- message_setting: keyData,
366
- robot_setting: undefined,
367
- };
368
-
369
- async function save() {
370
- dialog.dataLoading({visible: true});
371
- await ApiUser.setPublicConfig({
372
- key: `message_setting`,
373
- value: vm.message_setting,
374
- user_id: 'manager',
375
- });
376
- await ApiUser.setPublicConfig({
377
- key: `robot_auto_reply`,
378
- value: vm.robot_setting,
379
- user_id: 'manager',
380
- });
381
- dialog.dataLoading({visible: false});
382
- dialog.successMessage({text: '設定成功'});
383
- }
294
+ container: {
295
+ class: '',
296
+ style: '',
297
+ },
298
+ },
299
+ },
300
+ {
301
+ title: '回應',
302
+ key: 'response',
303
+ readonly: 'write',
304
+ type: 'textArea',
305
+ require: 'true',
306
+ style_data: {
307
+ label: {
308
+ class: 'form-label fs-base ',
309
+ style: '',
310
+ },
311
+ input: {
312
+ class: '',
313
+ style: '',
314
+ },
315
+ container: {
316
+ class: '',
317
+ style: '',
318
+ },
319
+ },
320
+ },
321
+ ],
322
+ },
323
+ ],
324
+ refresh: () => {},
325
+ formData: keyData,
326
+ })}
327
+ </div>
328
+ `);
329
+ });
330
+ },
331
+ divCreate: {
332
+ class: `p-2`,
333
+ style: ``,
334
+ },
335
+ };
336
+ })
337
+ );
338
+ } else if (BgCustomerMessage.vm.select_bt === 'preview') {
339
+ return `<div class="w-100 vh-100">${CustomerMessageUser.showCustomerMessage({
340
+ gvc: gvc,
341
+ userID: 'preview',
342
+ open: true,
343
+ type: 'preview',
344
+ })}</div>`;
345
+ } else if (BgCustomerMessage.vm.select_bt === 'setting') {
346
+ view.push(
347
+ gvc.bindView(() => {
348
+ const html = String.raw;
349
+ const vO: {
350
+ id: string;
351
+ loading: boolean;
352
+ data: any;
353
+ } = {
354
+ id: gvc.glitter.getUUID(),
355
+ loading: false,
356
+ data: {},
357
+ };
358
+ const keyData = ApiUser.getPublicConfig(`message_setting`, 'manager').then(res => {
359
+ vO.data = res.response.value;
360
+ gvc.notifyDataChange(vO.id);
361
+ });
362
+ return {
363
+ bind: vO.id,
364
+ view: () => {
365
+ if (vO.loading) {
366
+ return BgWidget.spinner();
367
+ }
368
+ const keyData = vO.data;
369
+ keyData.color = keyData.color ?? '#FE5541';
370
+ const dialog = new ShareDialog(gvc.glitter);
371
+ const vm = {
372
+ message_setting: keyData,
373
+ robot_setting: undefined,
374
+ };
384
375
 
385
- const view = [
386
- html`
387
- <div class="position-relative bgf6 d-flex align-items-center justify-content-between m-n2 p-2 border-bottom shadow">
388
- <span class="fs-6 fw-bold " style="color:black;">功能設定</span>
389
- ${BgWidget.darkButton(
390
- '儲存',
391
- gvc.event(() => {
392
- save();
393
- })
394
- )}
395
- </div>
396
- <div style="margin-top: 10px;" class="p-2">
397
- ${[
398
- ...(() => {
399
- if (keyData.toggle) {
400
- return [
401
- gvc.bindView(() => {
402
- keyData.ask_manual_keyword=keyData.ask_manual_keyword||'真人客服'
403
- keyData.ask_ai_keyword=keyData.ask_ai_keyword||'AI客服'
404
- const cid = gvc.glitter.getUUID()
405
- return {
406
- bind: cid,
407
- view: () => {
408
- return html`
409
- <div class="d-flex flex-column"
410
- style="gap:5px;">
411
- <div class="tx_normal fw-normal"
412
- style="">AI客服機器人
413
- </div>
414
- <div class="d-flex">
415
- ${BgWidget.switchButton(gvc, keyData.ai_toggle, (bool) => {
416
- keyData.ai_toggle = bool;
417
- gvc.notifyDataChange(cid)
418
- })}
419
- ${keyData.ai_toggle ? `啟用` : `關閉`}
420
- </div>
421
- ${keyData.ai_toggle ? html`
422
- <div class="mt-2 d-flex align-items-center"
423
- style="gap:10px;">
424
- ${BgWidget.grayButton('AI 問答設定', gvc.event(async () => {
425
- let keyData = (await ApiUser.getPublicConfig(`robot_ai_reply`, 'manager')).response.value || {};
426
- BgWidget.settingDialog({
427
- gvc: gvc,
428
- title: 'AI問答設定',
429
- innerHTML: (gvc) => {
430
- return gvc.bindView(() => {
431
- const id = gvc.glitter.getUUID();
432
- const html = String.raw;
433
- return {
434
- bind: id,
435
- view: () => {
436
- if (Array.isArray(keyData)) {
437
- keyData = {};
438
- }
439
- keyData.question = keyData.question ?? []
440
- const parId = gvc.glitter.getUUID()
441
- const id = gvc.glitter.getUUID()
376
+ async function save() {
377
+ dialog.dataLoading({ visible: true });
378
+ await ApiUser.setPublicConfig({
379
+ key: `message_setting`,
380
+ value: vm.message_setting,
381
+ user_id: 'manager',
382
+ });
383
+ await ApiUser.setPublicConfig({
384
+ key: `robot_auto_reply`,
385
+ value: vm.robot_setting,
386
+ user_id: 'manager',
387
+ });
388
+ dialog.dataLoading({ visible: false });
389
+ dialog.successMessage({ text: '設定成功' });
390
+ }
442
391
 
443
- function refresh() {
444
- gvc.notifyDataChange(id)
445
- }
392
+ const view = [
393
+ html` <div
394
+ class="position-fixed bottom-0 start-0 bgf6 d-flex align-items-center justify-content-between border-top p-2 border-bottom shadow"
395
+ style="width:480px;max-width: 100vw;"
396
+ >
397
+ <div></div>
398
+ ${BgWidget.darkButton(
399
+ '儲存',
400
+ gvc.event(() => {
401
+ save();
402
+ })
403
+ )}
404
+ </div>
405
+ <div style="margin-top: 10px;" class="p-2">
406
+ ${[
407
+ ...(() => {
408
+ if (keyData.toggle) {
409
+ return [
410
+ gvc.bindView(() => {
411
+ keyData.ask_manual_keyword = keyData.ask_manual_keyword || '真人客服';
412
+ keyData.ask_ai_keyword = keyData.ask_ai_keyword || 'AI客服';
413
+ const cid = gvc.glitter.getUUID();
414
+ return {
415
+ bind: cid,
416
+ view: () => {
417
+ return html`
418
+ <div class="d-flex flex-column" style="gap:5px;">
419
+ <div class="tx_normal fw-normal" style="">AI客服機器人</div>
420
+ <div class="d-flex">
421
+ ${BgWidget.switchButton(gvc, keyData.ai_toggle, bool => {
422
+ keyData.ai_toggle = bool;
423
+ gvc.notifyDataChange(cid);
424
+ })}
425
+ ${keyData.ai_toggle ? `啟用` : `關閉`}
426
+ </div>
427
+ ${keyData.ai_toggle
428
+ ? html` <div class="mt-2 d-flex align-items-center" style="gap:10px;">
429
+ ${BgWidget.grayButton(
430
+ 'AI 問答設定',
431
+ gvc.event(async () => {
432
+ let keyData =
433
+ (await ApiUser.getPublicConfig(`robot_ai_reply`, 'manager'))
434
+ .response.value || {};
435
+ BgWidget.settingDialog({
436
+ gvc: gvc,
437
+ title: 'AI問答設定',
438
+ innerHTML: gvc => {
439
+ return gvc.bindView(() => {
440
+ const id = gvc.glitter.getUUID();
441
+ const html = String.raw;
442
+ return {
443
+ bind: id,
444
+ view: () => {
445
+ if (Array.isArray(keyData)) {
446
+ keyData = {};
447
+ }
448
+ keyData.question = keyData.question ?? [];
449
+ const parId = gvc.glitter.getUUID();
450
+ const id = gvc.glitter.getUUID();
446
451
 
447
- return html`
448
- ${BgWidget.alertInfo('', [
449
- `<span class="fw-500 fs-6">*當AI判斷,客戶提出的問題與你設定的問題有關聯的話,將會直接回答你設定的回覆內容。</span>`,
450
- `<span class="fw-500 fs-6">*建議設定多個問答項目,來提升機器人客服的妥善率。</span>`,
451
- ], {
452
- class: 'p-2',
453
- style: ``
454
- })}
455
- <div style=""
456
- class="p-2">
452
+ function refresh() {
453
+ gvc.notifyDataChange(id);
454
+ }
457
455
 
458
- ${gvc.bindView(() => {
459
- return {
460
- bind: id,
461
- view: () => {
462
- return (keyData.question || []).map((d2: any, index: number) => {
463
- return html`
464
- <li onclick="${gvc.event(() => {
465
- const copy = JSON.parse(JSON.stringify(d2))
466
- BgWidget.settingDialog({
467
- gvc: gvc,
468
- title: '設定問答',
469
- innerHTML: (gvc) => {
470
- return [BgWidget.editeInput({
471
- gvc: gvc,
472
- title: '問題',
473
- placeHolder: `請輸入問題`,
474
- default: copy.ask,
475
- callback: (text) => {
476
- copy.ask = text;
477
- },
478
- }), BgWidget.textArea({
479
- gvc: gvc,
480
- title: '回答',
481
- placeHolder: `請輸入回答`,
482
- default: copy.response,
483
- callback: (text) => {
484
- copy.response = text;
485
- },
486
- })].map((dd) => {
487
- return `<div>${dd}</div>`
488
- }).join('')
489
- },
490
- footer_html: (gvc) => {
491
- return [
492
- BgWidget.cancel(gvc.event(() => {
493
- gvc.closeDialog()
494
- })),
495
- BgWidget.save(gvc.event(() => {
496
- refresh()
497
- gvc.closeDialog()
498
- }))
499
- ].join(``)
500
- }
501
- })
502
- })}">
503
- <div class="w-100 fw-500 d-flex align-items-center fs-6 hoverBtn h_item rounded px-2 hoverF2 mb-1 subComponentGuide"
504
- style="gap:5px;color:#393939;">
505
- <div class=" p-1 dragItem ">
506
- <i class="fa-solid fa-grip-dots-vertical d-flex align-items-center justify-content-center "
507
- style="width:15px;height:15px;"
508
- aria-hidden="true"></i>
509
- </div>
510
- <span style="max-width:calc(100% - 60px);text-overflow: ellipsis;white-space: nowrap;overflow: hidden;">${d2.ask}</span>
511
- <div class="flex-fill"></div>
512
- <div class="hoverBtn p-1 child"
513
- onclick="${gvc.event((e, event) => {
514
- event.stopPropagation();
515
- event.preventDefault();
516
- dialog.checkYesOrNot({
517
- text: '是否確認移除問答?',
518
- callback: (response) => {
519
- if (response) {
520
- keyData.question.splice(index, 1)
521
- gvc.notifyDataChange(id)
522
- }
523
- }
524
- })
525
- })}">
526
- <i class="fa-regular fa-trash d-flex align-items-center justify-content-center "
527
- aria-hidden="true"></i>
528
- </div>
529
- </div>
530
- </li>`
531
- }).join('')
532
- },
533
- divCreate: {
534
- class: `mx-n2`,
535
- elem: 'ul',
536
- option: [{
537
- key: 'id',
538
- value: parId
539
- }],
540
- },
541
- onCreate: () => {
542
- gvc.glitter.addMtScript(
543
- [
544
- {
545
- src: `https://raw.githack.com/SortableJS/Sortable/master/Sortable.js`,
546
- },
547
- ],
548
- () => {
549
- const interval = setInterval(() => {
550
- if ((window as any).Sortable) {
551
- try {
552
- gvc.addStyle(`
456
+ return html`
457
+ ${BgWidget.alertInfo(
458
+ '',
459
+ [
460
+ `<span class="fw-500 fs-6">*當AI判斷,客戶提出的問題與你設定的問題有關聯的話,將會直接回答你設定的回覆內容。</span>`,
461
+ `<span class="fw-500 fs-6">*建議設定多個問答項目,來提升機器人客服的妥善率。</span>`,
462
+ ],
463
+ {
464
+ class: 'p-2',
465
+ style: ``,
466
+ }
467
+ )}
468
+ <div style="" class="p-2">
469
+ ${gvc.bindView(() => {
470
+ return {
471
+ bind: id,
472
+ view: () => {
473
+ return (keyData.question || [])
474
+ .map((d2: any, index: number) => {
475
+ return html` <li
476
+ onclick="${gvc.event(() => {
477
+ const copy = JSON.parse(
478
+ JSON.stringify(d2)
479
+ );
480
+ BgWidget.settingDialog({
481
+ gvc: gvc,
482
+ title: '設定問答',
483
+ innerHTML: gvc => {
484
+ return [
485
+ BgWidget.editeInput({
486
+ gvc: gvc,
487
+ title: '問題',
488
+ placeHolder: `請輸入問題`,
489
+ default: copy.ask,
490
+ callback: text => {
491
+ copy.ask = text;
492
+ },
493
+ }),
494
+ BgWidget.textArea({
495
+ gvc: gvc,
496
+ title: '回答',
497
+ placeHolder: `請輸入回答`,
498
+ default: copy.response,
499
+ callback: text => {
500
+ copy.response = text;
501
+ },
502
+ }),
503
+ ]
504
+ .map(dd => {
505
+ return `<div>${dd}</div>`;
506
+ })
507
+ .join('');
508
+ },
509
+ footer_html: gvc => {
510
+ return [
511
+ BgWidget.cancel(
512
+ gvc.event(() => {
513
+ gvc.closeDialog();
514
+ })
515
+ ),
516
+ BgWidget.save(
517
+ gvc.event(() => {
518
+ refresh();
519
+ gvc.closeDialog();
520
+ })
521
+ ),
522
+ ].join(``);
523
+ },
524
+ });
525
+ })}"
526
+ >
527
+ <div
528
+ class="w-100 fw-500 d-flex align-items-center fs-6 hoverBtn h_item rounded px-2 hoverF2 mb-1 subComponentGuide"
529
+ style="gap:5px;color:#393939;"
530
+ >
531
+ <div class=" p-1 dragItem ">
532
+ <i
533
+ class="fa-solid fa-grip-dots-vertical d-flex align-items-center justify-content-center "
534
+ style="width:15px;height:15px;"
535
+ aria-hidden="true"
536
+ ></i>
537
+ </div>
538
+ <span
539
+ style="max-width:calc(100% - 60px);text-overflow: ellipsis;white-space: nowrap;overflow: hidden;"
540
+ >${d2.ask}</span
541
+ >
542
+ <div class="flex-fill"></div>
543
+ <div
544
+ class="hoverBtn p-1 child"
545
+ onclick="${gvc.event(
546
+ (e, event) => {
547
+ event.stopPropagation();
548
+ event.preventDefault();
549
+ dialog.checkYesOrNot({
550
+ text: '是否確認移除問答?',
551
+ callback: response => {
552
+ if (response) {
553
+ keyData.question.splice(
554
+ index,
555
+ 1
556
+ );
557
+ gvc.notifyDataChange(
558
+ id
559
+ );
560
+ }
561
+ },
562
+ });
563
+ }
564
+ )}"
565
+ >
566
+ <i
567
+ class="fa-regular fa-trash d-flex align-items-center justify-content-center "
568
+ aria-hidden="true"
569
+ ></i>
570
+ </div>
571
+ </div>
572
+ </li>`;
573
+ })
574
+ .join('');
575
+ },
576
+ divCreate: {
577
+ class: `mx-n2`,
578
+ elem: 'ul',
579
+ option: [
580
+ {
581
+ key: 'id',
582
+ value: parId,
583
+ },
584
+ ],
585
+ },
586
+ onCreate: () => {
587
+ gvc.glitter.addMtScript(
588
+ [
589
+ {
590
+ src: `https://raw.githack.com/SortableJS/Sortable/master/Sortable.js`,
591
+ },
592
+ ],
593
+ () => {
594
+ const interval = setInterval(() => {
595
+ if ((window as any).Sortable) {
596
+ try {
597
+ gvc.addStyle(`
553
598
  ul {
554
599
  list-style: none;
555
600
  padding: 0;
556
601
  }
557
602
  `);
558
603
 
559
- function swapArr(arr: any, index1: number, index2: number) {
560
- const data = arr[index1];
561
- arr.splice(index1, 1);
562
- arr.splice(index2, 0, data);
563
- }
604
+ function swapArr(
605
+ arr: any,
606
+ index1: number,
607
+ index2: number
608
+ ) {
609
+ const data = arr[index1];
610
+ arr.splice(index1, 1);
611
+ arr.splice(index2, 0, data);
612
+ }
564
613
 
565
- let startIndex = 0;
566
- //@ts-ignore
567
- Sortable.create(gvc.glitter.document.getElementById(parId), {
568
- handle: '.dragItem',
569
- group: gvc.glitter.getUUID(),
614
+ let startIndex = 0;
615
+ //@ts-ignore
616
+ Sortable.create(
617
+ gvc.glitter.document.getElementById(
618
+ parId
619
+ ),
620
+ {
621
+ handle: '.dragItem',
622
+ group: gvc.glitter.getUUID(),
570
623
 
571
- animation: 100,
572
- onChange: function (evt: any) {
573
- swapArr(keyData.question, startIndex, evt.newIndex);
574
- const newIndex = evt.newIndex
575
- startIndex = newIndex
576
- },
577
- onEnd: (evt: any) => {
578
-
579
- },
580
- onStart: function (evt: any) {
581
- startIndex = evt.oldIndex;
582
- },
583
- });
584
- } catch (e) {
585
- }
586
- clearInterval(interval);
587
- }
588
- }, 100);
589
- },
590
- () => {
591
- }
592
- );
593
- }
594
- }
595
- })}
596
- <div class="w-100"
597
- style="justify-content: center; align-items: center; gap: 4px; display: flex;color: #3366BB;cursor: pointer;"
598
- data-bs-toggle="dropdown"
599
- aria-haspopup="true"
600
- aria-expanded="false"
601
- onclick="${gvc.event(() => {
602
- const copy = {
603
- ask: '',
604
- response: ''
605
- }
606
- BgWidget.settingDialog({
607
- gvc: gvc,
608
- title: '設定問答',
609
- innerHTML: (gvc) => {
610
- return [BgWidget.editeInput({
611
- gvc: gvc,
612
- title: '問題',
613
- placeHolder: `請輸入問題`,
614
- default: copy.ask,
615
- callback: (text) => {
616
- copy.ask = text;
617
- },
618
- }), BgWidget.textArea({
619
- gvc: gvc,
620
- title: '回答',
621
- placeHolder: `請輸入回答`,
622
- default: copy.response,
623
- callback: (text) => {
624
- copy.response = text;
625
- },
626
- })].map((dd) => {
627
- return `<div>${dd}</div>`
628
- }).join('')
629
- },
630
- footer_html: (gvc) => {
631
- return [
632
- BgWidget.cancel(gvc.event(() => {
633
- gvc.closeDialog()
634
- })),
635
- BgWidget.save(gvc.event(() => {
636
- if (!copy.ask || !copy.response) {
637
- dialog.errorMessage({text: '內容不得為空'})
638
- return
639
- }
640
- keyData.question.push(copy)
641
- refresh()
642
- gvc.closeDialog()
643
- }))
644
- ].join(``)
645
- }
646
- })
647
- })}">
648
- <div style="font-size: 16px; font-family: Noto Sans; font-weight: 400; word-wrap: break-word">
649
- 新增一則問答
650
- </div>
651
- <i class="fa-solid fa-plus"
652
- aria-hidden="true"></i>
653
- </div>
654
- </div>
655
- `
656
- },
657
- divCreate: {
658
- class: `m-n2`,
659
- },
660
- };
661
- })
662
- },
663
- footer_html: (gvc) => {
664
- return [BgWidget.cancel(gvc.event(() => {
665
- gvc.closeDialog()
666
- }), '取消'), BgWidget.save(gvc.event(async () => {
667
- dialog.dataLoading({visible: true});
668
- await ApiUser.setPublicConfig({
669
- key: `robot_ai_reply`,
670
- value: keyData,
671
- user_id: 'manager',
672
- });
673
- dialog.dataLoading({visible: false});
674
- dialog.successMessage({text: '設定成功'});
675
- gvc.closeDialog()
676
- }), '儲存')].join('')
677
- }
678
- })
679
- }))}
680
- </div>` : ``}
681
- </div>
682
- `
683
- }
684
- }
685
- }),
686
- BgWidget.editeInput({
687
- gvc: gvc,
688
- title: '客服名稱',
689
- type: 'name',
690
- placeHolder: `請輸入客服名稱`,
691
- default: keyData.name,
692
- callback: (text) => {
693
- keyData.name = text;
694
- },
695
- }),
696
- EditorElem.uploadImage({
697
- title: '大頭照',
624
+ animation: 100,
625
+ onChange: function (
626
+ evt: any
627
+ ) {
628
+ swapArr(
629
+ keyData.question,
630
+ startIndex,
631
+ evt.newIndex
632
+ );
633
+ const newIndex =
634
+ evt.newIndex;
635
+ startIndex = newIndex;
636
+ },
637
+ onEnd: (evt: any) => {},
638
+ onStart: function (evt: any) {
639
+ startIndex = evt.oldIndex;
640
+ },
641
+ }
642
+ );
643
+ } catch (e) {}
644
+ clearInterval(interval);
645
+ }
646
+ }, 100);
647
+ },
648
+ () => {}
649
+ );
650
+ },
651
+ };
652
+ })}
653
+ <div
654
+ class="w-100"
655
+ style="justify-content: center; align-items: center; gap: 4px; display: flex;color: #3366BB;cursor: pointer;"
656
+ data-bs-toggle="dropdown"
657
+ aria-haspopup="true"
658
+ aria-expanded="false"
659
+ onclick="${gvc.event(() => {
660
+ const copy = {
661
+ ask: '',
662
+ response: '',
663
+ };
664
+ BgWidget.settingDialog({
698
665
  gvc: gvc,
699
- def: keyData.head || '',
700
- callback: (text: string) => {
701
- keyData.head = text;
666
+ title: '設定問答',
667
+ innerHTML: gvc => {
668
+ return [
669
+ BgWidget.editeInput({
670
+ gvc: gvc,
671
+ title: '問題',
672
+ placeHolder: `請輸入問題`,
673
+ default: copy.ask,
674
+ callback: text => {
675
+ copy.ask = text;
676
+ },
677
+ }),
678
+ BgWidget.textArea({
679
+ gvc: gvc,
680
+ title: '回答',
681
+ placeHolder: `請輸入回答`,
682
+ default: copy.response,
683
+ callback: text => {
684
+ copy.response = text;
685
+ },
686
+ }),
687
+ ]
688
+ .map(dd => {
689
+ return `<div>${dd}</div>`;
690
+ })
691
+ .join('');
702
692
  },
703
- }),
704
- EditorElem.colorSelect({
705
- gvc: gvc,
706
- title: '設定主色調',
707
- def: keyData.color,
708
- callback: (text) => {
709
- keyData.color = text;
710
- gvc.notifyDataChange(vO.id)
693
+ footer_html: gvc => {
694
+ return [
695
+ BgWidget.cancel(
696
+ gvc.event(() => {
697
+ gvc.closeDialog();
698
+ })
699
+ ),
700
+ BgWidget.save(
701
+ gvc.event(() => {
702
+ if (!copy.ask || !copy.response) {
703
+ dialog.errorMessage({
704
+ text: '內容不得為空',
705
+ });
706
+ return;
707
+ }
708
+ keyData.question.push(copy);
709
+ refresh();
710
+ gvc.closeDialog();
711
+ })
712
+ ),
713
+ ].join(``);
711
714
  },
712
- }),
713
- BgWidget.editeInput({
714
- gvc: gvc,
715
- title: '置頂標題',
716
- placeHolder: `請輸入置頂標題`,
717
- default: keyData.title,
718
- callback: (text) => {
719
- keyData.title = text;
720
- },
721
- }),
722
- BgWidget.textArea({
723
- gvc: gvc,
724
- title: '置頂內文',
725
- placeHolder: `請輸入置頂內文`,
726
- default: keyData.content,
727
- callback: (text) => {
728
- keyData.content = text;
729
- },
730
- })
731
- ]
732
- } else {
733
- return []
734
- }
735
- })()
736
- ].join(`<div class="my-2"></div>`)}
737
- </div>`,
738
- gvc.bindView(() => {
739
- const id = gvc.glitter.getUUID();
740
- const html = String.raw;
741
- return {
742
- bind: id,
743
- view: () => {
744
- if (!keyData.toggle) {
745
- return ``
746
- }
747
- return new Promise(async (resolve, reject) => {
748
- let keyData = (await ApiUser.getPublicConfig(`robot_auto_reply`, 'manager')).response.value || {};
749
- if (Array.isArray(keyData)) {
750
- keyData = {};
751
- }
752
- vm.robot_setting = keyData;
753
- keyData.question = keyData.question ?? []
754
- const parId = gvc.glitter.getUUID()
755
- const id = gvc.glitter.getUUID()
756
-
757
- function refresh() {
758
- gvc.notifyDataChange(id)
759
- }
760
-
761
- resolve(html`
762
- <div class="position-relative bgf6 d-flex align-items-center justify-content-between mx-n2 p-2 py-3 border-top border-bottom mt-2 shadow">
763
- <span class="fs-6 fw-bold d-flex flex-column"
764
- style="color:black;">常見問題
765
- ${BgWidget.grayNote('將顯示於客服聊天首頁,讓用戶直接點選')}</span>
715
+ });
716
+ })}"
717
+ >
718
+ <div
719
+ style="font-size: 16px; font-family: Noto Sans; font-weight: 400; word-wrap: break-word"
720
+ >
721
+ 新增一則問答
722
+ </div>
723
+ <i
724
+ class="fa-solid fa-plus"
725
+ aria-hidden="true"
726
+ ></i>
727
+ </div>
766
728
  </div>
767
- <div style="" class="p-2">
729
+ `;
730
+ },
731
+ divCreate: {
732
+ class: `m-n2`,
733
+ },
734
+ };
735
+ });
736
+ },
737
+ footer_html: gvc => {
738
+ return [
739
+ BgWidget.cancel(
740
+ gvc.event(() => {
741
+ gvc.closeDialog();
742
+ }),
743
+ '取消'
744
+ ),
745
+ BgWidget.save(
746
+ gvc.event(async () => {
747
+ dialog.dataLoading({ visible: true });
748
+ await ApiUser.setPublicConfig({
749
+ key: `robot_ai_reply`,
750
+ value: keyData,
751
+ user_id: 'manager',
752
+ });
753
+ dialog.dataLoading({ visible: false });
754
+ dialog.successMessage({ text: '設定成功' });
755
+ gvc.closeDialog();
756
+ }),
757
+ '儲存'
758
+ ),
759
+ ].join('');
760
+ },
761
+ });
762
+ })
763
+ )}
764
+ </div>`
765
+ : ``}
766
+ </div>
767
+ `;
768
+ },
769
+ };
770
+ }),
771
+ BgWidget.editeInput({
772
+ gvc: gvc,
773
+ title: '客服名稱',
774
+ type: 'name',
775
+ placeHolder: `請輸入客服名稱`,
776
+ default: keyData.name,
777
+ callback: text => {
778
+ keyData.name = text;
779
+ },
780
+ }),
781
+ EditorElem.uploadImage({
782
+ title: '大頭照',
783
+ gvc: gvc,
784
+ def: keyData.head || '',
785
+ callback: (text: string) => {
786
+ keyData.head = text;
787
+ },
788
+ }),
789
+ EditorElem.colorSelect({
790
+ gvc: gvc,
791
+ title: '設定主色調',
792
+ def: keyData.color,
793
+ callback: text => {
794
+ keyData.color = text;
795
+ gvc.notifyDataChange(vO.id);
796
+ },
797
+ }),
798
+ BgWidget.editeInput({
799
+ gvc: gvc,
800
+ title: '置頂標題',
801
+ placeHolder: `請輸入置頂標題`,
802
+ default: keyData.title,
803
+ callback: text => {
804
+ keyData.title = text;
805
+ },
806
+ }),
807
+ BgWidget.textArea({
808
+ gvc: gvc,
809
+ title: '置頂內文',
810
+ placeHolder: `請輸入置頂內文`,
811
+ default: keyData.content,
812
+ callback: text => {
813
+ keyData.content = text;
814
+ },
815
+ }),
816
+ ];
817
+ } else {
818
+ return [];
819
+ }
820
+ })(),
821
+ ].join(`<div class="my-2"></div>`)}
822
+ </div>`,
823
+ gvc.bindView(() => {
824
+ const id = gvc.glitter.getUUID();
825
+ const html = String.raw;
826
+ return {
827
+ bind: id,
828
+ view: () => {
829
+ if (!keyData.toggle) {
830
+ return ``;
831
+ }
832
+ return new Promise(async (resolve, reject) => {
833
+ let keyData =
834
+ (await ApiUser.getPublicConfig(`robot_auto_reply`, 'manager')).response.value || {};
835
+ if (Array.isArray(keyData)) {
836
+ keyData = {};
837
+ }
838
+ vm.robot_setting = keyData;
839
+ keyData.question = keyData.question ?? [];
840
+ const parId = gvc.glitter.getUUID();
841
+ const id = gvc.glitter.getUUID();
768
842
 
769
- ${gvc.bindView(() => {
770
- return {
771
- bind: id,
772
- view: () => {
773
- return (keyData.question || []).map((d2: any, index: number) => {
774
- return html`
775
- <li onclick="${gvc.event(() => {
776
- const copy = JSON.parse(JSON.stringify(d2))
777
- BgWidget.settingDialog({
778
- gvc: gvc,
779
- title: '設定問答',
780
- innerHTML: (gvc) => {
781
- return [BgWidget.editeInput({
782
- gvc: gvc,
783
- title: '問題',
784
- placeHolder: `請輸入問題`,
785
- default: copy.ask,
786
- callback: (text) => {
787
- copy.ask = text;
788
- },
789
- }), BgWidget.textArea({
790
- gvc: gvc,
791
- title: '回答',
792
- placeHolder: `請輸入回答`,
793
- default: copy.response,
794
- callback: (text) => {
795
- copy.response = text;
796
- },
797
- })].map((dd) => {
798
- return `<div>${dd}</div>`
799
- }).join('')
800
- },
801
- footer_html: (gvc) => {
802
- return [
803
- BgWidget.cancel(gvc.event(() => {
804
- gvc.closeDialog()
805
- })),
806
- BgWidget.save(gvc.event(() => {
807
- keyData.question[index] = copy
808
- refresh()
809
- gvc.closeDialog()
810
- }))
811
- ].join(``)
812
- }
813
- })
814
- })}">
815
- <div class="w-100 fw-500 d-flex align-items-center fs-6 hoverBtn h_item rounded px-2 hoverF2 mb-1 subComponentGuide"
816
- style="gap:5px;color:#393939;">
817
- <div class=" p-1 dragItem ">
818
- <i class="fa-solid fa-grip-dots-vertical d-flex align-items-center justify-content-center "
819
- style="width:15px;height:15px;"
820
- aria-hidden="true"></i>
821
- </div>
822
- <span>${d2.ask}</span>
823
- <div class="flex-fill"></div>
824
- <div class="hoverBtn p-1 child"
825
- onclick="${gvc.event((e, event) => {
826
- event.stopPropagation();
827
- event.preventDefault();
828
- dialog.checkYesOrNot({
829
- text: '是否確認移除問答?',
830
- callback: (response) => {
831
- if (response) {
832
- keyData.question.splice(index, 1)
833
- gvc.notifyDataChange(id)
834
- }
835
- }
836
- })
837
- })}">
838
- <i class="fa-regular fa-trash d-flex align-items-center justify-content-center "
839
- aria-hidden="true"></i>
840
- </div>
841
- </div>
842
- </li>`
843
- }).join('')
844
- },
845
- divCreate: {
846
- class: `mx-n2`,
847
- elem: 'ul',
848
- option: [{key: 'id', value: parId}],
849
- },
850
- onCreate: () => {
851
- gvc.glitter.addMtScript(
852
- [
853
- {
854
- src: `https://raw.githack.com/SortableJS/Sortable/master/Sortable.js`,
855
- },
856
- ],
857
- () => {
858
- const interval = setInterval(() => {
859
- if ((window as any).Sortable) {
860
- try {
861
- gvc.addStyle(`
843
+ function refresh() {
844
+ gvc.notifyDataChange(id);
845
+ }
846
+
847
+ resolve(html`
848
+ <div
849
+ class="position-relative bgf6 d-flex align-items-center justify-content-between mx-n2 p-2 py-3 border-top border-bottom mt-2 shadow"
850
+ >
851
+ <span class="fs-6 fw-bold d-flex flex-column" style="color:black;"
852
+ >常見問題 ${BgWidget.grayNote('將顯示於客服聊天首頁,讓用戶直接點選')}</span
853
+ >
854
+ </div>
855
+ <div style="" class="p-2">
856
+ ${gvc.bindView(() => {
857
+ return {
858
+ bind: id,
859
+ view: () => {
860
+ return (keyData.question || [])
861
+ .map((d2: any, index: number) => {
862
+ return html` <li
863
+ onclick="${gvc.event(() => {
864
+ const copy = JSON.parse(JSON.stringify(d2));
865
+ BgWidget.settingDialog({
866
+ gvc: gvc,
867
+ title: '設定問答',
868
+ innerHTML: gvc => {
869
+ return [
870
+ BgWidget.editeInput({
871
+ gvc: gvc,
872
+ title: '問題',
873
+ placeHolder: `請輸入問題`,
874
+ default: copy.ask,
875
+ callback: text => {
876
+ copy.ask = text;
877
+ },
878
+ }),
879
+ BgWidget.textArea({
880
+ gvc: gvc,
881
+ title: '回答',
882
+ placeHolder: `請輸入回答`,
883
+ default: copy.response,
884
+ callback: text => {
885
+ copy.response = text;
886
+ },
887
+ }),
888
+ ]
889
+ .map(dd => {
890
+ return `<div>${dd}</div>`;
891
+ })
892
+ .join('');
893
+ },
894
+ footer_html: gvc => {
895
+ return [
896
+ BgWidget.cancel(
897
+ gvc.event(() => {
898
+ gvc.closeDialog();
899
+ })
900
+ ),
901
+ BgWidget.save(
902
+ gvc.event(() => {
903
+ keyData.question[index] = copy;
904
+ refresh();
905
+ gvc.closeDialog();
906
+ })
907
+ ),
908
+ ].join(``);
909
+ },
910
+ });
911
+ })}"
912
+ >
913
+ <div
914
+ class="w-100 fw-500 d-flex align-items-center fs-6 hoverBtn h_item rounded px-2 hoverF2 mb-1 subComponentGuide"
915
+ style="gap:5px;color:#393939;"
916
+ >
917
+ <div class=" p-1 dragItem ">
918
+ <i
919
+ class="fa-solid fa-grip-dots-vertical d-flex align-items-center justify-content-center "
920
+ style="width:15px;height:15px;"
921
+ aria-hidden="true"
922
+ ></i>
923
+ </div>
924
+ <span>${d2.ask}</span>
925
+ <div class="flex-fill"></div>
926
+ <div
927
+ class="hoverBtn p-1 child"
928
+ onclick="${gvc.event((e, event) => {
929
+ event.stopPropagation();
930
+ event.preventDefault();
931
+ dialog.checkYesOrNot({
932
+ text: '是否確認移除問答?',
933
+ callback: response => {
934
+ if (response) {
935
+ keyData.question.splice(index, 1);
936
+ gvc.notifyDataChange(id);
937
+ }
938
+ },
939
+ });
940
+ })}"
941
+ >
942
+ <i
943
+ class="fa-regular fa-trash d-flex align-items-center justify-content-center "
944
+ aria-hidden="true"
945
+ ></i>
946
+ </div>
947
+ </div>
948
+ </li>`;
949
+ })
950
+ .join('');
951
+ },
952
+ divCreate: {
953
+ class: `mx-n2`,
954
+ elem: 'ul',
955
+ option: [{ key: 'id', value: parId }],
956
+ },
957
+ onCreate: () => {
958
+ gvc.glitter.addMtScript(
959
+ [
960
+ {
961
+ src: `https://raw.githack.com/SortableJS/Sortable/master/Sortable.js`,
962
+ },
963
+ ],
964
+ () => {
965
+ const interval = setInterval(() => {
966
+ if ((window as any).Sortable) {
967
+ try {
968
+ gvc.addStyle(`
862
969
  ul {
863
970
  list-style: none;
864
971
  padding: 0;
865
972
  }
866
973
  `);
867
974
 
868
- function swapArr(arr: any, index1: number, index2: number) {
869
- const data = arr[index1];
870
- arr.splice(index1, 1);
871
- arr.splice(index2, 0, data);
872
- }
873
-
874
- let startIndex = 0;
875
- //@ts-ignore
876
- Sortable.create(gvc.glitter.document.getElementById(parId), {
877
- handle: '.dragItem',
878
- group: gvc.glitter.getUUID(),
975
+ function swapArr(arr: any, index1: number, index2: number) {
976
+ const data = arr[index1];
977
+ arr.splice(index1, 1);
978
+ arr.splice(index2, 0, data);
979
+ }
879
980
 
880
- animation: 100,
881
- onChange: function (evt: any) {
882
- swapArr(keyData.question, startIndex, evt.newIndex);
883
- const newIndex = evt.newIndex
884
- startIndex = newIndex
885
- },
886
- onEnd: (evt: any) => {
981
+ let startIndex = 0;
982
+ //@ts-ignore
983
+ Sortable.create(gvc.glitter.document.getElementById(parId), {
984
+ handle: '.dragItem',
985
+ group: gvc.glitter.getUUID(),
887
986
 
888
- },
889
- onStart: function (evt: any) {
890
- startIndex = evt.oldIndex;
891
- },
892
- });
893
- } catch (e) {
894
- }
895
- clearInterval(interval);
896
- }
897
- }, 100);
898
- },
899
- () => {
900
- }
901
- );
902
- }
903
- }
904
- })}
905
- <div class="w-100"
906
- style="justify-content: center; align-items: center; gap: 4px; display: flex;color: #3366BB;cursor: pointer;"
907
- data-bs-toggle="dropdown"
908
- aria-haspopup="true" aria-expanded="false"
909
- onclick="${gvc.event(() => {
910
- const copy = {ask: '', response: ''}
911
- BgWidget.settingDialog({
912
- gvc: gvc,
913
- title: '設定問答',
914
- innerHTML: (gvc) => {
915
- return [BgWidget.editeInput({
916
- gvc: gvc,
917
- title: '問題',
918
- placeHolder: `請輸入問題`,
919
- default: copy.ask,
920
- callback: (text) => {
921
- copy.ask = text;
922
- },
923
- }), BgWidget.textArea({
924
- gvc: gvc,
925
- title: '回答',
926
- placeHolder: `請輸入回答`,
927
- default: copy.response,
928
- callback: (text) => {
929
- copy.response = text;
930
- },
931
- })].map((dd) => {
932
- return `<div>${dd}</div>`
933
- }).join('')
934
- },
935
- footer_html: (gvc) => {
936
- return [
937
- BgWidget.cancel(gvc.event(() => {
938
- gvc.closeDialog()
939
- })),
940
- BgWidget.save(gvc.event(() => {
941
- if (!copy.ask || !copy.response) {
942
- dialog.errorMessage({text: '內容不得為空'})
943
- return
944
- }
945
- keyData.question.push(copy)
946
- refresh()
947
- gvc.closeDialog()
948
- }))
949
- ].join(``)
950
- }
951
- })
952
- })}">
953
- <div style="font-size: 16px; font-family: Noto Sans; font-weight: 400; word-wrap: break-word">
954
- 新增一則回覆
955
- </div>
956
- <i class="fa-solid fa-plus"
957
- aria-hidden="true"></i>
958
- </div>
959
- </div>
960
- `);
961
- });
962
- },
963
- divCreate: {
964
- class: ``,
965
- },
966
- };
967
- }),
968
- ];
969
- return view.join('')
970
- },
971
- divCreate: {
972
- class: `p-2`,
973
- style: `height: calc(100vh - 132px);overflow-y:auto;${(parseInt(gvc.glitter.share.top_inset, 10)) ? `padding-bottom:${parseInt(gvc.glitter.share.top_inset, 10) + parseInt(gvc.glitter.share.bottom_inset, 10)}px !important;` : ``}`
987
+ animation: 100,
988
+ onChange: function (evt: any) {
989
+ swapArr(keyData.question, startIndex, evt.newIndex);
990
+ const newIndex = evt.newIndex;
991
+ startIndex = newIndex;
992
+ },
993
+ onEnd: (evt: any) => {},
994
+ onStart: function (evt: any) {
995
+ startIndex = evt.oldIndex;
996
+ },
997
+ });
998
+ } catch (e) {}
999
+ clearInterval(interval);
1000
+ }
1001
+ }, 100);
1002
+ },
1003
+ () => {}
1004
+ );
974
1005
  },
975
- };
976
- })
977
- );
978
- }
979
- return view.join('');
980
- }
981
- },
982
- divCreate: {
983
- style: `position:relative;`,
984
- class: `h-100`
985
- },
986
- onCreate: () => {
987
- $('.tooltip').remove();
988
- ($('[data-bs-toggle="tooltip"]') as any).tooltip();
989
- },
990
- };
991
- });
992
- }
993
-
994
- public static list(gvc: GVC, callback: (chat_id: any) => void): string {
995
- return gvc.bindView(() => {
996
- const html = String.raw;
997
- const listId = gvc.glitter.getUUID();
998
- let chatData: any = undefined;
999
- let unRead: any = undefined;
1000
-
1001
- function loadData() {
1002
- Chat.getChatRoom({
1003
- page: 0,
1004
- limit: 1000,
1005
- user_id: 'manager',
1006
- }).then(async (data) => {
1007
- chatData = data.response.data;
1008
- //過濾掉空白的聊天室
1009
- chatData = chatData.filter((data: any) => data.topMessage !== undefined);
1010
- Chat.getUnRead({user_id: 'manager'}).then((data) => {
1011
- unRead = data.response;
1012
- gvc.notifyDataChange(listId);
1013
- });
1014
- });
1006
+ };
1007
+ })}
1008
+ <div
1009
+ class="w-100"
1010
+ style="justify-content: center; align-items: center; gap: 4px; display: flex;color: #3366BB;cursor: pointer;"
1011
+ data-bs-toggle="dropdown"
1012
+ aria-haspopup="true"
1013
+ aria-expanded="false"
1014
+ onclick="${gvc.event(() => {
1015
+ const copy = { ask: '', response: '' };
1016
+ BgWidget.settingDialog({
1017
+ gvc: gvc,
1018
+ title: '設定問答',
1019
+ innerHTML: gvc => {
1020
+ return [
1021
+ BgWidget.editeInput({
1022
+ gvc: gvc,
1023
+ title: '問題',
1024
+ placeHolder: `請輸入問題`,
1025
+ default: copy.ask,
1026
+ callback: text => {
1027
+ copy.ask = text;
1028
+ },
1029
+ }),
1030
+ BgWidget.textArea({
1031
+ gvc: gvc,
1032
+ title: '回答',
1033
+ placeHolder: `請輸入回答`,
1034
+ default: copy.response,
1035
+ callback: text => {
1036
+ copy.response = text;
1037
+ },
1038
+ }),
1039
+ ]
1040
+ .map(dd => {
1041
+ return `<div>${dd}</div>`;
1042
+ })
1043
+ .join('');
1044
+ },
1045
+ footer_html: gvc => {
1046
+ return [
1047
+ BgWidget.cancel(
1048
+ gvc.event(() => {
1049
+ gvc.closeDialog();
1050
+ })
1051
+ ),
1052
+ BgWidget.save(
1053
+ gvc.event(() => {
1054
+ if (!copy.ask || !copy.response) {
1055
+ dialog.errorMessage({ text: '內容不得為空' });
1056
+ return;
1057
+ }
1058
+ keyData.question.push(copy);
1059
+ refresh();
1060
+ gvc.closeDialog();
1061
+ })
1062
+ ),
1063
+ ].join(``);
1064
+ },
1065
+ });
1066
+ })}"
1067
+ >
1068
+ <div
1069
+ style="font-size: 16px; font-family: Noto Sans; font-weight: 400; word-wrap: break-word"
1070
+ >
1071
+ 新增一則回覆
1072
+ </div>
1073
+ <i class="fa-solid fa-plus" aria-hidden="true"></i>
1074
+ </div>
1075
+ </div>
1076
+ <div style="height: 80px;"></div>
1077
+ `);
1078
+ });
1079
+ },
1080
+ divCreate: {
1081
+ class: ``,
1082
+ },
1083
+ };
1084
+ }),
1085
+ ];
1086
+ return view.join('');
1087
+ },
1088
+ divCreate: {
1089
+ class: `p-2`,
1090
+ style: `height: calc(100vh - 132px);overflow-y:auto;${parseInt(gvc.glitter.share.top_inset, 10) ? `padding-bottom:${parseInt(gvc.glitter.share.top_inset, 10) + parseInt(gvc.glitter.share.bottom_inset, 10)}px !important;` : ``}`,
1091
+ },
1092
+ };
1093
+ })
1094
+ );
1015
1095
  }
1096
+ return view.join('');
1097
+ }
1098
+ },
1099
+ divCreate: {
1100
+ style: `position:relative;`,
1101
+ class: `h-100`,
1102
+ },
1103
+ onCreate: () => {
1104
+ $('.tooltip').remove();
1105
+ ($('[data-bs-toggle="tooltip"]') as any).tooltip();
1106
+ },
1107
+ };
1108
+ });
1109
+ }
1016
1110
 
1017
- let socket: any = undefined
1018
- const url = new URL((window as any).glitterBackend)
1019
- let vm = {
1020
- close: false
1021
- }
1111
+ public static list(gvc: GVC, callback: (chat_id: any) => void): string {
1112
+ return gvc.bindView(() => {
1113
+ const html = String.raw;
1114
+ const listId = gvc.glitter.getUUID();
1115
+ let chatData: any = undefined;
1116
+ let unRead: any = undefined;
1022
1117
 
1023
- function connect() {
1024
- socket = (location.href.includes('https://')) ? new WebSocket(`wss://${url.hostname}/websocket`) : new WebSocket(`ws://${url.hostname}:9003`);
1025
- socket.addEventListener('open', function (event: any) {
1026
- console.log('Connected to update list server');
1027
- socket.send(JSON.stringify({
1028
- type: 'message-count-change',
1029
- user_id: 'manager',
1030
- app_name: (window as any).appName
1031
- }))
1032
- });
1033
- socket.addEventListener('message', async function (event: any) {
1034
- console.log(`update_message_count`)
1035
- const data = JSON.parse(event.data)
1036
- if (data.type === 'update_message_count') {
1037
- vm.close = true
1038
- socket && socket.close()
1039
- loadData()
1040
- }
1041
- });
1042
- socket.addEventListener('close', function (event: any) {
1043
- console.log('Disconnected from server');
1044
- if (!vm.close) {
1045
- console.log('Reconnected from server');
1046
- connect()
1047
- }
1048
- });
1049
- }
1118
+ function loadData() {
1119
+ Chat.getChatRoom({
1120
+ page: 0,
1121
+ limit: 1000,
1122
+ user_id: 'manager',
1123
+ }).then(async data => {
1124
+ chatData = data.response.data;
1125
+ //過濾掉空白的聊天室
1126
+ chatData = chatData.filter((data: any) => data.topMessage !== undefined);
1127
+ Chat.getUnRead({ user_id: 'manager' }).then(data => {
1128
+ unRead = data.response;
1129
+ gvc.notifyDataChange(listId);
1130
+ });
1131
+ });
1132
+ }
1050
1133
 
1051
- loadData()
1134
+ let socket: any = undefined;
1135
+ const url = new URL((window as any).glitterBackend);
1136
+ let vm = {
1137
+ close: false,
1138
+ };
1052
1139
 
1053
- return {
1054
- bind: listId,
1055
- view: () => {
1056
- if (chatData) {
1057
- const view = [];
1058
- try {
1059
- view.push(html`
1060
- <div class="p-2">
1061
- <div class="position-relative">
1062
- <input type="text" class="form-control pe-5" placeholder="搜尋用戶"/>
1063
- <i class="bx bx-search fs-xl text-nav position-absolute top-50 end-0 translate-middle-y me-3"></i>
1064
- </div>
1065
- </div>
1066
- <div style="max-height: calc(100vh - 180px);overflow-y: auto;">
1067
- ${chatData
1068
- .filter((dd: any) => {
1069
- return !['manager-operation_guide', 'manager-order_analysis', 'manager-writer'].includes(dd.chat_id)
1070
- }).map((dd: any) => {
1140
+ function connect() {
1141
+ const socket_id = gvc.glitter.getUUID();
1142
+ socket = location.href.includes('https://')
1143
+ ? new WebSocket(`wss://${url.hostname}/websocket`)
1144
+ : new WebSocket(`ws://${url.hostname}:9003`);
1145
+ socket.addEventListener('open', function (event: any) {
1146
+ console.log(`Connected to update list server-${socket_id}`);
1147
+ socket.send(
1148
+ JSON.stringify({
1149
+ type: 'message-count-change',
1150
+ user_id: 'manager',
1151
+ app_name: (window as any).appName,
1152
+ })
1153
+ );
1154
+ });
1155
+ socket.addEventListener('message', async function (event: any) {
1156
+ console.log(`update_message_count-${socket_id}`);
1157
+ const data = JSON.parse(event.data);
1158
+ if (data.type === 'update_message_count') {
1159
+ vm.close = true;
1160
+ socket && socket.close();
1161
+ loadData();
1162
+ }
1163
+ });
1164
+ socket.addEventListener('close', function (event: any) {
1165
+ console.log(`Disconnected from server-${socket_id}`);
1166
+ if (!vm.close) {
1167
+ console.log('Reconnected from server');
1168
+ connect();
1169
+ }
1170
+ });
1171
+ }
1071
1172
 
1072
- dd.topMessage = dd.topMessage ?? {}
1073
- dd.topMessage.text = dd.topMessage?.text ?? "圖片內容";
1074
- dd.user_data = dd.user_data ?? {}
1075
- if (dd.topMessage && dd.chat_id !== 'manager-preview') {
1076
- console.log(`unRead==>`, unRead)
1077
- const unReadCount = unRead.filter((d2: any) => {
1078
- return dd.chat_id === d2.chat_id;
1079
- }).length;
1080
- if (dd.chat_id) {
1081
- if (dd.chat_id.startsWith('line')) {
1082
- dd.user_data.head = dd.info.line.head;
1083
- dd.user_data.name = dd.info.line.name;
1084
- }
1085
- if (dd.chat_id.startsWith('fb')) {
1086
- dd.info.fb = dd.info.fb ?? {
1087
- head: `https://d3jnmi1tfjgtti.cloudfront.net/file/252530754/1704269678588-43.png`,
1088
- name: '訪客'
1089
- }
1090
- dd.user_data.head = dd.info.fb.head;
1091
- dd.user_data.name = dd.info.fb.name;
1092
- }
1093
- let head = (dd.user_data && dd.user_data.head) || `https://d3jnmi1tfjgtti.cloudfront.net/file/252530754/1704269678588-43.png`;
1094
- let name = (dd.user_data && dd.user_data.name) || `訪客`
1095
- let socket: any = undefined;
1096
- const vm = {
1097
- close: false
1098
- }
1099
- const id = gvc.glitter.getUUID()
1173
+ loadData();
1100
1174
 
1175
+ return {
1176
+ bind: listId,
1177
+ view: () => {
1178
+ if (chatData) {
1179
+ const view = [];
1180
+ try {
1181
+ view.push(html`
1182
+ <div class="p-2">
1183
+ <div class="position-relative">
1184
+ <input type="text" class="form-control pe-5" placeholder="搜尋用戶" />
1185
+ <i class="bx bx-search fs-xl text-nav position-absolute top-50 end-0 translate-middle-y me-3"></i>
1186
+ </div>
1187
+ </div>
1188
+ <div style="max-height: calc(100vh - 180px);overflow-y: auto;">
1189
+ ${chatData
1190
+ .filter((dd: any) => {
1191
+ return !['manager-operation_guide', 'manager-order_analysis', 'manager-writer'].includes(
1192
+ dd.chat_id
1193
+ );
1194
+ })
1195
+ .map((dd: any) => {
1196
+ dd.topMessage = dd.topMessage ?? {};
1197
+ dd.topMessage.text = dd.topMessage?.text ?? '圖片內容';
1198
+ dd.user_data = dd.user_data ?? {};
1199
+ if (dd.topMessage && dd.chat_id !== 'manager-preview') {
1200
+ const unReadCount = unRead.filter((d2: any) => {
1201
+ return dd.chat_id === d2.chat_id;
1202
+ }).length;
1203
+ if (dd.chat_id) {
1204
+ if (dd.chat_id.startsWith('line')) {
1205
+ dd.user_data.head = dd.info.line.head;
1206
+ dd.user_data.name = dd.info.line.name;
1207
+ }
1208
+ if (dd.chat_id.startsWith('fb')) {
1209
+ dd.info.fb = dd.info.fb ?? {
1210
+ head: `https://d3jnmi1tfjgtti.cloudfront.net/file/252530754/1704269678588-43.png`,
1211
+ name: '訪客',
1212
+ };
1213
+ dd.user_data.head = dd.info.fb.head;
1214
+ dd.user_data.name = dd.info.fb.name;
1215
+ }
1216
+ let head =
1217
+ (dd.user_data && dd.user_data.head) ||
1218
+ `https://d3jnmi1tfjgtti.cloudfront.net/file/252530754/1704269678588-43.png`;
1219
+ let name = (dd.user_data && dd.user_data.name) || `訪客`;
1220
+ let socket: any = undefined;
1221
+ const vm = {
1222
+ close: false,
1223
+ };
1224
+ const id = gvc.glitter.getUUID();
1101
1225
 
1102
- return gvc.bindView(() => {
1103
- return {
1104
- bind: id,
1105
- view: () => {
1106
- return `<div class="rounded-circle position-relative "
1226
+ return gvc.bindView(() => {
1227
+ return {
1228
+ bind: id,
1229
+ view: () => {
1230
+ return `<div class="rounded-circle position-relative "
1107
1231
  style="width: 40px;height: 40px;">
1108
1232
  <div
1109
1233
  class="rounded-circle text-white bg-danger ${unReadCount ? `` : `d-none`} fw-500 d-flex align-items-center justify-content-center me-2"
@@ -1113,28 +1237,27 @@ export class BgCustomerMessage {
1113
1237
  </div>
1114
1238
  <img
1115
1239
  src="${head}"
1116
- class="rounded-circle ${(dd.chat_id.startsWith('line') || dd.chat_id.startsWith('fb')) ? `` : `border`}"
1240
+ class="rounded-circle ${dd.chat_id.startsWith('line') || dd.chat_id.startsWith('fb') ? `` : `border`}"
1117
1241
  style="border-radius: 50%;${(() => {
1118
- if (dd.chat_id.startsWith('line')) {
1119
- return `border:2px solid green;`
1120
- } else if (dd.chat_id.startsWith('fb')) {
1121
- return `border:2px solid #0078ff;`
1122
- }
1242
+ if (dd.chat_id.startsWith('line')) {
1243
+ return `border:2px solid green;`;
1244
+ } else if (dd.chat_id.startsWith('fb')) {
1245
+ return `border:2px solid #0078ff;`;
1246
+ }
1123
1247
  })()}"
1124
1248
  width="40"
1125
1249
  alt="Devon Lane"
1126
1250
  />
1127
1251
  ${(() => {
1128
- let id: string = dd.chat_id
1129
- if (id.startsWith('line')) {
1130
- return `<i class="fa-brands fa-line bg-white rounded" style="position:absolute;right:0;bottom:0;color:green;"></i>`
1131
- }
1132
- if (id.startsWith('fb')) {
1133
-
1134
- return `<i class="fa-brands fa-facebook-messenger bg-white rounded" style="position:absolute;right:0;bottom:0;color:#0078ff;"></i>`
1135
- }
1136
- return ``
1137
- })()}
1252
+ let id: string = dd.chat_id;
1253
+ if (id.startsWith('line')) {
1254
+ return `<i class="fa-brands fa-line bg-white rounded" style="position:absolute;right:0;bottom:0;color:green;"></i>`;
1255
+ }
1256
+ if (id.startsWith('fb')) {
1257
+ return `<i class="fa-brands fa-facebook-messenger bg-white rounded" style="position:absolute;right:0;bottom:0;color:#0078ff;"></i>`;
1258
+ }
1259
+ return ``;
1260
+ })()}
1138
1261
  </div>
1139
1262
 
1140
1263
  <div class="w-100 ps-2 ms-1">
@@ -1145,166 +1268,172 @@ export class BgCustomerMessage {
1145
1268
  </div>
1146
1269
  <p class="fs-sm mb-0 "
1147
1270
  style="white-space: normal;${unReadCount ? `color:black;` : `color:#585c7b !important;`}">
1148
- ${(dd.topMessage ? dd.topMessage.text : ``).length > 50
1149
- ? (dd.topMessage ? dd.topMessage.text : ``).substring(0, 50) + '.....'
1150
- : dd.topMessage
1151
- ? dd.topMessage.text
1152
- : ``}
1153
- </p>
1154
- </div>`
1155
- },
1156
- divCreate: {
1157
- class: `d-flex align-items-center border-bottom text-decoration-none bg-faded-primary-hover py-3 px-4`,
1158
- style: `cursor: pointer;`,
1159
- option: [
1160
- {
1161
- key: 'onclick',
1162
- value: gvc.event(() => {
1163
- callback(dd);
1164
- })
1165
- }
1166
- ]
1271
+ ${
1272
+ (dd.topMessage ? dd.topMessage.text : ``).length > 50
1273
+ ? (dd.topMessage
1274
+ ? dd.topMessage.text
1275
+ : ``
1276
+ ).substring(0, 50) + '.....'
1277
+ : dd.topMessage
1278
+ ? dd.topMessage.text
1279
+ : ``
1167
1280
  }
1168
- }
1169
- })
1170
- }
1171
-
1172
- } else {
1173
- return ``;
1174
- }
1175
- })
1176
- .join('') ||
1177
- html`
1178
- <div class="d-flex align-items-center justify-content-center flex-column w-100"
1179
- style="width:700px;">
1180
- <lottie-player
1181
- style="max-width: 100%;width: 300px;"
1182
- src="https://assets10.lottiefiles.com/packages/lf20_rc6CDU.json"
1183
- speed="1"
1184
- loop="true"
1185
- background="transparent"
1186
- ></lottie-player>
1187
- <h3 class="text-dark fs-6 mt-n3 px-2"
1188
- style="line-height: 200%;text-align: center;">尚未收到任何訊息</h3>
1189
- </div>`}
1190
- </div>
1191
- `);
1192
- return view.join('');
1193
- } catch (e) {
1194
- console.log(e)
1195
- return `${e}`
1281
+ </p>
1282
+ </div>`;
1283
+ },
1284
+ divCreate: {
1285
+ class: `d-flex align-items-center border-bottom text-decoration-none bg-faded-primary-hover py-3 px-4`,
1286
+ style: `cursor: pointer;`,
1287
+ option: [
1288
+ {
1289
+ key: 'onclick',
1290
+ value: gvc.event(() => {
1291
+ callback(dd);
1292
+ }),
1293
+ },
1294
+ ],
1295
+ },
1296
+ };
1297
+ });
1196
1298
  }
1299
+ } else {
1300
+ return ``;
1301
+ }
1302
+ })
1303
+ .join('') ||
1304
+ html` <div
1305
+ class="d-flex align-items-center justify-content-center flex-column w-100"
1306
+ style="width:700px;"
1307
+ >
1308
+ <lottie-player
1309
+ style="max-width: 100%;width: 300px;"
1310
+ src="https://assets10.lottiefiles.com/packages/lf20_rc6CDU.json"
1311
+ speed="1"
1312
+ loop="true"
1313
+ background="transparent"
1314
+ ></lottie-player>
1315
+ <h3 class="text-dark fs-6 mt-n3 px-2" style="line-height: 200%;text-align: center;">
1316
+ 尚未收到任何訊息
1317
+ </h3>
1318
+ </div>`}
1319
+ </div>
1320
+ `);
1321
+ return view.join('');
1322
+ } catch (e) {
1323
+ console.log(e);
1324
+ return `${e}`;
1325
+ }
1326
+ } else {
1327
+ return html` <div class="d-flex align-items-center justify-content-center w-100 flex-column pt-3">
1328
+ <div class="spinner-border" role="status">
1329
+ <span class="sr-only"></span>
1330
+ </div>
1331
+ <span class="mt-2">載入中...</span>
1332
+ </div>`;
1333
+ }
1334
+ },
1335
+ divCreate: {},
1336
+ onCreate: () => {
1337
+ setTimeout(() => {
1338
+ vm.close = true;
1339
+ socket && socket.close();
1340
+ vm.close = false;
1341
+ connect();
1342
+ }, 50);
1343
+ },
1344
+ onDestroy: () => {
1345
+ vm.close = true;
1346
+ socket && socket.close();
1347
+ },
1348
+ };
1349
+ });
1350
+ }
1197
1351
 
1198
- } else {
1199
- return html`
1200
- <div class="d-flex align-items-center justify-content-center w-100 flex-column pt-3">
1201
- <div class="spinner-border" role="status">
1202
- <span class="sr-only"></span>
1203
- </div>
1204
- <span class="mt-2">載入中...</span>
1205
- </div>`;
1206
- }
1207
- },
1208
- divCreate: {},
1209
- onCreate: () => {
1210
- setTimeout(() => {
1211
- vm.close = false
1212
- connect()
1213
- }, 50)
1214
-
1215
- },
1216
- onDestroy: () => {
1217
- vm.close = true
1218
- socket && socket.close()
1219
- }
1220
- };
1221
- });
1222
- }
1223
-
1224
- public static toggle(visible: boolean, gvc: GVC) {
1225
- BgCustomerMessage.visible = visible;
1226
- BgCustomerMessage.vm.type = 'list';
1227
- if (visible) {
1228
- $('#BgCustomerMessageHover').removeClass('d-none');
1229
- $('#BgCustomerMessage').removeClass('scroll-out');
1230
- $('#BgCustomerMessage').addClass('scroll-in');
1231
- } else {
1232
- $('#BgCustomerMessageHover').addClass('d-none');
1233
- $('#BgCustomerMessage').addClass('scroll-out');
1234
- $('#BgCustomerMessage').removeClass('scroll-in');
1235
- }
1236
- gvc.notifyDataChange(BgCustomerMessage.id);
1352
+ public static toggle(visible: boolean, gvc: GVC) {
1353
+ BgCustomerMessage.visible = visible;
1354
+ BgCustomerMessage.vm.type = 'list';
1355
+ if (visible) {
1356
+ $('#BgCustomerMessageHover').removeClass('d-none');
1357
+ $('#BgCustomerMessage').removeClass('scroll-out');
1358
+ $('#BgCustomerMessage').addClass('scroll-in');
1359
+ } else {
1360
+ $('#BgCustomerMessageHover').addClass('d-none');
1361
+ $('#BgCustomerMessage').addClass('scroll-out');
1362
+ $('#BgCustomerMessage').removeClass('scroll-in');
1237
1363
  }
1364
+ gvc.notifyDataChange(BgCustomerMessage.id);
1365
+ }
1238
1366
 
1239
- public static userMessage(cf: {
1240
- gvc: GVC;
1241
- userID: string;
1242
- toUser: string;
1243
- width: number;
1244
- height: number;
1245
- color: string;
1246
- hideBar: boolean
1247
- }) {
1248
- const gvc = cf.gvc;
1249
- const html = String.raw;
1250
- cf.userID = `${cf.userID}`;
1251
- const chatID = [cf.userID, cf.toUser].sort().join('-');
1252
- return gvc.bindView(() => {
1253
- const id = gvc.glitter.getUUID();
1254
- return {
1255
- bind: id,
1256
- view: () => {
1257
- return ``;
1367
+ public static userMessage(cf: {
1368
+ gvc: GVC;
1369
+ userID: string;
1370
+ toUser: string;
1371
+ width: number;
1372
+ height: number;
1373
+ color: string;
1374
+ hideBar: boolean;
1375
+ }) {
1376
+ const gvc = cf.gvc;
1377
+ const html = String.raw;
1378
+ cf.userID = `${cf.userID}`;
1379
+ const chatID = [cf.userID, cf.toUser].sort().join('-');
1380
+ return gvc.bindView(() => {
1381
+ const id = gvc.glitter.getUUID();
1382
+ return {
1383
+ bind: id,
1384
+ view: () => {
1385
+ return ``;
1386
+ },
1387
+ divCreate: {
1388
+ elem: 'web-component',
1389
+ option: [
1390
+ {
1391
+ key: 'id',
1392
+ value: id,
1393
+ },
1394
+ ],
1395
+ class: `w-100 h-100`,
1396
+ style: `z-index:9999;bottom:0px;left:0px;`,
1397
+ },
1398
+ onCreate: async () => {
1399
+ BgCustomerMessage.config.hideBar = cf.hideBar;
1400
+ BgCustomerMessage.config.color = cf.color;
1401
+ await Chat.post({
1402
+ type: 'user',
1403
+ participant: [cf.userID, cf.toUser],
1404
+ });
1405
+ const viewId = gvc.glitter.getUUID();
1406
+ const chatView = html` <div class="w-100 h-100" style="position: relative;">
1407
+ ${BgCustomerMessage.detail({
1408
+ gvc: gvc,
1409
+ chat: {
1410
+ chat_id: chatID,
1411
+ type: 'user',
1412
+ },
1413
+ user_id: cf.userID,
1414
+ containerHeight: `${cf.height}px`,
1415
+ document: (document.querySelector('#' + id)! as any).shadowRoot,
1416
+ goBack: () => {
1417
+ gvc.notifyDataChange(viewId);
1418
+ },
1419
+ close: gvc.glitter.ut.frSize(
1420
+ {
1421
+ sm: undefined,
1258
1422
  },
1259
- divCreate: {
1260
- elem: 'web-component',
1261
- option: [
1262
- {
1263
- key: 'id',
1264
- value: id,
1265
- },
1266
- ],
1267
- class: `w-100 h-100`,
1268
- style: `z-index:9999;bottom:0px;left:0px;`,
1269
- },
1270
- onCreate: async () => {
1271
- BgCustomerMessage.config.hideBar = cf.hideBar;
1272
- BgCustomerMessage.config.color = cf.color;
1273
- await Chat.post({
1274
- type: 'user',
1275
- participant: [cf.userID, cf.toUser],
1276
- });
1277
- const viewId = gvc.glitter.getUUID();
1278
- const chatView = html`
1279
- <div class="w-100 h-100" style="position: relative;">
1280
- ${BgCustomerMessage.detail({
1281
- gvc: gvc,
1282
- chat: {
1283
- chat_id: chatID,
1284
- type: 'user',
1285
- },
1286
- user_id: cf.userID,
1287
- containerHeight: `${cf.height}px`,
1288
- document: (document.querySelector('#' + id)! as any).shadowRoot,
1289
- goBack: () => {
1290
- gvc.notifyDataChange(viewId);
1291
- },
1292
- close: gvc.glitter.ut.frSize(
1293
- {
1294
- sm: undefined,
1295
- },
1296
- () => {
1297
- gvc.notifyDataChange(id);
1298
- }
1299
- ),
1300
- })}
1301
- </div>`;
1423
+ () => {
1424
+ gvc.notifyDataChange(id);
1425
+ }
1426
+ ),
1427
+ })}
1428
+ </div>`;
1302
1429
 
1303
- const baseUrl = new URL('../', import.meta.url);
1304
- (document.querySelector('#' + id)! as any).addStyleLink(baseUrl.href + `assets/css/theme.css`);
1305
- (document.querySelector('#' + id)! as any).addStyleLink(baseUrl.href + `assets/vendor/boxicons/css/boxicons.min.css`);
1306
- (document.querySelector('#' + id)! as any).addStyleLink(`https://kit.fontawesome.com/cccedec0f8.css`);
1307
- (document.querySelector('#' + id)! as any).addStyle(`
1430
+ const baseUrl = new URL('../', import.meta.url);
1431
+ (document.querySelector('#' + id)! as any).addStyleLink(baseUrl.href + `assets/css/theme.css`);
1432
+ (document.querySelector('#' + id)! as any).addStyleLink(
1433
+ baseUrl.href + `assets/vendor/boxicons/css/boxicons.min.css`
1434
+ );
1435
+ (document.querySelector('#' + id)! as any).addStyleLink(`https://kit.fontawesome.com/cccedec0f8.css`);
1436
+ (document.querySelector('#' + id)! as any).addStyle(`
1308
1437
  .btn-white-primary {
1309
1438
  border: 2px solid ${BgCustomerMessage.config.color};
1310
1439
  justify-content: space-between;
@@ -1319,428 +1448,459 @@ export class BgCustomerMessage {
1319
1448
  color: white !important;
1320
1449
  }
1321
1450
  `);
1322
- (document.querySelector('#' + id)! as any).setView({
1323
- gvc: gvc,
1324
- view: chatView,
1325
- id: id,
1326
- });
1327
- },
1328
- };
1329
- });
1330
- }
1451
+ (document.querySelector('#' + id)! as any).setView({
1452
+ gvc: gvc,
1453
+ view: chatView,
1454
+ id: id,
1455
+ });
1456
+ },
1457
+ };
1458
+ });
1459
+ }
1331
1460
 
1332
- public static detail(cf: {
1333
- gvc: GVC;
1334
- chat: any;
1335
- user_id: string;
1336
- containerHeight: string;
1337
- document: any;
1338
- goBack: () => void;
1339
- close?: () => void
1340
- }) {
1341
- const gvc = cf.gvc;
1342
- const document = cf.document;
1343
- const html = String.raw;
1344
- return gvc.bindView(() => {
1345
- const id = gvc.glitter.getUUID();
1461
+ public static detail(cf: {
1462
+ gvc: GVC;
1463
+ chat: any;
1464
+ user_id: string;
1465
+ containerHeight: string;
1466
+ document: any;
1467
+ goBack: () => void;
1468
+ close?: () => void;
1469
+ }) {
1470
+ const gvc = cf.gvc;
1471
+ const document = cf.document;
1472
+ const html = String.raw;
1473
+ return gvc.bindView(() => {
1474
+ const id = gvc.glitter.getUUID();
1346
1475
 
1347
- return {
1476
+ return {
1477
+ bind: id,
1478
+ view: () => {
1479
+ return [
1480
+ gvc.bindView(() => {
1481
+ const id = gvc.glitter.getUUID();
1482
+ return {
1348
1483
  bind: id,
1349
1484
  view: () => {
1350
- return [
1351
- gvc.bindView(() => {
1352
- const id = gvc.glitter.getUUID();
1353
- return {
1354
- bind: id,
1355
- view: () => {
1356
- return new Promise(async (resolve, reject) => {
1357
- const chatRoom = (
1358
- await Chat.getChatRoom({
1359
- page: 0,
1360
- limit: 1000,
1361
- user_id: cf.user_id,
1362
- chat_id: cf.chat.chat_id,
1363
- })
1364
- ).response.data[0];
1365
- if (chatRoom.who === 'manager') {
1366
- chatRoom.user_data = BgCustomerMessage.config;
1367
- }
1368
-
1369
- if (chatRoom.chat_id.startsWith('line')) {
1370
- chatRoom.user_data.head = chatRoom.info.line?.head;
1371
- chatRoom.user_data.name = chatRoom.info.line?.name;
1372
- }
1373
- if (chatRoom.chat_id.startsWith('fb')) {
1374
- chatRoom.user_data.head = chatRoom.fb.line?.head;
1375
- chatRoom.user_data.name = chatRoom.fb.line?.name;
1376
- }
1377
- resolve(html`
1378
- <div
1379
- class="navbar d-flex align-items-center justify-content-between w-100 p-3 ${BgCustomerMessage.config.hideBar ? `d-none` : ``}"
1380
- style="background: ${BgCustomerMessage.config.color};"
1381
- >
1382
- <div class="d-flex align-items-center pe-3 w-100"
1383
- style="gap:10px;display: flex;align-items: center;">
1384
- <i
1385
- class="fa-solid fa-chevron-left fs-6"
1386
- style="color:white;cursor: pointer;"
1387
- onclick="${gvc.event(() => {
1388
- if (cf.user_id === 'manager') {
1389
- BgCustomerMessage.vm.type = 'list';
1390
- gvc.notifyDataChange(BgCustomerMessage.id);
1391
- } else {
1392
- cf.goBack();
1393
- }
1394
- })}"
1395
- ></i>
1396
- <img
1397
- src="${chatRoom.type === 'user'
1398
- ? (chatRoom.user_data && chatRoom.user_data.head) ||
1399
- chatRoom.user_data.head_img ||
1400
- 'https://d3jnmi1tfjgtti.cloudfront.net/file/252530754/1704269678588-43.png'
1401
- : `https://d3jnmi1tfjgtti.cloudfront.net/file/252530754/1704269678588-43.png`}"
1402
- class="rounded-circle border"
1403
- style="background: white;"
1404
- width="40"
1405
- alt="Albert Flores"
1406
- />
1407
- <h6 class="mb-0 px-1 text-white">
1408
- ${chatRoom.type === 'user' ? (chatRoom.user_data && chatRoom.user_data.name) || '訪客' : `群組`}</h6>
1409
- <div class="flex-fill" style="flex: 1;"></div>
1410
- <i
1411
- class="fa-regular fa-circle-xmark text-white fs-3 ${cf.close ? `` : `d-none`}"
1412
- onclick="${gvc.event(() => {
1413
- cf.close && cf.close();
1414
- })}"
1415
- ></i>
1416
- </div>
1417
- </div>`);
1418
- });
1419
- },
1420
- };
1421
- }),
1422
- gvc.bindView(() => {
1423
- const viewId = gvc.glitter.getUUID();
1424
- const messageID = gvc.glitter.getUUID();
1425
- const vm: {
1426
- data: any;
1427
- loading: boolean;
1428
- scrollToBtn: boolean;
1429
- lastScroll: number;
1430
- message: string;
1431
- prefixScroll: number;
1432
- last_read: any;
1433
- close: boolean;
1434
- } = {
1435
- data: [],
1436
- loading: true,
1437
- scrollToBtn: false,
1438
- lastScroll: -1,
1439
- message: '',
1440
- prefixScroll: 0,
1441
- last_read: {},
1442
- close: false,
1443
- };
1444
- //chat_id
1445
- Chat.getMessage({
1446
- page: 0,
1447
- limit: 50,
1448
- chat_id: cf.chat.chat_id,
1449
- user_id: cf.user_id,
1450
- }).then((res) => {
1485
+ return new Promise(async (resolve, reject) => {
1486
+ const chatRoom = (
1487
+ await Chat.getChatRoom({
1488
+ page: 0,
1489
+ limit: 1000,
1490
+ user_id: cf.user_id,
1491
+ chat_id: cf.chat.chat_id,
1492
+ })
1493
+ ).response.data[0];
1494
+ if (chatRoom.who === 'manager') {
1495
+ chatRoom.user_data = BgCustomerMessage.config;
1496
+ }
1451
1497
 
1452
- vm.data = res.response.data.reverse();
1453
- vm.last_read = res.response.lastRead;
1454
- vm.loading = false;
1455
- gvc.notifyDataChange(viewId);
1456
- });
1498
+ if (chatRoom.chat_id.startsWith('line')) {
1499
+ chatRoom.user_data.head = chatRoom.info.line?.head;
1500
+ chatRoom.user_data.name = chatRoom.info.line?.name;
1501
+ }
1502
+ if (chatRoom.chat_id.startsWith('fb')) {
1503
+ chatRoom.user_data.head = chatRoom.fb.line?.head;
1504
+ chatRoom.user_data.name = chatRoom.fb.line?.name;
1505
+ }
1506
+ resolve(
1507
+ html` <div
1508
+ class="navbar d-flex align-items-center justify-content-between w-100 p-3 ${BgCustomerMessage
1509
+ .config.hideBar
1510
+ ? `d-none`
1511
+ : ``}"
1512
+ style="background: ${BgCustomerMessage.config.color};"
1513
+ >
1514
+ <div
1515
+ class="d-flex align-items-center pe-3 w-100"
1516
+ style="gap:10px;display: flex;align-items: center;"
1517
+ >
1518
+ <i
1519
+ class="fa-solid fa-chevron-left fs-6"
1520
+ style="color:white;cursor: pointer;"
1521
+ onclick="${gvc.event(() => {
1522
+ if (cf.user_id === 'manager') {
1523
+ BgCustomerMessage.vm.type = 'list';
1524
+ gvc.notifyDataChange(BgCustomerMessage.id);
1525
+ } else {
1526
+ cf.goBack();
1527
+ }
1528
+ })}"
1529
+ ></i>
1530
+ <img
1531
+ src="${chatRoom.type === 'user'
1532
+ ? (chatRoom.user_data && chatRoom.user_data.head) ||
1533
+ chatRoom.user_data.head_img ||
1534
+ 'https://d3jnmi1tfjgtti.cloudfront.net/file/252530754/1704269678588-43.png'
1535
+ : `https://d3jnmi1tfjgtti.cloudfront.net/file/252530754/1704269678588-43.png`}"
1536
+ class="rounded-circle border"
1537
+ style="background: white;"
1538
+ width="40"
1539
+ alt="Albert Flores"
1540
+ />
1541
+ <h6 class="mb-0 px-1 text-white">
1542
+ ${chatRoom.type === 'user'
1543
+ ? (chatRoom.user_data && chatRoom.user_data.name) || '訪客'
1544
+ : `群組`}
1545
+ </h6>
1546
+ <div class="flex-fill" style="flex: 1;"></div>
1547
+ <i
1548
+ class="fa-regular fa-circle-xmark text-white fs-3 ${cf.close ? `` : `d-none`}"
1549
+ onclick="${gvc.event(() => {
1550
+ cf.close && cf.close();
1551
+ })}"
1552
+ ></i>
1553
+ </div>
1554
+ </div>`
1555
+ );
1556
+ });
1557
+ },
1558
+ };
1559
+ }),
1560
+ gvc.bindView(() => {
1561
+ const viewId = gvc.glitter.getUUID();
1562
+ const messageID = gvc.glitter.getUUID();
1563
+ const vm: {
1564
+ data: any;
1565
+ loading: boolean;
1566
+ scrollToBtn: boolean;
1567
+ lastScroll: number;
1568
+ message: string;
1569
+ prefixScroll: number;
1570
+ last_read: any;
1571
+ close: boolean;
1572
+ } = {
1573
+ data: [],
1574
+ loading: true,
1575
+ scrollToBtn: false,
1576
+ lastScroll: -1,
1577
+ message: '',
1578
+ prefixScroll: 0,
1579
+ last_read: {},
1580
+ close: false,
1581
+ };
1582
+ //chat_id
1583
+ Chat.getMessage({
1584
+ page: 0,
1585
+ limit: 50,
1586
+ chat_id: cf.chat.chat_id,
1587
+ user_id: cf.user_id,
1588
+ }).then(res => {
1589
+ vm.data = res.response.data.reverse();
1590
+ vm.last_read = res.response.lastRead;
1591
+ vm.loading = false;
1592
+ gvc.notifyDataChange(viewId);
1593
+ });
1457
1594
 
1458
- const url = new URL((window as any).glitterBackend);
1595
+ const url = new URL((window as any).glitterBackend);
1459
1596
 
1460
- let socket: any = undefined;
1597
+ let socket: any = undefined;
1461
1598
 
1462
- function connect() {
1463
- if (gvc.glitter.share.close_socket) {
1464
- gvc.glitter.share.close_socket();
1465
- }
1466
- vm.close = false;
1467
- socket = location.href.includes('https://') ? new WebSocket(`wss://${url.hostname}/websocket`) : new WebSocket(`ws://${url.hostname}:9003`);
1468
- gvc.glitter.share.close_socket = () => {
1469
- vm.close = true;
1470
- socket.close();
1471
- gvc.glitter.share.close_socket = undefined;
1472
- };
1473
- gvc.glitter.share.socket = socket;
1474
- socket.addEventListener('open', function (event: any) {
1475
- console.log('Connected to server');
1476
- socket.send(
1477
- JSON.stringify({
1478
- type: 'message',
1479
- chatID: cf.chat.chat_id,
1480
- user_id: cf.user_id,
1481
- app_name: (window as any).appName
1482
- })
1483
- );
1484
- });
1485
- let interVal: any = 0;
1486
- socket.addEventListener('message', function (event: any) {
1487
- const data = JSON.parse(event.data);
1488
- if (data.type === 'update_read_count') {
1489
- vm.last_read = data.data;
1490
- } else {
1491
- vm.data.push(data);
1492
- const element: any = document.querySelector('.chatContainer')!;
1493
- const st = element.scrollTop;
1494
- const ofs = element.offsetHeight;
1495
- const sh = element.scrollHeight;
1496
- for (const dd of document.querySelectorAll('.time-mute')) {
1497
- dd.remove();
1498
- }
1499
- document.querySelector(`#message-lines`).innerHTML += BgCustomerMessage.message_line(data, cf, vm.data.length - 1, vm, gvc);
1500
- if (st + ofs >= sh - 50) {
1501
- element.scrollTop = element.scrollHeight;
1502
- setTimeout(() => {
1503
- element.scrollTop = element.scrollHeight;
1504
- }, 1000)
1505
- }
1506
- }
1507
- });
1508
- socket.addEventListener('close', function (event: any) {
1509
- console.log('Disconnected from server');
1510
- if (!vm.close) {
1511
- console.log('Reconnected from server');
1512
- connect();
1513
- }
1514
- });
1515
- }
1599
+ function connect() {
1600
+ if (gvc.glitter.share.close_socket) {
1601
+ gvc.glitter.share.close_socket();
1602
+ }
1603
+ vm.close = false;
1604
+ socket = location.href.includes('https://')
1605
+ ? new WebSocket(`wss://${url.hostname}/websocket`)
1606
+ : new WebSocket(`ws://${url.hostname}:9003`);
1607
+ gvc.glitter.share.close_socket = () => {
1608
+ vm.close = true;
1609
+ socket.close();
1610
+ gvc.glitter.share.close_socket = undefined;
1611
+ };
1612
+ gvc.glitter.share.socket = socket;
1613
+ socket.addEventListener('open', function (event: any) {
1614
+ console.log('Connected to server');
1615
+ socket.send(
1616
+ JSON.stringify({
1617
+ type: 'message',
1618
+ chatID: cf.chat.chat_id,
1619
+ user_id: cf.user_id,
1620
+ app_name: (window as any).appName,
1621
+ })
1622
+ );
1623
+ });
1624
+ let interVal: any = 0;
1625
+ socket.addEventListener('message', function (event: any) {
1626
+ const data = JSON.parse(event.data);
1627
+ if (data.type === 'update_read_count') {
1628
+ vm.last_read = data.data;
1629
+ } else {
1630
+ vm.data.push(data);
1631
+ const element: any = document.querySelector('.chatContainer')!;
1632
+ const st = element.scrollTop;
1633
+ const ofs = element.offsetHeight;
1634
+ const sh = element.scrollHeight;
1635
+ for (const dd of document.querySelectorAll('.time-mute')) {
1636
+ dd.remove();
1637
+ }
1638
+ document.querySelector(`#message-lines`).innerHTML += BgCustomerMessage.message_line(
1639
+ data,
1640
+ cf,
1641
+ vm.data.length - 1,
1642
+ vm,
1643
+ gvc
1644
+ );
1645
+ if (st + ofs >= sh - 50) {
1646
+ element.scrollTop = element.scrollHeight;
1647
+ setTimeout(() => {
1648
+ element.scrollTop = element.scrollHeight;
1649
+ }, 1000);
1650
+ }
1651
+ }
1652
+ });
1653
+ socket.addEventListener('close', function (event: any) {
1654
+ console.log('Disconnected from server');
1655
+ if (!vm.close) {
1656
+ console.log('Reconnected from server');
1657
+ connect();
1658
+ }
1659
+ });
1660
+ }
1516
1661
 
1517
- connect();
1662
+ connect();
1518
1663
 
1519
- const textAreaId = gvc.glitter.getUUID();
1520
- const html = String.raw;
1521
- return {
1522
- bind: viewId,
1523
- view: () => {
1524
- if (vm.loading) {
1525
- return String.raw`<div class="d-flex align-items-center justify-content-center w-100 flex-column pt-3">
1664
+ const textAreaId = gvc.glitter.getUUID();
1665
+ const html = String.raw;
1666
+ return {
1667
+ bind: viewId,
1668
+ view: () => {
1669
+ if (vm.loading) {
1670
+ return String.raw`<div class="d-flex align-items-center justify-content-center w-100 flex-column pt-3">
1526
1671
  <div class="spinner-border" role="status">
1527
1672
  <span class="sr-only"></span>
1528
1673
  </div>
1529
1674
  <span class="mt-2">載入中...</span>
1530
1675
  </div>`;
1531
- }
1532
- return html` ${gvc.bindView(() => {
1533
- return {
1534
- bind: messageID,
1535
- view: () => {
1536
- return html`
1537
- <div class="my-auto flex-fill" id=""></div>
1538
- <div class="w-100" id="message-lines">
1539
- ${vm.data
1540
- .map((dd: any, index: number) => {
1541
- return BgCustomerMessage.message_line(dd, cf, index, vm, gvc);
1542
- })
1543
- .join('')}
1544
- </div>
1545
-
1546
- ${vm.data.length === 0
1547
- ? html`
1548
- <div class="w-100 text-center">
1549
- <div class="badge bg-secondary">
1550
- 尚未展開對話,於下方輸入訊息並傳送。
1551
- </div>
1552
- </div> `
1553
- : ``}`;
1554
- },
1555
- divCreate: {
1556
- class: `chatContainer p-3 d-flex flex-column`,
1557
- style: `overflow-y: auto;height: calc(${cf.containerHeight} - 220px);background: white;padding-bottom:80px !important;`,
1558
- },
1559
- onCreate: () => {
1560
- vm.close = false;
1561
- // 取得要監聽的元素
1562
- let targetElement = document.querySelector('.chatContainer')!;
1563
- if (vm.lastScroll === -1) {
1564
- setTimeout(() => {
1565
- document.querySelector('.chatContainer')!.scrollTop = document.querySelector('.chatContainer')!.scrollHeight;
1566
- }, 100)
1567
- } else {
1568
- if (vm.prefixScroll) {
1569
- vm.lastScroll = targetElement.scrollHeight - vm.prefixScroll + vm.lastScroll;
1570
- vm.prefixScroll = 0;
1571
- }
1572
- document.querySelector('.chatContainer')!.scrollTop = vm.lastScroll;
1573
- }
1574
- // 添加滾動事件監聽器
1575
- targetElement.addEventListener('scroll', () => {
1576
- vm.lastScroll = targetElement.scrollTop;
1577
- if (targetElement.scrollTop === 0) {
1578
- console.log(`scrollTop===0`);
1579
- if (vm.loading) {
1580
- return;
1581
- }
1582
- vm.loading = true;
1583
- Chat.getMessage({
1584
- page: 0,
1585
- limit: 50,
1586
- chat_id: cf.chat.chat_id,
1587
- olderID: vm.data[0].id,
1588
- user_id: cf.user_id,
1589
- }).then((res) => {
1590
- vm.loading = false;
1591
- vm.prefixScroll = targetElement.scrollHeight;
1592
- vm.data = res.response.data.reverse().concat(vm.data);
1593
- gvc.notifyDataChange(viewId);
1594
- });
1595
- }
1596
- });
1597
- },
1598
- };
1599
- })}
1600
- <div
1601
- class="card-footer border-top d-flex align-items-center w-100 border-0 pt-3 pb-3 px-4 position-fixed bottom-0 position-lg-absolute"
1602
- style="background: white;"
1603
- >
1676
+ }
1677
+ return html` ${gvc.bindView(() => {
1678
+ return {
1679
+ bind: messageID,
1680
+ view: () => {
1681
+ return html` <div class="my-auto flex-fill" id=""></div>
1682
+ <div class="w-100" id="message-lines">
1683
+ ${vm.data
1684
+ .map((dd: any, index: number) => {
1685
+ return BgCustomerMessage.message_line(dd, cf, index, vm, gvc);
1686
+ })
1687
+ .join('')}
1688
+ </div>
1604
1689
 
1605
- <div class="position-relative w-100 me-2 ">
1606
- ${gvc.bindView(() => {
1607
- return {
1608
- bind: textAreaId,
1609
- view: () => {
1610
- return vm.message ?? '';
1611
- },
1612
- divCreate: {
1613
- elem: `textArea`,
1614
- style: `max-height:100px;white-space: pre-wrap; word-wrap: break-word;height:40px;`,
1615
- class: `form-control`,
1616
- option: [
1617
- {key: 'placeholder', value: '輸入訊息內容'},
1618
- {
1619
- key: 'onchange',
1620
- value: gvc.event((e) => {
1621
- vm.message = e.value;
1622
- }),
1623
- },
1624
- ],
1625
- },
1626
- onCreate: () => {
1627
- const input = gvc.getBindViewElem(id).get(0);
1628
- input.addEventListener('input', function () {
1629
- console.log(`input.scrollHeight->`, input.scrollHeight);
1630
- input.style.height = 'auto'; // 重置高度
1631
- input.style.height = input.scrollHeight + 'px'; // 设置为内容高度
1632
- });
1633
- },
1634
- };
1635
- })}
1636
- </div>
1637
- <button
1638
- type="button"
1639
- class="btn btn-icon btn-lg d-sm-inline-flex ms-1"
1640
- style="height: 36px;background: ${BgCustomerMessage.config.color};"
1641
- onclick="${gvc.event(() => {
1642
- if (vm.message) {
1643
- Chat.postMessage({
1644
- chat_id: cf.chat.chat_id,
1645
- user_id: cf.user_id,
1646
- message: {
1647
- text: vm.message,
1648
- attachment: '',
1649
- },
1650
- }).then(() => {
1651
- vm.message = '';
1652
- });
1653
- const textArea = gvc.getBindViewElem(textAreaId).get(0);
1654
- textArea.value = '';
1655
- textArea.focus();
1656
- }
1657
- })}"
1658
- >
1659
- <i class="fa-regular fa-paper-plane-top"></i>
1660
- </button>
1661
- </div>`;
1662
- },
1663
- divCreate: {},
1664
- onCreate: () => {
1665
- },
1666
- onDestroy: () => {
1667
- vm.close = true;
1668
- socket.close();
1690
+ ${vm.data.length === 0
1691
+ ? html`
1692
+ <div class="w-100 text-center">
1693
+ <div class="badge bg-secondary">尚未展開對話,於下方輸入訊息並傳送。</div>
1694
+ </div>
1695
+ `
1696
+ : ``}`;
1697
+ },
1698
+ divCreate: {
1699
+ class: `chatContainer p-3 d-flex flex-column`,
1700
+ style: `overflow-y: auto;height: calc(${cf.containerHeight} - 220px);background: white;padding-bottom:80px !important;`,
1701
+ },
1702
+ onCreate: () => {
1703
+ vm.close = false;
1704
+ // 取得要監聽的元素
1705
+ let targetElement = document.querySelector('.chatContainer')!;
1706
+ if (vm.lastScroll === -1) {
1707
+ setTimeout(() => {
1708
+ document.querySelector('.chatContainer')!.scrollTop =
1709
+ document.querySelector('.chatContainer')!.scrollHeight;
1710
+ }, 100);
1711
+ } else {
1712
+ if (vm.prefixScroll) {
1713
+ vm.lastScroll = targetElement.scrollHeight - vm.prefixScroll + vm.lastScroll;
1714
+ vm.prefixScroll = 0;
1715
+ }
1716
+ document.querySelector('.chatContainer')!.scrollTop = vm.lastScroll;
1717
+ }
1718
+ // 添加滾動事件監聽器
1719
+ targetElement.addEventListener('scroll', () => {
1720
+ vm.lastScroll = targetElement.scrollTop;
1721
+ if (targetElement.scrollTop === 0) {
1722
+ console.log(`scrollTop===0`);
1723
+ if (vm.loading) {
1724
+ return;
1725
+ }
1726
+ vm.loading = true;
1727
+ Chat.getMessage({
1728
+ page: 0,
1729
+ limit: 50,
1730
+ chat_id: cf.chat.chat_id,
1731
+ olderID: vm.data[0].id,
1732
+ user_id: cf.user_id,
1733
+ }).then(res => {
1734
+ vm.loading = false;
1735
+ vm.prefixScroll = targetElement.scrollHeight;
1736
+ vm.data = res.response.data.reverse().concat(vm.data);
1737
+ gvc.notifyDataChange(viewId);
1738
+ });
1739
+ }
1740
+ });
1741
+ },
1742
+ };
1743
+ })}
1744
+ <div
1745
+ class="card-footer border-top d-flex align-items-center w-100 border-0 pt-3 pb-3 px-4 position-fixed bottom-0 position-lg-absolute"
1746
+ style="background: white;"
1747
+ >
1748
+ <div class="position-relative w-100 me-2 ">
1749
+ ${gvc.bindView(() => {
1750
+ return {
1751
+ bind: textAreaId,
1752
+ view: () => {
1753
+ return vm.message ?? '';
1754
+ },
1755
+ divCreate: {
1756
+ elem: `textArea`,
1757
+ style: `max-height:100px;white-space: pre-wrap; word-wrap: break-word;height:40px;`,
1758
+ class: `form-control`,
1759
+ option: [
1760
+ { key: 'placeholder', value: '輸入訊息內容' },
1761
+ {
1762
+ key: 'onchange',
1763
+ value: gvc.event(e => {
1764
+ vm.message = e.value;
1765
+ }),
1669
1766
  },
1670
- };
1671
- }),
1672
- ].join('');
1767
+ ],
1768
+ },
1769
+ onCreate: () => {
1770
+ const input = gvc.getBindViewElem(id).get(0);
1771
+ input.addEventListener('input', function () {
1772
+ console.log(`input.scrollHeight->`, input.scrollHeight);
1773
+ input.style.height = 'auto'; // 重置高度
1774
+ input.style.height = input.scrollHeight + 'px'; // 设置为内容高度
1775
+ });
1776
+ },
1777
+ };
1778
+ })}
1779
+ </div>
1780
+ <button
1781
+ type="button"
1782
+ class="btn btn-icon btn-lg d-sm-inline-flex ms-1"
1783
+ style="height: 36px;background: ${BgCustomerMessage.config.color};"
1784
+ onclick="${gvc.event(() => {
1785
+ if (vm.message) {
1786
+ Chat.postMessage({
1787
+ chat_id: cf.chat.chat_id,
1788
+ user_id: cf.user_id,
1789
+ message: {
1790
+ text: vm.message,
1791
+ attachment: '',
1792
+ },
1793
+ }).then(() => {
1794
+ vm.message = '';
1795
+ });
1796
+ const textArea = gvc.getBindViewElem(textAreaId).get(0);
1797
+ textArea.value = '';
1798
+ textArea.focus();
1799
+ }
1800
+ })}"
1801
+ >
1802
+ <i class="fa-regular fa-paper-plane-top"></i>
1803
+ </button>
1804
+ </div>`;
1673
1805
  },
1674
- };
1675
- });
1676
- }
1677
-
1678
- public static message_line(dd: any, cf: any, index: number, vm: any, gvc: GVC) {
1679
- const html = String.raw;
1680
- if (dd.user_id == 'manager') {
1681
- dd.user_data = BgCustomerMessage.config;
1682
- }
1683
-
1684
- function drawChatContent() {
1685
- if (dd.message.image) {
1686
- return html`<img src="${dd.message.image}">`
1687
- } else {
1688
- return dd.message.text.replace(/\n/g, '<br>')
1689
- }
1690
- }
1806
+ divCreate: {},
1807
+ onCreate: () => {},
1808
+ onDestroy: () => {
1809
+ vm.close = true;
1810
+ socket.close();
1811
+ },
1812
+ };
1813
+ }),
1814
+ ].join('');
1815
+ },
1816
+ };
1817
+ });
1818
+ }
1691
1819
 
1692
- if (cf.user_id !== dd.user_id) {
1820
+ public static message_line(dd: any, cf: any, index: number, vm: any, gvc: GVC) {
1821
+ const html = String.raw;
1822
+ if (dd.user_id == 'manager') {
1823
+ dd.user_data = BgCustomerMessage.config;
1824
+ }
1693
1825
 
1694
- return html`
1695
- <div class="mt-auto d-flex align-items-start ${vm.data[index + 1] && vm.data[index + 1].user_id === dd.user_id ? `mb-1` : `mb-3`}">
1696
- <img
1697
- src="${(dd.user_data && dd.user_data.head) || `https://d3jnmi1tfjgtti.cloudfront.net/file/252530754/1704269678588-43.png`}"
1698
- class="rounded-circle border"
1699
- width="40"
1700
- alt="Albert Flores"
1701
- />
1702
- <div class="ps-2 ms-1" style="max-width: 348px;">
1703
- <div class="p-3 mb-1 ${dd.message.image ? '' : 'py-2'}"
1704
- style="background:#eeeef1;border-top-right-radius: .5rem; border-bottom-right-radius: .5rem; border-bottom-left-radius: .5rem;white-space: normal;">
1826
+ function drawChatContent() {
1827
+ if (dd.message.image) {
1828
+ return html`<img src="${dd.message.image}" />`;
1829
+ } else {
1830
+ return dd.message.text.replace(/\n/g, '<br>');
1831
+ }
1832
+ }
1705
1833
 
1706
- ${drawChatContent()}
1707
- </div>
1708
- <div class="fs-sm text-muted ${vm.data[index + 1] && vm.data[index + 1].user_id === dd.user_id ? `d-none` : ``}">
1709
- ${gvc.glitter.ut.dateFormat(new Date(dd.created_time), 'MM-dd hh:mm')}
1710
- </div>
1711
- </div>
1712
- </div>`;
1713
- } else {
1714
- return html`
1715
- <div class="d-flex align-items-start justify-content-end ${vm.data[index + 1] && vm.data[index + 1].user_id === dd.user_id ? `mb-1` : `mb-3`}">
1716
- <div class="pe-2 me-1" style="max-width: 348px;">
1717
- <div
1718
- class=" text-light p-3 mb-1 ${dd?.message?.image ? '' : 'py-2'}"
1719
- style="background:${BgCustomerMessage.config.color};border-top-left-radius: .5rem; border-bottom-right-radius: .5rem; border-bottom-left-radius: .5rem;white-space: normal;"
1720
- >
1721
- ${drawChatContent()}
1722
- </div>
1723
- <div
1724
- class="time-mute fw-500 d-flex justify-content-end align-items-center fs-sm text-muted ${vm.data[index + 1] && vm.data[index + 1].user_id === dd.user_id ? `d-none` : ``}"
1725
- style="gap:5px;"
1726
- >
1727
- <span> ${gvc.glitter.ut.dateFormat(new Date(dd.created_time), 'MM/dd hh:mm')}</span>
1728
- ${vm.last_read.find((d2: any) => {
1729
- return d2.user_id !== cf.user_id && new Date(d2.last_read).getTime() >= new Date(dd.created_time).getTime();
1730
- })
1731
- ? `已讀`
1732
- : ``}
1733
- </div>
1734
- </div>
1735
- <img
1736
- src="${(dd.user_data && dd.user_data.head) || `https://d3jnmi1tfjgtti.cloudfront.net/file/252530754/1704269678588-43.png`}"
1737
- class="rounded-circle border"
1738
- width="40"
1739
- alt="Albert Flores"
1740
- />
1741
- </div>`;
1742
- }
1834
+ if (cf.user_id !== dd.user_id) {
1835
+ return html` <div
1836
+ class="mt-auto d-flex align-items-start ${vm.data[index + 1] && vm.data[index + 1].user_id === dd.user_id
1837
+ ? `mb-1`
1838
+ : `mb-3`}"
1839
+ >
1840
+ <img
1841
+ src="${(dd.user_data && dd.user_data.head) ||
1842
+ `https://d3jnmi1tfjgtti.cloudfront.net/file/252530754/1704269678588-43.png`}"
1843
+ class="rounded-circle border"
1844
+ width="40"
1845
+ alt="Albert Flores"
1846
+ />
1847
+ <div class="ps-2 ms-1" style="max-width: 348px;">
1848
+ <div
1849
+ class="p-3 mb-1 ${dd.message.image ? '' : 'py-2'}"
1850
+ style="background:#eeeef1;border-top-right-radius: .5rem; border-bottom-right-radius: .5rem; border-bottom-left-radius: .5rem;white-space: normal;"
1851
+ >
1852
+ ${drawChatContent()}
1853
+ </div>
1854
+ <div
1855
+ class="fs-sm text-muted ${vm.data[index + 1] && vm.data[index + 1].user_id === dd.user_id ? `d-none` : ``}"
1856
+ >
1857
+ ${gvc.glitter.ut.dateFormat(new Date(dd.created_time), 'MM-dd hh:mm')}
1858
+ </div>
1859
+ </div>
1860
+ </div>`;
1861
+ } else {
1862
+ return html` <div
1863
+ class="d-flex align-items-start justify-content-end ${vm.data[index + 1] &&
1864
+ vm.data[index + 1].user_id === dd.user_id
1865
+ ? `mb-1`
1866
+ : `mb-3`}"
1867
+ >
1868
+ <div class="pe-2 me-1" style="max-width: 348px;">
1869
+ <div
1870
+ class=" text-light p-3 mb-1 ${dd?.message?.image ? '' : 'py-2'}"
1871
+ style="background:${BgCustomerMessage.config
1872
+ .color};border-top-left-radius: .5rem; border-bottom-right-radius: .5rem; border-bottom-left-radius: .5rem;white-space: normal;"
1873
+ >
1874
+ ${drawChatContent()}
1875
+ </div>
1876
+ <div
1877
+ class="time-mute fw-500 d-flex justify-content-end align-items-center fs-sm text-muted ${vm.data[
1878
+ index + 1
1879
+ ] && vm.data[index + 1].user_id === dd.user_id
1880
+ ? `d-none`
1881
+ : ``}"
1882
+ style="gap:5px;"
1883
+ >
1884
+ <span> ${gvc.glitter.ut.dateFormat(new Date(dd.created_time), 'MM/dd hh:mm')}</span>
1885
+ ${vm.last_read.find((d2: any) => {
1886
+ return (
1887
+ d2.user_id !== cf.user_id && new Date(d2.last_read).getTime() >= new Date(dd.created_time).getTime()
1888
+ );
1889
+ })
1890
+ ? `已讀`
1891
+ : ``}
1892
+ </div>
1893
+ </div>
1894
+ <img
1895
+ src="${(dd.user_data && dd.user_data.head) ||
1896
+ `https://d3jnmi1tfjgtti.cloudfront.net/file/252530754/1704269678588-43.png`}"
1897
+ class="rounded-circle border"
1898
+ width="40"
1899
+ alt="Albert Flores"
1900
+ />
1901
+ </div>`;
1743
1902
  }
1903
+ }
1744
1904
  }
1745
1905
 
1746
1906
  (window as any).glitter.setModule(import.meta.url, BgCustomerMessage);