| | |
| | | <template> |
| | | <div class="service-box pb-150 flex flex-col"> |
| | | <van-nav-bar :title="$t('在线客服')" left-arrow @click-left="onClickLeft" fixed /> |
| | | <div class="flex-1" v-if="kefu_url"> |
| | | <iframe :src="kefu_url" width="100%" height="100%" frameborder="0"></iframe> |
| | | </div> |
| | | <div v-else class="localKefu flex-1 flex"> |
| | | <div class="flex flex-col px-32 box-border flex-1" ref="boxScroll" style="overflow:auto;"> |
| | | <div class="w-full py-10 text-grey text-center pt-10" @click="onMore" |
| | | :style="{ 'visibility': finished ? 'hidden' : 'visiable' }"> |
| | | {{ $t('历史消息') }}</div> |
| | | <ul class="flex flex-col pt-20"> |
| | | <li v-for="(item, index) in list" :key="item.id" class="flex flex-col mt-20" |
| | | v-if="item.delete_status == 0"> |
| | | <p class="font-26 text-center py-20 text-grey"> |
| | | {{ item.createtime }}</p> |
| | | <div class="flex" :class="item.send_receive === 'send' ? 'justify-end' : ''"> |
| | | <template v-if="item.send_receive === 'receive'"> |
| | | <img src="@/assets/image/assets-center/logo.png" class="w-81 h-81 mr-40" /> |
| | | <div class="responser px-50 py-35 font-30 rounded-lg font-26 chatBg"> |
| | | <p class="break-word textColor" style="max-width: 230px;" v-if="item.type === 'text'"> |
| | | {{ item.content }}</p> |
| | | <img v-else :src="item.content" class="w-200 h-200" @click="onPreview(item.content)" /> |
| | | </div> |
| | | </template> |
| | | <div class="py-25 px-50 responser-two rounded-lg flex flex-col chatBg" v-else> |
| | | <img :src="`${item.content}`" class="w-200 h-200" v-if="item.type === 'img'" |
| | | @click="onPreview(item.content)" /> |
| | | <p class="break-word textColor" v-else style="max-width: 230px;">{{ item.content }} |
| | | </p> |
| | | </div> |
| | | </div> |
| | | </li> |
| | | </ul> |
| | | </div> |
| | | <div |
| | | class="bottom flex justify-between h-130 items-center w-full fixed bottom-0 borderTop px-32 box-border bgBottom"> |
| | | <van-uploader :max-size="10000 * 1024" @oversize="onOversize" :after-read="afterRead"> |
| | | <img src="@/assets/image/service/photo.png" class="w-72 h-72" /> |
| | | </van-uploader> |
| | | <input type="text" v-model="value" :placeholder="$t('请输入您的消息...')" |
| | | class="flex-1 mx-20 h-full border-none bgBottom textColor" /> |
| | | <img src="@/assets/image/service/send.png" class="w-72 h-72" @click="send('text', value)" /> |
| | | </div> |
| | | </div> |
| | | <div class="service-box pb-150 flex flex-col"> |
| | | <van-nav-bar |
| | | :title="$t('在线客服')" |
| | | left-arrow |
| | | @click-left="onClickLeft" |
| | | fixed |
| | | /> |
| | | <div class="flex-1" v-if="kefu_url"> |
| | | <iframe |
| | | :src="kefu_url" |
| | | width="100%" |
| | | height="100%" |
| | | frameborder="0" |
| | | ></iframe> |
| | | </div> |
| | | <div v-else class="localKefu flex-1 flex"> |
| | | <div |
| | | class="flex flex-col px-32 box-border flex-1" |
| | | ref="boxScroll" |
| | | style="overflow: auto" |
| | | > |
| | | <div |
| | | class="w-full py-10 text-grey text-center pt-10" |
| | | @click="onMore" |
| | | :style="{ visibility: finished ? 'hidden' : 'visiable' }" |
| | | > |
| | | {{ $t("历史消息") }} |
| | | </div> |
| | | <ul class="flex flex-col pt-20"> |
| | | <li |
| | | v-for="(item, index) in list" |
| | | :key="item.id" |
| | | class="flex flex-col mt-20" |
| | | v-if="item.delete_status == 0" |
| | | > |
| | | <p class="font-26 text-center py-20 text-grey"> |
| | | {{ item.createtime }} |
| | | </p> |
| | | <div |
| | | class="flex" |
| | | :class="item.send_receive === 'send' ? 'justify-end' : ''" |
| | | > |
| | | <template v-if="item.send_receive === 'receive'"> |
| | | <img |
| | | src="@/assets/image/assets-center/logo.png" |
| | | class="w-81 h-81 mr-40" |
| | | /> |
| | | <div |
| | | class="responser px-50 py-35 font-30 rounded-lg font-26 chatBg" |
| | | > |
| | | <p |
| | | class="break-word textColor" |
| | | style="max-width: 230px" |
| | | v-if="item.type === 'text'" |
| | | > |
| | | {{ item.content }} |
| | | </p> |
| | | <img |
| | | v-else |
| | | :src="item.content" |
| | | class="w-200 h-200" |
| | | @click="onPreview(item.content)" |
| | | /> |
| | | </div> |
| | | </template> |
| | | <div |
| | | class="py-25 px-50 responser-two rounded-lg flex flex-col chatBg" |
| | | v-else |
| | | > |
| | | <img |
| | | :src="`${item.content}`" |
| | | class="w-200 h-200" |
| | | v-if="item.type === 'img'" |
| | | @click="onPreview(item.content)" |
| | | /> |
| | | <p class="break-word textColor" v-else style="max-width: 230px"> |
| | | {{ item.content }} |
| | | </p> |
| | | </div> |
| | | </div> |
| | | </li> |
| | | </ul> |
| | | </div> |
| | | <div |
| | | class="bottom flex justify-between h-130 items-center w-full fixed bottom-0 borderTop px-32 box-border bgBottom" |
| | | > |
| | | <van-uploader |
| | | :max-size="10000 * 1024" |
| | | @oversize="onOversize" |
| | | :after-read="afterRead" |
| | | > |
| | | <img src="@/assets/image/service/photo.png" class="w-72 h-72" /> |
| | | </van-uploader> |
| | | <input |
| | | type="text" |
| | | v-model="value" |
| | | :placeholder="$t('请输入您的消息...')" |
| | | class="flex-1 mx-20 h-full border-none bgBottom textColor" |
| | | /> |
| | | <span @click="send('text', value)"> |
| | | <img src="@/assets/image/service/send.png" class="w-72 h-72" /> |
| | | </span> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | import { mapGetters } from "vuex"; |
| | | import { _getMsg, _getUnreadMsg, _sendMsg } from '@/API/im.api' |
| | | import { _uploadImage } from '@/API/fund.api' |
| | | import { Uploader, ImagePreview } from 'vant' |
| | | import { _getMsg, _getUnreadMsg, _sendMsg } from "@/API/im.api"; |
| | | import { _uploadImage } from "@/API/fund.api"; |
| | | import { Uploader, ImagePreview } from "vant"; |
| | | export default { |
| | | name: 'CustomerService', |
| | | components: { |
| | | [Uploader.name]: Uploader |
| | | name: "CustomerService", |
| | | components: { |
| | | [Uploader.name]: Uploader, |
| | | }, |
| | | data() { |
| | | return { |
| | | list: [], |
| | | value: "", |
| | | lastMsgId: "", |
| | | interval: null, |
| | | unread: 0, |
| | | finished: false, // 没有历史消息 |
| | | currentScrollTop: 0, |
| | | isScrollBottom: false, |
| | | }; |
| | | }, |
| | | computed: { |
| | | ...mapGetters("home", ["kefu_url"]), |
| | | }, |
| | | created() { |
| | | this.fetchList(); |
| | | }, |
| | | mounted() { |
| | | window.addEventListener("scroll", this.handleScroll, true); |
| | | }, |
| | | methods: { |
| | | onOversize(file) { |
| | | console.log(file); |
| | | this.$toast(this.$t("文件大小不能超过10m")); |
| | | }, |
| | | data() { |
| | | return { |
| | | list: [], |
| | | value: '', |
| | | lastMsgId: '', |
| | | interval: null, |
| | | unread: 0, |
| | | finished: false, // 没有历史消息 |
| | | currentScrollTop: 0, |
| | | isScrollBottom: false |
| | | onPreview(url) { |
| | | // 预览 |
| | | ImagePreview([url]); |
| | | }, |
| | | showTime(index) { |
| | | // 时间显示 |
| | | if (index === 0) { |
| | | return true; |
| | | } |
| | | if (index === this.list.length - 1) { |
| | | return false; |
| | | } |
| | | if ( |
| | | this.list[index].createtime.split(" ")[0] === |
| | | this.list[index + 1].createtime.split(" ")[1] |
| | | ) { |
| | | return false; |
| | | } |
| | | }, |
| | | afterRead(file) { |
| | | // 文件上传 |
| | | this.$toast.loading({ duration: 0 }); |
| | | _uploadImage(file, (percent) => { |
| | | console.log(percent); |
| | | }) |
| | | .then((data) => { |
| | | this.$toast.clear(); |
| | | this.send("img", data); |
| | | }) |
| | | .catch(() => { |
| | | this.$toast.clear(); |
| | | file.status = "failed"; |
| | | file.message = this.$t("图片上传失败"); |
| | | }); |
| | | }, |
| | | fetchList(message_id = "") { |
| | | // 获取消息列表 |
| | | _getMsg({ message_id }).then((data) => { |
| | | // this.lastMsgId |
| | | if (!this.lastMsgId) { |
| | | this.lastMsgId = data.length && data[data.length - 1]["id"]; |
| | | } |
| | | }, |
| | | computed: { |
| | | ...mapGetters('home', ['kefu_url']) |
| | | }, |
| | | created() { |
| | | this.fetchList() |
| | | }, |
| | | mounted() { |
| | | window.addEventListener('scroll', this.handleScroll, true) |
| | | }, |
| | | methods: { |
| | | onOversize(file) { |
| | | console.log(file); |
| | | this.$toast(this.$t('文件大小不能超过10m')); |
| | | }, |
| | | onPreview(url) { // 预览 |
| | | ImagePreview([url]) |
| | | }, |
| | | showTime(index) { // 时间显示 |
| | | if (index === 0) { |
| | | return true |
| | | } |
| | | if (index === this.list.length - 1) { |
| | | return false |
| | | } |
| | | if (this.list[index].createtime.split(' ')[0] === this.list[index + 1].createtime.split(' ')[1]) { |
| | | return false |
| | | } |
| | | }, |
| | | afterRead(file) { // 文件上传 |
| | | this.$toast.loading({ duration: 0 }) |
| | | _uploadImage(file, (percent) => { |
| | | console.log(percent) |
| | | }).then(data => { |
| | | this.$toast.clear() |
| | | this.send('img', data) |
| | | }).catch(() => { |
| | | this.$toast.clear(); |
| | | file.status = 'failed'; |
| | | file.message = this.$t('图片上传失败'); |
| | | }) |
| | | }, |
| | | fetchList(message_id = '') { // 获取消息列表 |
| | | _getMsg({ message_id }).then(data => { // this.lastMsgId |
| | | if (!this.lastMsgId) { |
| | | this.lastMsgId = data.length && data[data.length - 1]['id'] |
| | | } |
| | | if (data.length) { |
| | | if (message_id) { // 加载更多 |
| | | this.lastMsgId = data[data.length - 1]['id'] |
| | | this.list = [...data.reverse(), ...this.list] |
| | | } else { |
| | | let list = [...this.list, ...data.reverse()] |
| | | let hash = {}; |
| | | list = list.reverse().reduce(function (preVal, curVal) { |
| | | hash[curVal.id] ? ' ' : hash[curVal.id] = true && preVal.push(curVal); |
| | | return preVal |
| | | }, []); |
| | | this.list = list.reverse() |
| | | } |
| | | if (this.isScrollBottom) { |
| | | this.$refs.boxScroll.scrollTop = this.$refs.boxScroll.scrollHeight - this.$refs.boxScroll.offsetHeight |
| | | } |
| | | this.currentScrollTop = this.$refs.boxScroll.scrollTop; |
| | | if (data.length < 10) { |
| | | this.finished = true |
| | | } |
| | | } |
| | | |
| | | // else { |
| | | // this.list = [{ id: '1', send_receive: 'receive', content: this.$t('你好,欢迎来到我们的数字货币平台!'), type: 'text'}] |
| | | // } |
| | | if (!message_id) { |
| | | this.clearInterval() |
| | | this.interval = setInterval(() => { |
| | | this.fetchList() |
| | | }, 1000) |
| | | } |
| | | }) |
| | | }, |
| | | handleScroll() { |
| | | if (this.$refs.boxScroll.scrollTop == this.currentScrollTop) { |
| | | this.isScrollBottom = true |
| | | } else { |
| | | this.isScrollBottom = false |
| | | } |
| | | }, |
| | | onMore() { // 加载更多 |
| | | this.fetchList(this.lastMsgId) |
| | | }, |
| | | clearInterval() { |
| | | if (this.interval) { |
| | | clearInterval(this.interval) |
| | | this.interval = null |
| | | } |
| | | }, |
| | | fetchUnread() { // 获取未读 |
| | | _getUnreadMsg().then(data => { |
| | | this.unread = data |
| | | }) |
| | | }, |
| | | onClickLeft() { // 返回 |
| | | this.$router.go(-1); |
| | | }, |
| | | send(type = 'text', content = '') { // 发送消息, img 也当消息text |
| | | if (!content) { |
| | | this.$toast(this.$t('请输入消息内容')) |
| | | return |
| | | } |
| | | _sendMsg(type, content).then(data => { |
| | | console.log(data) |
| | | this.isScrollBottom = true |
| | | this.value = '' |
| | | // document.getElementById('bottom').click() |
| | | }) |
| | | if (data.length) { |
| | | if (message_id) { |
| | | // 加载更多 |
| | | this.lastMsgId = data[data.length - 1]["id"]; |
| | | this.list = [...data.reverse(), ...this.list]; |
| | | } else { |
| | | let list = [...this.list, ...data.reverse()]; |
| | | let hash = {}; |
| | | list = list.reverse().reduce(function (preVal, curVal) { |
| | | hash[curVal.id] |
| | | ? " " |
| | | : (hash[curVal.id] = true && preVal.push(curVal)); |
| | | return preVal; |
| | | }, []); |
| | | this.list = list.reverse(); |
| | | } |
| | | if (this.isScrollBottom) { |
| | | this.$refs.boxScroll.scrollTop = |
| | | this.$refs.boxScroll.scrollHeight - |
| | | this.$refs.boxScroll.offsetHeight; |
| | | } |
| | | this.currentScrollTop = this.$refs.boxScroll.scrollTop; |
| | | if (data.length < 10) { |
| | | this.finished = true; |
| | | } |
| | | } |
| | | |
| | | // else { |
| | | // this.list = [{ id: '1', send_receive: 'receive', content: this.$t('你好,欢迎来到我们的数字货币平台!'), type: 'text'}] |
| | | // } |
| | | if (!message_id) { |
| | | this.clearInterval(); |
| | | this.interval = setInterval(() => { |
| | | this.fetchList(); |
| | | }, 1000); |
| | | } |
| | | }); |
| | | }, |
| | | beforeDestroy() { |
| | | this.clearInterval() |
| | | handleScroll() { |
| | | if (this.$refs.boxScroll.scrollTop == this.currentScrollTop) { |
| | | this.isScrollBottom = true; |
| | | } else { |
| | | this.isScrollBottom = false; |
| | | } |
| | | }, |
| | | activated() { |
| | | window.addEventListener('scroll', this.handleScroll, true) |
| | | onMore() { |
| | | // 加载更多 |
| | | this.fetchList(this.lastMsgId); |
| | | }, |
| | | deactivated() { |
| | | this.clearInterval() |
| | | window.removeEventListener('scroll', this.handleScroll) |
| | | clearInterval() { |
| | | if (this.interval) { |
| | | clearInterval(this.interval); |
| | | this.interval = null; |
| | | } |
| | | }, |
| | | destroyed() { |
| | | window.removeEventListener('scroll', this.handleScroll) |
| | | } |
| | | } |
| | | fetchUnread() { |
| | | // 获取未读 |
| | | _getUnreadMsg().then((data) => { |
| | | this.unread = data; |
| | | }); |
| | | }, |
| | | onClickLeft() { |
| | | // 返回 |
| | | this.$router.go(-1); |
| | | }, |
| | | send(type = "text", content = "") { |
| | | // 发送消息, img 也当消息text |
| | | if (!content) { |
| | | this.$toast(this.$t("请输入消息内容")); |
| | | return; |
| | | } |
| | | _sendMsg(type, content).then((data) => { |
| | | console.log(data); |
| | | this.isScrollBottom = true; |
| | | this.value = ""; |
| | | // document.getElementById('bottom').click() |
| | | }); |
| | | }, |
| | | }, |
| | | beforeDestroy() { |
| | | this.clearInterval(); |
| | | }, |
| | | activated() { |
| | | window.addEventListener("scroll", this.handleScroll, true); |
| | | }, |
| | | deactivated() { |
| | | this.clearInterval(); |
| | | window.removeEventListener("scroll", this.handleScroll); |
| | | }, |
| | | destroyed() { |
| | | window.removeEventListener("scroll", this.handleScroll); |
| | | }, |
| | | }; |
| | | </script> |
| | | <style lang="scss" scoped> |
| | | .service-box { |
| | | width: 100%; |
| | | height: 100%; |
| | | box-sizing: border-box; |
| | | width: 100%; |
| | | height: 100%; |
| | | box-sizing: border-box; |
| | | |
| | | ::v-deep .van-hairline--bottom::after { |
| | | @include themify() { |
| | | border-color: themed("border_color"); |
| | | } |
| | | ::v-deep .van-hairline--bottom::after { |
| | | @include themify() { |
| | | border-color: themed("border_color"); |
| | | } |
| | | } |
| | | } |
| | | |
| | | .break-word { |
| | | word-wrap: break-word; |
| | | white-space: pre-wrap; |
| | | word-wrap: break-word; |
| | | white-space: pre-wrap; |
| | | } |
| | | |
| | | .max-w-230 { |
| | | max-width: 230px; |
| | | max-width: 230px; |
| | | } |
| | | |
| | | .responser { |
| | | position: relative; |
| | | position: relative; |
| | | |
| | | &::after { |
| | | content: ''; |
| | | width: 0; |
| | | height: 0; |
| | | border-top: 10px solid transparent; |
| | | border-bottom: 10px solid transparent; |
| | | &::after { |
| | | content: ""; |
| | | width: 0; |
| | | height: 0; |
| | | border-top: 10px solid transparent; |
| | | border-bottom: 10px solid transparent; |
| | | |
| | | @include themify() { |
| | | border-right: 2px solid themed("chat_bg"); |
| | | } |
| | | |
| | | position: absolute; |
| | | left: -20px; |
| | | top: 20px; |
| | | @include themify() { |
| | | border-right: 2px solid themed("chat_bg"); |
| | | } |
| | | |
| | | position: absolute; |
| | | left: -20px; |
| | | top: 20px; |
| | | } |
| | | } |
| | | |
| | | .responser-two { |
| | | position: relative; |
| | | position: relative; |
| | | |
| | | &::after { |
| | | content: ''; |
| | | width: 0; |
| | | height: 0; |
| | | border-bottom: 10px solid transparent; |
| | | border-top: 10px solid transparent; |
| | | &::after { |
| | | content: ""; |
| | | width: 0; |
| | | height: 0; |
| | | border-bottom: 10px solid transparent; |
| | | border-top: 10px solid transparent; |
| | | |
| | | @include themify() { |
| | | border-left: 20px solid themed("chat_bg"); |
| | | } |
| | | |
| | | position: absolute; |
| | | right: -19px; |
| | | top: 20px; |
| | | @include themify() { |
| | | border-left: 20px solid themed("chat_bg"); |
| | | } |
| | | |
| | | position: absolute; |
| | | right: -19px; |
| | | top: 20px; |
| | | } |
| | | } |
| | | |
| | | .borderTop { |
| | | @include themify() { |
| | | border-top: 1px solid themed("border_color"); |
| | | } |
| | | @include themify() { |
| | | border-top: 1px solid themed("border_color"); |
| | | } |
| | | } |
| | | |
| | | .localKefu { |
| | | overflow: auto; |
| | | padding-bottom: 40px; |
| | | overflow: auto; |
| | | padding-bottom: 40px; |
| | | } |
| | | |
| | | .van-nav-bar--fixed { |
| | | position: relative !important; |
| | | position: relative !important; |
| | | } |
| | | |
| | | .bottom { |
| | | margin-bottom: constant(safe-area-inset-bottom); |
| | | margin-bottom: env(safe-area-inset-bottom); |
| | | margin-bottom: constant(safe-area-inset-bottom); |
| | | margin-bottom: env(safe-area-inset-bottom); |
| | | } |
| | | </style> |