From a0a85d13e9f8387678037cc2b6913b56b30f9b23 Mon Sep 17 00:00:00 2001
From: admin <344137771@qq.com>
Date: Tue, 03 Feb 2026 18:04:12 +0800
Subject: [PATCH] 1
---
/dev/null | 396 ---------------
src/views/customerService/index - 接外链版本.vue | 377 +++++++++++++++
src/views/customerService/index.vue | 707 ++++++++++++++-------------
3 files changed, 740 insertions(+), 740 deletions(-)
diff --git "a/src/views/customerService/index - \345\211\257\346\234\254.vue" "b/src/views/customerService/index - \345\211\257\346\234\254.vue"
deleted file mode 100644
index 2fe2cf0..0000000
--- "a/src/views/customerService/index - \345\211\257\346\234\254.vue"
+++ /dev/null
@@ -1,396 +0,0 @@
-<template>
- <div class="service-box flex flex-col" :class="homesStore.kefu_url ? '' : 'pb-40'">
- <div>
- <van-nav-bar ref="navEl" :title="$t('onLineService')" left-arrow @click-left="onClickLeft" fixed />
- <div class="px-3.5 py-5" v-if="state == 0">
- <div class="white">{{ $t('OrdersWill') }} <span style="color: #1194F7">{{ dayjs.duration(remainingTime,
- 'seconds').format('mm:ss') }}</span> {{
- $t('afterCancel')
- }}</div>
- <div class="mt-3">
- <span class="mr-1" style="color: #8A919E">{{ $t('lumpSum') }}</span>
- <span class="white">{{ payInfo.currency }} {{ payInfo.amount }}</span>
- </div>
- <div class="mt-5">
- <van-button class="w-full" type="primary" @click="router.back()">{{ $t('toPay') }}</van-button>
- </div>
- </div>
- </div>
- <div class="flex-1" v-if="homesStore.kefu_url">
- <iframe :src="generateExtranetLink()" width="100%" height="100%" frameborder="0"></iframe>
- </div>
- <div class="localKefu flex-1 flex" v-else>
- <div class="flex flex-col px-10 box-border" ref="boxScrollEl" style="overflow:auto;">
- <div class="w-full py-4 text-grey text-center pt-30 text-30" @click="onMore"
- :style="{ 'display': finished ? 'none' : 'block' }">
- {{ $t('historyMessage') }}
- </div>
- <ul class="flex flex-col pt-3">
- <li v-for="(item, index) in list" :key="item.id" class="flex flex-col my-3">
- <!-- <p class="text-center py-2 text-grey text-30" v-if="showTime(index)">{{
- item.createtime &&
- item.createtime.split(' ')[0]
- }}</p> -->
- <template v-if="item.delete_status != -1">
- <p class="text-center pb-3 text-grey text-30">{{
- item.createtime
- }}</p>
- <div class="flex" :class="item.send_receive === 'send' ? 'justify-end' : ''">
- <template v-if="item.send_receive === 'receive'">
- <img src="@/assets/image/service/responser.png" class="w-20 h-20 mr-5" />
- <div class="responser px-12 py-8 text-30 left-chatBg">
- <p class="break-word textColor text-30" style="max-width: 200px;"
- v-if="item.content_type === 'text' || 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-8 px-12 rounded-md flex flex-col right-chatBg" v-else>
- <img :src="`${item.content}`" class="w-200 h-200"
- v-if="item.content_type === 'img' || item.type === 'img'" @click="onPreview(item.content)" />
- <p class="break-word text-white text-30" v-else style="max-width: 200px;">{{ item.content }}</p>
- </div>
- </div>
- </template>
- </li>
- </ul>
- </div>
-
- <div
- class="bottom bottomBox flex justify-between items-center w-full fixed bottom-0 borderTop px-4 box-border bgBottom">
- <van-uploader :max-size="10000 * 1024" @oversize="onOversize" :after-read="afterRead">
- <img src="@/assets/image/service/photo2.png" class="w-12 h-12" />
- </van-uploader>
- <input type="text" v-model="message" :placeholder="$t('entryYouMessage')"
- class="flex-1 mx-3 h-full border-none textColor chatBg" maxlength="500" />
- <img src="@/assets/image/service/send2.png" class="w-12 h-12" @click="throttleSend(message)" />
- </div>
- </div>
- </div>
-</template>
-
-<script setup>
-import { Uploader, showImagePreview } from 'vant'
-import { _getMsg, _getUnreadMsg, _sendMsg } from '@/service/im.api'
-import { _uploadImage } from '@/service/upload.api'
-import { ref, onMounted, onUnmounted, onBeforeMount } from "vue";
-import { useI18n } from "vue-i18n";
-import { throttle } from '@/utils/index'
-import { closeToast, showToast, showLoadingToast } from "vant";
-import { useRoute, useRouter } from 'vue-router';
-import { getc2cOrder } from "@/service/recharge.api.js";
-import { useHomesStore } from "@/store/homes.store";
-import { SET_KEFU } from "@/store/types.store";
-import { useUserStore } from '@/store/user';
-import dayjs from 'dayjs';
-import duration from 'dayjs/plugin/duration';
-dayjs.extend(duration);
-
-const userStore = useUserStore()
-const { t } = useI18n()
-const homesStore = useHomesStore();
-const router = useRouter()
-const route = useRoute()
-const list = ref([])
-const message = ref('')
-const lastMsgId = ref('')
-const interval = ref(null)
-const unread = ref(0)
-const finished = ref(false)
-const isScrollBottom = ref(true)
-const currentScrollTop = ref(0)
-const androidAttrs = ref(null)
-const navEl = ref(null);
-const boxScrollEl = ref(null);
-const navHeight = ref(0);
-const payInfo = ref({})
-const remainingTime = ref(0)
-
-let state = ref(null)
-let orderNo = ""
-let partyId = ""
-onMounted(() => {
- // 美洽客服
- // const _ll="&id="+_id.value+"&name="+_name.value
- const _ll=""
- // console.log(_ll)
- const _uull='https://cdn.chat20gm.cfd/chat_online/index?channelId=1958101585091772416'+_ll;
- window.location.href=_uull
-
-})
-// onMounted_bak(() => {
-// orderNo = ""
-// partyId = ""
-// navHeight.value = navEl.value.$el.getBoundingClientRect().height
-// if (route.query.order_no) {
-// getc2cOrderDetails(route.query.order_no, (data) => {
-// console.log("getc2cOrderDetails = " + JSON.stringify(data))
-// orderNo = data.orderNo;
-// partyId = data.partyId;
-// fetchList()
-// })
-// } else {
-// if (!homesStore.kefu_url) {
-// fetchList()
-// }
-// }
-// setInterval(() => {
-// getCountdown()
-// }, 1000)
-// const model = navigator.userAgent;
-// // 判断是否是安卓手机,是则是true
-// androidAttrs.value = model.indexOf('Android') > -1 || model.indexOf('Linux') > -1
-// window.addEventListener('scroll', handleScroll, true)
-// })
-
-onBeforeMount(() => {
- homesStore[SET_KEFU]()
-})
-
-//获取订单详情
-const getc2cOrderDetails = (orderNo, call) => {
- getc2cOrder({ order_no: orderNo }).then((res) => {
- payInfo.value = res
- state.value = payInfo.value.state
- remainingTime.value = res.autoCancelTimeRemain
- if (call) { call(res) }
- })
-}
-
-//第三方客服带用户id
-const generateExtranetLink = () => {
- let extranetLink = ''
- if (userStore.userInfo && userStore.userInfo.usercode) {
- const userData = encodeURIComponent(JSON.stringify({ name: userStore.userInfo.usercode, comment: '' }))
- let params = `&clientid=${userStore.userInfo.usercode}&metadata=${userData}`;
- extranetLink = homesStore.kefu_url + params;
- } else {
- extranetLink = homesStore.kefu_url
- }
- // extranetLink = homesStore.kefu_url + params;
- console.log('generateExtranetLink', extranetLink)
- // console.log('extranetLink',extranetLink)
- return extranetLink;
-}
-
-const throttleSend = throttle((message) => {
- send('text', message)
-}, 500)
-
-const onOversize = (file) => {
- showToast(t('fileMaxLimit'));
-}
-const onPreview = (url) => { // 预览
- showImagePreview([url])
-}
-const showTime = (index) => { // 时间显示
- if (index === 0) {
- return true
- }
- if (index === list.value.length - 1) {
- return false
- }
- if (list.value[index].createtime.split(' ')[0] === list.value[index + 1].createtime.split(' ')[1]) {
- return false
- }
-}
-const afterRead = (file) => { // 文件上传
- showLoadingToast({ duration: 0 })
- _uploadImage(file, (percent) => {
- console.log(percent)
- }).then(data => {
- closeToast()
- send('img', data)
- }).catch(() => {
- showToast(t('失败'))
- })
-}
-const fetchList = async (message_id = '') => { // 获取消息列表
- console.log("orderNo = " + orderNo);
- console.log("partyId = " + partyId);
- _getMsg({ message_id }, orderNo, partyId).then(data => { //
- if (!lastMsgId.value) {
- lastMsgId.value = data.length && data[data.length - 1]['id']
- }
- if (data.length) {
- if (message_id) { // 加载更多
- lastMsgId.value = data[data.length - 1]['id']
- list.value = [...data.reverse(), ...list.value]
- } else {
- list.value = [...list.value, ...data.reverse()]
- let hash = {};
- list.value = list.value.reduce(function (preVal, curVal) {
- hash[curVal.id] ? ' ' : hash[curVal.id] = true && preVal.push(curVal);
- return preVal
- }, []);
- list.value.forEach((item, index) => {
- data.forEach((item2, index2) => {
- if (item.id === item2.id) {
- item.delete_status = item2.delete_status
- }
- })
- })
-
- }
-
- if (isScrollBottom.value) {
- boxScrollEl.value.scrollTop = boxScrollEl.value.scrollHeight - boxScrollEl.value.offsetHeight
- }
- currentScrollTop.value = boxScrollEl.value.scrollTop;
- if (data.length < 10) {
- finished.value = true
- }
- }
- if (!message_id) {
- clearIntervalTimer()
- interval.value = setInterval(() => {
- fetchList()
- }, 1000)
- }
- })
-}
-
-const handleScroll = () => {
- if (boxScrollEl.value) {
- if (boxScrollEl.value.scrollTop === currentScrollTop.value) {
- isScrollBottom.value = true
- } else {
- isScrollBottom.value = false
- }
- }
-}
-
-const onMore = () => { // 加载更多
- fetchList(lastMsgId.value)
-}
-const clearIntervalTimer = () => {
- if (interval.value) {
- clearInterval(interval.value)
- interval.value = null
- }
-}
-const fetchUnread = () => { // 获取未读
- _getUnreadMsg(orderNo, partyId).then(data => {
- unread.value = data
- })
-}
-const onClickLeft = () => { // 返回
- router.go(-1);
-}
-const send = (type = 'text', content = '') => { // 发送消息, img 也当消息text
- if (!content) {
- showToast(t('entryMessageContent'))
- return
- }
- _sendMsg(type, content, orderNo, partyId).then(async data => {
- message.value = ''
- isScrollBottom.value = true
- // document.getElementById('bottom').click()
- // await fetchList()
- })
-}
-const getCountdown = () => {
- if (remainingTime.value > 0) {
- remainingTime.value = remainingTime.value - 1
- } else {
- remainingTime.value = 0
- }
-}
-
-onUnmounted(() => {
- clearIntervalTimer()
-})
-
-</script>
-<style lang="scss" scoped>
-.service-box {
- font-size: 14px;
- width: 100%;
- height: 100vh;
- box-sizing: border-box;
- background: $mainBgColor;
- overflow: hidden;
-
- :deep(.van-hairline--bottom::after) {
- border-color: $mainBgColor;
- }
-}
-
-.break-word {
- word-wrap: break-word;
- white-space: pre-wrap;
-}
-
-.max-w-230 {
- max-width: 115px;
-}
-
-.responser {
- position: relative;
-
- &::after {
- content: '';
- width: 0;
- height: 0;
- border-top: 5px solid transparent;
- border-bottom: 5px solid transparent;
- border-right: 10px solid $input_background;
- position: absolute;
- left: -10px;
- top: 10px;
- }
-}
-
-.borderTop {
- border-top: 1px solid $border_color;
-}
-
-.bottomBox {
- height: 65px;
-}
-
-.white {
- color: $text_color;
-}
-
-.chatBg {
- background: $input_background;
- height: 36px;
- padding: 8px 18px;
- border-radius: 18px;
- color: $text_color;
- font-size: 14px;
- border: 1px solid $chat-border;
-}
-
-.right-chatBg {
- position: relative;
- background: $color_main;
- color: $text_color;
-
- &::after {
- content: '';
- width: 0;
- height: 0;
- border-top: 5px solid transparent;
- border-bottom: 5px solid transparent;
- border-left: 10px solid $color_main;
- position: absolute;
- right: -8px;
- top: 14px;
- }
-}
-
-.left-chatBg {
- background: $input_background;
-}
-
-.localKefu {
- overflow: auto;
- flex-direction: column;
-}
-
-.van-nav-bar--fixed {
- position: relative !important;
-}
-</style>
diff --git "a/src/views/customerService/index - \346\216\245\345\244\226\351\223\276\347\211\210\346\234\254.vue" "b/src/views/customerService/index - \346\216\245\345\244\226\351\223\276\347\211\210\346\234\254.vue"
new file mode 100644
index 0000000..1d77954
--- /dev/null
+++ "b/src/views/customerService/index - \346\216\245\345\244\226\351\223\276\347\211\210\346\234\254.vue"
@@ -0,0 +1,377 @@
+<template>
+ <div class="service-box flex flex-col pb-40">
+ <iframe height="100%" src="https://cdn.chat20gm.cfd/chat_online/index?channelId=1958101585091772416"></iframe>
+ </div>
+</template>
+
+<script setup>
+ import {
+ Uploader,
+ showImagePreview
+ } from 'vant'
+ import {
+ _getMsg,
+ _getUnreadMsg,
+ _sendMsg
+ } from '@/service/im.api'
+ import {
+ _uploadImage
+ } from '@/service/upload.api'
+ import {
+ ref,
+ onMounted,
+ onUnmounted,
+ onBeforeMount
+ } from "vue";
+ import {
+ useI18n
+ } from "vue-i18n";
+ import {
+ throttle
+ } from '@/utils/index'
+ import {
+ closeToast,
+ showToast,
+ showLoadingToast
+ } from "vant";
+ import {
+ useRoute,
+ useRouter
+ } from 'vue-router';
+ import {
+ getc2cOrder
+ } from "@/service/recharge.api.js";
+ import {
+ useHomesStore
+ } from "@/store/homes.store";
+ import {
+ SET_KEFU
+ } from "@/store/types.store";
+ import {
+ useUserStore
+ } from '@/store/user';
+ import dayjs from 'dayjs';
+ import duration from 'dayjs/plugin/duration';
+ dayjs.extend(duration);
+
+ const userStore = useUserStore()
+ const {
+ t
+ } = useI18n()
+ const homesStore = useHomesStore();
+ const router = useRouter()
+ const route = useRoute()
+ const list = ref([])
+ const message = ref('')
+ const lastMsgId = ref('')
+ const interval = ref(null)
+ const unread = ref(0)
+ const finished = ref(false)
+ const isScrollBottom = ref(true)
+ const currentScrollTop = ref(0)
+ const androidAttrs = ref(null)
+ const navEl = ref(null);
+ const boxScrollEl = ref(null);
+ const navHeight = ref(0);
+ const payInfo = ref({})
+ const remainingTime = ref(0)
+
+ let state = ref(null)
+ let orderNo = ""
+ let partyId = ""
+ onMounted(() => {
+ // 美洽客服
+ // const _ll="&id="+_id.value+"&name="+_name.value
+ // const _ll=""
+ // console.log(_ll)
+ // const _uull='https://cdn.chat20gm.cfd/chat_online/index?channelId=1958101585091772416'+_ll;
+ // window.location.href=_uull
+
+ })
+ // onMounted_bak(() => {
+ // orderNo = ""
+ // partyId = ""
+ // navHeight.value = navEl.value.$el.getBoundingClientRect().height
+ // if (route.query.order_no) {
+ // getc2cOrderDetails(route.query.order_no, (data) => {
+ // console.log("getc2cOrderDetails = " + JSON.stringify(data))
+ // orderNo = data.orderNo;
+ // partyId = data.partyId;
+ // fetchList()
+ // })
+ // } else {
+ // if (!homesStore.kefu_url) {
+ // fetchList()
+ // }
+ // }
+ // setInterval(() => {
+ // getCountdown()
+ // }, 1000)
+ // const model = navigator.userAgent;
+ // // 判断是否是安卓手机,是则是true
+ // androidAttrs.value = model.indexOf('Android') > -1 || model.indexOf('Linux') > -1
+ // window.addEventListener('scroll', handleScroll, true)
+ // })
+
+ onBeforeMount(() => {
+ homesStore[SET_KEFU]()
+ })
+
+ //获取订单详情
+ const getc2cOrderDetails = (orderNo, call) => {
+ getc2cOrder({
+ order_no: orderNo
+ }).then((res) => {
+ payInfo.value = res
+ state.value = payInfo.value.state
+ remainingTime.value = res.autoCancelTimeRemain
+ if (call) {
+ call(res)
+ }
+ })
+ }
+
+ //第三方客服带用户id
+ const generateExtranetLink = () => {
+ let extranetLink = ''
+ if (userStore.userInfo && userStore.userInfo.usercode) {
+ const userData = encodeURIComponent(JSON.stringify({
+ name: userStore.userInfo.usercode,
+ comment: ''
+ }))
+ let params = `&clientid=${userStore.userInfo.usercode}&metadata=${userData}`;
+ extranetLink = homesStore.kefu_url + params;
+ } else {
+ extranetLink = homesStore.kefu_url
+ }
+ // extranetLink = homesStore.kefu_url + params;
+ console.log('generateExtranetLink', extranetLink)
+ // console.log('extranetLink',extranetLink)
+ return extranetLink;
+ }
+
+ const throttleSend = throttle((message) => {
+ send('text', message)
+ }, 500)
+
+ const onOversize = (file) => {
+ showToast(t('fileMaxLimit'));
+ }
+ const onPreview = (url) => { // 预览
+ showImagePreview([url])
+ }
+ const showTime = (index) => { // 时间显示
+ if (index === 0) {
+ return true
+ }
+ if (index === list.value.length - 1) {
+ return false
+ }
+ if (list.value[index].createtime.split(' ')[0] === list.value[index + 1].createtime.split(' ')[1]) {
+ return false
+ }
+ }
+ const afterRead = (file) => { // 文件上传
+ showLoadingToast({
+ duration: 0
+ })
+ _uploadImage(file, (percent) => {
+ console.log(percent)
+ }).then(data => {
+ closeToast()
+ send('img', data)
+ }).catch(() => {
+ showToast(t('失败'))
+ })
+ }
+ const fetchList = async (message_id = '') => { // 获取消息列表
+ console.log("orderNo = " + orderNo);
+ console.log("partyId = " + partyId);
+ _getMsg({
+ message_id
+ }, orderNo, partyId).then(data => { //
+ if (!lastMsgId.value) {
+ lastMsgId.value = data.length && data[data.length - 1]['id']
+ }
+ if (data.length) {
+ if (message_id) { // 加载更多
+ lastMsgId.value = data[data.length - 1]['id']
+ list.value = [...data.reverse(), ...list.value]
+ } else {
+ list.value = [...list.value, ...data.reverse()]
+ let hash = {};
+ list.value = list.value.reduce(function(preVal, curVal) {
+ hash[curVal.id] ? ' ' : hash[curVal.id] = true && preVal.push(curVal);
+ return preVal
+ }, []);
+ list.value.forEach((item, index) => {
+ data.forEach((item2, index2) => {
+ if (item.id === item2.id) {
+ item.delete_status = item2.delete_status
+ }
+ })
+ })
+
+ }
+
+ if (isScrollBottom.value) {
+ boxScrollEl.value.scrollTop = boxScrollEl.value.scrollHeight - boxScrollEl.value
+ .offsetHeight
+ }
+ currentScrollTop.value = boxScrollEl.value.scrollTop;
+ if (data.length < 10) {
+ finished.value = true
+ }
+ }
+ if (!message_id) {
+ clearIntervalTimer()
+ interval.value = setInterval(() => {
+ fetchList()
+ }, 1000)
+ }
+ })
+ }
+
+ const handleScroll = () => {
+ if (boxScrollEl.value) {
+ if (boxScrollEl.value.scrollTop === currentScrollTop.value) {
+ isScrollBottom.value = true
+ } else {
+ isScrollBottom.value = false
+ }
+ }
+ }
+
+ const onMore = () => { // 加载更多
+ fetchList(lastMsgId.value)
+ }
+ const clearIntervalTimer = () => {
+ if (interval.value) {
+ clearInterval(interval.value)
+ interval.value = null
+ }
+ }
+ const fetchUnread = () => { // 获取未读
+ _getUnreadMsg(orderNo, partyId).then(data => {
+ unread.value = data
+ })
+ }
+ const onClickLeft = () => { // 返回
+ router.go(-1);
+ }
+ const send = (type = 'text', content = '') => { // 发送消息, img 也当消息text
+ if (!content) {
+ showToast(t('entryMessageContent'))
+ return
+ }
+ _sendMsg(type, content, orderNo, partyId).then(async data => {
+ message.value = ''
+ isScrollBottom.value = true
+ // document.getElementById('bottom').click()
+ // await fetchList()
+ })
+ }
+ const getCountdown = () => {
+ if (remainingTime.value > 0) {
+ remainingTime.value = remainingTime.value - 1
+ } else {
+ remainingTime.value = 0
+ }
+ }
+
+ onUnmounted(() => {
+ clearIntervalTimer()
+ })
+</script>
+<style lang="scss" scoped>
+ .service-box {
+ font-size: 14px;
+ width: 100%;
+ height: 100vh;
+ box-sizing: border-box;
+ background: $mainBgColor;
+ overflow: hidden;
+
+ :deep(.van-hairline--bottom::after) {
+ border-color: $mainBgColor;
+ }
+ }
+
+ .break-word {
+ word-wrap: break-word;
+ white-space: pre-wrap;
+ }
+
+ .max-w-230 {
+ max-width: 115px;
+ }
+
+ .responser {
+ position: relative;
+
+ &::after {
+ content: '';
+ width: 0;
+ height: 0;
+ border-top: 5px solid transparent;
+ border-bottom: 5px solid transparent;
+ border-right: 10px solid $input_background;
+ position: absolute;
+ left: -10px;
+ top: 10px;
+ }
+ }
+
+ .borderTop {
+ border-top: 1px solid $border_color;
+ }
+
+ .bottomBox {
+ height: 65px;
+ }
+
+ .white {
+ color: $text_color;
+ }
+
+ .chatBg {
+ background: $input_background;
+ height: 36px;
+ padding: 8px 18px;
+ border-radius: 18px;
+ color: $text_color;
+ font-size: 14px;
+ border: 1px solid $chat-border;
+ }
+
+ .right-chatBg {
+ position: relative;
+ background: $color_main;
+ color: $text_color;
+
+ &::after {
+ content: '';
+ width: 0;
+ height: 0;
+ border-top: 5px solid transparent;
+ border-bottom: 5px solid transparent;
+ border-left: 10px solid $color_main;
+ position: absolute;
+ right: -8px;
+ top: 14px;
+ }
+ }
+
+ .left-chatBg {
+ background: $input_background;
+ }
+
+ .localKefu {
+ overflow: auto;
+ flex-direction: column;
+ }
+
+ .van-nav-bar--fixed {
+ position: relative !important;
+ }
+</style>
\ No newline at end of file
diff --git a/src/views/customerService/index.vue b/src/views/customerService/index.vue
index 1d77954..2f8351f 100644
--- a/src/views/customerService/index.vue
+++ b/src/views/customerService/index.vue
@@ -1,377 +1,396 @@
<template>
- <div class="service-box flex flex-col pb-40">
- <iframe height="100%" src="https://cdn.chat20gm.cfd/chat_online/index?channelId=1958101585091772416"></iframe>
- </div>
+ <div class="service-box flex flex-col" :class="homesStore.kefu_url ? '' : 'pb-40'">
+ <div>
+ <van-nav-bar ref="navEl" :title="$t('onLineService')" left-arrow @click-left="onClickLeft" fixed />
+ <div class="px-3.5 py-5" v-if="state == 0">
+ <div class="white">{{ $t('OrdersWill') }} <span style="color: #1194F7">{{ dayjs.duration(remainingTime,
+ 'seconds').format('mm:ss') }}</span> {{
+ $t('afterCancel')
+ }}</div>
+ <div class="mt-3">
+ <span class="mr-1" style="color: #8A919E">{{ $t('lumpSum') }}</span>
+ <span class="white">{{ payInfo.currency }} {{ payInfo.amount }}</span>
+ </div>
+ <div class="mt-5">
+ <van-button class="w-full" type="primary" @click="router.back()">{{ $t('toPay') }}</van-button>
+ </div>
+ </div>
+ </div>
+ <div class="flex-1" v-if="homesStore.kefu_url">
+ <iframe :src="generateExtranetLink()" width="100%" height="100%" frameborder="0"></iframe>
+ </div>
+ <div class="localKefu flex-1 flex" v-else>
+ <div class="flex flex-col px-10 box-border" ref="boxScrollEl" style="overflow:auto;">
+ <div class="w-full py-4 text-grey text-center pt-30 text-30" @click="onMore"
+ :style="{ 'display': finished ? 'none' : 'block' }">
+ {{ $t('historyMessage') }}
+ </div>
+ <ul class="flex flex-col pt-3">
+ <li v-for="(item, index) in list" :key="item.id" class="flex flex-col my-3">
+ <!-- <p class="text-center py-2 text-grey text-30" v-if="showTime(index)">{{
+ item.createtime &&
+ item.createtime.split(' ')[0]
+ }}</p> -->
+ <template v-if="item.delete_status != -1">
+ <p class="text-center pb-3 text-grey text-30">{{
+ item.createtime
+ }}</p>
+ <div class="flex" :class="item.send_receive === 'send' ? 'justify-end' : ''">
+ <template v-if="item.send_receive === 'receive'">
+ <img src="@/assets/image/service/responser.png" class="w-20 h-20 mr-5" />
+ <div class="responser px-12 py-8 text-30 left-chatBg">
+ <p class="break-word textColor text-30" style="max-width: 200px;"
+ v-if="item.content_type === 'text' || 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-8 px-12 rounded-md flex flex-col right-chatBg" v-else>
+ <img :src="`${item.content}`" class="w-200 h-200"
+ v-if="item.content_type === 'img' || item.type === 'img'" @click="onPreview(item.content)" />
+ <p class="break-word text-white text-30" v-else style="max-width: 200px;">{{ item.content }}</p>
+ </div>
+ </div>
+ </template>
+ </li>
+ </ul>
+ </div>
+
+ <div
+ class="bottom bottomBox flex justify-between items-center w-full fixed bottom-0 borderTop px-4 box-border bgBottom">
+ <van-uploader :max-size="10000 * 1024" @oversize="onOversize" :after-read="afterRead">
+ <img src="@/assets/image/service/photo2.png" class="w-12 h-12" />
+ </van-uploader>
+ <input type="text" v-model="message" :placeholder="$t('entryYouMessage')"
+ class="flex-1 mx-3 h-full border-none textColor chatBg" maxlength="500" />
+ <img src="@/assets/image/service/send2.png" class="w-12 h-12" @click="throttleSend(message)" />
+ </div>
+ </div>
+ </div>
</template>
<script setup>
- import {
- Uploader,
- showImagePreview
- } from 'vant'
- import {
- _getMsg,
- _getUnreadMsg,
- _sendMsg
- } from '@/service/im.api'
- import {
- _uploadImage
- } from '@/service/upload.api'
- import {
- ref,
- onMounted,
- onUnmounted,
- onBeforeMount
- } from "vue";
- import {
- useI18n
- } from "vue-i18n";
- import {
- throttle
- } from '@/utils/index'
- import {
- closeToast,
- showToast,
- showLoadingToast
- } from "vant";
- import {
- useRoute,
- useRouter
- } from 'vue-router';
- import {
- getc2cOrder
- } from "@/service/recharge.api.js";
- import {
- useHomesStore
- } from "@/store/homes.store";
- import {
- SET_KEFU
- } from "@/store/types.store";
- import {
- useUserStore
- } from '@/store/user';
- import dayjs from 'dayjs';
- import duration from 'dayjs/plugin/duration';
- dayjs.extend(duration);
+import { Uploader, showImagePreview } from 'vant'
+import { _getMsg, _getUnreadMsg, _sendMsg } from '@/service/im.api'
+import { _uploadImage } from '@/service/upload.api'
+import { ref, onMounted, onUnmounted, onBeforeMount } from "vue";
+import { useI18n } from "vue-i18n";
+import { throttle } from '@/utils/index'
+import { closeToast, showToast, showLoadingToast } from "vant";
+import { useRoute, useRouter } from 'vue-router';
+import { getc2cOrder } from "@/service/recharge.api.js";
+import { useHomesStore } from "@/store/homes.store";
+import { SET_KEFU } from "@/store/types.store";
+import { useUserStore } from '@/store/user';
+import dayjs from 'dayjs';
+import duration from 'dayjs/plugin/duration';
+dayjs.extend(duration);
- const userStore = useUserStore()
- const {
- t
- } = useI18n()
- const homesStore = useHomesStore();
- const router = useRouter()
- const route = useRoute()
- const list = ref([])
- const message = ref('')
- const lastMsgId = ref('')
- const interval = ref(null)
- const unread = ref(0)
- const finished = ref(false)
- const isScrollBottom = ref(true)
- const currentScrollTop = ref(0)
- const androidAttrs = ref(null)
- const navEl = ref(null);
- const boxScrollEl = ref(null);
- const navHeight = ref(0);
- const payInfo = ref({})
- const remainingTime = ref(0)
+const userStore = useUserStore()
+const { t } = useI18n()
+const homesStore = useHomesStore();
+const router = useRouter()
+const route = useRoute()
+const list = ref([])
+const message = ref('')
+const lastMsgId = ref('')
+const interval = ref(null)
+const unread = ref(0)
+const finished = ref(false)
+const isScrollBottom = ref(true)
+const currentScrollTop = ref(0)
+const androidAttrs = ref(null)
+const navEl = ref(null);
+const boxScrollEl = ref(null);
+const navHeight = ref(0);
+const payInfo = ref({})
+const remainingTime = ref(0)
- let state = ref(null)
- let orderNo = ""
- let partyId = ""
- onMounted(() => {
- // 美洽客服
- // const _ll="&id="+_id.value+"&name="+_name.value
- // const _ll=""
- // console.log(_ll)
- // const _uull='https://cdn.chat20gm.cfd/chat_online/index?channelId=1958101585091772416'+_ll;
- // window.location.href=_uull
+let state = ref(null)
+let orderNo = ""
+let partyId = ""
+// onMounted(() => {
+// // 美洽客服
+// // const _ll="&id="+_id.value+"&name="+_name.value
+// // const _ll=""
- })
- // onMounted_bak(() => {
- // orderNo = ""
- // partyId = ""
- // navHeight.value = navEl.value.$el.getBoundingClientRect().height
- // if (route.query.order_no) {
- // getc2cOrderDetails(route.query.order_no, (data) => {
- // console.log("getc2cOrderDetails = " + JSON.stringify(data))
- // orderNo = data.orderNo;
- // partyId = data.partyId;
- // fetchList()
- // })
- // } else {
- // if (!homesStore.kefu_url) {
- // fetchList()
- // }
- // }
- // setInterval(() => {
- // getCountdown()
- // }, 1000)
- // const model = navigator.userAgent;
- // // 判断是否是安卓手机,是则是true
- // androidAttrs.value = model.indexOf('Android') > -1 || model.indexOf('Linux') > -1
- // window.addEventListener('scroll', handleScroll, true)
- // })
+// // const _uull='https://cdn.chat20gm.cfd/chat_online/index?channelId=1958101585091772416'+_ll;
+// // window.location.href=_uull
+// })
- onBeforeMount(() => {
- homesStore[SET_KEFU]()
- })
+onMounted(() => {
+ orderNo = ""
+ partyId = ""
+ navHeight.value = navEl.value.$el.getBoundingClientRect().height
+ if (route.query.order_no) {
+ getc2cOrderDetails(route.query.order_no, (data) => {
+ console.log("getc2cOrderDetails = " + JSON.stringify(data))
+ orderNo = data.orderNo;
+ partyId = data.partyId;
+ fetchList()
+ })
+ } else {
+ if (!homesStore.kefu_url) {
+ fetchList()
+ }
+ }
+ setInterval(() => {
+ getCountdown()
+ }, 1000)
+ const model = navigator.userAgent;
+ // 判断是否是安卓手机,是则是true
+ androidAttrs.value = model.indexOf('Android') > -1 || model.indexOf('Linux') > -1
+ window.addEventListener('scroll', handleScroll, true)
+})
- //获取订单详情
- const getc2cOrderDetails = (orderNo, call) => {
- getc2cOrder({
- order_no: orderNo
- }).then((res) => {
- payInfo.value = res
- state.value = payInfo.value.state
- remainingTime.value = res.autoCancelTimeRemain
- if (call) {
- call(res)
- }
- })
- }
+onBeforeMount(() => {
+ homesStore[SET_KEFU]()
+})
- //第三方客服带用户id
- const generateExtranetLink = () => {
- let extranetLink = ''
- if (userStore.userInfo && userStore.userInfo.usercode) {
- const userData = encodeURIComponent(JSON.stringify({
- name: userStore.userInfo.usercode,
- comment: ''
- }))
- let params = `&clientid=${userStore.userInfo.usercode}&metadata=${userData}`;
- extranetLink = homesStore.kefu_url + params;
- } else {
- extranetLink = homesStore.kefu_url
- }
- // extranetLink = homesStore.kefu_url + params;
- console.log('generateExtranetLink', extranetLink)
- // console.log('extranetLink',extranetLink)
- return extranetLink;
- }
+//获取订单详情
+const getc2cOrderDetails = (orderNo, call) => {
+ getc2cOrder({ order_no: orderNo }).then((res) => {
+ payInfo.value = res
+ state.value = payInfo.value.state
+ remainingTime.value = res.autoCancelTimeRemain
+ if (call) { call(res) }
+ })
+}
- const throttleSend = throttle((message) => {
- send('text', message)
- }, 500)
+//第三方客服带用户id
+const generateExtranetLink = () => {
+ let extranetLink = ''
+ if (userStore.userInfo && userStore.userInfo.usercode) {
+ const userData = encodeURIComponent(JSON.stringify({ name: userStore.userInfo.usercode, comment: '' }))
+ let params = `&clientid=${userStore.userInfo.usercode}&metadata=${userData}`;
+ extranetLink = homesStore.kefu_url + params;
+ } else {
+ extranetLink = homesStore.kefu_url
+ }
+ // extranetLink = homesStore.kefu_url + params;
+ console.log('generateExtranetLink', extranetLink)
+ // console.log('extranetLink',extranetLink)
+ return extranetLink;
+}
- const onOversize = (file) => {
- showToast(t('fileMaxLimit'));
- }
- const onPreview = (url) => { // 预览
- showImagePreview([url])
- }
- const showTime = (index) => { // 时间显示
- if (index === 0) {
- return true
- }
- if (index === list.value.length - 1) {
- return false
- }
- if (list.value[index].createtime.split(' ')[0] === list.value[index + 1].createtime.split(' ')[1]) {
- return false
- }
- }
- const afterRead = (file) => { // 文件上传
- showLoadingToast({
- duration: 0
- })
- _uploadImage(file, (percent) => {
- console.log(percent)
- }).then(data => {
- closeToast()
- send('img', data)
- }).catch(() => {
- showToast(t('失败'))
- })
- }
- const fetchList = async (message_id = '') => { // 获取消息列表
- console.log("orderNo = " + orderNo);
- console.log("partyId = " + partyId);
- _getMsg({
- message_id
- }, orderNo, partyId).then(data => { //
- if (!lastMsgId.value) {
- lastMsgId.value = data.length && data[data.length - 1]['id']
- }
- if (data.length) {
- if (message_id) { // 加载更多
- lastMsgId.value = data[data.length - 1]['id']
- list.value = [...data.reverse(), ...list.value]
- } else {
- list.value = [...list.value, ...data.reverse()]
- let hash = {};
- list.value = list.value.reduce(function(preVal, curVal) {
- hash[curVal.id] ? ' ' : hash[curVal.id] = true && preVal.push(curVal);
- return preVal
- }, []);
- list.value.forEach((item, index) => {
- data.forEach((item2, index2) => {
- if (item.id === item2.id) {
- item.delete_status = item2.delete_status
- }
- })
- })
+const throttleSend = throttle((message) => {
+ send('text', message)
+}, 500)
- }
+const onOversize = (file) => {
+ showToast(t('fileMaxLimit'));
+}
+const onPreview = (url) => { // 预览
+ showImagePreview([url])
+}
+const showTime = (index) => { // 时间显示
+ if (index === 0) {
+ return true
+ }
+ if (index === list.value.length - 1) {
+ return false
+ }
+ if (list.value[index].createtime.split(' ')[0] === list.value[index + 1].createtime.split(' ')[1]) {
+ return false
+ }
+}
+const afterRead = (file) => { // 文件上传
+ showLoadingToast({ duration: 0 })
+ _uploadImage(file, (percent) => {
+ console.log(percent)
+ }).then(data => {
+ closeToast()
+ send('img', data)
+ }).catch(() => {
+ showToast(t('失败'))
+ })
+}
+const fetchList = async (message_id = '') => { // 获取消息列表
+ console.log("orderNo = " + orderNo);
+ console.log("partyId = " + partyId);
+ _getMsg({ message_id }, orderNo, partyId).then(data => { //
+ if (!lastMsgId.value) {
+ lastMsgId.value = data.length && data[data.length - 1]['id']
+ }
+ if (data.length) {
+ if (message_id) { // 加载更多
+ lastMsgId.value = data[data.length - 1]['id']
+ list.value = [...data.reverse(), ...list.value]
+ } else {
+ list.value = [...list.value, ...data.reverse()]
+ let hash = {};
+ list.value = list.value.reduce(function (preVal, curVal) {
+ hash[curVal.id] ? ' ' : hash[curVal.id] = true && preVal.push(curVal);
+ return preVal
+ }, []);
+ list.value.forEach((item, index) => {
+ data.forEach((item2, index2) => {
+ if (item.id === item2.id) {
+ item.delete_status = item2.delete_status
+ }
+ })
+ })
- if (isScrollBottom.value) {
- boxScrollEl.value.scrollTop = boxScrollEl.value.scrollHeight - boxScrollEl.value
- .offsetHeight
- }
- currentScrollTop.value = boxScrollEl.value.scrollTop;
- if (data.length < 10) {
- finished.value = true
- }
- }
- if (!message_id) {
- clearIntervalTimer()
- interval.value = setInterval(() => {
- fetchList()
- }, 1000)
- }
- })
- }
+ }
- const handleScroll = () => {
- if (boxScrollEl.value) {
- if (boxScrollEl.value.scrollTop === currentScrollTop.value) {
- isScrollBottom.value = true
- } else {
- isScrollBottom.value = false
- }
- }
- }
+ if (isScrollBottom.value) {
+ boxScrollEl.value.scrollTop = boxScrollEl.value.scrollHeight - boxScrollEl.value.offsetHeight
+ }
+ currentScrollTop.value = boxScrollEl.value.scrollTop;
+ if (data.length < 10) {
+ finished.value = true
+ }
+ }
+ if (!message_id) {
+ clearIntervalTimer()
+ interval.value = setInterval(() => {
+ fetchList()
+ }, 1000)
+ }
+ })
+}
- const onMore = () => { // 加载更多
- fetchList(lastMsgId.value)
- }
- const clearIntervalTimer = () => {
- if (interval.value) {
- clearInterval(interval.value)
- interval.value = null
- }
- }
- const fetchUnread = () => { // 获取未读
- _getUnreadMsg(orderNo, partyId).then(data => {
- unread.value = data
- })
- }
- const onClickLeft = () => { // 返回
- router.go(-1);
- }
- const send = (type = 'text', content = '') => { // 发送消息, img 也当消息text
- if (!content) {
- showToast(t('entryMessageContent'))
- return
- }
- _sendMsg(type, content, orderNo, partyId).then(async data => {
- message.value = ''
- isScrollBottom.value = true
- // document.getElementById('bottom').click()
- // await fetchList()
- })
- }
- const getCountdown = () => {
- if (remainingTime.value > 0) {
- remainingTime.value = remainingTime.value - 1
- } else {
- remainingTime.value = 0
- }
- }
+const handleScroll = () => {
+ if (boxScrollEl.value) {
+ if (boxScrollEl.value.scrollTop === currentScrollTop.value) {
+ isScrollBottom.value = true
+ } else {
+ isScrollBottom.value = false
+ }
+ }
+}
- onUnmounted(() => {
- clearIntervalTimer()
- })
+const onMore = () => { // 加载更多
+ fetchList(lastMsgId.value)
+}
+const clearIntervalTimer = () => {
+ if (interval.value) {
+ clearInterval(interval.value)
+ interval.value = null
+ }
+}
+const fetchUnread = () => { // 获取未读
+ _getUnreadMsg(orderNo, partyId).then(data => {
+ unread.value = data
+ })
+}
+const onClickLeft = () => { // 返回
+ router.go(-1);
+}
+const send = (type = 'text', content = '') => { // 发送消息, img 也当消息text
+ if (!content) {
+ showToast(t('entryMessageContent'))
+ return
+ }
+ _sendMsg(type, content, orderNo, partyId).then(async data => {
+ message.value = ''
+ isScrollBottom.value = true
+ // document.getElementById('bottom').click()
+ // await fetchList()
+ })
+}
+const getCountdown = () => {
+ if (remainingTime.value > 0) {
+ remainingTime.value = remainingTime.value - 1
+ } else {
+ remainingTime.value = 0
+ }
+}
+
+onUnmounted(() => {
+ clearIntervalTimer()
+})
+
</script>
<style lang="scss" scoped>
- .service-box {
- font-size: 14px;
- width: 100%;
- height: 100vh;
- box-sizing: border-box;
- background: $mainBgColor;
- overflow: hidden;
+.service-box {
+ font-size: 14px;
+ width: 100%;
+ height: 100vh;
+ box-sizing: border-box;
+ background: $mainBgColor;
+ overflow: hidden;
- :deep(.van-hairline--bottom::after) {
- border-color: $mainBgColor;
- }
- }
+ :deep(.van-hairline--bottom::after) {
+ border-color: $mainBgColor;
+ }
+}
- .break-word {
- word-wrap: break-word;
- white-space: pre-wrap;
- }
+.break-word {
+ word-wrap: break-word;
+ white-space: pre-wrap;
+}
- .max-w-230 {
- max-width: 115px;
- }
+.max-w-230 {
+ max-width: 115px;
+}
- .responser {
- position: relative;
+.responser {
+ position: relative;
- &::after {
- content: '';
- width: 0;
- height: 0;
- border-top: 5px solid transparent;
- border-bottom: 5px solid transparent;
- border-right: 10px solid $input_background;
- position: absolute;
- left: -10px;
- top: 10px;
- }
- }
+ &::after {
+ content: '';
+ width: 0;
+ height: 0;
+ border-top: 5px solid transparent;
+ border-bottom: 5px solid transparent;
+ border-right: 10px solid $input_background;
+ position: absolute;
+ left: -10px;
+ top: 10px;
+ }
+}
- .borderTop {
- border-top: 1px solid $border_color;
- }
+.borderTop {
+ border-top: 1px solid $border_color;
+}
- .bottomBox {
- height: 65px;
- }
+.bottomBox {
+ height: 65px;
+}
- .white {
- color: $text_color;
- }
+.white {
+ color: $text_color;
+}
- .chatBg {
- background: $input_background;
- height: 36px;
- padding: 8px 18px;
- border-radius: 18px;
- color: $text_color;
- font-size: 14px;
- border: 1px solid $chat-border;
- }
+.chatBg {
+ background: $input_background;
+ height: 36px;
+ padding: 8px 18px;
+ border-radius: 18px;
+ color: $text_color;
+ font-size: 14px;
+ border: 1px solid $chat-border;
+}
- .right-chatBg {
- position: relative;
- background: $color_main;
- color: $text_color;
+.right-chatBg {
+ position: relative;
+ background: $color_main;
+ color: $text_color;
- &::after {
- content: '';
- width: 0;
- height: 0;
- border-top: 5px solid transparent;
- border-bottom: 5px solid transparent;
- border-left: 10px solid $color_main;
- position: absolute;
- right: -8px;
- top: 14px;
- }
- }
+ &::after {
+ content: '';
+ width: 0;
+ height: 0;
+ border-top: 5px solid transparent;
+ border-bottom: 5px solid transparent;
+ border-left: 10px solid $color_main;
+ position: absolute;
+ right: -8px;
+ top: 14px;
+ }
+}
- .left-chatBg {
- background: $input_background;
- }
+.left-chatBg {
+ background: $input_background;
+}
- .localKefu {
- overflow: auto;
- flex-direction: column;
- }
+.localKefu {
+ overflow: auto;
+ flex-direction: column;
+}
- .van-nav-bar--fixed {
- position: relative !important;
- }
-</style>
\ No newline at end of file
+.van-nav-bar--fixed {
+ position: relative !important;
+}
+</style>
--
Gitblit v1.9.3