增加客服组件

This commit is contained in:
龙运模 2024-11-09 17:04:46 +08:00
parent 0b9b5e2aef
commit 372ca89f07
6 changed files with 436 additions and 54 deletions

54
src/api/model/customer.js Normal file
View File

@ -0,0 +1,54 @@
import config from "@/config"
import http from "@/utils/request"
export default {
send: {
url: `${config.API_URL}/customer.service.send.message`,
name: "发送消息到用户",
post: async function(data){
return await http.post(this.url, data);
}
},
list: {
url: `${config.API_URL}/customer.service.message.list`,
name: "获取消息列表",
post: async function(data){
return await http.post(this.url, data);
}
},
typeList: {
url: `${config.API_URL}/customer.service.type.list`,
name: "问题工单常量",
post: async function(data){
return await http.post(this.url, data);
}
},
delete: {
url: `${config.API_URL}/customer.service.message.delete`,
name: "删除消息记录",
post: async function(data){
return await http.post(this.url, data);
}
},
recordList: {
url: `${config.API_URL}/customer.service.message.record.list`,
name: "消息记录列表",
post: async function(data){
return await http.post(this.url, data);
}
},
customer: {
url: `${config.API_URL}/customer.service.random.assign`,
name: "随机客服",
post: async function(data){
return await http.post(this.url, data);
}
},
read: {
url: `${config.API_URL}/customer.service.message.read`,
name: "标记已读",
post: async function(data){
return await http.post(this.url, data);
}
},
}

View File

