|
@@ -28,7 +28,11 @@
|
|
|
</div>
|
|
|
</transition>
|
|
|
<div class="group-chart-footer">
|
|
|
- <ChartAction :options="getActionList" :isLink="isTurnPeople" :isRobot="isShowNps" @action="onChartAction" @upload-image="onUploadImage" @upload-attach="onUploadAttach" @turn="onTurnPeople" @close="onCloseScreen"></ChartAction>
|
|
|
+ <div v-if="isTurnPeople && from === 'aside'" class="action-customer-aside-container">
|
|
|
+ <div class="action-customer-item turn-btn" @click.stop="onKeywordsBtn('转人工')">转人工</div>
|
|
|
+ <div class="action-customer-item" v-for="(item, index) in customerBtnList" :key="index" @click.stop="onKeywordsBtn(item)">{{item}}</div>
|
|
|
+ </div>
|
|
|
+ <ChartAction :options="getActionList" :btn="customerBtnList" :isLink="isTurnPeople" :isRobot="isShowNps" @action="onChartAction" @upload-image="onUploadImage" @upload-attach="onUploadAttach" @turn="onKeywordsBtn" @close="onCloseScreen"></ChartAction>
|
|
|
<ChartInput ref="chartInput" v-model="msgVal" @on-input="onChartInput" @confirm="onSendMsg" @m-blur="messageBlur">
|
|
|
<div class="hint-box" v-show="hintShow">
|
|
|
<img src="@/assets/image/close_.png" alt="" class="close" @click="hintShow = false">
|
|
@@ -83,8 +87,8 @@ import { Container, Main, Avatar, Badge, Button, Input, Divider, Drawer } from '
|
|
|
import AsideView from '@/components/aside/'
|
|
|
import MessageList from '@/components/MessageList'
|
|
|
import { mapState, mapMutations, mapActions, mapGetters } from 'vuex'
|
|
|
-import { getChartGroupInfo, robotInfo, createChatSession, getUserList, getMessageCount, closeChatSession, getWebSocketNode, robotFindAnswer, customerEval, joinChartGroup, createChartGroup, guessWantAsk } from '@/api/modules/'
|
|
|
-import { getLink, debounce, removeHtmlStyle, setTrack } from '@/utils/'
|
|
|
+import { getChartGroupInfo, robotInfo, createChatSession, getUserList, getMessageCount, closeChatSession, getWebSocketNode, robotFindAnswer, customerEval, joinChartGroup, createChartGroup, guessWantAsk, getTurnCustomerKeywords } from '@/api/modules/'
|
|
|
+import { getLink, debounce, removeHtmlStyle, setTrack, dateFormatter } from '@/utils/'
|
|
|
import CommunicateBook from '@/components/communicateBook/index'
|
|
|
import GroupInfo from '@/components/group-info/'
|
|
|
|
|
@@ -95,7 +99,7 @@ import ChartInput from '@/components/MessageInput.vue'
|
|
|
import Rate from '@/components/rate/'
|
|
|
|
|
|
export default {
|
|
|
- name: 'CustomerServiceView',
|
|
|
+ name: 'CustomerView',
|
|
|
components: {
|
|
|
AsideView,
|
|
|
MessageList,
|
|
@@ -175,7 +179,9 @@ export default {
|
|
|
historyQuestion: [],
|
|
|
from: '',
|
|
|
resource: '',
|
|
|
- showAside: false
|
|
|
+ showAside: false,
|
|
|
+ customerBtnList: [], // // 可转人工客服的按钮列表
|
|
|
+ customerKeywords: [] // 可转人工客服的关键词列表
|
|
|
}
|
|
|
},
|
|
|
computed: {
|
|
@@ -306,6 +312,7 @@ export default {
|
|
|
this.getUserNoLoginFn()
|
|
|
}
|
|
|
this.getMessageCountFn()
|
|
|
+ this.getTurnCustomerKey()
|
|
|
},
|
|
|
mounted () {
|
|
|
this.$bus.$on('bus_customerText', this.onCustomerText)
|
|
@@ -529,10 +536,7 @@ export default {
|
|
|
// 更新聊天列表最后消息及未读数量
|
|
|
this.getUserListLastMsg(rUserId, 1, content, time)
|
|
|
}
|
|
|
- // 客服离线状态离线状态
|
|
|
- if (noCustom) {
|
|
|
- console.log('客服离线, 发送机器人欢迎语')
|
|
|
- const apiParams = {
|
|
|
+ const apiParams = {
|
|
|
ownType: 2,
|
|
|
title: '机器人首次回复',
|
|
|
content: this.excuse.welcome,
|
|
@@ -552,6 +556,9 @@ export default {
|
|
|
headImg: this.autoUserInfo.img,
|
|
|
nickName: this.autoUserInfo.name
|
|
|
}
|
|
|
+ // 客服离线状态离线状态
|
|
|
+ if (noCustom) {
|
|
|
+ console.log('客服离线, 发送机器人欢迎语')
|
|
|
// 只有离线状态且content返回值为空的情况下(自动转人工),才需要展示机器人欢迎语,其它情况不需要展示
|
|
|
if (!content) {
|
|
|
this.onSendCommon({ apiParams, socketParams }, true)
|
|
@@ -829,10 +836,10 @@ export default {
|
|
|
content: `${this.autoUserInfo.name}和剑鱼标讯建立了会话`
|
|
|
})
|
|
|
// 创建完会话直接转人工
|
|
|
- setTimeout(() => {
|
|
|
- // 自动转人工
|
|
|
- this.onTurnPeople('', 'auto')
|
|
|
- }, 1000)
|
|
|
+ // setTimeout(() => {
|
|
|
+ // // 自动转人工
|
|
|
+ // this.onTurnPeople('', 'auto')
|
|
|
+ // }, 1000)
|
|
|
})
|
|
|
}
|
|
|
}
|
|
@@ -856,42 +863,44 @@ export default {
|
|
|
this.other.headImg = this.other.userType === 1 ? data?.headimage : ''
|
|
|
callback && callback(data)
|
|
|
// 首次回复 需保存
|
|
|
- // if (isSave) {
|
|
|
- // const apiParams = {
|
|
|
- // ownType: 2,
|
|
|
- // title: '机器人首次回复',
|
|
|
- // content: data.reply?.Content,
|
|
|
- // item: 8,
|
|
|
- // itemType: 4, // 机器人信息
|
|
|
- // sendId: this.other.sessionId, // 发送人标识(客服发送信息时该值为会话标识,用户聊天时该值不传)
|
|
|
- // type: 1,
|
|
|
- // link: '',
|
|
|
- // fool: 2
|
|
|
- // }
|
|
|
- // // 新增:与机器人聊天也发websocket告知
|
|
|
- // const socketParams = {
|
|
|
- // type: 27,
|
|
|
- // rUserId: this.other.userId,
|
|
|
- // rUserType: this.other.userType,
|
|
|
- // contentType: 1,
|
|
|
- // headImg: this.autoUserInfo.img,
|
|
|
- // nickName: this.autoUserInfo.name
|
|
|
- // }
|
|
|
- // // 延迟1秒
|
|
|
- // setTimeout(() => {
|
|
|
- // this.onSendCommon({ apiParams, socketParams }, true)
|
|
|
- // }, 1000)
|
|
|
- // if (this.isShowNps === 0) {
|
|
|
- // this.robotOvertimeReply()
|
|
|
- // }
|
|
|
- // }
|
|
|
+ if (isSave) {
|
|
|
+ const apiParams = {
|
|
|
+ ownType: 2,
|
|
|
+ title: '机器人首次回复',
|
|
|
+ content: data.reply?.Content,
|
|
|
+ item: 8,
|
|
|
+ itemType: 4, // 机器人信息
|
|
|
+ sendId: this.other.sessionId, // 发送人标识(客服发送信息时该值为会话标识,用户聊天时该值不传)
|
|
|
+ type: 1,
|
|
|
+ link: '',
|
|
|
+ fool: 2
|
|
|
+ }
|
|
|
+ // 新增:与机器人聊天也发websocket告知
|
|
|
+ const socketParams = {
|
|
|
+ type: 27,
|
|
|
+ rUserId: this.other.userId,
|
|
|
+ rUserType: this.other.userType,
|
|
|
+ contentType: 1,
|
|
|
+ headImg: this.autoUserInfo.img,
|
|
|
+ nickName: this.autoUserInfo.name
|
|
|
+ }
|
|
|
+ // 延迟1秒
|
|
|
+ setTimeout(() => {
|
|
|
+ this.onSendCommon({ apiParams, socketParams }, true)
|
|
|
+ }, 1000)
|
|
|
+ if (this.isShowNps === 0) {
|
|
|
+ this.robotOvertimeReply()
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
},
|
|
|
// 机器人根据问题自动回复
|
|
|
async robotAutoReply (question, type = 1) {
|
|
|
// 如果是跟用户或者人工聊则不用自动回复
|
|
|
- if (this.other.userType >= 2 || !this.other.isRobot) return
|
|
|
- const kfKeywords = ['客服', '人工', '人工客服']
|
|
|
+ if (this.other.userType >= 2 || !this.other.isRobot || !this.userSessionBadge) return
|
|
|
+ // const kfKeywords = ['客服', '人工', '人工客服']
|
|
|
+ const kfKeywords = this.customerKeywords
|
|
|
+ console.log(kfKeywords, 'kfKeywords')
|
|
|
if (kfKeywords.includes(question.replace(/\s+/g, ''))) {
|
|
|
// 转人工客服
|
|
|
this.onTurnPeople(question.replace(/\s+/g, ''), '')
|
|
@@ -1485,7 +1494,6 @@ export default {
|
|
|
this.groupPerson = data
|
|
|
},
|
|
|
onFullScreen () {
|
|
|
- console.log('全屏')
|
|
|
try {
|
|
|
// 通知父页面关闭当前会话窗口,并新打开会话页面
|
|
|
window.parent.postMessage({
|
|
@@ -1494,12 +1502,49 @@ export default {
|
|
|
} catch (error) {}
|
|
|
},
|
|
|
onCloseScreen () {
|
|
|
- console.log('关闭会话窗口')
|
|
|
try {
|
|
|
window.parent.postMessage({
|
|
|
action: 'close'
|
|
|
}, location.origin)
|
|
|
} catch (error) {}
|
|
|
+ },
|
|
|
+ // 获取可转人工的关键词/按钮名称
|
|
|
+ async getTurnCustomerKey () {
|
|
|
+ const { data } = await getTurnCustomerKeywords()
|
|
|
+ if (data) {
|
|
|
+ this.customerBtnList = data.filter(v => {
|
|
|
+ return v.state && v.state === 1
|
|
|
+ }).map(n => n.name)
|
|
|
+ this.customerKeywords = data.map(v => v.name)
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 点击转人工/咨询/使用等按钮生成系统消息
|
|
|
+ onKeywordsBtn(content) {
|
|
|
+ const params = {
|
|
|
+ ownType: 1,
|
|
|
+ title: '点击按钮',
|
|
|
+ item: 8,
|
|
|
+ itemType: 6, // 系统信息
|
|
|
+ receiveId: this.other.sessionId,
|
|
|
+ type: 1,
|
|
|
+ link: '',
|
|
|
+ content: `${dateFormatter(new Date().getTime())} 点击了“${content}”`
|
|
|
+ }
|
|
|
+ this.saveMessageAction(params).then(res => {
|
|
|
+ const { error_code: code } = res
|
|
|
+ if (code === 0) {
|
|
|
+ params.create_time = res.data.create_time
|
|
|
+ params.fool = 2
|
|
|
+ params.messageId = res.data.messageId
|
|
|
+ this.$refs.chartContainer.pushMsg(params)
|
|
|
+ setTimeout(() => {
|
|
|
+ this.onTurnPeople(content)
|
|
|
+ }, 1000)
|
|
|
+ } else {
|
|
|
+ params.error = true
|
|
|
+ this.$refs.chartContainer.pushMsg(params)
|
|
|
+ }
|
|
|
+ })
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -1550,7 +1595,7 @@ export default {
|
|
|
max-height: 310px;
|
|
|
padding: 0 32px 24px;
|
|
|
background: #f6f6f6;
|
|
|
- border-top: 1px solid #DADADA;
|
|
|
+ //border-top: 1px solid #DADADA;
|
|
|
}
|
|
|
.rate-container{
|
|
|
padding: 0 32px;
|
|
@@ -1629,6 +1674,29 @@ export default {
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+.action-customer-aside-container{
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: flex-end;
|
|
|
+ padding: 8px 0;
|
|
|
+ .action-customer-item{
|
|
|
+ padding: 3px 9px;
|
|
|
+ margin-right: 8px;
|
|
|
+ font-size: 12px;
|
|
|
+ line-height: 18px;
|
|
|
+ border-radius: 4px;
|
|
|
+ border: 1px solid #E0E0E0;
|
|
|
+ background: #fff;
|
|
|
+ color: #686868;
|
|
|
+ cursor: pointer;
|
|
|
+ &.turn-btn{
|
|
|
+ padding-left: 44px;
|
|
|
+ background: url('~@/assets/image/hand-gray.png') no-repeat 8px center #fff;
|
|
|
+ background-size: 18px 18px;
|
|
|
+ cursor: pointer;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
</style>
|
|
|
<style lang="scss">
|
|
|
.aside-layout {
|