huzheng12
2024-05-06 3ed2cb78a690b64c3b2646d35e1500081186dfa3
src/page/chat/index.vue
@@ -7,27 +7,35 @@
        </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('订单将在倒计时结束时取消。') }}&nbsp;<span class="text-blue">{{ time |
              format }}</span></div>
            <div class="font-40 c2cColor" v-if="time > 0">
              {{ $t("订单将在倒计时结束时取消。") }}&nbsp;<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>
@@ -45,41 +53,88 @@
        </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>
@@ -102,14 +157,23 @@
    </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>
@@ -117,19 +181,14 @@
</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,
@@ -140,181 +199,206 @@
  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>
@@ -323,7 +407,7 @@
}
.bg-right {
  background: #1D91FF !important;
  background: #1d91ff !important;
}
.sell {
@@ -341,7 +425,7 @@
    outline: none;
  }
}
.chat-page{
.chat-page {
  overflow: auto;
}
@@ -350,7 +434,7 @@
  top: 50%;
  transform: translateY(-50%);
}
.bottom-box{
.bottom-box {
  @include themify() {
    background: themed("main_background") !important;
  }