chat-customer-47net 1.2.3 → 1.2.4

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.
@@ -995,7 +995,7 @@ var render$8 = function () {
995
995
  return _vm.handleTouchEnd(e, "handleStartNewConversation");
996
996
  }
997
997
  }
998
- }, [_vm._v(" Start new conversation 💬 ")]) : _vm._e()], 2)]);
998
+ }, [_vm._v(" Start New Conversation 💬 ")]) : _vm._e()], 2)]);
999
999
  };
1000
1000
  var staticRenderFns$7 = [function () {
1001
1001
  var _vm = this;
@@ -1098,7 +1098,7 @@ const __vue2_script$7 = {
1098
1098
  }
1099
1099
  };
1100
1100
  const __cssModules$7 = {};
1101
- var __component__$7 = /* @__PURE__ */normalizeComponent(__vue2_script$7, render$8, staticRenderFns$7, false, __vue2_injectStyles$7, "e869095a", null, null);
1101
+ var __component__$7 = /* @__PURE__ */normalizeComponent(__vue2_script$7, render$8, staticRenderFns$7, false, __vue2_injectStyles$7, "3ede58da", null, null);
1102
1102
  function __vue2_injectStyles$7(context) {
1103
1103
  for (let o in __cssModules$7) {
1104
1104
  this[o] = __cssModules$7[o];
@@ -1284,7 +1284,7 @@ var render$6 = function () {
1284
1284
  return _vm.handleTouchEnd(e, "new");
1285
1285
  }
1286
1286
  }
1287
- }, [_vm._v(" Start new conversation 💬 ")])])]);
1287
+ }, [_vm._v(" Start New Conversation 💬 ")])])]);
1288
1288
  };
1289
1289
  var staticRenderFns$5 = [];
1290
1290
  const ConsultConversations_vue_vue_type_style_index_0_scoped_true_lang = "";
@@ -1332,7 +1332,7 @@ const __vue2_script$5 = {
1332
1332
  }
1333
1333
  };
1334
1334
  const __cssModules$5 = {};
