Merge pull request 'master' (#106) from master into test

Reviewed-on: http://git.feashow.cn/feashow/SmartOpsWeb/pulls/106
This commit is contained in:
2024-09-25 09:58:05 +00:00
5 changed files with 288 additions and 88 deletions

View File

@@ -1,78 +1,87 @@
<script setup> <script setup>
import LiveCallItem from '@/components/liveCall/LiveCallItem.vue' import LiveCallItem from '@/components/liveCall/LiveCallItem.vue'
import { watch } from 'vue'; import {getHistoryCallContent} from '@/api/workbench';
import { getHistoryCallContent } from '../../api/workbench';
const dialogVisible = ref(false); const dialogVisible = ref(false);
const recordLeftRef = ref(null); const recordLeftRef = ref(null);
const props = defineProps({ const props = defineProps({
rowData: String rowData: String
}) })
const open = (row) => { const open = (row) => {
dialogVisible.value = true; dialogVisible.value = true;
}; };
const leftHeadData = ref({ const leftHeadData = ref({
username: '张三', username: '张三',
phone: '13546812315', phone: '13546812315',
orderName: '张三工单', orderName: '张三工单',
}) })
const recordLeftObj = ref({ const recordLeftObj = ref({
content: [] content: []
}); });
const convertArrayToMap=(array)=> {
const map = new Map();
array.forEach(item => {
// 如果时间戳对应的键已经存在,则添加到现有数组中
if (map.has(item.conversationTimestamp)) {
map.get(item.conversationTimestamp).push(item);
} else {
// 否则,创建一个新的数组并添加元素
map.set(item.conversationTimestamp, [item]);
}
});
return map;
}
watch(() => props.rowData, async (newVal) => { watch(() => props.rowData, async (newVal) => {
recordLeftObj.value.content = [] recordLeftObj.value.content = []
const info = ref({}) // let map1 = new Map()
await getHistoryCallContent(newVal).then(data => { await getHistoryCallContent(newVal).then(res => {
// console.log(data); res.data?.forEach(item => {
info.value=data.data[0] item.textVoList = convertArrayToMap(item.textVoList);
data.data[0].textVoList.forEach(item => {
recordLeftObj.value.content.push(item)
})
}) })
console.log(info.value); recordLeftObj.value = res.data
console.info("🚀 ~method:res.data -----", res.data)
leftHeadData.value.username = info.value.callIdNumber; if (res.data && res.data.length > 0) {
leftHeadData.value.phone = info.value.callPhone; leftHeadData.value.username = res.data[0].callIdNumber || '--';
leftHeadData.value.orderName = info.value.orderName||'--'; leftHeadData.value.phone = res.data[0].callPhone || '--';
leftHeadData.value.orderName = res.data[0].orderName || '--';
}
})
}) })
const scrollToBottom = (scrollbarRef) => { const scrollToBottom = (scrollbarRef) => {
if (scrollbarRef) { if (scrollbarRef) {
const container = scrollbarRef.$el.querySelector('.el-scrollbar__wrap'); const container = scrollbarRef.$el.querySelector('.el-scrollbar__wrap');
container.style.scrollBehavior = 'smooth'; // 添加平滑滚动效果 container.style.scrollBehavior = 'smooth'; // 添加平滑滚动效果
container.scrollTop = container.scrollHeight; container.scrollTop = container.scrollHeight;
} }
}; };
scrollToBottom(recordLeftRef.value) scrollToBottom(recordLeftRef.value)
defineExpose({ defineExpose({
open, open,
}); });
//5555
</script> </script>
<template> <template>
<el-dialog v-model="dialogVisible" title="历史通话记录" width="600" class="box"> <el-dialog v-model="dialogVisible" title="历史通话记录" width="600" class="box">
<LiveCallItem ref="recordLeftRef" :recordObj="recordLeftObj" :headData="leftHeadData" style="width: 100%;" /> <LiveCallItem ref="recordLeftRef" :recordArray="recordLeftObj" :headData="leftHeadData" style="width: 100%;"/>
<template #footer> <template #footer>
<div class="dialog-footer"> <div class="dialog-footer">
<el-button type="primary" @click="dialogVisible = false"> <el-button type="primary" @click="dialogVisible = false">
关闭 关闭
</el-button> </el-button>
</div> </div>
</template> </template>
</el-dialog> </el-dialog>
</template> </template>
<style> <style>
.box { .box {
height: 68vh; height: 68vh;
} }
</style> </style>

View File

