feat(chat): 添加转人工客服功能
This commit is contained in:
parent
909cf26549
commit
fc97ec241c
|
|
@ -236,18 +236,21 @@ const install = (Vue, vm) => {
|
|||
// 获取消息接收方用户信息
|
||||
let GetReceiverUserInfoApi = (params = {}) =>
|
||||
vm.$u.get("api/Dialogue/GetReceiverUserInfo", params);
|
||||
// 置顶一个会话
|
||||
let OverheadOneDialogueApi = (params = {}) =>
|
||||
vm.$u.post("api/Dialogue/OverheadOneDialogue", params);
|
||||
// 将会话消息标记为已读
|
||||
let ReadMessageApi = (params = {}) =>
|
||||
vm.$u.post("api/Dialogue/ReadMessage", params);
|
||||
// 置顶一个会话
|
||||
let OverheadOneDialogueApi = (params = {}) =>
|
||||
vm.$u.post("api/Dialogue/OverheadOneDialogue", params);
|
||||
// 将会话消息标记为已读
|
||||
let ReadMessageApi = (params = {}) =>
|
||||
vm.$u.post("api/Dialogue/ReadMessage", params);
|
||||
// 删除会话
|
||||
let DeleteDialogueApi = (params = {}) =>
|
||||
vm.$u.post("api/Dialogue/DeleteDialogue", params);
|
||||
// 转人工服务
|
||||
let TransferToALiveAgentApi = (params = {}) =>
|
||||
vm.$u.post("api/Dialogue/TransferToALiveAgent", params);
|
||||
|
||||
// 将各个定义的接口名称,统一放进对象挂载到vm.$u.api(因为vm就是this,也即this.$u.api)下
|
||||
vm.$u.api = {
|
||||
vm.$u.api = {
|
||||
UploadSingleImage,
|
||||
getTeacherInfo,
|
||||
getData,
|
||||
|
|
@ -306,16 +309,17 @@ const install = (Vue, vm) => {
|
|||
UpdateUserApi,
|
||||
GetTeacherListApi,
|
||||
GetDialogueListApi,
|
||||
GetDialogueList_UserApi,
|
||||
AddDialogueApi,
|
||||
SendMessage_PrivateApi,
|
||||
GetChatHistoryDataApi,
|
||||
GetReceiverUserInfoApi,
|
||||
OverheadOneDialogueApi,
|
||||
ReadMessageApi,
|
||||
DeleteDialogueApi,
|
||||
};
|
||||
};
|
||||
GetDialogueList_UserApi,
|
||||
AddDialogueApi,
|
||||
SendMessage_PrivateApi,
|
||||
GetChatHistoryDataApi,
|
||||
GetReceiverUserInfoApi,
|
||||
OverheadOneDialogueApi,
|
||||
ReadMessageApi,
|
||||
DeleteDialogueApi,
|
||||
TransferToALiveAgentApi,
|
||||
};
|
||||
};
|
||||
|
||||
export default {
|
||||
install,
|
||||
|
|
|
|||
|
|
@ -136,11 +136,77 @@
|
|||
{{ message.displayTime }}
|
||||
</view>
|
||||
|
||||
<!-- 转人工选择卡片(独立消息,不属于AI回复,不展示头像/反馈) -->
|
||||
<view
|
||||
class="message-transfer"
|
||||
v-if="message.customType === 'transferCard'"
|
||||
:id="'msg-' + message.id"
|
||||
>
|
||||
<view class="transfer-card">
|
||||
<view class="transfer-card-title">
|
||||
请选择您要咨询的类型,以便系统为您转接对应的客服
|
||||
</view>
|
||||
<view class="transfer-card-options">
|
||||
<view
|
||||
class="transfer-option"
|
||||
:class="{
|
||||
selected: message.selectedConsultationType === 1,
|
||||
disabled:
|
||||
isTransferSubmitting ||
|
||||
message.transferStatus === 'done',
|
||||
}"
|
||||
@click.stop="handleTransferTypeSelect(1)"
|
||||
>
|
||||
<u-icon
|
||||
name="account"
|
||||
size="44"
|
||||
:color="
|
||||
message.selectedConsultationType === 1
|
||||
? '#4A6CF7'
|
||||
: '#C0C4CC'
|
||||
"
|
||||
></u-icon>
|
||||
<text class="transfer-option-text">招生咨询</text>
|
||||
</view>
|
||||
<view
|
||||
class="transfer-option"
|
||||
:class="{
|
||||
selected: message.selectedConsultationType === 0,
|
||||
disabled:
|
||||
isTransferSubmitting ||
|
||||
message.transferStatus === 'done',
|
||||
}"
|
||||
@click.stop="handleTransferTypeSelect(0)"
|
||||
>
|
||||
<u-icon
|
||||
name="account"
|
||||
size="44"
|
||||
:color="
|
||||
message.selectedConsultationType === 0
|
||||
? '#4A6CF7'
|
||||
: '#C0C4CC'
|
||||
"
|
||||
></u-icon>
|
||||
<text class="transfer-option-text">迎新咨询</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view
|
||||
class="transfer-card-status"
|
||||
v-if="
|
||||
isTransferSubmitting ||
|
||||
!!message.transferTipText
|
||||
"
|
||||
>
|
||||
{{ getTransferCardTip(message) }}
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 用户消息 -->
|
||||
<!-- 0 用户消息 -->
|
||||
<view
|
||||
class="message-right"
|
||||
v-if="message.interactMode === 0"
|
||||
v-else-if="message.interactMode === 0"
|
||||
:id="'msg-' + message.id"
|
||||
>
|
||||
<view class="message-content">
|
||||
|
|
@ -157,7 +223,9 @@
|
|||
<!-- 1 Ai回复 3 热门回复 -->
|
||||
<view
|
||||
class="message-left"
|
||||
v-if="message.interactMode === 1 || message.interactMode === 3"
|
||||
v-else-if="
|
||||
message.interactMode === 1 || message.interactMode === 3
|
||||
"
|
||||
:id="'msg-' + message.id"
|
||||
>
|
||||
<image
|
||||
|
|
@ -306,6 +374,8 @@ export default {
|
|||
isChat: false,
|
||||
currentConversationId: "", // 当前对话的ID
|
||||
currentDMid: "", // 当前对话的DMId
|
||||
activeTransferCardId: "", // 当前选中的转人工卡片ID
|
||||
isTransferSubmitting: false, // 转人工请求中(用于失败时不改messageGroups)
|
||||
advicePhoneShow: false,
|
||||
perfectInfoShow: false,
|
||||
isLoading: false, // loadingMore
|
||||
|
|
@ -566,6 +636,11 @@ export default {
|
|||
return;
|
||||
}
|
||||
|
||||
if (item.title === "转人工") {
|
||||
this.handleTransferEntryClick();
|
||||
return;
|
||||
}
|
||||
|
||||
if (item.title === "电话咨询") {
|
||||
this.advicePhoneShow = true;
|
||||
return;
|
||||
|
|
@ -584,6 +659,126 @@ export default {
|
|||
}
|
||||
},
|
||||
|
||||
createLocalUserTextMessage(messageText) {
|
||||
return {
|
||||
id: Math.random().toString(36).substring(2, 15),
|
||||
message: messageText,
|
||||
sendDate: "",
|
||||
isSend: true,
|
||||
isRead: false,
|
||||
interactMode: 0,
|
||||
messageType: 0,
|
||||
timeLabel: 0,
|
||||
displayTime: "",
|
||||
};
|
||||
},
|
||||
|
||||
createTransferCardMessage() {
|
||||
return {
|
||||
id: "transfer_" + Math.random().toString(36).substring(2, 15),
|
||||
message: "",
|
||||
sendDate: "",
|
||||
isSend: true,
|
||||
isRead: false,
|
||||
interactMode: 1,
|
||||
messageType: 0,
|
||||
timeLabel: 0,
|
||||
displayTime: "",
|
||||
customType: "transferCard",
|
||||
transferStatus: "idle",
|
||||
selectedConsultationType: null,
|
||||
transferTipText: "",
|
||||
};
|
||||
},
|
||||
|
||||
handleTransferEntryClick() {
|
||||
if (!this.isChat) {
|
||||
this.resetChatState();
|
||||
}
|
||||
|
||||
this.isLoadingMore = false;
|
||||
this.isTransferSubmitting = false;
|
||||
|
||||
this.messageGroups = (this.messageGroups || []).filter(
|
||||
(m) => !(m && m.customType === "transferCard")
|
||||
);
|
||||
|
||||
this.messageGroups.push(this.createLocalUserTextMessage("转人工"));
|
||||
const card = this.createTransferCardMessage();
|
||||
this.activeTransferCardId = card.id;
|
||||
this.messageGroups.push(card);
|
||||
},
|
||||
|
||||
getTransferCardTip(message) {
|
||||
if (!message) return "";
|
||||
if (this.isTransferSubmitting) return "正在为您转接人工客服,请稍等...";
|
||||
if (message.transferTipText) return message.transferTipText;
|
||||
return "";
|
||||
},
|
||||
|
||||
handleTransferTypeSelect(consultationType) {
|
||||
const cardId = this.activeTransferCardId;
|
||||
const findCardIndex = () => {
|
||||
if (cardId) {
|
||||
const byId = this.messageGroups.findIndex(
|
||||
(m) => m && m.id === cardId
|
||||
);
|
||||
if (byId >= 0) return byId;
|
||||
}
|
||||
return this.messageGroups.findIndex(
|
||||
(m) => m && m.customType === "transferCard"
|
||||
);
|
||||
};
|
||||
const idx = findCardIndex();
|
||||
if (idx < 0) return;
|
||||
|
||||
const current = this.messageGroups[idx] || {};
|
||||
if (this.isTransferSubmitting || current.transferStatus === "done") return;
|
||||
|
||||
const next = {
|
||||
...current,
|
||||
transferStatus: "idle",
|
||||
selectedConsultationType: consultationType,
|
||||
transferTipText: "",
|
||||
};
|
||||
this.$set(this.messageGroups, idx, next);
|
||||
this.isTransferSubmitting = true;
|
||||
|
||||
const params = {
|
||||
consultationType,
|
||||
message: "转人工",
|
||||
ip: "",
|
||||
};
|
||||
|
||||
if (this.currentDMid) {
|
||||
params.dialogueManagementId = this.currentDMid;
|
||||
}
|
||||
|
||||
this.$u.api.TransferToALiveAgentApi(params).then((res) => {
|
||||
this.isTransferSubmitting = false;
|
||||
const nextIdx = findCardIndex();
|
||||
if (nextIdx < 0) return;
|
||||
const succeed = res && res.succeed !== false;
|
||||
const serverTip =
|
||||
(res && res.data && res.data.message) || (res && res.error) || "";
|
||||
if (!succeed) {
|
||||
const updated = {
|
||||
...this.messageGroups[nextIdx],
|
||||
transferStatus: "idle",
|
||||
transferTipText: serverTip,
|
||||
};
|
||||
this.$set(this.messageGroups, nextIdx, updated);
|
||||
return;
|
||||
}
|
||||
const updated = {
|
||||
...this.messageGroups[nextIdx],
|
||||
transferStatus: "done",
|
||||
transferTipText: serverTip,
|
||||
};
|
||||
this.$set(this.messageGroups, nextIdx, updated);
|
||||
});
|
||||
},
|
||||
|
||||
// 修改发送消息的方法
|
||||
sendMessageFn() {
|
||||
if (!this.messageValue) {
|
||||
|
|
@ -1449,6 +1644,79 @@ export default {
|
|||
text-align: left;
|
||||
}
|
||||
}
|
||||
|
||||
.message-transfer {
|
||||
width: 100%;
|
||||
margin-bottom: 40rpx;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.transfer-card {
|
||||
width: 100%;
|
||||
background-color: #ffffff;
|
||||
border-radius: 16rpx;
|
||||
padding: 40rpx 36rpx;
|
||||
box-shadow: 0 6rpx 20rpx rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.transfer-card-title {
|
||||
padding: 0 16rpx;
|
||||
font-family: PingFang SC;
|
||||
font-size: 32rpx;
|
||||
color: #333333;
|
||||
line-height: 1.6;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.transfer-card-options {
|
||||
margin-top: 32rpx;
|
||||
// padding: 24rpx;
|
||||
border-radius: 16rpx;
|
||||
// background-color: #f6f8ff;
|
||||
display: flex;
|
||||
gap: 36rpx;
|
||||
}
|
||||
|
||||
.transfer-option {
|
||||
flex: 1;
|
||||
height: 112rpx;
|
||||
border-radius: 16rpx;
|
||||
background-color: #f6f8fa;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
.transfer-option.selected {
|
||||
background-color: #eef0fe;
|
||||
border-color: #dbe3ff;
|
||||
}
|
||||
|
||||
.transfer-option.disabled {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.transfer-option-text {
|
||||
font-family: PingFang SC;
|
||||
font-size: 30rpx;
|
||||
color: #333333;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.transfer-option.selected .transfer-option-text {
|
||||
color: #4a6cf7;
|
||||
}
|
||||
|
||||
.transfer-card-status {
|
||||
margin-top: 24rpx;
|
||||
text-align: center;
|
||||
font-size: 28rpx;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
.chat-footer {
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ const store = new Vuex.Store({
|
|||
vuex_token: lifeData.vuex_token ? lifeData.vuex_token : "",
|
||||
// 如果vuex_version无需保存到本地永久存储,无需lifeData.vuex_version方式
|
||||
vuex_version: "1.0.0",
|
||||
vuex_aiMessageGroups: [],
|
||||
// 当前聊天窗口消息列表(数组
|
||||
vuex_msgList: [],
|
||||
// 最近联系人/会话列表
|
||||
|
|
|
|||
Loading…
Reference in New Issue