You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1153 lines
37 KiB
1153 lines
37 KiB
{extend name="public/container"}
|
|
{block name="title"}客服工作台{/block}
|
|
{block name="head"}
|
|
<style>
|
|
@import "/static/css/google.min.css";
|
|
|
|
.head-box {
|
|
position: relative;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
color: #fff;
|
|
height: 45px;
|
|
background: linear-gradient(85deg, #3875ea 0%, #1890fc 100%);
|
|
}
|
|
|
|
.head-box span {
|
|
position: absolute;
|
|
width: 45px;
|
|
height: 100%;
|
|
left: 0;
|
|
top: 0;
|
|
text-align: center;
|
|
line-height: 45px;
|
|
}
|
|
|
|
.chat-box {
|
|
display: flex;
|
|
flex-direction: column;
|
|
height: 100%;
|
|
height: 100vh;
|
|
background: #f0f1f2;
|
|
}
|
|
|
|
.chat-box .head-box {
|
|
background: linear-gradient(85deg, #3875ea 0%, #1890fc 100%);
|
|
}
|
|
|
|
.chat-box .head-box .title-hd {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
position: relative;
|
|
height: 43px;
|
|
padding: 0 0.3rem;
|
|
color: #fff;
|
|
}
|
|
|
|
.chat-box .head-box .title-hd .icon-fanhui {
|
|
position: absolute;
|
|
left: 0.3rem;
|
|
top: 50%;
|
|
transform: translateY(-50%);
|
|
}
|
|
|
|
.chat-box .head-box .title-hd .icon-gengduo2 {
|
|
/* #ifdef MP */
|
|
position: absolute;
|
|
right: 2.1rem;
|
|
top: 50%;
|
|
transform: translateY(-50%);
|
|
/* #endif */
|
|
}
|
|
|
|
.chat-box .scroll-box {
|
|
flex: 1;
|
|
}
|
|
|
|
.chat-box .footer-box {
|
|
display: flex;
|
|
align-items: center;
|
|
height: 1rem;
|
|
padding: 0 0.3rem;
|
|
color: rgba(0, 0, 0, 0.8);
|
|
background: #f7f7f7;
|
|
}
|
|
|
|
.chat-box .footer-box .words .iconfont {
|
|
font-size: 0.5rem;
|
|
}
|
|
|
|
.chat-box .footer-box .input-box {
|
|
display: flex;
|
|
align-items: center;
|
|
width: 4.92rem;
|
|
height: 0.64rem;
|
|
padding-right: 0.05rem;
|
|
margin-left: 0.18rem;
|
|
background-color: #fff;
|
|
border-radius: 0.32rem;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.chat-box .footer-box .input-box input {
|
|
flex: 1;
|
|
padding-left: 0.2rem;
|
|
height: 100%;
|
|
border: transparent !important;
|
|
}
|
|
|
|
.chat-box .footer-box .input-box .ivu-input,
|
|
.chat-box .footer-box .input-box .ivu-input:hover,
|
|
.chat-box .footer-box .input-box .ivu-input:focus {
|
|
border: transparent;
|
|
box-shadow: none;
|
|
}
|
|
|
|
.chat-box .footer-box .input-box .iconfont {
|
|
font-size: 0.5rem;
|
|
color: #ccc;
|
|
font-weight: normal;
|
|
}
|
|
|
|
.chat-box .footer-box .input-box .isSend {
|
|
color: #3875ea;
|
|
}
|
|
|
|
.chat-box .footer-box .emoji .iconfont {
|
|
margin-left: 0.18rem;
|
|
font-size: 0.5rem;
|
|
}
|
|
|
|
.chat-box .footer-box .more .iconfont {
|
|
margin-left: 0.18rem;
|
|
font-size: 0.5rem;
|
|
}
|
|
|
|
.tool-wrapper {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
padding: 0.45rem 0.6rem;
|
|
background: #fff;
|
|
font-size: 0.24rem;
|
|
}
|
|
|
|
.tool-wrapper .tool-item {
|
|
text-align: center;
|
|
}
|
|
|
|
.tool-wrapper .tool-item img {
|
|
width: 1.04rem;
|
|
height: 1.04rem;
|
|
}
|
|
|
|
.slider-banner {
|
|
padding-bottom: 0.25rem;
|
|
background: #fff;
|
|
}
|
|
|
|
.slider-banner .em {
|
|
display: inline-block;
|
|
width: 0.5rem;
|
|
height: 0.5rem;
|
|
margin: 0.4rem 0 0 0.5rem;
|
|
}
|
|
|
|
.words-mask {
|
|
z-index: 50;
|
|
position: fixed;
|
|
left: 0;
|
|
top: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
background: rgba(0, 0, 0, 0.5);
|
|
}
|
|
|
|
.words-mask .content {
|
|
position: absolute;
|
|
left: 0;
|
|
right: 0;
|
|
top: 1.14rem;
|
|
bottom: 0;
|
|
display: flex;
|
|
flex-direction: column;
|
|
background: #fff;
|
|
border-radius: 0.06rem 0.06rem 0px 0px;
|
|
}
|
|
|
|
.words-mask .content .title-box {
|
|
padding: 0 0.3rem 0.3rem;
|
|
position: relative;
|
|
border-bottom: 1px solid #f5f6f9;
|
|
}
|
|
|
|
.words-mask .content .title-box .tab-box {
|
|
position: relative;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
padding: 0.4rem 2.2rem 0.3rem;
|
|
font-size: 0.32rem;
|
|
color: #9f9f9f;
|
|
}
|
|
|
|
.words-mask .content .title-box .tab-box .on {
|
|
color: #3875ea;
|
|
font-weight: bold;
|
|
}
|
|
|
|
.words-mask .content .title-box .tab-box .right-icon {
|
|
position: absolute;
|
|
right: 0;
|
|
top: 50%;
|
|
transform: translateY(-50%);
|
|
}
|
|
|
|
.words-mask .content .title-box .tab-box .right-icon .iconfont {
|
|
margin-left: 0.2rem;
|
|
font-size: 0.48rem;
|
|
color: #c8cad0;
|
|
}
|
|
|
|
.words-mask .content .title-box .input-box {
|
|
display: flex;
|
|
align-items: center;
|
|
width: 6.9rem;
|
|
height: 0.64rem;
|
|
padding-right: 0.05rem;
|
|
margin-left: 0.18rem;
|
|
border-radius: 0.32rem;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.words-mask .content .title-box .input-box .ivu-input {
|
|
background: #f5f6f9;
|
|
}
|
|
|
|
.words-mask .content .title-box .input-box .ivu-input,
|
|
.words-mask .content .title-box .input-box .ivu-input:hover,
|
|
.words-mask .content .title-box .input-box .ivu-input:focus {
|
|
border: transparent;
|
|
box-shadow: none;
|
|
}
|
|
|
|
.words-mask .content .title-box .icon-cha1 {
|
|
position: absolute;
|
|
right: 0;
|
|
top: 50%;
|
|
transform: translateY(-50%);
|
|
}
|
|
|
|
.words-mask .content .scroll-box {
|
|
flex: 1;
|
|
display: flex;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.words-mask .content .scroll-box .scroll-left {
|
|
width: 1.76rem;
|
|
height: 100%;
|
|
overflow-y: scroll;
|
|
-webkit-overflow-scrolling: touch;
|
|
background: #f5f6f9;
|
|
}
|
|
|
|
.words-mask .content .scroll-box .scroll-left .left-item {
|
|
position: relative;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
width: 100%;
|
|
height: 1.09rem;
|
|
color: #282828;
|
|
font-size: 0.26rem;
|
|
}
|
|
|
|
.words-mask .content .scroll-box .scroll-left .left-item.active {
|
|
color: #3875ea;
|
|
background: #fff;
|
|
}
|
|
|
|
.words-mask .content .scroll-box .scroll-left .left-item.active:after {
|
|
content: ' ';
|
|
position: absolute;
|
|
left: 0;
|
|
top: 50%;
|
|
transform: translateY(-50%);
|
|
width: 0.06rem;
|
|
height: 0.46rem;
|
|
background: #3875ea;
|
|
}
|
|
|
|
.words-mask .content .scroll-box .scroll-left .left-item.add_cate {
|
|
color: #9f9f9f;
|
|
font-size: 0.26rem;
|
|
}
|
|
|
|
.words-mask .content .scroll-box .scroll-left .left-item.add_cate .iconfont {
|
|
margin-right: 0.1rem;
|
|
font-size: 0.24rem;
|
|
}
|
|
|
|
.words-mask .content .scroll-box .right-box {
|
|
flex: 1;
|
|
overflow: scroll;
|
|
-webkit-overflow-scrolling: touch;
|
|
}
|
|
|
|
.words-mask .content .scroll-box .msg-item {
|
|
padding: 0.25rem 0.3rem;
|
|
color: #888;
|
|
font-size: 0.28rem;
|
|
}
|
|
|
|
.words-mask .content .scroll-box .msg-item .title {
|
|
margin-right: 0.2rem;
|
|
color: #282828;
|
|
}
|
|
|
|
.words-mask .content .scroll-box .msg-item.add-mg {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: flex-end;
|
|
font-size: 0.28rem;
|
|
padding: 0.15rem 0.3rem;
|
|
}
|
|
|
|
.words-mask .content .scroll-box .msg-item.add-mg .iconfont {
|
|
font-size: 0.36rem;
|
|
margin-right: 0.1rem;
|
|
}
|
|
|
|
.chat-scroll-box {
|
|
flex: 1;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.chat-scroll-box .day-box {
|
|
margin-bottom: 0.2rem;
|
|
font-size: 0.24rem;
|
|
color: #999;
|
|
text-align: center;
|
|
}
|
|
|
|
.chat-scroll-box .chat-item {
|
|
display: flex;
|
|
margin-bottom: 0.36rem;
|
|
font-size: 0.28rem;
|
|
}
|
|
|
|
.chat-scroll-box .chat-item .avatar {
|
|
width: 0.8rem;
|
|
height: 0.8rem;
|
|
border-radius: 50%;
|
|
}
|
|
|
|
.chat-scroll-box .chat-item .msg-box {
|
|
display: flex;
|
|
align-items: center;
|
|
max-width: 4.52rem;
|
|
margin-left: 0.22rem;
|
|
padding: 0.1rem 0.24rem;
|
|
background: #fff;
|
|
border-radius: 0.14rem;
|
|
word-break: break-all;
|
|
color: #333;
|
|
}
|
|
|
|
.chat-scroll-box .chat-item .img-box {
|
|
width: 2.7rem;
|
|
margin-left: 0.22rem;
|
|
}
|
|
|
|
.chat-scroll-box .chat-item .img-box img {
|
|
width: 2.7rem;
|
|
border-radius: 6px;
|
|
}
|
|
|
|
.chat-scroll-box .chat-item .product-box {
|
|
width: 4.52rem;
|
|
background-color: #fff;
|
|
border-radius: 0.14rem;
|
|
overflow: hidden;
|
|
margin-left: 0.22rem;
|
|
}
|
|
|
|
.chat-scroll-box .chat-item .product-box img {
|
|
width: 4.52rem;
|
|
}
|
|
|
|
.chat-scroll-box .chat-item .product-box .info {
|
|
padding: 0.16rem 0.26rem;
|
|
}
|
|
|
|
.chat-scroll-box .chat-item .product-box .info .price {
|
|
font-size: 0.36rem;
|
|
color: #f74c31;
|
|
}
|
|
|
|
.chat-scroll-box .chat-item .product-box .info .price text {
|
|
font-size: 0.28rem;
|
|
}
|
|
|
|
.chat-scroll-box .chat-item .order-box {
|
|
width: 4.52rem;
|
|
margin-left: 0.22rem;
|
|
background-color: #fff;
|
|
border-radius: 0.14rem;
|
|
}
|
|
|
|
.chat-scroll-box .chat-item .order-box .title {
|
|
padding: 0.15rem 0.2rem;
|
|
font-size: 0.26rem;
|
|
color: #282828;
|
|
border-bottom: 1px solid #eceff8;
|
|
}
|
|
|
|
.chat-scroll-box .chat-item .order-box .info {
|
|
display: flex;
|
|
padding: 0.2rem;
|
|
}
|
|
|
|
.chat-scroll-box .chat-item .order-box .info img {
|
|
width: 1.24rem;
|
|
height: 1.24rem;
|
|
border-radius: 0.06rem;
|
|
}
|
|
|
|
.chat-scroll-box .chat-item .order-box .info .product-info {
|
|
flex: 1;
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: space-between;
|
|
margin-left: 0.16rem;
|
|
}
|
|
|
|
.chat-scroll-box .chat-item .order-box .info .product-info .name {
|
|
font-size: 0.26rem;
|
|
}
|
|
|
|
.chat-scroll-box .chat-item .order-box .info .product-info .price {
|
|
font-size: 0.3rem;
|
|
color: #f74c31;
|
|
}
|
|
|
|
.chat-scroll-box .chat-item.right-box {
|
|
flex-direction: row-reverse;
|
|
}
|
|
|
|
.chat-scroll-box .chat-item.right-box .msg-box {
|
|
margin-left: 0;
|
|
margin-right: 0.22rem;
|
|
background-color: #9cec60;
|
|
}
|
|
|
|
.chat-scroll-box .chat-item.right-box .img-box {
|
|
margin-left: 0;
|
|
margin-right: 0.22rem;
|
|
}
|
|
|
|
.chat-scroll-box .chat-item.right-box .product-box {
|
|
margin-left: 0;
|
|
margin-right: 0.22rem;
|
|
}
|
|
|
|
.chat-scroll-box .chat-item.right-box .order-box {
|
|
margin-left: 0;
|
|
margin-right: 0.22rem;
|
|
}
|
|
|
|
.chat-scroll-box .chat-item .em {
|
|
margin: 0;
|
|
}
|
|
|
|
.transfer-mask {
|
|
z-index: 30;
|
|
position: fixed;
|
|
left: 0;
|
|
top: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
background: rgba(0, 0, 0, 0.5);
|
|
}
|
|
|
|
.transfer-mask .content {
|
|
position: absolute;
|
|
left: 0;
|
|
bottom: 0;
|
|
transform: translateY(100%);
|
|
top: 2.5rem;
|
|
right: 0;
|
|
display: flex;
|
|
flex-direction: column;
|
|
background: #fff;
|
|
border-radius: 0.16rem 0.16rem 0px 0px;
|
|
}
|
|
|
|
.transfer-mask .content.on {
|
|
animation: up 0.2s linear;
|
|
animation-fill-mode: forwards;
|
|
}
|
|
|
|
.transfer-mask .content .title {
|
|
position: relative;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
height: 1.1rem;
|
|
font-size: 0.32rem;
|
|
font-weight: bold;
|
|
color: #282828;
|
|
}
|
|
|
|
.transfer-mask .content .title .iconfont {
|
|
position: absolute;
|
|
right: 0.3rem;
|
|
top: 50%;
|
|
transform: translateY(-50%);
|
|
color: #c8cad0;
|
|
font-size: 0.44rem;
|
|
}
|
|
|
|
.transfer-mask .content .list-wrapper {
|
|
flex: 1;
|
|
padding-left: 0.3rem;
|
|
overflow-y: scroll;
|
|
-webkit-overflow-scrolling: touch;
|
|
}
|
|
|
|
.transfer-mask .content .list-wrapper .list-item {
|
|
display: flex;
|
|
align-items: center;
|
|
padding: 0.16rem 0;
|
|
border-bottom: 1px solid #f0f2f7;
|
|
}
|
|
|
|
.transfer-mask .content .list-wrapper .list-item .check-box {
|
|
width: 0.72rem;
|
|
}
|
|
|
|
.transfer-mask .content .list-wrapper .list-item .avatar-box img {
|
|
width: 0.9rem;
|
|
height: 0.9rem;
|
|
border-radius: 0.06rem;
|
|
}
|
|
|
|
.transfer-mask .content .list-wrapper .list-item .nickName {
|
|
margin-left: 0.28rem;
|
|
color: #282828;
|
|
font-size: 0.3rem;
|
|
font-weight: bold;
|
|
}
|
|
|
|
.transfer-mask .content .btn {
|
|
width: 6.9rem;
|
|
height: 0.86rem;
|
|
margin: 0.5rem auto;
|
|
color: #fff;
|
|
background: #3875ea;
|
|
font-size: 0.3rem;
|
|
border-radius: 0.43rem !important;
|
|
}
|
|
|
|
@keyframes up {
|
|
0% {
|
|
transform: translateY(100%);
|
|
}
|
|
|
|
100% {
|
|
transform: translateY(0);
|
|
}
|
|
}
|
|
|
|
.emoji-outer {
|
|
position: absolute;
|
|
right: .5rem;
|
|
bottom: .3rem;
|
|
width: .5rem;
|
|
height: .5rem;
|
|
}
|
|
</style>
|
|
<script>
|
|
document.documentElement.style.fontSize = "calc(100vw/7.5)";
|
|
</script>
|
|
{/block}
|
|
{block name="content"}
|
|
<div class="chat-box" id="app" v-cloak>
|
|
<div class="head-box">
|
|
<div class="back" @click="goBack"><span class="iconfont iconfanhui"></span></div>
|
|
<div class="title">{{nickname}} - 对话详情</div>
|
|
</div>
|
|
<div class="chat-scroll-box">
|
|
<vue-scroll :ops="ops" ref="scrollBox" @refresh-activate="handleActivate" @refresh-start="handleStart" @refresh-before-deactivate="handleBeforeDeactivate" @refresh-deactivate="handleDeactivate">
|
|
<div class="slot-refresh" slot="refresh-deactive"></div>
|
|
<div class="slot-refresh" slot="refresh-beforeDeactive"></div>
|
|
<div id="chatBox" class="chat" ref="chat" style="padding: .3rem .3rem 0;">
|
|
<div v-for="(item,index) in records" :key="index" :id="`chat_${item.id}`">
|
|
<div class="day-box" v-if="item.show">{{item.time}}</div>
|
|
<div class="day-box" v-if="item.msn_type == 24 && item.kefu_info">已将用户转接到{{item.kefu_info.nickname}}</div>
|
|
<div class="chat-item" :class="{'right-box': item.is_kefu_send && item.uid == kefuInfo.id}" v-else-if="item.msn_type != 24">
|
|
<img class="avatar" :src="item.avatar" mode="">
|
|
<!-- 消息 -->
|
|
<div class="msg-box" v-if="item.msn_type==1" v-html="item.msn"></div>
|
|
<!-- 图片 -->
|
|
<div class="img-box" v-if="item.msn_type==3" v-viewer><img :src="item.msn" mode="widthFix"></div>
|
|
<!-- 商品 -->
|
|
<div class="product-box" v-if="item.msn_type==5">
|
|
<img :src="item.productInfo.image" mode="widthFix">
|
|
<div class="info">
|
|
<div class="price"><span>¥</span>{{item.productInfo.price}}</div>
|
|
<div class="name line2">{{item.productInfo.store_name}}</div>
|
|
</div>
|
|
</div>
|
|
<!-- 订单 -->
|
|
<div class="order-box" v-if="item.msn_type==6">
|
|
<div class="title">订单ID: {{item.orderInfo.order_id}}</div>
|
|
<div class="info">
|
|
<img :src="item.orderInfo.cartInfo[0].productInfo.image">
|
|
<div class="product-info">
|
|
<div class="name line2">{{item.orderInfo.cartInfo[0].productInfo.store_name}}</div>
|
|
<div class="price">¥{{item.orderInfo.cartInfo[0].productInfo.price}}</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</vue-scroll>
|
|
</div>
|
|
<div class="footer-box">
|
|
<!-- <div class="words" @click="showWords"><span class="iconfont iconhuashu1"></span></div> -->
|
|
<div class="input-box">
|
|
<i-input v-model="con" placeholder="请输入内容" style="font-size: .28rem"></i-input>
|
|
<span class="iconfont iconfasong" @click="sendText" :class="{isSend:isSend}"></span>
|
|
</div>
|
|
<div class="emoji" @click="openBox(1)"><span class="iconfont iconbiaoqing2"></span></div>
|
|
<div class="more" @click="openBox(2)"><span class="iconfont icongengduozhankai1"></span></div>
|
|
</div>
|
|
<!-- 工具 -->
|
|
<div class="tool-wrapper" v-if="isTool">
|
|
<div class="tool-item">
|
|
<Upload :show-upload-list="false" class="mr10 mb10" :before-upload="beforeUpload" :format="['jpg','jpeg','png','gif']" style="margin-top: 1px;display: inline-block">
|
|
<img src="/kefu-assets/assets/images/tool-01.png" mode="">
|
|
<div>图片</div>
|
|
</Upload>
|
|
|
|
</div>
|
|
<div class="tool-item" @click="goTransfer">
|
|
<img src="/kefu-assets/assets/images/tool-02.png" mode="">
|
|
<div>转接</div>
|
|
</div>
|
|
<div class="tool-item" @click="goAdminOrder">
|
|
<img src="/kefu-assets/assets/images/tool-03.png" mode="">
|
|
<div>交易订单</div>
|
|
</div>
|
|
<!-- <div class="tool-item" @click="goodsInfo">
|
|
<img src="/kefu-assets/assets/images/tool-04.png" mode="">
|
|
<div>商品信息</div>
|
|
</div> -->
|
|
</div>
|
|
<!-- 表情 -->
|
|
<div class="banner slider-banner" v-show="isSwiper">
|
|
<swiper class="swiper-wrapper" ref="mySwiper" :options="swiperOptions">
|
|
<swiper-slide v-for="(emojiList, index) in emojiGroup" :key="index">
|
|
<i class="em" :class="emoji" v-for="emoji in emojiList" :key="emoji" @click="addEmoji(emoji)"></i>
|
|
</swiper-slide>
|
|
</swiper>
|
|
</div>
|
|
<!-- 常用语 -->
|
|
<!-- <words :isWords="isWords" @closeBox="closeBox" @selectMsg="selectMsg"></words> -->
|
|
<!-- 转接 -->
|
|
<div class="transfer-mask" v-if="isTransfer">
|
|
<div class="content" :class="{on:isTransfer}">
|
|
<div class="title">转接客服<span class="iconfont iconcha" @click="closeTransfer"></span></div>
|
|
<div class="list-wrapper">
|
|
<radio-group v-model="activeKF">
|
|
<Radio class="list-item" v-for="(item,index) in transferList" :label="item.id" :key="index">
|
|
<div class="avatar-box">
|
|
<img :src="item.avatar" alt="">
|
|
</div>
|
|
<p class="nickName">{{item.nickname}}</p>
|
|
</Radio>
|
|
</radio-group>
|
|
</div>
|
|
<i-button class="btn" @click="confirm">确定</i-button>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
{/block}
|
|
{block name="script"}
|
|
<script>
|
|
window.$P = JSON.parse.bind(JSON);
|
|
|
|
const mp3 = new Audio("/kefu-assets/assets/audio/notice.wav");
|
|
|
|
const chunk = function(arr, num) {
|
|
num = num * 1 || 1;
|
|
var ret = [];
|
|
arr.forEach(function(item, i) {
|
|
if (i % num === 0) {
|
|
ret.push([]);
|
|
}
|
|
ret[ret.length - 1].push(item);
|
|
});
|
|
return ret;
|
|
};
|
|
|
|
require([
|
|
"vue",
|
|
"kefu-assets/api/kefu",
|
|
"kefu-assets/libs/socket",
|
|
"iview",
|
|
"dayjs",
|
|
"v-viewer",
|
|
"happy-scroll",
|
|
"vue-scroll",
|
|
"kefu-assets/components/empty/index",
|
|
"kefu-assets/components/mobile/words/index",
|
|
"kefu-assets/libs/emoji",
|
|
"vue-awesome-swiper",
|
|
], (Vue, kefuApi, Socket, iView, dayjs, VueViewer, happyScroll, vueScroll, empty, words, emojiList, vueAwesomeSwiper) => {
|
|
Vue.use(vueAwesomeSwiper);
|
|
Vue.use(happyScroll.default);
|
|
Vue.use(vueScroll);
|
|
Vue.use(iView);
|
|
Vue.use(VueViewer.default);
|
|
|
|
Vue.prototype.bus = new Vue();
|
|
Vue.prototype.$socket = Socket;
|
|
|
|
const kefuInfo = $P(`{$kefuInfo}`);
|
|
const userInfo = $P(`{$userInfo}`);
|
|
|
|
new Vue({
|
|
el: "#app",
|
|
data() {
|
|
return {
|
|
ops: {
|
|
vuescroll: {
|
|
mode: 'slide',
|
|
enable: false,
|
|
auto: false,
|
|
autoLoadDistance: 0,
|
|
pullRefresh: {
|
|
enable: true,
|
|
auto: false,
|
|
autoLoadDistance: 0,
|
|
tips: {
|
|
deactive: '',
|
|
active: '上拉加载更多',
|
|
start: 'Loading...',
|
|
beforeDeactive: ' '
|
|
},
|
|
},
|
|
pushLoad: {
|
|
enable: false,
|
|
|
|
}
|
|
},
|
|
bar: {
|
|
background: '#393232',
|
|
opacity: '.5',
|
|
size: '2px'
|
|
}
|
|
},
|
|
swiperOptions: {},
|
|
status: false,
|
|
loading: false,
|
|
isTool: false,
|
|
isSwiper: false,
|
|
isWords: false,
|
|
autoplay: false,
|
|
circular: true,
|
|
interval: 3000,
|
|
duration: 500,
|
|
emojiGroup: chunk(emojiList, 21),
|
|
|
|
con: '',
|
|
toUid: "{$userInfo.uid}",
|
|
limit: 15,
|
|
upperId: 0,
|
|
chatList: [],
|
|
kefuInfo,
|
|
userInfo,
|
|
scrollTop: 0,
|
|
active: true,
|
|
isScroll: true,
|
|
oldHeight: 0,
|
|
selector: '',
|
|
transferList: [], //转接列表
|
|
isTransfer: false,
|
|
uploadData: {}, // 上传参数
|
|
header: {},
|
|
fileUrl: '',
|
|
tourist: 0,
|
|
activeKF: ''
|
|
}
|
|
},
|
|
components: {
|
|
words
|
|
},
|
|
computed: {
|
|
isSend() {
|
|
if (this.con.length == 0) {
|
|
return false
|
|
} else {
|
|
return true
|
|
}
|
|
},
|
|
records() {
|
|
return this.chatList.map((item, index) => {
|
|
item.time = dayjs(item.add_time * 1000).format('MMMDo h:mm')
|
|
if (index) {
|
|
if (
|
|
item.add_time -
|
|
this.chatList[index - 1].add_time >=
|
|
300
|
|
) {
|
|
item.show = true;
|
|
} else {
|
|
item.show = false;
|
|
}
|
|
} else {
|
|
item.show = true;
|
|
}
|
|
return item;
|
|
});
|
|
},
|
|
},
|
|
created() {
|
|
this.toUid = "{$userInfo.uid}";
|
|
this.nickname = "{$userInfo.nickname}";
|
|
|
|
window.document.title = `${this.nickname} - 对话详情`;
|
|
this.getChatList();
|
|
|
|
this.getToken()
|
|
.then(token => {
|
|
if (!token) return;
|
|
this.$socket.then(ws => {
|
|
ws.send({
|
|
type: "kefu_login",
|
|
data: token
|
|
});
|
|
// 消息接收
|
|
ws.$on(["reply", "chat"], data => {
|
|
if (!data.is_kefu_send &&
|
|
data.uid != "{$userInfo.uid}") return;
|
|
|
|
if (data.msn_type == 1 || data.msn_type == 2) {
|
|
data.msn = this.replace_em(data.msn)
|
|
}
|
|
if (data.msn_type == 5) return
|
|
this.chatList.push(data)
|
|
|
|
this.$refs["scrollBox"].refresh();
|
|
this.$nextTick(() => {
|
|
this.scrollBom()
|
|
})
|
|
});
|
|
|
|
ws.$on("socket_error", () => {
|
|
this.$util.Tips({
|
|
title: '连接失败'
|
|
})
|
|
});
|
|
|
|
ws.$on("request_transfer", (data) => {
|
|
this.$Modal.confirm({
|
|
title: "请求转接用户",
|
|
content: data.nickname + "请求将用户转接给您,是否同意?",
|
|
cancelText: "拒绝",
|
|
onOk: () => {
|
|
ws.send({
|
|
type: "accept_transfer",
|
|
data: {
|
|
kefu_id: data.kefu_id,
|
|
uid: data.uid
|
|
}
|
|
});
|
|
},
|
|
onCancel: () => {
|
|
ws.send({
|
|
type: "reject_transfer",
|
|
data: {
|
|
kefu_id: data.kefu_id,
|
|
uid: data.uid
|
|
}
|
|
})
|
|
}
|
|
});
|
|
});
|
|
|
|
ws.$on("accept_transfer", (data) => {
|
|
this.$Notice.success({
|
|
title: "同意转接通知",
|
|
desc: data.nickname + "已同意您的转接请求"
|
|
});
|
|
ws.send({
|
|
type: "chat",
|
|
data: {
|
|
msn_type: 24,
|
|
msn: data.kefu_id,
|
|
to_uid: data.uid,
|
|
}
|
|
});
|
|
});
|
|
ws.$on("reject_transfer", (data) => {
|
|
this.$Notice.error({
|
|
title: "拒绝转接通知",
|
|
desc: data.nickname + "已拒绝您的转接请求"
|
|
});
|
|
});
|
|
});
|
|
});
|
|
},
|
|
methods: {
|
|
async getToken() {
|
|
try {
|
|
const res = await kefuApi.getToken();
|
|
return res.data.token;
|
|
} catch (err) {
|
|
this.$Message.error(err.msg);
|
|
return false;
|
|
}
|
|
},
|
|
goBack() {
|
|
window.history.length > 1 ? window.history.back() : (window.location.href = "{:Url('index')}");
|
|
},
|
|
update(e) {
|
|
// 上传照片
|
|
let file = e;
|
|
let param = new FormData(); // 创建form对象
|
|
param.append("filename", "file"); // 通过append向form对象添加数据进去
|
|
param.append("file", file); // 通过append向form对象添加数据进去
|
|
|
|
kefuApi.uploadImg(param)
|
|
.then(res => {
|
|
if (res.code === 200) {
|
|
this.$Message.success("上传成功!");
|
|
this.sendMsg(res.data.url, 3);
|
|
} else {
|
|
this.$Message.error(res.msg);
|
|
}
|
|
})
|
|
.catch(err => {
|
|
|
|
});
|
|
},
|
|
// 上传之前
|
|
beforeUpload(e) {
|
|
this.update(e);
|
|
return false;
|
|
},
|
|
// 滚动到底部
|
|
scrollBom() {
|
|
setTimeout(res => {
|
|
let num = parseFloat(document.getElementById('chatBox').offsetHeight)
|
|
if (this.$refs["scrollBox"]) {
|
|
this.$refs["scrollBox"].scrollTo({
|
|
y: num
|
|
},
|
|
300
|
|
);
|
|
}
|
|
|
|
}, 300)
|
|
},
|
|
// 底部功能区打开
|
|
openBox(key) {
|
|
if (key == 1) {
|
|
this.isTool = false
|
|
this.isSwiper = !this.isSwiper
|
|
} else {
|
|
this.isSwiper = false
|
|
this.isTool = !this.isTool
|
|
}
|
|
this.$refs["scrollBox"].refresh();
|
|
this.$nextTick(() => {
|
|
this.scrollBom();
|
|
})
|
|
},
|
|
showWords() {
|
|
this.isWords = true
|
|
},
|
|
// 转接
|
|
goTransfer() {
|
|
this.isTransfer = true;
|
|
this.getTransferList();
|
|
},
|
|
// 转接关闭
|
|
closeTransfer() {
|
|
this.isTransfer = false
|
|
},
|
|
// 转接确认
|
|
confirm() {
|
|
if (this.activeKF) {
|
|
this.$socket.then(ws => {
|
|
ws.send({
|
|
data: {
|
|
kefu_id: this.activeKF,
|
|
uid: this.toUid
|
|
},
|
|
type: "request_transfer"
|
|
});
|
|
});
|
|
|
|
this.isTransfer = false;
|
|
} else {
|
|
this.$Message.error('请选择转接客服')
|
|
}
|
|
},
|
|
// 表情点击
|
|
addEmoji(item) {
|
|
let val = `[${item}]`
|
|
this.con += val
|
|
},
|
|
// 聊天表情转换
|
|
replace_em(str) {
|
|
str = str.replace(/\[em-([a-z_]*)\]/g, "<span class='em em-$1'/></span>");
|
|
return str;
|
|
},
|
|
// 获取聊天列表
|
|
getChatList() {
|
|
kefuApi.serviceList({
|
|
limit: this.limit,
|
|
uid: this.toUid,
|
|
upper_id: this.upperId,
|
|
is_tourist: 0
|
|
}).then(res => {
|
|
var sH = 0
|
|
res.data.forEach(el => {
|
|
if (el.msn_type == 1 || el.msn_type == 2) {
|
|
el.msn = this.replace_em(el.msn)
|
|
}
|
|
})
|
|
let selector = ''
|
|
if (this.upperId == 0) {
|
|
selector = `chat_${res.data[res.data.length - 1].id}`;
|
|
} else {
|
|
selector = `chat_${this.chatList[0].id}`;
|
|
}
|
|
this.selector = selector
|
|
this.chatList = [...res.data, ...this.chatList];
|
|
this.loading = false
|
|
this.isScroll = res.data.length >= this.limit
|
|
this.$nextTick(() => {
|
|
this.$refs["scrollBox"].refresh();
|
|
if (this.upperId == 0) {
|
|
setTimeout(res => {
|
|
let num = parseFloat(document.getElementById(selector).offsetTop) - 60
|
|
this.$refs["scrollBox"].scrollTo({
|
|
y: num
|
|
},
|
|
0
|
|
);
|
|
}, 300)
|
|
}
|
|
})
|
|
})
|
|
},
|
|
// 发送消息
|
|
sendText() {
|
|
if (!this.isSend) {
|
|
return this.$Message.error('请输入内容')
|
|
}
|
|
this.sendMsg(this.con, 1);
|
|
this.con = ''
|
|
},
|
|
// ws发送
|
|
sendMsg(msn, msn_type) {
|
|
let obj = {
|
|
type: 'chat',
|
|
data: {
|
|
msn,
|
|
msn_type,
|
|
to_uid: this.toUid
|
|
}
|
|
}
|
|
this.$socket.then(ws => {
|
|
ws.send(obj);
|
|
})
|
|
},
|
|
// 图片上传
|
|
uploadImg() {
|
|
let self = this
|
|
self.$util.uploadImageOne('upload/image', function(res) {
|
|
if (res.status == 200) {
|
|
self.sendMsg(res.data.url, 3)
|
|
}
|
|
});
|
|
},
|
|
// 常用于选择
|
|
selectWords(item) {
|
|
this.isWords = false
|
|
this.sendMsg(item.message, 1)
|
|
},
|
|
// 管理员订单
|
|
goAdminOrder() {
|
|
window.location.href = "{:Url('mobile_order')}?uid=" + this.toUid;
|
|
},
|
|
// 滚动到底部
|
|
height() {
|
|
let self = this
|
|
var scrollTop = 0
|
|
let info = uni.createSelectorQuery().select(".chat");
|
|
setTimeout(res => {
|
|
info.boundingClientRect(function(data) { //data - 各种参数
|
|
scrollTop = data.height
|
|
if (self.active) {
|
|
self.scrollTop = parseInt(scrollTop) + 500
|
|
} else {
|
|
self.scrollTop = parseInt(scrollTop) + 100
|
|
}
|
|
}).exec()
|
|
}, 1000)
|
|
},
|
|
// 转接列表
|
|
getTransferList() {
|
|
kefuApi.transferList({
|
|
uid: this.toUid
|
|
}).then(res => {
|
|
this.transferList = res.data;
|
|
})
|
|
},
|
|
// 关闭常用语
|
|
closeBox() {
|
|
this.isWords = false
|
|
},
|
|
// 选择话术
|
|
selectMsg(data) {
|
|
this.con += data
|
|
this.isWords = false
|
|
},
|
|
handleActivate(vm, refreshDom) {
|
|
this.upperId = this.chatList[0].id
|
|
},
|
|
handleStart(vm, refreshDom, done) {
|
|
setTimeout(() => {
|
|
// load finished
|
|
done();
|
|
}, 2000)
|
|
},
|
|
handleBeforeDeactivate(vm, refreshDom, done) {
|
|
this.getChatList()
|
|
|
|
this.$on('change', data => {
|
|
if (data) done();
|
|
})
|
|
},
|
|
handleDeactivate(vm, refreshDom) {
|
|
let num = parseFloat(document.getElementById(this.selector).offsetTop) - 60
|
|
this.$refs["scrollBox"].scrollTo({
|
|
y: num
|
|
},
|
|
0
|
|
);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
</script>
|
|
{/block} |