@tencentcloud/ai-desk-customer-vue 1.7.0 → 1.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/components/CustomerServiceChat/feedback-modal/index.vue +3 -0
- package/components/CustomerServiceChat/index-web.vue +32 -4
- package/components/CustomerServiceChat/message-input/index-web.vue +18 -1
- package/components/CustomerServiceChat/message-list/index-web.vue +3 -2
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/marked.ts +3 -15
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-desk.vue +9 -1
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-multi-form/component-pc/input-pc.vue +1 -1
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-multi-form/form-mobile.vue +2 -1
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-queue-confirmation.vue +96 -0
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/message-stream.vue +314 -20
- package/components/CustomerServiceChat/message-list/message-elements/message-desk/message-desk-elements/styles/common.scss +87 -84
- package/components/CustomerServiceChat/message-list/message-elements/message-large-stream.vue +6 -1
- package/components/CustomerServiceChat/message-list/message-elements/message-text.vue +2 -4
- package/components/CustomerServiceChat/style/common.scss +65 -62
- package/components/common/common.scss +49 -47
- package/constant.ts +9 -1
- package/locales/en/aidesk.ts +2 -0
- package/locales/es/aidesk.ts +2 -0
- package/locales/fil/aidesk.ts +2 -0
- package/locales/id/aidesk.ts +2 -0
- package/locales/ja/aidesk.ts +2 -0
- package/locales/ko/aidesk.ts +2 -0
- package/locales/ms/aidesk.ts +2 -0
- package/locales/ru/aidesk.ts +2 -0
- package/locales/th/aidesk.ts +2 -0
- package/locales/vi/aidesk.ts +2 -0
- package/locales/zh_cn/aidesk.ts +2 -0
- package/locales/zh_tw/aidesk.ts +2 -0
- package/package.json +1 -1
- package/utils/heartbeat-handler.ts +65 -0
- package/utils/index.ts +3 -3
- package/utils/utils.ts +23 -0
|
@@ -1,63 +1,66 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
1
|
+
.ai-desk-customer {
|
|
2
|
+
:where(ul, ol, li) {
|
|
3
|
+
margin: 0;
|
|
4
|
+
padding: 0;
|
|
5
|
+
font-style: normal;
|
|
6
|
+
list-style: none;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
:where(dt, dd, dl, h1, h2, h3, h4, p) {
|
|
10
|
+
margin: 0;
|
|
11
|
+
padding: 0;
|
|
12
|
+
font-style: normal;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
:where(img) {
|
|
16
|
+
border:0;
|
|
17
|
+
vertical-align:middle;
|
|
18
|
+
pointer-events:none;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
:where(body) {
|
|
22
|
+
color:#000;
|
|
23
|
+
background:#FFF;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.clear {
|
|
27
|
+
clear:both;
|
|
28
|
+
height:1px;
|
|
29
|
+
width:100%;
|
|
30
|
+
overflow:hidden;
|
|
31
|
+
margin-top:-1px;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
:where(a) {
|
|
35
|
+
color:#000;
|
|
36
|
+
text-decoration:none;
|
|
37
|
+
cursor: pointer;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
:where(a:hover) {
|
|
41
|
+
text-decoration:none;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
:where(input, textarea) {
|
|
45
|
+
user-select: auto;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
:where(input:focus, input:active, textarea:focus, textarea:active) {
|
|
49
|
+
outline: none;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.chat-aside {
|
|
53
|
+
position: absolute;
|
|
54
|
+
top: 50px;
|
|
55
|
+
right: 0;
|
|
56
|
+
box-sizing: border-box;
|
|
57
|
+
width: 360px !important;
|
|
58
|
+
border-radius: 8px 0 0 8px;
|
|
59
|
+
z-index: 9999;
|
|
60
|
+
max-height: calc(100% - 50px);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
:where(pre, button, input, select, textarea) {
|
|
64
|
+
font-family: inherit;
|
|
65
|
+
}
|
|
63
66
|
}
|
|
@@ -1,50 +1,52 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
clear
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
1
|
+
.ai-desk-customer {
|
|
2
|
+
:where(body, div, ul, ol, dt, dd, li, dl, h1, h2, h3, h4, p) {
|
|
3
|
+
margin:0;
|
|
4
|
+
padding:0;
|
|
5
|
+
font-style:normal;
|
|
6
|
+
|
|
7
|
+
/* font:12px/22px"\5B8B\4F53",Arial,Helvetica,sans-serif; */
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
:where(ol, ul, li) {
|
|
11
|
+
list-style:none;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
:where(img) {
|
|
15
|
+
border:0;
|
|
16
|
+
vertical-align:middle;
|
|
17
|
+
pointer-events:none;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
:where(body) {
|
|
21
|
+
color:#000;
|
|
22
|
+
background:#FFF;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.clear {
|
|
26
|
+
clear:both;
|
|
27
|
+
height:1px;
|
|
28
|
+
width:100%;
|
|
29
|
+
overflow:hidden;
|
|
30
|
+
margin-top:-1px;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
:where(a) {
|
|
34
|
+
color:#000;
|
|
35
|
+
text-decoration:none;
|
|
36
|
+
cursor: pointer;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
:where(a:hover) {
|
|
40
|
+
text-decoration:none;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
:where(input, textarea) {
|
|
44
|
+
user-select: auto;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
:where(input:focus, input:active, textarea:focus, textarea:active) {
|
|
48
|
+
outline: none;
|
|
49
|
+
}
|
|
48
50
|
}
|
|
49
51
|
|
|
50
52
|
.chat-aside {
|
package/constant.ts
CHANGED
|
@@ -37,8 +37,10 @@ export const CUSTOM_MESSAGE_SRC = {
|
|
|
37
37
|
CONCURRENCY_LIMIT: '36',
|
|
38
38
|
TIMEOUT_WARNING: '37',
|
|
39
39
|
TRANSFER_TO_HUMAN: '39',
|
|
40
|
-
|
|
40
|
+
GET_SETTINGS: '42',
|
|
41
41
|
SEND_FEEDBACK: '43',
|
|
42
|
+
SEND_HEARTBEAT: '44',
|
|
43
|
+
QUEUE_CONFIRMATION: '45',
|
|
42
44
|
};
|
|
43
45
|
|
|
44
46
|
// im message extra type
|
|
@@ -149,6 +151,12 @@ export const WHITE_LIST = [
|
|
|
149
151
|
CUSTOM_MESSAGE_SRC.TIMEOUT_WARNING,
|
|
150
152
|
CUSTOM_MESSAGE_SRC.TRANSFER_TO_TASK_FLOW,
|
|
151
153
|
CUSTOM_MESSAGE_SRC.TRANSFER_TO_HUMAN,
|
|
154
|
+
CUSTOM_MESSAGE_SRC.QUEUE_CONFIRMATION,
|
|
155
|
+
];
|
|
156
|
+
|
|
157
|
+
export const SHOW_IF_FLOW_IN = [
|
|
158
|
+
CUSTOM_MESSAGE_SRC.MULTI_FORM,
|
|
159
|
+
CUSTOM_MESSAGE_SRC.QUEUE_CONFIRMATION,
|
|
152
160
|
];
|
|
153
161
|
|
|
154
162
|
export const TOOLBAR_BUTTON_TYPE = {
|
package/locales/en/aidesk.ts
CHANGED
|
@@ -40,5 +40,7 @@ const AIDesk = {
|
|
|
40
40
|
"当前前方排队人数": "Queue Position",
|
|
41
41
|
"结束排队": "Leave Queue",
|
|
42
42
|
"评价提交超过3分钟,无法更改。感谢您的反馈!": "Once a review has been submitted for more than 3 minutes, it cannot be modified.",
|
|
43
|
+
"不能发送空白消息": "Unable to send blank message",
|
|
44
|
+
"确认转人工": "Confirm transfer to agent",
|
|
43
45
|
}
|
|
44
46
|
export default AIDesk;
|
package/locales/es/aidesk.ts
CHANGED
|
@@ -40,5 +40,7 @@ const AIDesk = {
|
|
|
40
40
|
"当前前方排队人数": "Posición en la cola",
|
|
41
41
|
"结束排队": "Salir de la cola",
|
|
42
42
|
"评价提交超过3分钟,无法更改。感谢您的反馈!": "Una valoración enviada hace más de 3 minutos no puede modificarse.",
|
|
43
|
+
"不能发送空白消息": "No se puede enviar un mensaje vacío",
|
|
44
|
+
"确认转人工": "Confirmar transferencia a agente",
|
|
43
45
|
}
|
|
44
46
|
export default AIDesk;
|
package/locales/fil/aidesk.ts
CHANGED
|
@@ -39,5 +39,7 @@ const AIDesk = {
|
|
|
39
39
|
"当前前方排队人数": "Bilang ng mga tao sa unahan sa pila",
|
|
40
40
|
"结束排队": "Umalis sa pila",
|
|
41
41
|
"评价提交超过3分钟,无法更改。感谢您的反馈!": "Kapag lumipas na ang 3 minuto mula sa pagsusumite ng review, hindi na ito mababago.",
|
|
42
|
+
"不能发送空白消息": "Hindi maaaring magpadala ng blangkong mensahe",
|
|
43
|
+
"确认转人工": "Kumpirmahin ang paglipat sa ahente",
|
|
42
44
|
}
|
|
43
45
|
export default AIDesk;
|
package/locales/id/aidesk.ts
CHANGED
|
@@ -39,5 +39,7 @@ const AIDesk = {
|
|
|
39
39
|
"当前前方排队人数": "Jumlah orang di depan antrian saat ini",
|
|
40
40
|
"结束排队": "Keluar dari antrian",
|
|
41
41
|
"评价提交超过3分钟,无法更改。感谢您的反馈!": "Ulasan yang dikirim lebih dari 3 menit tidak dapat diubah.",
|
|
42
|
+
"不能发送空白消息": "Tidak dapat mengirim pesan kosong",
|
|
43
|
+
"确认转人工": "Konfirmasi transfer ke agen",
|
|
42
44
|
}
|
|
43
45
|
export default AIDesk;
|
package/locales/ja/aidesk.ts
CHANGED
package/locales/ko/aidesk.ts
CHANGED
package/locales/ms/aidesk.ts
CHANGED
|
@@ -39,5 +39,7 @@ const AIDesk = {
|
|
|
39
39
|
"当前前方排队人数": "Bilangan orang di hadapan dalam barisan sekarang",
|
|
40
40
|
"结束排队": "Tinggalkan barisan",
|
|
41
41
|
"评价提交超过3分钟,无法更改。感谢您的反馈!": "Ulasan yang dihantar lebih dari 3 minit tidak boleh diubah.",
|
|
42
|
+
"不能发送空白消息": "Tidak dapat menghantar mesej kosong",
|
|
43
|
+
"确认转人工": "Sahkan pindah kepada ejen",
|
|
42
44
|
}
|
|
43
45
|
export default AIDesk;
|
package/locales/ru/aidesk.ts
CHANGED
|
@@ -39,5 +39,7 @@ const AIDesk = {
|
|
|
39
39
|
"当前前方排队人数": "Текущее количество человек впереди в очереди",
|
|
40
40
|
"结束排队": "Выйти из очереди",
|
|
41
41
|
"评价提交超过3分钟,无法更改。感谢您的反馈!": "Отзыв нельзя изменить после истечения 3 минут с момента отправки.",
|
|
42
|
+
"不能发送空白消息": "Невозможно отправить пустое сообщение",
|
|
43
|
+
"确认转人工": "Подтвердить перевод на оператора",
|
|
42
44
|
}
|
|
43
45
|
export default AIDesk;
|
package/locales/th/aidesk.ts
CHANGED
|
@@ -39,5 +39,7 @@ const AIDesk = {
|
|
|
39
39
|
"当前前方排队人数": "จำนวนผู้รอคิวด้านหน้าในขณะนี้",
|
|
40
40
|
"结束排队": "ออกจากคิว",
|
|
41
41
|
"评价提交超过3分钟,无法更改。感谢您的反馈!": "รีวิวที่ส่งไปแล้วเกิน 3 นาทีจะไม่สามารถแก้ไขได้",
|
|
42
|
+
"不能发送空白消息": "ไม่สามารถส่งข้อความว่างได้",
|
|
43
|
+
"确认转人工": "ยืนยันการโอนย้ายไปยังเจ้าหน้าที่",
|
|
42
44
|
}
|
|
43
45
|
export default AIDesk;
|
package/locales/vi/aidesk.ts
CHANGED
|
@@ -39,5 +39,7 @@ const AIDesk = {
|
|
|
39
39
|
"当前前方排队人数": "Số người đang chờ trước bạn trong hàng",
|
|
40
40
|
"结束排队": "Rời khỏi hàng",
|
|
41
41
|
"评价提交超过3分钟,无法更改。感谢您的反馈!": "Đánh giá sau khi gửi hơn 3 phút sẽ không thể chỉnh sửa.",
|
|
42
|
+
"不能发送空白消息": "Không thể gửi tin nhắn trống",
|
|
43
|
+
"确认转人工": "Xác nhận chuyển tiếp sang nhân viên",
|
|
42
44
|
}
|
|
43
45
|
export default AIDesk;
|
package/locales/zh_cn/aidesk.ts
CHANGED
package/locales/zh_tw/aidesk.ts
CHANGED
package/package.json
CHANGED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { CUSTOM_MESSAGE_SRC } from "../constant";
|
|
2
|
+
import TUIChatEngine, { TUIStore, StoreName, TUIChatService } from "../@aidesk/uikit-engine";
|
|
3
|
+
|
|
4
|
+
let heartbeatTimer: ReturnType<typeof setTimeout> | null = null;
|
|
5
|
+
let isHeartbeatRunning = false;
|
|
6
|
+
let currentConversationID = TUIStore.getData(StoreName.CONV, 'currentConversationID');
|
|
7
|
+
const HEARTBEAT_INTERVAL = 30000; // 30 秒
|
|
8
|
+
|
|
9
|
+
// 在人工排队时发送心跳
|
|
10
|
+
export async function sendHeartbeat(conversationID: string, eventName: string) {
|
|
11
|
+
await TUIChatService.sendCustomMessage({
|
|
12
|
+
to: conversationID.slice(3),
|
|
13
|
+
conversationType: TUIChatEngine.TYPES.CONV_C2C,
|
|
14
|
+
payload: {
|
|
15
|
+
data: JSON.stringify({
|
|
16
|
+
customerServicePlugin: 0,
|
|
17
|
+
src: CUSTOM_MESSAGE_SRC.SEND_HEARTBEAT,
|
|
18
|
+
userClientEvent: {
|
|
19
|
+
event: eventName,
|
|
20
|
+
},
|
|
21
|
+
}),
|
|
22
|
+
},
|
|
23
|
+
needReadReceipt: false,
|
|
24
|
+
},{ onlineUserOnly: true });
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function canSendHeartbeat() {
|
|
28
|
+
const isQueuing = TUIStore.getData(StoreName.CUSTOM, 'isQueuing');
|
|
29
|
+
const queueLeavePageTimeoutEnable = TUIStore.getData(StoreName.CUSTOM, 'queueLeavePageTimeoutEnable');
|
|
30
|
+
currentConversationID = TUIStore.getData(StoreName.CONV, 'currentConversationID');
|
|
31
|
+
const queueNumber = isQueuing && isQueuing.conversationID === currentConversationID ? isQueuing.value : -1;
|
|
32
|
+
if (queueNumber < 0 || !queueLeavePageTimeoutEnable || !currentConversationID) {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function startHeartbeat() {
|
|
39
|
+
if (!canSendHeartbeat() || isHeartbeatRunning) {
|
|
40
|
+
stopHeartbeat();
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
isHeartbeatRunning = true;
|
|
45
|
+
(async function loop() {
|
|
46
|
+
if (!canSendHeartbeat() || !isHeartbeatRunning) {
|
|
47
|
+
stopHeartbeat();
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
await sendHeartbeat(currentConversationID, "sessionPageHeartbeat");
|
|
51
|
+
|
|
52
|
+
heartbeatTimer = setTimeout(() => {
|
|
53
|
+
heartbeatTimer = null;
|
|
54
|
+
loop();
|
|
55
|
+
}, HEARTBEAT_INTERVAL);
|
|
56
|
+
})();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function stopHeartbeat() {
|
|
60
|
+
if (heartbeatTimer !== null) {
|
|
61
|
+
clearTimeout(heartbeatTimer!);
|
|
62
|
+
heartbeatTimer = null;
|
|
63
|
+
}
|
|
64
|
+
isHeartbeatRunning = false;
|
|
65
|
+
}
|
package/utils/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { customerServicePayloadType } from '../interface';
|
|
2
|
-
import { CUSTOM_MESSAGE_SRC, TYPES, WHITE_LIST } from '../constant';
|
|
2
|
+
import { CUSTOM_MESSAGE_SRC, SHOW_IF_FLOW_IN, TYPES, WHITE_LIST } from '../constant';
|
|
3
3
|
import { IMessageModel } from '../@aidesk/uikit-engine';
|
|
4
4
|
|
|
5
5
|
// Determine if it is a JSON string
|
|
@@ -71,9 +71,9 @@ export const isMessageInvisible = (message: IMessageModel): boolean => {
|
|
|
71
71
|
const isCustomerMessage = message?.type === TYPES.MSG_CUSTOM;
|
|
72
72
|
const isGroupTipMessage = message?.type === TYPES.MSG_GROUP_TIP;
|
|
73
73
|
const isCustomerInvisible = customerServicePayload?.src && !WHITE_LIST.includes(customerServicePayload?.src);
|
|
74
|
-
const
|
|
74
|
+
const isShowIfFlowInMessage: boolean = customerServicePayload?.src !== null && SHOW_IF_FLOW_IN.includes(customerServicePayload?.src as string) && message.flow === 'out';
|
|
75
75
|
const isRobot = customerServicePayload?.src === CUSTOM_MESSAGE_SRC.ROBOT && robotCommandArray.indexOf(customerServicePayload?.content?.command) !== -1;
|
|
76
|
-
return (isCustomerMessage && (isCustomerInvisible || isRobot ||
|
|
76
|
+
return (isCustomerMessage && (isCustomerInvisible || isRobot || isShowIfFlowInMessage)) || isGroupTipMessage;
|
|
77
77
|
};
|
|
78
78
|
|
|
79
79
|
// 如果用户选择 block cookies,此时访问 localStorage 浏览器会抛错
|
package/utils/utils.ts
CHANGED
|
@@ -420,4 +420,27 @@ export function throttle(
|
|
|
420
420
|
func.apply(this, args);
|
|
421
421
|
}
|
|
422
422
|
};
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
export function getStyledATagFromText(text, className, linkColor, title) {
|
|
426
|
+
// 开启 url 识别时先移除 html 标签,避免 xss 漏洞
|
|
427
|
+
// 预处理文本:移除换行符和制表符
|
|
428
|
+
const preprocessedText = text.replace(/[\n\t]/g, '').trim();
|
|
429
|
+
|
|
430
|
+
// 先移除HTML标签避免XSS漏洞
|
|
431
|
+
const sanitizedText = preprocessedText.replace(/<[^>]+>/g, '');
|
|
432
|
+
|
|
433
|
+
// 匹配URL:从http://或https://开始,匹配尽可能长的有效URL字符序列
|
|
434
|
+
// 包括:字母数字、-._~:/?#[]@!$&'()*+,;=% 等URL允许的字符
|
|
435
|
+
const ret = sanitizedText.replace(/https?:\/\/[\w\-._~:/?#\[\]@!$&'()*+,;=%]+/g, (matchedUrl) => {
|
|
436
|
+
// 检查URL是否包含中文字符,如果包含则跳过处理
|
|
437
|
+
const chineseRegex = /[\u4e00-\u9fff]/;
|
|
438
|
+
if (chineseRegex.test(matchedUrl)) {
|
|
439
|
+
return matchedUrl; // 不处理包含中文的URL
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
const encodedUrl = encodeURI(matchedUrl);
|
|
443
|
+
return `<a target="_blank" rel="noreferrer noopener" class="${className}" style="color:${linkColor}; text-decoration:underline" href="${encodedUrl}" title="${title || ''}">${title ? title : matchedUrl}</a>`;
|
|
444
|
+
});
|
|
445
|
+
return ret;
|
|
423
446
|
}
|