@ -0,0 +1,228 @@
<template>
<div class="customerBox">
<el-image class="img" @click="openCustomer" src="/img/CustomerService.svg"></el-image>
<div class="customerView" v-if="customerShow">
<span class="arrow"></span>
<div class="viewBody">
<div class="title">智能客服
<el-icon class="close" size="18" @click="closeCustomer"><el-icon-Close/></el-icon>
</div>
<div class="bodyMain">
<el-scrollbar>
<div class="tagList">
<div class="tagItem" v-for="(item,index) in tagList" :key="index">{{item.name}}</div>
</div>
<div class="msgList">
<div class="msgItem" :class="item.type === 2?'msgRightItem':''" v-for="(item,index) in msgList" :key="index">
<div class="avatar" v-if="item.type === 1">
<el-avatar :size="36" :src="item.avatar" fit="contain">
<img src="https://cube.elemecdn.com/e/fd/0fc7d20532fdaf769a25683617711png.png"/>
</el-avatar>
</div>
<div class="msgText">
<div class="msgTitle">{{item.title}}</div>
<div class="textCom">{{item.msg}}</div>
</div>
<div class="avatar" v-if="item.type === 2">
<el-avatar :size="36" :src="item.avatar" fit="contain">
<img src="https://cube.elemecdn.com/e/fd/0fc7d20532fdaf769a25683617711png.png"/>
</el-avatar>
</div>
</div>
</div>
</el-scrollbar>
</div>
<div class="footer">
<el-input class="customTextarea" v-model="params.text" resize="none" type="textarea" :row="2" placeholder="请简短描述您的问题"></el-input>
<div class="saveBtn" :class="params.text!==''?'saveActive':''"> </div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: "index",
data(){
return{
customerShow:false,
params:{
text:''
},
tagList:[
{name:'搜索引擎和数据查询'},
{name:'用户体验和设计'},
{name:'技术和兼容性'},
{name:'质量问题'},
{name:'其他'},
],
msgList:[
{type:1,avatar:"https://dm-auto.oss-cn-shanghai.aliyuncs.com/xw_cloud/image/login_logo.png",title:"在线客服",msg:"您好,请问您需要什么帮助?"},
{type:1,avatar:"https://dm-auto.oss-cn-shanghai.aliyuncs.com/xw_cloud/image/login_logo.png",title:"在线客服",msg:"我是您的智能在线客服,您可以把你的问题告诉我,我会尽我所能帮助您。"},
{type:2,avatar:"https://dm-auto.oss-cn-shanghai.aliyuncs.com/xw_cloud/5.gif",title:"龙隆",msg:"怎么能快速的挣够一百万"}
]
}
},
mounted() {
},
methods:{
openCustomer(){
this.customerShow = !this.customerShow;
},
closeCustomer(){
this.customerShow = false;
},
}
}
</script>
<style scoped lang="scss">
.customerBox{
position: fixed;
right: 40px;
bottom: 80px;
z-index: 10;
.img{
width: 56px;
height: 56px;
}
.customerView{
width: 300px;
height: 430px;
position: absolute;
right: 0;
bottom: 70px;
background: #fff;
box-shadow: 0 4px 4px rgba(19,103,193,0.3);
border: 1px solid #B7D7F9;
border-radius: 8px;
.viewBody{
display: flex;
flex-direction: column;
height: 100%;
.title{
padding: 15px 10px;
border-bottom: 1px solid #F6F6F6;
font-size: 14px;
font-weight: 500;
display: flex;
align-items: center;
justify-content: space-between;
.close{
cursor: pointer;
}
}
.bodyMain{
flex: 1;
overflow: hidden;
.tagList{
display: flex;
flex-wrap: wrap;
padding: 0 10px;
.tagItem{
background: #F4F4F4;
padding: 10px;
border-radius: 4px;
margin: 10px 10px 0 0;
color: #555;
}
}
.msgList{
padding: 10px;
.msgItem{
display: flex;
margin-bottom: 8px;
.avatar{
padding-right: 10px;
}
.msgText{
.msgTitle{
padding: 6px 0;
color: #555;
}
.textCom{
background: #f5f5f5;
border-radius: 4px;
padding: 10px;
}
}
}
.msgRightItem{
justify-content: flex-end;
.avatar{
padding-left: 10px;
padding-right: 0;
}
.msgText{
.msgTitle{
text-align: right;
}
.textCom{
background: var(--el-color-primary);
color: var(--el-color-white);
}
}
}
}
}
.footer{
padding: 10px;
border-top: 1px solid #F6F6F6;
position: relative;
.customTextarea{
font-size:13px;
::v-deep .el-textarea__inner{
box-shadow: none;
border: 0;
padding-right: 60px;
}
::v-deep .el-textarea__inner::-webkit-scrollbar{
width: 0;
}
}
.saveBtn{
position: absolute;
bottom:22px;
right: 10px;
z-index: 10;
padding: 7px 15px;
background: #f4f4f5;
color: #A8ABB2;
border-radius: 3px;
cursor: not-allowed;
}
.saveActive{
cursor: pointer;
background: var(--el-color-primary);
color: var(--el-color-white);
}
}
}
}
.arrow{
position: absolute;
bottom: -5px;
right: 12px;
z-index: 1;
}
.arrow:before{
content: "";
position: absolute;
bottom: 0;
right: 12px;
z-index:1;
width: 8px;
height: 8px;
border: 1px solid #B7D7F9;
border-left-color:transparent;
border-top-color:transparent;
transform:rotate(45deg);
background: #fff;
}
}
</style>

View File

