| | |
| | | </template> |
| | | <template #title> |
| | | <div class="flex items-center"> |
| | | <img class="w-32 h-32" :src="detail.c2cUserHeadImg" alt=""> |
| | | <span class="ml-11 font-700 font-28">{{ detail.c2cUserNickName }}</span> |
| | | <img class="w-32 h-32" :src="detail.c2cUserHeadImg" alt="" /> |
| | | <span class="ml-11 font-700 font-28">{{ |
| | | detail.c2cUserNickName |
| | | }}</span> |
| | | </div> |
| | | </template> |
| | | </order-nav> |
| | | <div class="pt-30 px-32 pb-32 tabBackground"> |
| | | <template v-if="detail.direction == 'buy'"> |
| | | <template v-if="detail.state == 0"> |
| | | <div class="font-40 c2cColor" v-if="time > 0">{{ $t('订单将在倒计时结束时取消。') }} <span class="text-blue">{{ time | |
| | | format }}</span></div> |
| | | <div class="font-40 c2cColor" v-if="time > 0"> |
| | | {{ $t("订单将在倒计时结束时取消。") }} <span |
| | | class="text-blue" |
| | | >{{ time | format }}</span |
| | | > |
| | | </div> |
| | | |
| | | <div class="font-40 c2cColor" v-else>{{ $t('您的订单已超时') }}</div> |
| | | <div class="font-40 c2cColor" v-else> |
| | | {{ $t("您的订单已超时") }} |
| | | </div> |
| | | <van-count-down class="flex font-700 mx-10" :time="time"> |
| | | <template #default="timeData"> |
| | | <span class="block">{{ timeData.hours }}</span> |
| | | <span class="colon">:</span> |
| | | <span class="block">{{ timeData.minutes }}</span> |
| | | <span class="colon">:</span> |
| | | <span class="block">{{ timeData.seconds }}</span> |
| | | </template> |
| | | </van-count-down> |
| | | <template #default="timeData"> |
| | | <span class="block">{{ timeData.hours }}</span> |
| | | <span class="colon">:</span> |
| | | <span class="block">{{ timeData.minutes }}</span> |
| | | <span class="colon">:</span> |
| | | <span class="block">{{ timeData.seconds }}</span> |
| | | </template> |
| | | </van-count-down> |
| | | <!-- <span class="block" v-if="time.hours">{{ |
| | | time.hours |
| | | }}</span> |
| | |
| | | </template> |
| | | <div class="flex justify-between items-center mt-31"> |
| | | <div class="font-26 text-black"> |
| | | <span class="text-grey">{{ $t('金额') }}</span> |
| | | <span class="ml-14 c2cColor">{{ detail.currency }} {{ detail.amount && (detail.amount).toFixed(2) }}</span> |
| | | <span class="text-grey">{{ $t("金额") }}</span> |
| | | <span class="ml-14 c2cColor" |
| | | >{{ detail.currency }} |
| | | {{ detail.amount && detail.amount.toFixed(2) }}</span |
| | | > |
| | | </div> |
| | | <div class="font-30 text-blue" @click="$router.push('/appeal')">{{ $t('举报') }}</div> |
| | | <div class="font-30 text-blue" @click="$router.push('/appeal')"> |
| | | {{ $t("举报") }} |
| | | </div> |
| | | </div> |
| | | <van-button v-if="detail.direction == 'buy' && detail.state == 0" class="w-full mt-44 font-31 rounded-lg" |
| | | color="#1D91FF" type="info" @click="gotoPay">{{ $t('去付款') }}</van-button> |
| | | <van-button |
| | | v-if="detail.direction == 'buy' && detail.state == 0" |
| | | class="w-full mt-44 font-31 rounded-lg" |
| | | color="#1D91FF" |
| | | type="info" |
| | | @click="gotoPay" |
| | | >{{ $t("去付款") }}</van-button |
| | | > |
| | | </div> |
| | | </div> |
| | | <div class="content flex-1 pb-200"> |
| | | <div class="flex flex-col px-32 box-border"> |
| | | <div class="w-full py-10 text-grey text-center pt-100" @click="onMore" |
| | | :style="{ 'visibility': finished ? 'hidden' : 'visiable' }"> |
| | | {{ $t('历史消息') }}</div> |
| | | <div |
| | | class="w-full py-10 text-grey text-center pt-100" |
| | | @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"> |
| | | <p class="font-26 text-center py-20 text-grey" v-if="showTime(index)">{{ item.createtime && |
| | | item.createtime.split(' ')[0] }}</p> |
| | | <div class="flex" :class="item.send_receive === 'send' ? 'justify-end' : ''"> |
| | | |
| | | <li |
| | | v-for="(item, index) in list" |
| | | :key="item.id" |
| | | class="flex flex-col mt-20" |
| | | > |
| | | <p |
| | | class="font-26 text-center py-20 text-grey" |
| | | v-if="showTime(index)" |
| | | > |
| | | {{ item.createtime && item.createtime.split(" ")[0] }} |
| | | </p> |
| | | <div |
| | | class="flex" |
| | | :class="item.send_receive === 'send' ? 'justify-end' : ''" |
| | | > |
| | | <template v-if="item.send_receive === 'receive'"> |
| | | <img :src="detail.c2cUserHeadImg" class="w-81 h-81 mr-40" /> |
| | | <div class="responser bg-grey px-50 py-35 font-30 rounded-lg font-26 chatBg bg-right" |
| | | style="border-radius: 20px 20px 20px 0"> |
| | | <p class="break-word textColor" style="max-width: 230px; word-break: break-word;" |
| | | v-if="item.type === 'text'">{{ item.content }}</p> |
| | | <img v-else :src="item.content" class="w-200 h-200" @click="onPreview(item.content)" /> |
| | | <div |
| | | class="responser bg-grey px-50 py-35 font-30 rounded-lg font-26 chatBg bg-right" |
| | | style="border-radius: 20px 20px 20px 0" |
| | | > |
| | | <p |
| | | class="break-word textColor" |
| | | style="max-width: 230px; word-break: break-word" |
| | | v-if="item.type === 'text'" |
| | | > |
| | | {{ item.content }} |
| | | </p> |
| | | <span v-else @click="onPreview(item.content)"> |
| | | <img :src="item.content" class="w-200 h-200" /> |
| | | </span> |
| | | </div> |
| | | </template> |
| | | <div class="py-25 px-50 rounded-lg flex flex-col chatBg bg-right" style="border-radius: 20px 20px 0 20px" |
| | | 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; word-break: break-word;color: #fff"> |
| | | {{ item.content }}</p> |
| | | <div |
| | | class="py-25 px-50 rounded-lg flex flex-col chatBg bg-right" |
| | | style="border-radius: 20px 20px 0 20px" |
| | | v-else |
| | | > |
| | | <span |
| | | v-if="item.type === 'img'" |
| | | @click="onPreview(item.content)" |
| | | > |
| | | <img :src="`${item.content}`" class="w-200 h-200" /> |
| | | </span> |
| | | |
| | | <p |
| | | class="break-word textColor" |
| | | v-else |
| | | style="max-width: 230px; word-break: break-word; color: #fff" |
| | | > |
| | | {{ item.content }} |
| | | </p> |
| | | </div> |
| | | </div> |
| | | </li> |
| | |
| | | </div> --> |
| | | <div class="fixed bottom-0 bottom-box left-0 w-full px-32 box-border pb-80"> |
| | | <div |
| | | class="pl-30 flex justify-between relative w-full h-120 items-center pr-140 box-border rounded-xl tabBackground chat-input"> |
| | | <van-uploader :max-size="10000 * 1024" @oversize="onOversize" :after-read="afterRead"> |
| | | class="pl-30 flex justify-between relative w-full h-120 items-center pr-140 box-border rounded-xl tabBackground chat-input" |
| | | > |
| | | <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 class="w-full h-full font-32 pl-40 inputBackground c2cColor" type="text" v-model="message" |
| | | :placeholder="$t('请输入您的消息...')"> |
| | | <input |
| | | class="w-full h-full font-32 pl-40 inputBackground c2cColor" |
| | | type="text" |
| | | v-model="message" |
| | | :placeholder="$t('请输入您的消息...')" |
| | | /> |
| | | <div class="right-34 chat-icon" @click="send('text', message)"> |
| | | <img class="w-54" src="~@/assets/image/c2c/Vector(1).png" alt=""> |
| | | <img class="w-54" src="~@/assets/image/c2c/Vector(1).png" alt="" /> |
| | | </div> |
| | | </div> |
| | | </div> |
| | |
| | | </template> |
| | | |
| | | <script> |
| | | import { |
| | | Icon, |
| | | Button, |
| | | Uploader, ImagePreview, |
| | | CountDown |
| | | } from "vant"; |
| | | import { Icon, Button, Uploader, ImagePreview, CountDown } from "vant"; |
| | | import OrderNav from "@/components/order-nav/OrderNav"; |
| | | import { _uploadImage } from '@/API/fund.api' |
| | | import { _uploadImage } from "@/API/fund.api"; |
| | | import otcApi from "@/API/otc.js"; |
| | | |
| | | export default { |
| | | name: "ChatIndex", |
| | | props: ['type'], // 标识买家还是卖家 |
| | | props: ["type"], // 标识买家还是卖家 |
| | | components: { |
| | | [Icon.name]: Icon, |
| | | [Button.name]: Button, |
| | |
| | | data() { |
| | | return { |
| | | list: [], |
| | | lastMsgId: '', |
| | | lastMsgId: "", |
| | | finished: false, // 没有历史消息 |
| | | message: '', |
| | | orderNo: '', |
| | | message: "", |
| | | orderNo: "", |
| | | detail: {}, |
| | | inter: null, |
| | | timerData: null, |
| | | time: '' // 剩余时间 |
| | | } |
| | | time: "", // 剩余时间 |
| | | }; |
| | | }, |
| | | filters: { |
| | | format(val) { |
| | | return Math.floor(val / 60) + ':' + val % 60 |
| | | } |
| | | return Math.floor(val / 60) + ":" + (val % 60); |
| | | }, |
| | | }, |
| | | async created() { |
| | | this.orderNo = this.$store.state.c2c.order_no |
| | | const res = await otcApi.ctcOrderGetDetail({ order_no: this.orderNo, language: this.$i18n.locale }); |
| | | this.detail = res.data |
| | | const { autoCancelTimeRemain } = this.detail |
| | | this.time = autoCancelTimeRemain |
| | | this.orderNo = this.$store.state.c2c.order_no; |
| | | const res = await otcApi.ctcOrderGetDetail({ |
| | | order_no: this.orderNo, |
| | | language: this.$i18n.locale, |
| | | }); |
| | | this.detail = res.data; |
| | | const { autoCancelTimeRemain } = this.detail; |
| | | this.time = autoCancelTimeRemain; |
| | | if (this.time > 0) { |
| | | this.timerData = setInterval(() => { |
| | | this.time-- |
| | | this.time--; |
| | | if (this.time <= 0) { |
| | | clearInterval(this.timerData) |
| | | clearInterval(this.timerData); |
| | | } |
| | | }, 2000) |
| | | }, 2000); |
| | | } |
| | | this.fetchList() |
| | | this.fetchList(); |
| | | }, |
| | | methods: { |
| | | fixStrSell() { |
| | | let str = '' |
| | | let str = ""; |
| | | if (this.detail.state == 0) { |
| | | str = this.$t('等待买家付款') |
| | | str = this.$t("等待买家付款"); |
| | | } else if (this.detail.state == 1) { |
| | | str = this.$t('请放行') |
| | | str = this.$t("请放行"); |
| | | } else if (this.detail.state == 2) { |
| | | str = this.$t('申诉中') |
| | | str = this.$t("申诉中"); |
| | | } else if (this.detail.state == 3) { |
| | | str = this.$t('已完成') |
| | | str = this.$t("已完成"); |
| | | } else if (this.detail.state == 4) { |
| | | str = this.$t('已取消') |
| | | str = this.$t("已取消"); |
| | | } else if (this.detail.state == 5) { |
| | | str = this.$t('已超时') |
| | | str = this.$t("已超时"); |
| | | } |
| | | return str |
| | | return str; |
| | | }, |
| | | fixStrBuy() { |
| | | let str = '' |
| | | let str = ""; |
| | | if (this.detail.state == 1) { |
| | | str = this.$t('等待卖家放行') |
| | | str = this.$t("等待卖家放行"); |
| | | } else if (this.detail.state == 2) { |
| | | str = this.$t('申诉中') |
| | | str = this.$t("申诉中"); |
| | | } else if (this.detail.state == 3) { |
| | | str = this.$t('已完成') |
| | | str = this.$t("已完成"); |
| | | } else if (this.detail.state == 4) { |
| | | str = this.$t('已取消') |
| | | str = this.$t("已取消"); |
| | | } else if (this.detail.state == 5) { |
| | | str = this.$t('已超时') |
| | | str = this.$t("已超时"); |
| | | } |
| | | return str |
| | | return str; |
| | | }, |
| | | gotoPay() { |
| | | if (this.detail.state == 0) { |
| | | this.$router.push({ path: '/paymentBuy' }) |
| | | this.$router.push({ path: "/paymentBuy" }); |
| | | } |
| | | }, |
| | | onOversize(file) { |
| | | console.log(file); |
| | | this.$toast(this.$t('文件大小不能超过10m')); |
| | | this.$toast(this.$t("文件大小不能超过10m")); |
| | | }, |
| | | onPreview(url) { // 预览 |
| | | ImagePreview([url]) |
| | | onPreview(url) { |
| | | // 预览 |
| | | ImagePreview([url]); |
| | | }, |
| | | showTime(index) { // 时间显示 |
| | | showTime(index) { |
| | | // 时间显示 |
| | | if (index === 0) { |
| | | return true |
| | | return true; |
| | | } |
| | | if (index === this.list.length - 1) { |
| | | return false |
| | | return false; |
| | | } |
| | | if (this.list[index].createtime.split(' ')[0] === this.list[index + 1].createtime.split(' ')[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 }) |
| | | 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() |
| | | console.log(percent); |
| | | }) |
| | | .then((data) => { |
| | | this.$toast.clear(); |
| | | this.send("img", data); |
| | | }) |
| | | .catch(() => { |
| | | this.$toast.clear(); |
| | | }); |
| | | }, |
| | | fetchList(message_id = '') { // 获取消息列表 |
| | | otcApi.otcOnlinechatList({ |
| | | messageId: message_id, |
| | | orderNo: this.detail.orderNo |
| | | }).then(res => { // this.lastMsgId |
| | | if (!this.lastMsgId) { |
| | | this.lastMsgId = res.data.length && res.data[res.data.length - 1]['id'] |
| | | } |
| | | if (res.data.length) { |
| | | if (message_id) { // 加载更多 |
| | | this.lastMsgId = res.data[res.data.length - 1]['id'] |
| | | this.list = [...res.data.reverse(), ...this.list] |
| | | fetchList(message_id = "") { |
| | | // 获取消息列表 |
| | | otcApi |
| | | .otcOnlinechatList({ |
| | | messageId: message_id, |
| | | orderNo: this.detail.orderNo, |
| | | }) |
| | | .then((res) => { |
| | | // this.lastMsgId |
| | | if (!this.lastMsgId) { |
| | | this.lastMsgId = |
| | | res.data.length && res.data[res.data.length - 1]["id"]; |
| | | } |
| | | if (res.data.length) { |
| | | if (message_id) { |
| | | // 加载更多 |
| | | this.lastMsgId = res.data[res.data.length - 1]["id"]; |
| | | this.list = [...res.data.reverse(), ...this.list]; |
| | | } else { |
| | | this.list = [...this.list, ...res.data.reverse()]; |
| | | let hash = {}; |
| | | this.list = this.list.reduce(function (preVal, curVal) { |
| | | hash[curVal.id] |
| | | ? " " |
| | | : (hash[curVal.id] = true && preVal.push(curVal)); |
| | | return preVal; |
| | | }, []); |
| | | } |
| | | if (res.data.length < 10) { |
| | | this.finished = true; |
| | | } |
| | | } else { |
| | | this.list = [...this.list, ...res.data.reverse()] |
| | | let hash = {}; |
| | | this.list = this.list.reduce(function (preVal, curVal) { |
| | | hash[curVal.id] ? ' ' : hash[curVal.id] = true && preVal.push(curVal); |
| | | return preVal |
| | | }, []); |
| | | this.list = []; |
| | | } |
| | | if (res.data.length < 10) { |
| | | this.finished = true |
| | | if (!message_id) { |
| | | this.clearInterval(); |
| | | this.inter = setInterval(() => { |
| | | this.fetchList(); |
| | | }, 2000); |
| | | } |
| | | } else { |
| | | this.list = [] |
| | | } |
| | | if (!message_id) { |
| | | this.clearInterval() |
| | | this.inter = setInterval(() => { |
| | | this.fetchList() |
| | | }, 2000) |
| | | } |
| | | }) |
| | | |
| | | }); |
| | | }, |
| | | onMore() { // 加载更多 |
| | | this.fetchList(this.lastMsgId) |
| | | onMore() { |
| | | // 加载更多 |
| | | this.fetchList(this.lastMsgId); |
| | | }, |
| | | clearInterval() { |
| | | if (this.inter) { |
| | | clearInterval(this.inter) |
| | | this.inter = null |
| | | clearInterval(this.inter); |
| | | this.inter = null; |
| | | } |
| | | }, |
| | | send(type = 'text', content = '') { // 发送消息, img 也当消息text |
| | | send(type = "text", content = "") { |
| | | // 发送消息, img 也当消息text |
| | | if (!content) { |
| | | this.$toast(this.$t('请输入消息内容')) |
| | | return |
| | | this.$toast(this.$t("请输入消息内容")); |
| | | return; |
| | | } |
| | | otcApi.otcOnlinechat({ |
| | | orderNo: this.detail.orderNo, |
| | | type, |
| | | content |
| | | }).then(data => { |
| | | console.log(data) |
| | | this.message = '' |
| | | // document.getElementById('bottom').click() |
| | | this.fetchList() |
| | | setTimeout(() => { |
| | | this.bottomScrollClick() |
| | | },1000) |
| | | // setTimeout(() => { |
| | | // window.scrollTo(0, document.documentElement.scrollHeight) |
| | | // }, 1000) |
| | | }) |
| | | otcApi |
| | | .otcOnlinechat({ |
| | | orderNo: this.detail.orderNo, |
| | | type, |
| | | content, |
| | | }) |
| | | .then((data) => { |
| | | console.log(data); |
| | | this.message = ""; |
| | | // document.getElementById('bottom').click() |
| | | this.fetchList(); |
| | | setTimeout(() => { |
| | | this.bottomScrollClick(); |
| | | }, 1000); |
| | | // setTimeout(() => { |
| | | // window.scrollTo(0, document.documentElement.scrollHeight) |
| | | // }, 1000) |
| | | }); |
| | | }, |
| | | bottomScrollClick() { |
| | | this.$nextTick(() => { |
| | | let scrollEl = this.$refs.mianscroll; |
| | | scrollEl.scrollTo({ top: scrollEl.scrollHeight + 400, behavior: 'smooth' }); |
| | | scrollEl.scrollTo({ |
| | | top: scrollEl.scrollHeight + 400, |
| | | behavior: "smooth", |
| | | }); |
| | | }); |
| | | } |
| | | }, |
| | | }, |
| | | beforeDestroy() { |
| | | this.clearInterval() |
| | | } |
| | | } |
| | | this.clearInterval(); |
| | | }, |
| | | }; |
| | | </script> |
| | | |
| | | <style lang="scss" scoped> |
| | |
| | | } |
| | | |
| | | .bg-right { |
| | | background: #1D91FF !important; |
| | | background: #1d91ff !important; |
| | | } |
| | | |
| | | .sell { |
| | |
| | | outline: none; |
| | | } |
| | | } |
| | | .chat-page{ |
| | | .chat-page { |
| | | overflow: auto; |
| | | } |
| | | |
| | |
| | | top: 50%; |
| | | transform: translateY(-50%); |
| | | } |
| | | .bottom-box{ |
| | | .bottom-box { |
| | | @include themify() { |
| | | background: themed("main_background") !important; |
| | | } |