优化客服消息

This commit is contained in:
龙运模 2024-11-12 19:07:26 +08:00
parent 2e332c8986
commit 8e660fd657
5 changed files with 161 additions and 40 deletions

View File

@ -7,26 +7,30 @@
<div class="title">智能客服 <div class="title">智能客服
<el-icon class="close" size="18" @click="closeCustomer"><el-icon-Close/></el-icon> <el-icon class="close" size="18" @click="closeCustomer"><el-icon-Close/></el-icon>
</div> </div>
<div class="bodyMain"> <div class="bodyMain affix-container">
<el-scrollbar> <el-scrollbar ref="scrollbar" height="100%" @scroll="scroll">
<div class="tagList"> <div class="innerRefCom">
<div class="tagItem" v-for="(item,index) in tagList" :key="index" @click="typeActive(item)">{{item.label}}</div> <div class="tagList" ref="tagList">
</div> <div class="tagItem" v-for="(item,index) in tagList" :key="index" @click="typeActive(item)">{{item.label}}</div>
<div class="msgList"> </div>
<div class="msgItem" :class="user_id != item.to_user_id?'msgRightItem':''" v-for="(item,index) in msgList" :key="index"> <div class="msgList">
<div class="avatar" v-if="user_id === item.to_user_id"> <div class="msgItem" :class="user_id != item.to_user_id?'msgRightItem':''" v-for="(item,index) in msgList" :key="index">
<el-avatar :size="36" :src="item.from_user.avatar" fit="contain"> <div class="avatar" v-if="user_id === item.to_user_id">
<img src="https://cube.elemecdn.com/e/fd/0fc7d20532fdaf769a25683617711png.png"/> <el-avatar :size="36" :src="item.from_user.avatar" fit="cover">
</el-avatar> <img src="https://cube.elemecdn.com/e/fd/0fc7d20532fdaf769a25683617711png.png"/>
</div> </el-avatar>
<div class="msgText"> </div>
<div class="msgTitle">{{item.from_user && item.from_user.name?item.from_user.name:'匿名'}}</div> <div class="msgText">
<div class="textCom">{{item.to_message}}</div> <div class="msgTitle">{{item.from_user && item.from_user.name?item.from_user.name:'匿名'}}</div>
</div> <div class="textCom">
<div class="avatar" v-if="user_id != item.to_user_id"> <div v-html="item.to_message"></div>
<el-avatar :size="36" :src="item.avatar" fit="contain"> </div>
<img src="https://cube.elemecdn.com/e/fd/0fc7d20532fdaf769a25683617711png.png"/> </div>
</el-avatar> <div class="avatar" v-if="user_id != item.to_user_id">
<el-avatar :size="36" :src="item.from_user.avatar" fit="cover">
<img src="https://cube.elemecdn.com/e/fd/0fc7d20532fdaf769a25683617711png.png"/>
</el-avatar>
</div>
</div> </div>
</div> </div>
</div> </div>
@ -53,7 +57,6 @@ export default {
type:"", type:"",
to_user_id:"", to_user_id:"",
to_message:"", to_message:"",
}, },
tagList:[], tagList:[],
msgList:[], msgList:[],
@ -79,22 +82,32 @@ export default {
switch(res.data.type) { switch(res.data.type) {
case 36: case 36:
this.msgList = res.data.rows; this.msgList = res.data.rows;
this.scrollDown();
break; break;
case 37: case 37:
this.params.to_user_id = res.data.user.uid; this.params.to_user_id = res.data.user.uid;
this.msgList = [{
to_user_id:this.user_id,
from_user:{
name:res.data.user.user_info.name,
avatar:res.data.user.user_info.avatar
},
to_message:res.data.to_message
}]
break; break;
default: default:
break; break;
} }
} }
}, },
openCustomer(){ openCustomer(){
this.customerShow = !this.customerShow; this.customerShow = !this.customerShow;
if(this.customerShow){ if(this.customerShow){
this.getAssign(); this.getAssign();
this.getRecordList(); this.getRecordList();
this.customerType(); this.customerType();
//
this.scrollDown();
} }
}, },
closeCustomer(){ closeCustomer(){
@ -107,14 +120,6 @@ export default {
async getRecordList() { async getRecordList() {
await this.$API.customer.list.post(); await this.$API.customer.list.post();
}, },
async sendCustomer() {
if(this.params.to_message =="") return
const res = await this.$API.customer.send.post(this.params);
if(res.code == 200){
this.tagList.push({});
this.params.to_message = "";
}
},
async customerType() { async customerType() {
const res = await this.$API.customer.typeList.post(); const res = await this.$API.customer.typeList.post();
if (res.code == 200) { if (res.code == 200) {
@ -123,20 +128,57 @@ export default {
}, },
typeActive(item){ typeActive(item){
this.params.type = item.value; this.params.type = item.value;
} },
async sendCustomer() {
if(this.params.to_message =="") return
const res = await this.$API.customer.send.post(this.params);
if(res.code == 200){
const userInfo = this.$TOOL.data.get("USER_INFO");
this.msgList.push({
to_user_id:-1,
from_user:{
name:userInfo.name,
avatar:userInfo.avatar
},
to_message:this.params.to_message
});
this.params.to_message = "";
this.scrollDown();
}
},
scroll({scrollTop}){
if(scrollTop>10){
this.$refs.tagList.style.position = "absolute";
this.$refs.tagList.style.background = "#fff";
}else{
this.$refs.tagList.style.position = "relative";
this.$refs.tagList.style.background = "";
}
},
scrollDown() {
this.$nextTick(() => {
const wrap = this.$refs.scrollbar;
if(wrap){
const e = wrap.$el.querySelector('.el-scrollbar__wrap')
e.scrollTop = e.scrollHeight;
}
})
},
} }
} }
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.customerBox{ .customerBox{
position: fixed; position: absolute;
right: 40px; right: 40px;
bottom: 80px; bottom: 40px;
z-index: 10; z-index: 1000;
.img{ .img{
width: 56px; width: 56px;
height: 56px; height: 56px;
cursor: pointer;
} }
.customerView{ .customerView{
width: 380px; width: 380px;
@ -165,19 +207,26 @@ export default {
cursor: pointer; cursor: pointer;
} }
} }
.affix-container {
position: relative;
}
.bodyMain{ .bodyMain{
flex: 1; flex: 1;
overflow: hidden; overflow: hidden;
.tagList{ .tagList{
position: relative;
left: 0;
z-index: 0;
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
padding: 0 10px; padding: 0 10px 10px 10px;
.tagItem{ .tagItem{
background: #F4F4F4; background: #F4F4F4;
padding: 10px; padding: 10px;
border-radius: 4px; border-radius: 4px;
margin: 10px 10px 0 0; margin: 10px 10px 0 0;
color: #555; color: #555;
cursor: pointer;
} }
} }
.msgList{ .msgList{
@ -190,7 +239,7 @@ export default {
} }
.msgText{ .msgText{
.msgTitle{ .msgTitle{
padding: 6px 0; padding: 0 0 8px 0;
color: #555; color: #555;
} }
.textCom{ .textCom{

View File

@ -0,0 +1,39 @@
// 自定义拖拉指令
export default{
mounted(el) {
let startX, startY, initialMouseX, initialMouseY;
const parent = el.parentElement;
function onMouseMove(event) {
const dx = event.clientX - initialMouseX;
const dy = event.clientY - initialMouseY;
let newLeft = startX + dx;
let newTop = startY + dy;
// 确保拖拽元素不会超出父级容器的范围
const maxX = parent.clientWidth - el.offsetWidth;
const maxY = parent.clientHeight - el.offsetHeight;
newLeft = Math.max(0, Math.min(newLeft, maxX));
newTop = Math.max(0, Math.min(newTop, maxY));
el.style.left = newLeft + 'px';
el.style.top = newTop + 'px';
}
function onMouseUp() {
document.removeEventListener('mousemove', onMouseMove);
document.removeEventListener('mouseup', onMouseUp);
}
el.addEventListener('mousedown', (event) => {
startX = el.offsetLeft;
startY = el.offsetTop;
initialMouseX = event.clientX;
initialMouseY = event.clientY;
document.addEventListener('mousemove', onMouseMove);
document.addEventListener('mouseup', onMouseUp);
});
}
}

View File

@ -43,6 +43,7 @@ import time from './directives/time'
import copy from './directives/copy' import copy from './directives/copy'
import number from './directives/number' import number from './directives/number'
import focus from './directives/focus' import focus from './directives/focus'
import draggable from './directives/draggable'
import errorHandler from './utils/errorHandler' import errorHandler from './utils/errorHandler'
import * as elIcons from '@element-plus/icons-vue' import * as elIcons from '@element-plus/icons-vue'
@ -100,6 +101,7 @@ export default {
app.directive('copy', copy) app.directive('copy', copy)
app.directive('number', number) app.directive('number', number)
app.directive('focus', focus) app.directive('focus', focus)
app.directive('draggable', draggable)
//统一注册el-icon图标 //统一注册el-icon图标
for(let icon in elIcons){ for(let icon in elIcons){

View File

@ -140,6 +140,7 @@ export default {
overflow: hidden; overflow: hidden;
padding: 0; padding: 0;
border-radius: 0; border-radius: 0;
position: relative;
.pageBody{ .pageBody{
height: 100%; height: 100%;
display: flex; display: flex;
@ -273,4 +274,11 @@ export default {
} }
} }
.customerBoxView{
position: absolute;
right: 15px;
top: 80%;
z-index: 2000;
cursor: move;
}
</style> </style>

View File

@ -26,7 +26,7 @@
<div class="mainBody"> <div class="mainBody">
<div class="mainTitle">龙隆</div> <div class="mainTitle">龙隆</div>
<div class="mainView"> <div class="mainView">
<el-scrollbar> <el-scrollbar ref="scrollbar">
<div class="msgList"> <div class="msgList">
<div class="msgItem" :class="user_id === item.to_user_id?'msgRightItem':''" v-for="(item,index) in msgList" :key="index"> <div class="msgItem" :class="user_id === item.to_user_id?'msgRightItem':''" v-for="(item,index) in msgList" :key="index">
<div class="avatar" v-if="user_id != item.to_user_id"> <div class="avatar" v-if="user_id != item.to_user_id">
@ -36,7 +36,9 @@
</div> </div>
<div class="msgText"> <div class="msgText">
<div class="msgTitle">{{item.from_user && item.from_user.name?item.from_user.name:'匿名'}}</div> <div class="msgTitle">{{item.from_user && item.from_user.name?item.from_user.name:'匿名'}}</div>
<div class="textCom">{{item.to_message}}</div> <div class="textCom">
<div v-html="item.to_message"></div>
</div>
</div> </div>
<div class="avatar" v-if="user_id === item.to_user_id"> <div class="avatar" v-if="user_id === item.to_user_id">
<el-avatar :size="36" :src="item.from_user.avatar" fit="contain"> <el-avatar :size="36" :src="item.from_user.avatar" fit="contain">
@ -102,7 +104,7 @@ export default {
contactsList:[ contactsList:[
{name:"龙隆",msg:"嘻嘻"}, {name:"龙隆",msg:"嘻嘻"},
{name:"骁骁",msg:"测试信息"}, {name:"骁骁",msg:"测试信息"},
{name:"",msg:"怎么能快速挣够一百万"}, {name:"管理员",msg:"怎么能快速挣够一百万"},
{name:"",msg:"真机运行不需要检查更新真机运行时appid固定为'HBuilder'"}, {name:"",msg:"真机运行不需要检查更新真机运行时appid固定为'HBuilder'"},
{name:"",msg:"真机运行不需要检查更新真机运行时appid固定为'HBuilder'"}, {name:"",msg:"真机运行不需要检查更新真机运行时appid固定为'HBuilder'"},
], ],
@ -129,6 +131,7 @@ export default {
switch(res.data.type) { switch(res.data.type) {
case 36: case 36:
this.msgList = res.data.rows; this.msgList = res.data.rows;
this.scrollDown();
break; break;
case 37: case 37:
this.params.to_user_id = res.data.user.uid; this.params.to_user_id = res.data.user.uid;
@ -143,9 +146,29 @@ export default {
if(this.params.to_message =="") return if(this.params.to_message =="") return
const res = await this.$API.customer.send.post(this.params); const res = await this.$API.customer.send.post(this.params);
if(res.code == 200){ if(res.code == 200){
const userInfo = this.$TOOL.data.get("USER_INFO");
this.msgList.push({
to_user_id:userInfo.id,
from_user:{
name:userInfo.name,
avatar:userInfo.avatar
},
to_message:this.params.to_message
});
this.params.to_message = ""; this.params.to_message = "";
this.scrollDown();
} }
}, },
scrollDown() {
this.$nextTick(() => {
const wrap = this.$refs.scrollbar;
if(wrap){
const e = wrap.$el.querySelector('.el-scrollbar__wrap')
e.scrollTop = e.scrollHeight;
}
})
},
} }
} }
</script> </script>
@ -247,7 +270,7 @@ export default {
} }
.msgText{ .msgText{
.msgTitle{ .msgTitle{
padding: 6px 0; padding:0 0 8px 0;
color: #555; color: #555;
} }
.textCom{ .textCom{