|
|
@@ -0,0 +1,503 @@
|
|
|
+<template>
|
|
|
+ <view class="page">
|
|
|
+ <view class="flex_c pages" @touchmove="touchmove">
|
|
|
+ <scroll-view class="scroll-view flex1" scroll-y scroll-with-animation :scroll-top="top" scroll-with-animation @scroll="scroll" @scrolltoupper="scrolltoupper" @scrolltolower="scrolltolower">
|
|
|
+ <view style="padding: 30rpx 30rpx">
|
|
|
+ <block v-for="(item,index) in list" :key="index">
|
|
|
+ <view class="text_26 color__ time">
|
|
|
+ {{ renderMessageDate(item, index) }}
|
|
|
+ </view>
|
|
|
+ <view class="message" :class="[item.userType]">
|
|
|
+ <image :src="item.avatar" v-if="item.userType === 'friend'" class="avatar" mode="widthFix"></image>
|
|
|
+ <view class="content" v-if="item.messageType === 'image'">
|
|
|
+ <image :src="item.content" mode="widthFix"></image>
|
|
|
+ </view>
|
|
|
+ <view class="content" v-else>
|
|
|
+ <view class="" v-if="item.msgType == 'quick'">
|
|
|
+ <view class="quickCon">{{item.content}}</view>
|
|
|
+ <view class="quickList" v-if="item.list.length > 0">
|
|
|
+ <view class="list-items" v-for="(qItem,indx) in item.list" @click="quickQs(qItem)">{{qItem.question}}</view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view class="" v-else-if="item.msgType == 'address'">
|
|
|
+ 1
|
|
|
+ </view>
|
|
|
+ <view class="" v-else-if="item.msgType == 'order'">
|
|
|
+ 2
|
|
|
+ </view>
|
|
|
+ <view class="" v-else-if="item.msgType == 'image'">
|
|
|
+ 3
|
|
|
+ </view>
|
|
|
+ <view class="" v-else-if="item.msgType == 'pay'">
|
|
|
+ 4
|
|
|
+ </view>
|
|
|
+ <view v-else>
|
|
|
+ <view v-html="renderTextMessage(item.content)"></view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <image :src="item.avatar" v-if="item.userType === 'self'" class="avatar" mode="widthFix"></image>
|
|
|
+ </view>
|
|
|
+ </block>
|
|
|
+ </view>
|
|
|
+ </scroll-view>
|
|
|
+ <view class="tool">
|
|
|
+ <view class="tool-option">
|
|
|
+ <view class="input-text">
|
|
|
+ <textarea class="input" placeholder="输入点什么呢..." auto-height="true" confirm-type="send" type="text"
|
|
|
+ :maxlength="-1" :adjust-position="false" v-model="text" confirm-hold
|
|
|
+ :show-confirm-bar="false" @confirm="sendingText" @keyboardheightchange="keyboardheightchange" />
|
|
|
+ </view>
|
|
|
+ <view class="check-img">
|
|
|
+ <view class="check-icon" @click="tapEmoji"><image src="@/static/image/face.svg" mode="aspectFill"></image></view>
|
|
|
+ <view class="check-icon" @click="tapMore"><image src="@/static/image/more.svg" mode="aspectFill"></image></view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <template v-if="keyboardHeight>0">
|
|
|
+ <view class="keyboardheight" :style="{ height: keyboardHeight + 'px' }"></view>
|
|
|
+ </template>
|
|
|
+ <view>
|
|
|
+ <emoji v-model="isEmoji" @onEmoji="onEmoji" @deleteFn="deleteFn" @sendingText="sendingText" @sendingEmojiPack="sendingEmojiPack"></emoji>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+var {Push} = require("@/static/js/push.js")
|
|
|
+import * as Api from "@/static/api/msg.js";
|
|
|
+import form from "@/static/js/form.js";
|
|
|
+let cursor = 0; //输入框光标
|
|
|
+var app;
|
|
|
+import emoji from '@/components/bottom-operation/emoji.vue';
|
|
|
+import { mapState } from 'vuex';
|
|
|
+import {
|
|
|
+ show,
|
|
|
+ formatDate,
|
|
|
+ throttle,
|
|
|
+ openimg,
|
|
|
+ getLocation,
|
|
|
+ to as tofn
|
|
|
+} from '@/utils/index.js';
|
|
|
+import { EmojiDecoder, emojiMap } from '@/utils/EmojiDecoder.js';
|
|
|
+const emojiUrl = 'https://imgcache.qq.com/open/qcloud/tim/assets/emoji/';
|
|
|
+const decoder = new EmojiDecoder(emojiUrl, emojiMap);
|
|
|
+export default {
|
|
|
+ components: {
|
|
|
+ emoji
|
|
|
+ },
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ text: '',
|
|
|
+ list: [],
|
|
|
+ allLoaded:false,
|
|
|
+ msgPage:2,
|
|
|
+ top: 0,
|
|
|
+ isEmoji:false,
|
|
|
+ isMore:false,
|
|
|
+ keyboardHeight:0,
|
|
|
+ pushObj:null,
|
|
|
+ wsAuth:"https://tran.jsshuita.cn/plugin/webman/push/auth",
|
|
|
+ wsUrl: 'wss://tran.jsshuita.cn/ws',
|
|
|
+ _friendAvatar:"",
|
|
|
+ _selfAvatar:"",
|
|
|
+ isKeyboard:false,
|
|
|
+ screenWidth:0
|
|
|
+ };
|
|
|
+ },
|
|
|
+ computed: mapState({
|
|
|
+ //显示时间
|
|
|
+ renderMessageDate() {
|
|
|
+ return (message, index) => {
|
|
|
+ if (message.timestamp - this.list[index + 1]?.timestamp > 3 * 60 * 1000) {
|
|
|
+ return formatDate(message.timestamp, 'timestamp');
|
|
|
+ }
|
|
|
+ return '';
|
|
|
+ };
|
|
|
+ },
|
|
|
+ }),
|
|
|
+ onLoad(options) {
|
|
|
+ app = this;
|
|
|
+ app.optionsData = options;
|
|
|
+ uni.setNavigationBarTitle({
|
|
|
+ title:"加载中..."
|
|
|
+ });
|
|
|
+ const systemInfo = uni.getSystemInfoSync();
|
|
|
+ app.screenWidth = systemInfo.screenWidth;
|
|
|
+ app.getService(options)
|
|
|
+ },
|
|
|
+ beforeDestroy() {
|
|
|
+ cursor = 0;
|
|
|
+ this.pushObj.disconnect()
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ scroll(){},
|
|
|
+ // 滚动到底部
|
|
|
+ scrolltolower() {
|
|
|
+ // if (this.history.allLoaded) return;
|
|
|
+ // console.log('触底')
|
|
|
+ // this.getMoreMsg()
|
|
|
+ // this.loadHistoryMessage();
|
|
|
+ },
|
|
|
+ // 滚动到顶部
|
|
|
+ scrolltoupper() {
|
|
|
+ if (this.allLoaded) return;
|
|
|
+ console.log('滚动到顶部')
|
|
|
+ this.getMoreMsg()
|
|
|
+ },
|
|
|
+ getMoreMsg(){
|
|
|
+ this.allLoaded = true;
|
|
|
+ var formData = this.optionsData;
|
|
|
+ const tokenPoi = uni.getStorageSync("contact");
|
|
|
+ formData.page = this.msgPage;
|
|
|
+ formData.poi = tokenPoi.poi_id;
|
|
|
+ Api.msg(formData).then((res)=>{
|
|
|
+ if(res.code == 0) {
|
|
|
+ return this.$dialog.showSuccess(res.msg)
|
|
|
+ }
|
|
|
+ if (res.data.rows.length > 0) {
|
|
|
+ this.msgPage ++;
|
|
|
+ this.allLoaded = false;
|
|
|
+ var msgData = res.data.rows;
|
|
|
+ var pushData = [];
|
|
|
+ if (msgData.length > 0) {
|
|
|
+ msgData.forEach(item => pushData.push(app.formatMsg(item)))
|
|
|
+ }
|
|
|
+ // console.log("pushData",pushData)
|
|
|
+ // app.list = [...app.list,...pushData]
|
|
|
+ app.list.unshift(...pushData)
|
|
|
+ // this.scrollToBottom()
|
|
|
+ } else {
|
|
|
+ this.allLoaded = true;
|
|
|
+ }
|
|
|
+ })
|
|
|
+ },
|
|
|
+ quickQs(data){
|
|
|
+ if (!data.answer) return ;
|
|
|
+ app.list.push({
|
|
|
+ content: data.answer,
|
|
|
+ userType: 'self',
|
|
|
+ avatar: app._selfAvatar,
|
|
|
+ msgType:"text",
|
|
|
+ list:[]
|
|
|
+ })
|
|
|
+ app.scrollToBottom()
|
|
|
+ },
|
|
|
+ renderTextMessage(text) {
|
|
|
+ if (!text) return "";
|
|
|
+ console.log("text",text)
|
|
|
+ text = text.replace(/\n/g, '');
|
|
|
+ if (!text) return '<span>' + '[未知内容]' + '</span>';
|
|
|
+ return '<span>' + decoder.decode(text) + '</span>';
|
|
|
+ },
|
|
|
+ getService(options){
|
|
|
+ Api.checkIn(options).then((res)=>{
|
|
|
+ uni.setNavigationBarTitle({
|
|
|
+ title:"与"+res.data.store.name+"对话中"
|
|
|
+ })
|
|
|
+ app._selfAvatar = res.data.avatar.self;
|
|
|
+ app._friendAvatar = res.data.avatar.friend;
|
|
|
+ var msgData = res.data.msg.rows;
|
|
|
+ var pushData = [];
|
|
|
+ if (msgData.length > 0) {
|
|
|
+ msgData.forEach(item => pushData.push(app.formatMsg(item)))
|
|
|
+ }
|
|
|
+ var quickData = res.data.quick;
|
|
|
+ pushData.push({
|
|
|
+ content: quickData.star_msg,
|
|
|
+ userType: 'friend',
|
|
|
+ avatar: res.data.avatar.friend,
|
|
|
+ msgType:"quick",
|
|
|
+ list:quickData.quick
|
|
|
+ })
|
|
|
+ console.log("pushData",pushData)
|
|
|
+ app.list = [...app.list,...pushData]
|
|
|
+ this.scrollToBottom()
|
|
|
+ })
|
|
|
+ },
|
|
|
+ formatMsg(item){
|
|
|
+ var payload = "";
|
|
|
+ if (item.type == 'text') {
|
|
|
+ payload = item.content
|
|
|
+ }
|
|
|
+ if (item.type == 'order') {
|
|
|
+ var order = JSON.parse(item.content)
|
|
|
+ payload = order
|
|
|
+ }
|
|
|
+ if (item.type == 'pay') {
|
|
|
+ var order = JSON.parse(item.content)
|
|
|
+ payload = order
|
|
|
+ }
|
|
|
+ if (item.type == 'address') {
|
|
|
+ var order = JSON.parse(item.content)
|
|
|
+ payload = order
|
|
|
+ }
|
|
|
+ if (item.type == 'image') {
|
|
|
+ payload = item.content
|
|
|
+ }
|
|
|
+ const message = {
|
|
|
+ content: payload,
|
|
|
+ userType: item.userType,
|
|
|
+ avatar: item.avatar,
|
|
|
+ msgType:item.type,
|
|
|
+ list:[],
|
|
|
+ timestamp: item.time,
|
|
|
+ };
|
|
|
+ return message;
|
|
|
+ },
|
|
|
+ tapMore(){
|
|
|
+
|
|
|
+ },
|
|
|
+ keyboardheightchange(e){
|
|
|
+ // app.$dialog.showSuccess('asdasdasd')
|
|
|
+ const height = e.detail.height;
|
|
|
+ if (height > 0) {
|
|
|
+ this.isEmoji = false;
|
|
|
+ this.isMore = false;
|
|
|
+ this.isKeyboard = true;
|
|
|
+ } else {
|
|
|
+ this.isKeyboard = false;
|
|
|
+ }
|
|
|
+ this.keyboardHeight = height;
|
|
|
+ setTimeout(()=>{
|
|
|
+ this.scrollToBottom()
|
|
|
+ }, 150)
|
|
|
+ },
|
|
|
+ touchmove(){
|
|
|
+ this.isFocus = false;
|
|
|
+ this.isFocisEmojius = false;
|
|
|
+ this.isEmoji = false;
|
|
|
+ this.isMore = false;
|
|
|
+ this.isKeyboard = false;
|
|
|
+ this.keyboardHeight = 0
|
|
|
+ },
|
|
|
+ onEmoji(key) {
|
|
|
+ const text = `${this.text.slice(0, cursor)}${key}${this.text.slice(cursor)}`;
|
|
|
+ this.text = text;
|
|
|
+ },
|
|
|
+ sendingEmojiPack(){},
|
|
|
+ // 删除表情
|
|
|
+ deleteFn() {
|
|
|
+ const str = this.text.charAt(this.text.length - 1);
|
|
|
+ if (str === ']') {
|
|
|
+ let metaChars = /\[.*?(\u4e00*\u597d*)\]/g;
|
|
|
+ let xstr = '';
|
|
|
+ this.text.replace(metaChars, (match) => {
|
|
|
+ xstr = match;
|
|
|
+ });
|
|
|
+ var text = this.text;
|
|
|
+
|
|
|
+ function del(str) {
|
|
|
+ return text.slice(0, text.length - str.length);
|
|
|
+ }
|
|
|
+ this.text = del(xstr);
|
|
|
+ } else {
|
|
|
+ this.text = this.text.substring(0, this.text.length - 1);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ tapEmoji() {
|
|
|
+ this.isEmoji = !this.isEmoji;
|
|
|
+ if (this.isEmoji) {
|
|
|
+ this.isKeyboard = true;
|
|
|
+ }
|
|
|
+ this.isMore = false;
|
|
|
+ setTimeout(()=>{
|
|
|
+ this.scrollToBottom()
|
|
|
+ }, 150)
|
|
|
+ },
|
|
|
+ sendingText() {
|
|
|
+ if (!this.text) return ;
|
|
|
+ this.list.push({
|
|
|
+ content: this.text,
|
|
|
+ userType: 'self',
|
|
|
+ avatar: this._selfAvatar
|
|
|
+ })
|
|
|
+ this.text = ''
|
|
|
+ this.scrollToBottom()
|
|
|
+ // 模拟对方回复
|
|
|
+ // setTimeout(()=>{
|
|
|
+ // this.list.push({
|
|
|
+ // content: '周末什么安排',
|
|
|
+ // userType: 'friend',
|
|
|
+ // avatar: this._friendAvatar
|
|
|
+ // })
|
|
|
+ // this.scrollToBottom()
|
|
|
+ // }, 1500)
|
|
|
+ },
|
|
|
+ chooseImage() {
|
|
|
+ uni.chooseImage({
|
|
|
+ // sourceType: 'album',
|
|
|
+ success: (res) => {
|
|
|
+ this.list.push({
|
|
|
+ content: res.tempFilePaths[0],
|
|
|
+ userType: 'self',
|
|
|
+ messageType: 'image',
|
|
|
+ avatar: this._selfAvatar
|
|
|
+ })
|
|
|
+ this.scrollToBottom()
|
|
|
+ // 模拟对方回复
|
|
|
+ setTimeout(()=>{
|
|
|
+ this.list.push({
|
|
|
+ content: '你好呀,朋友~',
|
|
|
+ userType: 'friend',
|
|
|
+ avatar: this._friendAvatar
|
|
|
+ })
|
|
|
+ this.scrollToBottom()
|
|
|
+ }, 1500)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ },
|
|
|
+ scrollToBottom() {
|
|
|
+ if (this.isEmoji) {
|
|
|
+ var px = 600 * (app.screenWidth / 750)
|
|
|
+ this.top = (this.list.length + px) * 1000
|
|
|
+ } else {
|
|
|
+ this.top = (this.list.length + parseInt(this.keyboardHeight)) * 1000
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+.pages {
|
|
|
+ position: fixed;
|
|
|
+ z-index: 1;
|
|
|
+ top: 0;
|
|
|
+ left: 0;
|
|
|
+ bottom: 0;
|
|
|
+ right: 0;
|
|
|
+ background-color: #ededed;
|
|
|
+}
|
|
|
+.safe-box{width: 100%;height: env(safe-area-inset-bottom);}
|
|
|
+.scroll-view {
|
|
|
+ /* #ifdef H5 */
|
|
|
+ height: calc(100vh - 44px);
|
|
|
+ /* #endif */
|
|
|
+ /* #ifndef H5 */
|
|
|
+ height: 0;
|
|
|
+ /* #endif */
|
|
|
+ background: #eee;
|
|
|
+ box-sizing: border-box;
|
|
|
+}
|
|
|
+.message {
|
|
|
+ display: flex;
|
|
|
+ align-items: flex-start;
|
|
|
+ margin-bottom: 30rpx;
|
|
|
+ .quickList{
|
|
|
+ margin-top: 10upx;
|
|
|
+ .list-items {
|
|
|
+ color: blue;
|
|
|
+ font-size: 28upx;
|
|
|
+ line-height: 48upx;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .avatar {
|
|
|
+ width: 80rpx;
|
|
|
+ height: 80rpx;
|
|
|
+ border-radius: 10rpx;
|
|
|
+ margin-right: 30rpx;
|
|
|
+ }
|
|
|
+ .content {
|
|
|
+ min-height: 80rpx;
|
|
|
+ max-width: 60vw;
|
|
|
+ box-sizing: border-box;
|
|
|
+ font-size: 28rpx;
|
|
|
+ line-height: 1.3;
|
|
|
+ padding: 20rpx;
|
|
|
+ border-radius: 10rpx;
|
|
|
+ background: #fff;
|
|
|
+ image {
|
|
|
+ width: 200rpx;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ &.self {
|
|
|
+ justify-content: flex-end;
|
|
|
+ .avatar {
|
|
|
+ margin: 0 0 0 30rpx;
|
|
|
+ }
|
|
|
+ .content {
|
|
|
+ position: relative;
|
|
|
+ &::after {
|
|
|
+ position: absolute;
|
|
|
+ content: '';
|
|
|
+ width: 0;
|
|
|
+ height: 0;
|
|
|
+ border: 16rpx solid transparent;
|
|
|
+ border-left: 16rpx solid #fff;
|
|
|
+ right: -28rpx;
|
|
|
+ top: 24rpx;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ &.friend {
|
|
|
+ .content {
|
|
|
+ position: relative;
|
|
|
+ &::after {
|
|
|
+ position: absolute;
|
|
|
+ content: '';
|
|
|
+ width: 0;
|
|
|
+ height: 0;
|
|
|
+ border: 16rpx solid transparent;
|
|
|
+ border-right: 16rpx solid #fff;
|
|
|
+ left: -28rpx;
|
|
|
+ top: 24rpx;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.tool {
|
|
|
+ // min-height: 120rpx;
|
|
|
+ // position: fixed;
|
|
|
+ // right: 0;
|
|
|
+ // left: 0;
|
|
|
+ // bottom: 0;
|
|
|
+ background: #fff;
|
|
|
+ padding: 20rpx 0 20rpx 0;
|
|
|
+ padding-bottom: calc(20rpx + constant(safe-area-inset-bottom)/2) !important;
|
|
|
+ padding-bottom: calc(20rpx + env(safe-area-inset-bottom)/2) !important;
|
|
|
+ .tool-option{
|
|
|
+ display: flex;
|
|
|
+ align-items: flex-start;
|
|
|
+ box-sizing: border-box;
|
|
|
+ padding: 0 20rpx;
|
|
|
+ }
|
|
|
+ .input-text{
|
|
|
+ flex: 1;width: 100%;
|
|
|
+ box-sizing: border-box;
|
|
|
+ padding: 10rpx 14rpx;
|
|
|
+ min-height: 84rpx;
|
|
|
+ max-height: 300rpx;
|
|
|
+ overflow: auto;
|
|
|
+ border-radius: 10rpx;
|
|
|
+ background-color: #eee;
|
|
|
+ .input{
|
|
|
+ margin: 10rpx 0;
|
|
|
+ width: 100%;
|
|
|
+ font-size: 28upx;
|
|
|
+ height: 100%;
|
|
|
+ background-color: #eee;
|
|
|
+ min-height: 48rpx;
|
|
|
+ max-height: 300rpx;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .check-img{
|
|
|
+ display: flex;align-items: center;justify-content: center;
|
|
|
+ .check-icon{width: 84rpx;height: 84rpx;display: flex;align-items: center;justify-content: center;}
|
|
|
+ image{width: 75%;height: 75%;}
|
|
|
+ }
|
|
|
+
|
|
|
+ .thumb {
|
|
|
+ width: 64rpx;
|
|
|
+ }
|
|
|
+}
|
|
|
+.time {
|
|
|
+ width: 100%;
|
|
|
+ color: #a3a3a3;
|
|
|
+ line-height: 100rpx;
|
|
|
+ text-align: center;
|
|
|
+ font-size: 24rpx;
|
|
|
+}
|
|
|
+</style>
|