@@ -3,30 +3,35 @@
<div class="header"> <div class="header">
<div> <div>
<span style="margin-right: 20px">{{ headData.username }}</span> <span style="margin-right: 20px">{{ headData.username }}</span>
<span>{{ headData.phone }}</span> <span>电话号码{{ headData.phone }}</span>
</div> </div>
<div><span>工单名称{{ headData.orderName }}</span></div> <div><span>工单名称{{ headData.orderName }}</span></div>
</div> </div>
<el-scrollbar ref="scrollbarRef" class="scrollbar"> <el-scrollbar ref="scrollbarRef" class="scrollbar">
<div class="chat-content" ref="innerRef"> <div class="chat-content" ref="innerRef">
<div v-for="(item,index) in recordObj.content" :key="index"> <div v-for="(item,index) in recordArray" :key="index">
<div class="time-grap"><span>{{ item.conversationTimestamp || '6月5日 12:05' }}</span></div> <div v-for="[key,value] of item.textVoList">
<!-- 我的 --> <div class="time-grap"><span>{{ key || '6月5日 12:05' }}</span></div>
<div v-if="item.speaker==0" class="word-my"> <div v-for="(recordItem) in value">
<div class="info"> <!-- 我的 -->
<p class="name">{{ item.speaker==0?headData.username:'AI助手' }} </p> <div v-if="recordItem.speaker==0" class="word-my">
<div class="info-content">{{ item.message }}</div> <div class="info">
</div> <p class="name">{{ recordItem.speaker == 0 ? recordItem.callIdNumber : 'AI助手' }} </p>
<el-avatar text="我"/> <div class="info-content">{{ recordItem.message }}</div>
</div> </div>
<!-- 对方 --> <el-avatar text="我"/>
<div v-else class="word"> </div>
<el-avatar text="对方"/> <!-- 对方 -->
<div class="info"> <div v-else class="word">
<p class="name">{{ item.speaker==0?headData.username:'AI助手' }} </p> <el-avatar text="对方"/>
<div class="info-content">{{ item.message }}</div> <div class="info">
<p class="name">{{ recordItem.speaker == 0 ? recordItem.callIdNumber : 'AI助手' }} </p>
<div class="info-content">{{ recordItem.message }}</div>
</div>
</div>
</div> </div>
</div> </div>
<el-divider border-style="dotted" v-if="item">一轮通话结束~~</el-divider>
</div> </div>
</div> </div>
</el-scrollbar> </el-scrollbar>
@@ -35,19 +40,20 @@
<script setup> <script setup>
import {defineProps} from "vue"; import {defineProps} from "vue";
const scrollbarRef=ref()
const scrollbarRef = ref()
const props = defineProps({ const props = defineProps({
recordObj: { recordArray: {
type: Object, type: Array,
default: {} default: []
}, },
headData: { headData: {
type: Object, type: Object,
default: {} default: {}
}, },
}) })
const getScrollbarRef=()=>{ const getScrollbarRef = () => {
return scrollbarRef.value return scrollbarRef.value
} }
defineExpose({ defineExpose({
getScrollbarRef getScrollbarRef

View File

@@ -0,0 +1,201 @@
<template>
<div class="live-call">
<div class="header">
<div>
<span style="margin-right: 20px">{{ headData.username }}</span>
<span>{{ headData.phone }}</span>
</div>
<div><span>工单名称{{ headData.orderName }}</span></div>
</div>
<el-scrollbar ref="scrollbarRef" class="scrollbar">
<div class="chat-content" ref="innerRef">
<div v-for="(item,index) in recordObj.content" :key="index">
<div class="time-grap"><span>{{ item.conversationTimestamp || '6月5日 12:05' }}</span></div>
<!-- 我的 -->
<div v-if="item.speaker==0" class="word-my">
<div class="info">
<p class="name">{{ item.speaker==0?headData.username:'AI助手' }} </p>
<div class="info-content">{{ item.message }}</div>
</div>
<el-avatar text="我"/>
</div>
<!-- 对方 -->
<div v-else class="word">
<el-avatar text="对方"/>
<div class="info">
<p class="name">{{ item.speaker==0?headData.username:'AI助手' }} </p>
<div class="info-content">{{ item.message }}</div>
</div>
</div>
</div>
</div>
</el-scrollbar>
</div>
</template>
<script setup>
import {defineProps} from "vue";
const scrollbarRef=ref()
const props = defineProps({
recordObj: {
type: Object,
default: {}
},
headData: {
type: Object,
default: {}
},
})
const getScrollbarRef=()=>{
return scrollbarRef.value
}
defineExpose({
getScrollbarRef
})
</script>
<style lang="scss" scoped>
.live-call {
width: 48%;
height: 47vh;
margin-bottom: 20px;
overflow: hidden;
border: 1px solid #d5d4d4;
border-radius: 10px;
.header {
display: flex;
justify-content: space-around;
align-items: center;
height: 40px;
border-bottom: 1px solid #d5d4d4;
}
.scrollbar {
padding: 10px 10px 0 10px;
height: 42vh;
.el-scrollbar__wrap {
height: 100%;
overflow: scroll;
overflow-x: auto;
}
// 聊天内容样式
.chat-content {
width: 100%;
.time-grap {
display: flex;
align-items: center;
justify-content: center;
> span {
font-size: 13px;
padding: 5px 10px;
border: 1px solid #d7d9da;
border-radius: 25px;
}
margin-bottom: 10px;
}
.word {
display: flex;
margin-bottom: 20px;
img {
width: 40px;
height: 40px;
border-radius: 50%;
}
.info {
margin-left: 10px;
.name {
font-size: 12px;
color: rgba(51, 51, 51, 0.8);
margin: 0;
height: 20px;
line-height: 20px;
margin-top: -5px;
}
.info-content {
padding: 10px;
font-size: 14px;
background: #f5f5f5;
position: relative;
margin-top: 8px;
border: 1px solid #f5f5f5;
}
//小三角形
.info-content::before {
position: absolute;
left: -8px;
top: 8px;
content: '';
border-right: 10px solid #f5f5f5;
border-top: 8px solid transparent;
border-bottom: 8px solid transparent;
}
}
}
.word-my {
display: flex;
justify-content: flex-end;
margin-bottom: 20px;
img {
width: 40px;
height: 40px;
border-radius: 50%;
}
.info {
width: 90%;
margin-left: 10px;
text-align: right;
.name {
font-size: 12px;
color: rgba(51, 51, 51, 0.8);
height: 20px;
line-height: 20px;
margin-top: -5px;
margin-right: 10px;
}
.info-content {
max-width: 70%;
padding: 10px;
font-size: 14px;
float: right;
margin-right: 10px;
position: relative;
margin-top: 8px;
background: #A3C3F6;
text-align: left;
}
//小三角形
.info-content::after {
position: absolute;
right: -8px;
top: 8px;
content: '';
border-left: 10px solid #A3C3F6;
border-top: 8px solid transparent;
border-bottom: 8px solid transparent;
}
}
}
}
}
}
</style>

View File

@@ -1,8 +1,8 @@
<template> <template>
<!--测试 张三 : 17260625724565 李四: 17260625724123--> <!--测试 张三 : 17260625724565 李四: 17260625724123-->
<div class="live-call-block"> <div class="live-call-block">
<live-call-item ref="recordLeftRef" :recordObj="recordLeftObj" :headData="leftHeadData"/> <live-call-item-home ref="recordLeftRef" :recordObj="recordLeftObj" :headData="leftHeadData"/>
<live-call-item ref="recordRightRef" :recordObj="recordRightObj" :headData="rightHeadData"/> <live-call-item-home ref="recordRightRef" :recordObj="recordRightObj" :headData="rightHeadData"/>
</div> </div>
</template> </template>
@@ -108,8 +108,8 @@ const handleLogout = () => {
const initWebSocket = () => { const initWebSocket = () => {
try { try {
// const wsUrl=setWsUrl(`/ws/text/${token}`) // const wsUrl=setWsUrl(`/ws/text/${token}`)
// const wsUrl = `ws://frp.feashow.cn:31800/ws/text/${token}` const wsUrl = `ws://frp.feashow.cn:31800/ws/text/${token}`
const wsUrl = `ws://112.19.165.99:20002/api/ws/text/${token}` // const wsUrl = `ws://112.19.165.99:20002/api/ws/text/${token}`
socket = new WebSocket(wsUrl) socket = new WebSocket(wsUrl)
// 2. ws.send()给服务器发送信息 // 2. ws.send()给服务器发送信息
//连接发生错误的回调方法 //连接发生错误的回调方法

View File

@@ -5,7 +5,7 @@
<LiveCall /> <LiveCall />
</div> </div>
<div class="call-history"><h3 >历史通话记录</h3> <div class="call-history"><h3 >历史通话记录</h3>
<fvTable ref="tableIns" :tableConfig="tableConfig" :data="mockData" @headBtnClick="headBtnClick"></fvTable> <fvTable ref="tableIns" :tableConfig="tableConfig"></fvTable>
<voice ref="voiceRef" title="语音详情"/> <voice ref="voiceRef" title="语音详情"/>
<infoLiveCall ref="infoLiveCallRef" :rowData="rowData"/> <infoLiveCall ref="infoLiveCallRef" :rowData="rowData"/>
</div> </div>
@@ -20,19 +20,6 @@ const rowData = ref()
const infoLiveCallRef=ref() const infoLiveCallRef=ref()
const voiceRef=ref() const voiceRef=ref()
const tableIns = ref() const tableIns = ref()
const mockData = ref([
{
workOrderNumber: 1211,
workOrderTime: '2022-02-09 00 : 12',
state: 0,
callState: '01'
},
{
workOrderNumber: 232,
state: 1,
callState: '02'
}
])
const auths = reactive({ const auths = reactive({
report: ['mosr:collect:reported'], report: ['mosr:collect:reported'],
}) })
@@ -77,7 +64,7 @@ const tableConfig = reactive({
}, },
{ {
prop: 'workOrderNumber', prop: 'workOrderNumber',
label: '号码', label: '电话号码',
align: 'center' align: 'center'
}, },
{ {
@@ -133,10 +120,7 @@ const tableConfig = reactive({
api: '/order/list', api: '/order/list',
params: { params: {
orderState:'2' orderState:'2'
}, }
btns: [
// {name: '新增', key: 'add',type:'primary',icon:'Plus'},
]
}) })
const handleVoice = (row) => { const handleVoice = (row) => {
voiceRef.value.open(true) voiceRef.value.open(true)