1335
- var __component__$5 = /* @__PURE__ */normalizeComponent(__vue2_script$5, render$6, staticRenderFns$5, false, __vue2_injectStyles$5, "368dd12c", null, null);
1335
+ var __component__$5 = /* @__PURE__ */normalizeComponent(__vue2_script$5, render$6, staticRenderFns$5, false, __vue2_injectStyles$5, "61a191ac", null, null);
1336
1336
  function __vue2_injectStyles$5(context) {
1337
1337
  for (let o in __cssModules$5) {
1338
1338
  this[o] = __cssModules$5[o];
@@ -6127,7 +6127,7 @@ var render$5 = function () {
6127
6127
  }, [_c("b", {
6128
6128
  staticClass: "markdown-body",
6129
6129
  domProps: {
6130
- "innerHTML": _vm._s(_vm.markdownToHtml)
6130
+ "innerHTML": _vm._s(_vm.displayedHtml)
6131
6131
  }
6132
6132
  }), _c("span", {
6133
6133
  staticClass: "time"
@@ -6148,16 +6148,30 @@ var render$5 = function () {
6148
6148
  on: {
6149
6149
  "click": _vm.handleLinkClick
6150
6150
  }
6151
- }, [_c("b", {
6151
+ }, [_vm.chatType === "ai-thinking" ? _c("b", {
6152
+ staticClass: "thinking-dot",
6153
+ attrs: {
6154
+ "aria-hidden": "true"
6155
+ }
6156
+ }, [_vm._v(" thinking "), _c("i", {
6157
+ staticClass: "dot"
6158
+ }), _c("i", {
6159
+ staticClass: "dot"
6160
+ }), _c("i", {
6161
+ staticClass: "dot"
6162
+ })]) : _c("b", {
6152
6163
  staticClass: "markdown-body",
6153
6164
  domProps: {
6154
- "innerHTML": _vm._s(_vm.markdownToHtml)
6165
+ "innerHTML": _vm._s(_vm.displayedHtml)
6155
6166
  }
6156
- }), _vm.chatType === "ai" && _vm.chatAction === "human agent" ? _c("i", {
6167
+ }), _vm.chatType === "ai" && _vm.chatAction === "human agent" && !_vm.isTyping ? _c("i", {
6157
6168
  staticClass: "to-human"
6158
6169
  }, [_c("i", {
6159
6170
  on: {
6160
- "click": _vm.changeByHumanAgent
6171
+ "click": function ($event) {
6172
+ $event.stopPropagation();
6173
+ return _vm.changeByHumanAgent.apply(null, arguments);
6174
+ }
6161
6175
  }
6162
6176
  }, [_vm._v("Connect with an Agent")])]) : _vm._e(), _c("span", {
6163
6177
  staticClass: "time"
@@ -6279,6 +6293,7 @@ var staticRenderFns$4 = [function () {
6279
6293
  const ConsultChatItem_vue_vue_type_style_index_0_scoped_true_lang = "";
6280
6294
  const ConsultChatItem_vue_vue_type_style_index_1_lang = "";
6281
6295
  const hexToRgb = hex => {
6296
+ if (!hex || hex[0] !== "#") return "0, 0, 0";
6282
6297
  const r = parseInt(hex.slice(1, 3), 16);
6283
6298
  const g = parseInt(hex.slice(3, 5), 16);
6284
6299
  const b = parseInt(hex.slice(5, 7), 16);
@@ -6287,13 +6302,13 @@ const hexToRgb = hex => {
6287
6302
  const render$4 = new marked.Renderer();
6288
6303
  marked.setOptions({
6289
6304
  renderer: render$4,
6290
- // 这是必填项
6291
6305
  gfm: true,
6292
- pedantic: false
6306
+ pedantic: false,
6307
+ breaks: true,
6308
+ sanitize: false
6293
6309
  });
6294
6310
  const __vue2_script$4 = {
6295
6311
  name: "ConsultChatItem",
6296
- components: {},
6297
6312
  props: {
6298
6313
  item: {
6299
6314
  type: Object,
@@ -6362,6 +6377,24 @@ const __vue2_script$4 = {
6362
6377
  socket: {
6363
6378
  type: Object,
6364
6379
  default: () => ({})
6380
+ },
6381
+ // 强制打开打字机(父组件可传)
6382
+ stream: {
6383
+ type: Boolean,
6384
+ default: false
6385
+ },
6386
+ // 调速相关
6387
+ typeSpeed: {
6388
+ type: Number,
6389
+ default: 20
6390
+ },
6391
+ chunk: {
6392
+ type: Number,
6393
+ default: 1
6394
+ },
6395
+ charsPerRender: {
6396
+ type: Number,
6397
+ default: 3
6365
6398
  }
6366
6399
  },
6367
6400
  data() {
@@ -6370,7 +6403,12 @@ const __vue2_script$4 = {
6370
6403
  email: ((_a2 = this.initData.user) == null ? void 0 : _a2.email) || "",
6371
6404
  clientEmail: ((_b = this.initData.user) == null ? void 0 : _b.email) || "",
6372
6405
  clientName: ((_c = this.initData.user) == null ? void 0 : _c.name) || "",
6373
- clientQuestion: ""
6406
+ clientQuestion: "",
6407
+ displayedHtml: "",
6408
+ _typeController: null,
6409
+ isTyping: false,
6410
+ // 标记组件已挂载:只有当 _hasMounted 为 true 时,新的 message 才会触发打字机
6411
+ _hasMounted: false
6374
6412
  };
6375
6413
  },
6376
6414
  computed: {
@@ -6380,30 +6418,140 @@ const __vue2_script$4 = {
6380
6418
  userId() {
6381
6419
  return getClientId();
6382
6420
  },
6383
- markdownToHtml() {
6384
- const text = this.message.replace(/ {2,}/g, match => " ".repeat(match.length));
6385
- const renderer = new marked.Renderer();
6386
- renderer.link = href => {
6387
- const currentDomain = window.location.hostname;
6388
- const targetDomain = new URL(href.href).hostname;
6389
- if (targetDomain === currentDomain) {
6390
- return `<a href="${href.href}" data-internal-link="true">${href.text}</a>`;
6391
- }
6392
- return `<a href="${href.href}" target="_blank" rel="noopener noreferrer">${href.text}</a>`;
6393
- };
6394
- marked.setOptions({
6395
- breaks: true,
6396
- sanitize: false,
6397
- renderer
6398
- });
6399
- return marked(text);
6421
+ _shouldType() {
6422
+ return this.stream || this.chatType === "ai" && this.userOrOther !== "user";
6400
6423
  }
6401
6424
  },
6425
+ watch: {
6426
+ message(newVal, oldVal) {
6427
+ this.stopTypewriter();
6428
+ if (this._shouldType && newVal && this._hasMounted && this.item.source === "socket") {
6429
+ this.isTyping = true;
6430
+ this._typeController = this.typewriterRender(newVal, {
6431
+ speed: this.typeSpeed,
6432
+ chunk: this.chunk,
6433
+ charsPerRender: this.charsPerRender,
6434
+ onUpdate: html2 => {
6435
+ this.displayedHtml = html2;
6436
+ },
6437
+ onComplete: () => {
6438
+ this.isTyping = false;
6439
+ this.$nextTick(() => {
6440
+ this.$emit("toBottom");
6441
+ });
6442
+ }
6443
+ });
6444
+ } else {
6445
+ this.displayedHtml = this.renderFull(newVal || "");
6446
+ this.isTyping = false;
6447
+ }
6448
+ }
6449
+ },
6450
+ mounted() {
6451
+ this.displayedHtml = this.renderFull(this.message || "");
6452
+ this.isTyping = false;
6453
+ this.$nextTick(() => {
6454
+ this._hasMounted = true;
6455
+ });
6456
+ },
6457
+ beforeDestroy() {
6458
+ this.stopTypewriter();
6459
+ },
6402
6460
  methods: {
6403
- async changeByHumanAgent() {
6404
- if (this.activeItem.assigned) {
6461
+ renderFull(src) {
6462
+ const text = (src || "").replace(/ {2,}/g, match => "&nbsp;".repeat(match.length));
6463
+ return marked(text);
6464
+ },
6465
+ typewriterRender(message, opts = {}) {
6466
+ const speed = typeof opts.speed === "number" ? opts.speed : 40;
6467
+ const chunk = Math.max(1, typeof opts.chunk === "number" ? opts.chunk : 1);
6468
+ const charsPerRender = Math.max(1, typeof opts.charsPerRender === "number" ? opts.charsPerRender : 3);
6469
+ const onUpdate = typeof opts.onUpdate === "function" ? opts.onUpdate : html2 => {
6470
+ this.displayedHtml = html2;
6471
+ };
6472
+ const onComplete = typeof opts.onComplete === "function" ? opts.onComplete : () => {};
6473
+ if (!message) {
6474
+ onUpdate("");
6475
+ onComplete();
6476
+ return {
6477
+ stop() {}
6478
+ };
6479
+ }
6480
+ const preprocess = s => (s || "").replace(/ {2,}/g, m => "&nbsp;".repeat(m.length));
6481
+ const src = preprocess(message);
6482
+ const len = src.length;
6483
+ let index = 0;
6484
+ let stopped = false;
6485
+ let timer = null;
6486
+ const step = () => {
6487
+ if (stopped) return;
6488
+ index = Math.min(len, index + chunk);
6489
+ if (index % charsPerRender === 0 || index === len) {
6490
+ try {
6491
+ const html2 = marked(src.slice(0, index));
6492
+ onUpdate(html2);
6493
+ } catch (err) {
6494
+ onUpdate(marked(src));
6495
+ stopped = true;
6496
+ onComplete();
6497
+ return;
6498
+ }
6499
+ }
6500
+ if (index >= len) {
6501
+ stopped = true;
6502
+ onComplete();
6503
+ return;
6504
+ }
6505
+ timer = setTimeout(step, speed);
6506
+ };
6507
+ timer = setTimeout(step, speed);
6508
+ return {
6509
+ stop() {
6510
+ stopped = true;
6511
+ if (timer) {
6512
+ clearTimeout(timer);
6513
+ timer = null;
6514
+ }
6515
+ }
6516
+ };
6517
+ },
6518
+ stopTypewriter() {
6519
+ if (this._typeController && typeof this._typeController.stop === "function") {
6520
+ this._typeController.stop();
6521
+ }
6522
+ this._typeController = null;
6523
+ this.isTyping = false;
6524
+ },
6525
+ // 点击消息:若正在打字则跳过,直接显示完整内容
6526
+ handleLinkClick(e) {
6527
+ if (e.target.tagName === "A") {
6528
+ e.preventDefault();
6529
+ const href = e.target.getAttribute("href");
6530
+ this.handleInternalLink(href);
6405
6531
  return;
6406
6532
  }
6533
+ if (this._typeController) {
6534
+ this.stopTypewriter();
6535
+ this.displayedHtml = this.renderFull(this.message || "");
6536
+ }
6537
+ },
6538
+ handleInternalLink(href) {
6539
+ try {
6540
+ const currentDomain = window.location.hostname;
6541
+ const targetDomain = new URL(href).hostname;
6542
+ if (targetDomain === currentDomain) {
6543
+ const path = new URL(href).pathname + new URL(href).search + new URL(href).hash;
6544
+ if (this.$router) this.$router.push(path);else window.location.href = href;
6545
+ } else {
6546
+ window.open(href, "_blank");
6547
+ }
6548
+ } catch (err) {
6549
+ window.open(href, "_blank");
6550
+ }
6551
+ },
6552
+ async changeByHumanAgent() {
6553
+ var _a2;
6554
+ if ((_a2 = this.activeItem) == null ? void 0 : _a2.assigned) return;
6407
6555
  this.$emit("changeTopToast", "Searching for agent");
6408
6556
  try {
6409
6557
  await updateRoomByHumanAgent({
@@ -6430,7 +6578,7 @@ const __vue2_script$4 = {
6430
6578
  }
6431
6579
  return;
6432
6580
  }
6433
- if (this.email && !this.email.match(/^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+((.[a-zA-Z0-9_-]{2,3}){1,2})$/)) {
6581
+ if (this.email && !this.email.match(/^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+((\.[a-zA-Z0-9_-]{2,3}){1,2})$/)) {
6434
6582
  if (this.$sweetalert) {
6435
6583
  this.$sweetalert.insert({
6436
6584
  title: "Something went wrong",
@@ -6462,7 +6610,7 @@ const __vue2_script$4 = {
6462
6610
  }
6463
6611
  return;
6464
6612
  }
6465
- if (this.clientEmail && !this.clientEmail.match(/^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+((.[a-zA-Z0-9_-]{2,3}){1,2})$/)) {
6613
+ if (this.clientEmail && !this.clientEmail.match(/^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+((\.[a-zA-Z0-9_-]{2,3}){1,2})$/)) {
6466
6614
  if (this.$sweetalert) {
6467
6615
  this.$sweetalert.insert({
6468
6616
  title: "Something went wrong",
@@ -6507,32 +6655,11 @@ const __vue2_script$4 = {
6507
6655
  question: this.clientQuestion,
6508
6656
  updateTime: this.updateTime
6509
6657
  });
6510
- },
6511
- handleLinkClick(e) {
6512
- if (e.target.tagName === "A") {
6513
- e.preventDefault();
6514
- const href = e.target.getAttribute("href");
6515
- this.handleInternalLink(href);
6516
- }
6517
- },
6518
- handleInternalLink(href) {
6519
- const currentDomain = window.location.hostname;
6520
- const targetDomain = new URL(href).hostname;
6521
- if (targetDomain === currentDomain) {
6522
- const path = new URL(href).pathname + new URL(href).search + new URL(href).hash;
6523
- if (this.$router) {
6524
- this.$router.push(path);
6525
- } else {
6526
- window.location.href = href;
6527
- }
6528
- } else {
6529
- window.open(href, "_blank");
6530
- }
6531
6658
  }
6532
6659
  }
6533
6660
  };
6534
6661
  const __cssModules$4 = {};
6535
- var __component__$4 = /* @__PURE__ */normalizeComponent(__vue2_script$4, render$5, staticRenderFns$4, false, __vue2_injectStyles$4, "5f248ee8", null, null);
6662
+ var __component__$4 = /* @__PURE__ */normalizeComponent(__vue2_script$4, render$5, staticRenderFns$4, false, __vue2_injectStyles$4, "c56244c0", null, null);
6536
6663
  function __vue2_injectStyles$4(context) {
6537
6664
  for (let o in __cssModules$4) {
6538
6665
  this[o] = __cssModules$4[o];
@@ -6588,7 +6715,8 @@ var render$3 = function () {
6588
6715
  on: {
6589
6716
  "submitEmail": _vm.submitEmail,
6590
6717
  "sendLeaveMessage": _vm.sendLeaveMessage,
6591
- "changeTopToast": _vm.changeTopToast
6718
+ "changeTopToast": _vm.changeTopToast,
6719
+ "toBottom": _vm.scrollToBottom
6592
6720
  }
6593
6721
  });
6594
6722
  }), 1)], 1), _vm.activeItem.status === "3" ? _c("div", {
@@ -6803,7 +6931,7 @@ const __vue2_script$3 = {
6803
6931
  }
6804
6932
  };
6805
6933
  const __cssModules$3 = {};
6806
- var __component__$3 = /* @__PURE__ */normalizeComponent(__vue2_script$3, render$3, staticRenderFns$3, false, __vue2_injectStyles$3, "b72de9f2", null, null);
6934
+ var __component__$3 = /* @__PURE__ */normalizeComponent(__vue2_script$3, render$3, staticRenderFns$3, false, __vue2_injectStyles$3, "07011d53", null, null);
6807
6935
  function __vue2_injectStyles$3(context) {
6808
6936
  for (let o in __cssModules$3) {
6809
6937
  this[o] = __cssModules$3[o];
@@ -6930,7 +7058,8 @@ const __vue2_script$2 = {
6930
7058
  avatar: item.avatar || "",
6931
7059
  time: chatShowDateTime(item.updateTime),
6932
7060
  updateTime: item.updateTime,
6933
- type: item.type || 1
7061
+ type: item.type || 1,
7062
+ source: item.source || ""
6934
7063
  };
6935
7064
  });
6936
7065
  return list2;
@@ -6995,7 +7124,7 @@ const __vue2_script$2 = {
6995
7124
  onListenMessage() {
6996
7125
  this.socket.on("message", message => {
6997
7126
  if (message.roomId === this.onRoomId) {
6998
- this.pushChat(message);
7127
+ this.pushChat(message, "socket");
6999
7128
  this.scrollToBottom();
7000
7129
  if (message.type === 7 && this.$refs.dialogComponent) {
7001
7130
  this.$refs.dialogComponent.changePauseConversation(true);
@@ -7120,7 +7249,7 @@ const __vue2_script$2 = {
7120
7249
  logOut() {
7121
7250
  this.socket.emit("logOut");
7122
7251
  },
7123
- pushChat(data) {
7252
+ pushChat(data, source) {
7124
7253
  const {
7125
7254
  userId,
7126
7255
  message,
@@ -7132,14 +7261,18 @@ const __vue2_script$2 = {
7132
7261
  type
7133
7262
  } = data;
7134
7263
  if (data.chatType === "ai") {
7135
- const onThinking = this.chats.chatList.find(item => item.chatType === "ai-thinking" && item.thinkingCode === data.thinkingCode);
7136
- if (onThinking) {
7137
- const index = this.chats.chatList.indexOf(onThinking);
7138
- this.chats.chatList.splice(index, 1, {
7264
+ const thinkingIndex = this.chats.chatList.findIndex(item => item.chatType === "ai-thinking" && item.thinkingCode === data.thinkingCode);
7265
+ const waitingIndex = this.chats.chatList.findIndex(item => item.chatType === "ai-thinking-waiting" && item.thinkingCode === data.thinkingCode);
7266
+ if (thinkingIndex !== -1) {
7267
+ const exist = this.chats.chatList[thinkingIndex];
7268
+ this.chats.chatList.splice(thinkingIndex, 1, {
7139
7269
  ...data,
7140
- updateTime: onThinking.updateTime
7141
- // 保留原时间戳
7270
+ updateTime: exist.updateTime,
7271
+ source: source || ""
7142
7272
  });
7273
+ if (waitingIndex !== -1 && waitingIndex !== thinkingIndex) {
7274
+ this.chats.chatList.splice(waitingIndex, 1);
7275
+ }
7143
7276
  return;
7144
7277
  }
7145
7278
  }
@@ -7153,7 +7286,8 @@ const __vue2_script$2 = {
7153
7286
  chatAction,
7154
7287
  roomId,
7155
7288
  thinkingCode: data.thinkingCode || "",
7156
- type
7289
+ type,
7290
+ source: source || ""
7157
7291
  });
7158
7292
  },
7159
7293
  handleSend(message) {
@@ -7274,7 +7408,7 @@ const __vue2_script$2 = {
7274
7408
  }
7275
7409
  };
7276
7410
  const __cssModules$2 = {};
7277
- var __component__$2 = /* @__PURE__ */normalizeComponent(__vue2_script$2, render$2, staticRenderFns$2, false, __vue2_injectStyles$2, "8ac5416e", null, null);
7411
+ var __component__$2 = /* @__PURE__ */normalizeComponent(__vue2_script$2, render$2, staticRenderFns$2, false, __vue2_injectStyles$2, "253fc2e7", null, null);
7278
7412
  function __vue2_injectStyles$2(context) {
7279
7413
  for (let o in __cssModules$2) {
7280
7414
  this[o] = __cssModules$2[o];
@@ -7646,8 +7780,10 @@ const __vue2_script = {
7646
7780
  this.updateOpenView(false);
7647
7781
  }
7648
7782
  if (route === "dialog") {
7649
- this.updateOpenView(true);
7650
- this.clearClinetUnRead();
7783
+ setTimeout(() => {
7784
+ this.updateOpenView(true);
7785
+ this.clearClinetUnRead();
7786
+ }, 300);
7651
7787
  }
7652
7788
  },
7653
7789
  initAudio() {