@ -29,6 +29,7 @@ import scSearch from "./components/scSearch";
import scExport from "./components/scExport";
import scExportList from "./components/scExport/exportList";
import scImport from "./components/scImport";
import scCustomer from "./components/scCustomer"
import scStatusIndicator from './components/scMini/scStatusIndicator'
import scTrend from './components/scMini/scTrend'
@ -87,6 +88,7 @@ export default {
app.component('scExport', scExport);
app.component('scExportList', scExportList);
app.component('scImport', scImport);
app.component('scCustomer', scCustomer);
//注册全局指令
app.directive('authSetup', authSetup)

View File

@ -1,4 +1,5 @@
/* 全局 */
html{font-size: 62.5%}
#app, body, html {width: 100%;height: 100%;background-color: #f6f8f9;font-size: 12px;}
a {color: #333;text-decoration: none;}
a:hover, a:focus {color: #000;text-decoration: none;}

View File

@ -7,19 +7,26 @@
<div class="rowView">
<div class="rowList">
<div class="colItem" v-for="(item,index) in list" :key="index">
<el-icon size="60" v-if="item.icon"><component :is="item.icon"/></el-icon>
<div class="name">
{{item.name}}
<el-icon size="30"><sc-icon-ArrowRightServe/></el-icon>
<div class="cardView">
<el-icon size="56" v-if="item.icon"><component :is="item.icon"/></el-icon>
<div class="name">
{{item.name}}
<el-icon class="icon" size="30"><sc-icon-ArrowRightServe/></el-icon>
</div>
</div>
<div class="describe">
<el-icon size="56" v-if="item.icon"><component :is="item.icon"/></el-icon>
<div class="name">
占位占位占位占位占位占位占位占位占位占位占位占位占位占位
<el-icon class="icon" size="30"><sc-icon-ArrowRightServe/></el-icon>
</div>
</div>
</div>
</div>
</div>
<div class="recommend">
<div class="title">智能推荐</div>
<div class="mainView">
<div class="viewItem" v-for="(item,index) in recommendList" :key="index" :style="{'background':item.color,'left':item.left,'top':item.top,'zIndex':index+1}">{{item.name}}</div>
</div>
<div class="mainView" ref="bubble"></div>
</div>
<div class="history">
<div class="title">搜索历史</div>
@ -32,9 +39,7 @@
</el-scrollbar>
<!--客服-->
<div class="customerBox">
<el-image class="img" src="/img/CustomerService.svg"></el-image>
</div>
<scCustomer />
</el-main>
</div>
</template>
@ -57,20 +62,27 @@ export default {
{name:"其他",icon:"sc-icon-OtherServe",url:''},
],
recommendList:[
{name:'维保期限查询',color:'#436FFF',left:'2%',top:'2%'},
{name:'主控部件查询',color:'#FF8543',left:'15%',top:'10%'},
{name:'智能客服',color:'#22D3F6',left:'28%',top:'5%'},
{name:'我的产品',color:'#0FCA44',left:'40%',top:'8%'},
{name:'订单号查询',color:'#FBCA0A',left:'70%',top:'2%'},
{name:'主控部件查询',color:'#FF8543',left:'57%',top:'12%'},
{name:'我的产品',color:'#FF8543',left:'77%',top:'62%'},
{name:'主控部件查询',color:'#FF8543',left:'57%',top:'12%'},
{name:'问题单',color:'#FF4B51',left:'6%',top:'32%'},
{name:'主控部件查询',color:'#FF8543',left:'17%',top:'47%'},
{name:'我的产品',color:'#0FCA44',left:'32%',top:'42%'},
{name:'问题单',color:'#FF4B51',left:'46%',top:'32%'},
{name:'维保期限查询',color:'#436FFF',left:'72%',top:'32%'},
{name:'订单号查询',color:'#FBCA0A',left:'52%',top:'58%'},
{name:'维保期限查询',color:'#436FFF'},
{name:'主控部件查询',color:'#FF8543'},
{name:'智能客服',color:'#22D3F6'},
{name:'我的产品',color:'#0FCA44'},
{name:'订单号查询',color:'#FBCA0A'},
{name:'主控部件查询',color:'#FF8543'},
{name:'我的产品',color:'#32af40'},
{name:'主控部件查询',color:'#FF8543'},
{name:'问题单',color:'#FF4B51'},
{name:'主控部件查询',color:'#FF8543'},
{name:'我的产品',color:'#0FCA44'},
{name:'问题单',color:'#FF4B51'},
{name:'维保期限查询',color:'#436FFF'},
{name:'订单号查询',color:'#FBCA0A'},
{name:'我的产品',color:'#0FCA44'},
{name:'订单号查询',color:'#FBCA0A'},
{name:'主控部件查询',color:'#94471d'},
{name:'我的产品',color:'#FF8543'},
{name:'主控部件查询',color:'#3d7a80'},
{name:'问题单',color:'#FF4B51'},
{name:'主控部件查询',color:'#FF8543'},
],
historyList:[
{name:'搜索历史文案占位……'},
@ -85,6 +97,33 @@ export default {
{name:'维保工单'},
]
}
},
mounted() {
for (let i = 0; i < this.recommendList.length; i++) {
const bubble = this.getCreateBubble(this.recommendList[i]);
this.$refs.bubble.appendChild(bubble);
}
},
methods:{
getCreateBubble(item){
const containerWidth = this.$refs.bubble.offsetWidth;
const containerHeight = this.$refs.bubble.offsetHeight;
const bubble = document.createElement('div');
bubble.className = 'bubble';
const maxX = containerWidth - 160;
const maxY = containerHeight - 38;
const x = Math.floor(Math.random() * maxX);
const y = Math.floor(Math.random() * maxY);
bubble.style.left = `${x}px`;
bubble.style.top = `${y}px`;
bubble.style.maxWidth = '160px';
bubble.style.maxHeight = '38px';
bubble.style.background = `${item.color}`;
bubble.innerText =`${item.name}`;
return bubble
}
}
}
</script>
@ -105,61 +144,111 @@ export default {
display: flex;
flex-direction: column;
.rowView{
width: 100%;
height: 320px;
padding: 2%;
height: 220px;
padding: 20px 0;
}
.rowList{
max-width: 1200px;
margin: 0 auto;
height: 100%;
display: flex;
border: 1px solid #aaa;
.colItem{
flex: 1;
border-right: 1px solid #aaa;
border: 1px solid #aaa;
padding: 20px;
display: flex;
position: relative;
margin-left: -1px;
.cardView{
height: 100%;
width: 100%;
display: flex;
flex-direction: column;
justify-content: space-between;
.name{
display: flex;
align-items: center;
justify-content: space-between;
font-size: 18px;
.icon{
margin-left: 10px;
}
}
}
.describe{
display: none;
}
}
.colItem:hover{
border-top-color: var(--el-color-primary);
border-bottom-color: var(--el-color-primary);
}
.colItem:hover .describe{
height: 100%;
width: 100%;
background: rgba(255,255,255,1);
color: var(--el-color-primary);
position: absolute;
left: 0;
top: 0;
z-index: 10;
cursor: pointer;
padding: 20px;
display: flex;
flex-direction: column;
justify-content: space-between;
.name{
display: flex;
align-items: center;
align-items: flex-end;
justify-content: space-between;
font-size: 18px;
font-size: 16px;
.icon{
margin-left: 10px;
}
}
}
.colItem:last-child{
border-right: 0;
}
}
.recommend{
.title{
padding:0 2%;
max-width: 1200px;
margin: 0 auto;
height: 80px;
display: flex;
align-items: center;
font-size: 22px;
}
.mainView{
padding: 20px 2%;
padding: 20px 0;
max-width: 1200px;
margin: 0 auto;
background: #F8F8F8;
display: flex;
justify-content: flex-start;
flex-wrap: wrap;
position: relative;
height: 300px;
.viewItem{
padding: 20px 60px;
::v-deep .bubble{
display: flex;
align-items: center;
justify-content: center;
border: 1px solid #F8F8F8;
position: absolute;
border-radius: 50px;
color: #fff;
margin: 20px;
font-size: 16px;
position: absolute;
padding:6px 20px;
box-shadow: 0 2px 4px rgba(0,0,0,0.2);
}
::v-deep .bubble:hover{
transform: scale(1.1);
cursor: pointer;
}
}
}
.history{
.title{
padding:0 2%;
max-width: 1200px;
margin: 0 auto;
height: 80px;
display: flex;
align-items: center;
@ -167,7 +256,9 @@ export default {
font-size: 22px;
}
.mainView{
padding: 20px 2% 80px 2%;
padding: 20px 0 80px 0;
max-width: 1200px;
margin: 0 auto;
display: flex;
flex-wrap: wrap;
.viewItem{
@ -181,14 +272,4 @@ export default {
}
}
.customerBox{
position: fixed;
right: 40px;
bottom: 80px;
z-index: 10;
.img{
width: 80px;
height: 80px;
}
}
</style>

View File

@ -2,7 +2,7 @@
<el-header class="pageHeader" style="height:55px;">
<div class="common-header-left">
<div class="common-header-logo">
<img class="logo" src="https://dm-auto.oss-cn-shanghai.aliyuncs.com/xw_cloud/image/login_logo.png">
<img class="logo" @click="getBack" src="https://dm-auto.oss-cn-shanghai.aliyuncs.com/xw_cloud/image/login_logo.png">
</div>
<div class="common-header-title">
<div class="headerView">
@ -78,6 +78,21 @@
export default {
props: {
title: { type: String, default: "" }
},
data(){
return{
}
},
mounted() {
},
methods:{
getBack(){
this.$router.push({
path:'/login'
})
}
}
}
</script>
@ -88,6 +103,7 @@ export default {
display: flex;
.common-header-title{
flex: 1;
border-left: 0;
}
}
.headerView{