You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1808 lines
52 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<view class="content">
<!-- 聊天内容 -->
<scroll-view class="chat" scroll-y="true" scroll-with-animation="true" :scroll-into-view="scrollToView"
refresher-enabled="true" :refresher-triggered="triggered" :refresher-threshold="100"
refresher-background="#f0f0f0" @refresherpulling="onPulling"
@refresherrefresh="onRefresh" @refresherrestore="onRestore" @refresherabort="onAbort">
<view class="chat-main" :style="{paddingBottom:inputh+'px'}">
<!-- <view class="chat-ls" v-if="unshiftmsg.length==0">
<view class="chat-time">现在可以开始聊天了.</view>
</view> -->
<view class="chat-ls" v-for="(item,index) in unshiftmsg" :key="index" :id="'msg'+ index">
<view class="chat-time" v-if="item.fromtime != ''">{{changeTime(item.fromtime)}}</view>
<view class="msg-m msg-left" v-if="item.fromuser !== userid">
<view class="user-img" >
<image class="uimg" :src="item.headimg" @error="handleImageError($event,index)"></image>
<text class="uname">{{item.fromname}}</text>
</view>
<view class="message" v-if="item.type == 'txt'">
<!-- 文字 -->
<view class="msg-text">
<text selectable>{{item.content}}</text>
</view>
</view>
<view class="message" v-if="item.type == 'image'" @tap="previewImg(item.content)">
<!-- 图像 -->
<image :src="item.content" class="msg-img" mode="widthFix"></image>
</view>
<view class="messagevideo" v-if="item.type == 'video'">
<!-- 视频 -->
<myVideo :videoUrl="item.content"></myVideo>
</view>
<view class="message" v-if="item.type == 'audio'" @click="playVoice(item.content,item.ifaudio,index)">
<!-- 音频 -->
<view class="msg-text voice" :style="{width:item.time*40+'rpx'}">
<view class="voicel" v-if="item.ifaudio" >
<div class="bg voicePlay"></div>
</view>
<image v-else src="../../static/icon/horn.png" class="voice-img"></image>
{{item.time}}″
</view>
</view>
<view class="message" v-if="item.type == 'product'">
<view v-if="item.send" class="msg-product" @click="gotoDetail(item)">
<view v-if="item.send.type==3" class="zx">
<view class="zxname">订单咨询</view>
<view class="zxview">查看订单</view>
</view>
<view class="msg-con">
<image class="img" :src="item.send.pic" mode="aspectFit"></image>
<view class="info">
<view class="name">
<text class="ntxt">{{item.send.name}}</text>
<text v-if="item.send.spData" v-for="(value, key) in item.send.spData" :key="key" class="txt">
{{ key }}: {{ value }}
</text>
</view>
<view class="xq">
<view class="list">
<view v-if="item.send.type==3" class="ord">
购买金额:¥ <text style="font-size: 30rpx;">{{item.send.price}}</text>{{(item.send.unit?'/'+item.send.unit:'')}}
</view>
<view v-else class="price">
¥{{item.send.price+(item.send.unit?'/'+item.send.unit:'')}}
</view>
<view v-if="item.send.quantity" class="qty">
{{item.send.quantity?'共('+item.send.quantity+(item.send.unit?item.send.unit:'件')+')':''}}
</view>
<div v-if="item.send.spData" v-for="(value, key) in item.send.spData" :key="key" class="qty">
{{ key }}: {{ value }}
</div>
</view>
<button class="btn" type="primary" v-if="item.send.type==1">去购买</button>
<button class="btn" type="primary" v-if="item.send.type==2">去购买</button>
</view>
</view>
</view>
</view>
</view>
</view>
<view class="msg-m msg-right" v-if="item.fromuser == userid">
<view class="user-img" >
<image class="uimg" :src="item.headimg" @error="handleImageError($event,index)" ></image>
<!-- <text class="uname">我</text> -->
<text class="uname">{{item.fromname}}</text>
</view>
<view v-if="item.type == 'txt'" class="message">
<view class="msg-text">
<text selectable>{{item.content}}</text>
</view>
</view>
<view v-if="item.type == 'image'" @tap="previewImg(item.content)" class="message">
<image :src="item.content" class="msg-img" mode="widthFix"></image>
</view>
<view v-if="item.type == 'video'" class="messagevideo">
<!-- 视频 -->
<myVideo :videoUrl="item.content"></myVideo>
</view>
<view v-if="item.type == 'audio'" @click="playVoice(item.content,item.ifaudio,index)" class="message">
<!-- 音频 -->
<view class="msg-text voice" :style="{width: item.time>2? item.time*40+'rpx' :'auto'}">
{{item.time}}″
<view class="voicel" v-if="item.ifaudio" >
<div class="bg voicePlay"></div>
</view>
<image v-else src="../../static/icon/hornrw.png" class="voice-img"></image>
</view>
</view>
<view v-if="item.type == 'product'" class="message" >
<view v-if="item.send" class="msg-product" @click="gotoDetail(item)">
<view v-if="item.send.type==3" class="zx">
<view class="zxname">订单咨询</view>
<view class="zxview">查看订单</view>
</view>
<view class="msg-con">
<image class="img" :src="item.send.pic" mode="aspectFit"></image>
<view class="info">
<view class="name">
<text class="ntxt">{{item.send.name}}</text>
<text v-if="item.send.spData" v-for="(value, key) in item.send.spData" :key="key" class="txt">
{{ key }}: {{ value }}
</text>
</view>
<view class="xq">
<view class="list">
<view v-if="item.send.type==3" class="ord">
购买金额:¥ <text style="font-size: 30rpx;">{{item.send.price}}</text>{{(item.send.unit?'/'+item.send.unit:'')}}
</view>
<view v-else class="price">
¥{{item.send.price+(item.send.unit?'/'+item.send.unit:'')}}
</view>
<view class="qty">
{{item.send.quantity?'共('+item.send.quantity+(item.send.unit?item.send.unit:'件')+')':''}}
</view>
</view>
<button class="btn" type="primary" v-if="item.send.type==1">去购买</button>
<button class="btn" type="primary" v-if="item.send.type==2">去购买</button>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</view>
</scroll-view>
<view class="popup" v-if="ifsend&&sendinfo">
<view class="tipcon" click="gotoXQ()">
<image class="img" :src="sendinfo.pic" mode="aspectFit"></image>
<view class="info">
<view class="name">
<text class="ntxt">{{sendinfo.name}}</text>
<text v-if="sendinfo.spData" v-for="(value, key) in sendinfo.spData" :key="key" class="txt">
{{ key }}: {{ value }}
</text>
</view>
<view class="xq">
<view class="list">
<view v-if="sendinfo.type==3" class="ord">
购买金额:¥ <text style="font-size: 30rpx;">{{sendinfo.price}}</text>{{(sendinfo.unit?'/'+sendinfo.unit:'')}}
</view>
<view v-else class="price">
¥{{sendinfo.price+(sendinfo.unit?'/'+sendinfo.unit:'')}}
</view>
<view class="qty">
{{sendinfo.quantity?'共('+sendinfo.quantity+(sendinfo.unit?sendinfo.unit:'件')+')':''}}
</view>
</view>
<button class="btn" type="primary" v-if="sendinfo.type==1" @click="sendServer()">发送商品</button>
<button class="btn" type="primary" v-if="sendinfo.type==2" @click="sendServer()">发送课程</button>
<button class="btn" type="primary" v-if="sendinfo.type==3" @click="sendServer()">发送订单</button>
</view>
<view class="close">
<uni-icons type="closeempty" color="#bebdbd" size="16" @click="close()" ></uni-icons>
</view>
</view>
</view>
</view>
<submit @inputs="inputs" @heights="heights"></submit>
<u-toast ref="uToast" />
</view>
</template>
<script>
import { myCache } from '../../utils/utils.js';
import dateTime from '@/common/dateTime.js';
import submit from '@/components/chat/submit.vue';
import myVideo from "@/components/myVideo.vue";
//音频播放
const innerAudioContext = uni.createInnerAudioContext();
export default {
components: {
submit,
myVideo
},
data() {
return {
text:"",
triggered: false,
userName: "",
userid: "",
userheadimg: "",
info:{},// 会话基本信息
imgurl:"",// uni.$http.baseUrl,
iftop:true,
msg: [], // 排序用,暂不使用
// 反转数据接收
unshiftmsg: [
// {
// fromuser: "11",
// fromname: "Madeline 老师 (女)",
// fromtime:'2025-06-20 10:00:00',
// headimg:require("@/static/image/i1.png"),
// content:'Hixxx我是普拉提教练小a周日上午10点的课您可以准时参加吧',
// type:'txt'
// },
], // chatrurn
imgMsg: [],
scrollToView: '',
oldTime: new Date(),
inputh: '90',
ifaudio:false, // 是否音频
socketTask: null, // WebSocket实例
isConnected: false, // WebSocket连接状态
heartbeatInterval: null, // 心跳包20秒连接一次
heartbeatTimeout: 20000, // 心跳间隔时间例如每20秒发送一次
// 是否需要发送 商品,课程,订单
ifsend: false,
sendinfo:{
// type:1,// 1 商品2 课程3订单
// id:63,
// orderId:"6455194061326336",
// name:"零基础教练培训",
// pic:"/static/image/i1.png",
// price:1000,
// unit: "元",
// brandName: "yoga",
// isCourse: 0,
// quantity:1,
// spData:{"颜色":"绿","尺寸":"80"}
}
}
},
onLoad(options) {
var user = myCache('user');
// 本人聊天信息
this.userName=user.nickName?user.nickName:"";
this.userid=user.userid?user.userid:"";
this.userheadimg=user.avatar?user.avatar:require("@/static/image/girl.png");
if(options.data){
// 会话信息
this.info=JSON.parse(decodeURIComponent(options.data));
console.log("chat",this.info)
// 会话标题
var title = this.info.chatName;
uni.setNavigationBarTitle({
title: title,
});
if(this.info.sendinfo){
this.ifsend=true;
this.sendinfo=this.info.sendinfo;
this.$forceUpdate();
}
else{
this.ifsend=false;
this.sendinfo=null;
this.$forceUpdate();
}
// 先获取聊天记录缓存
this.getchatstore();
}
},
onShow() {
// 跳转到最后一条数据 与前面的:id进行对照
setTimeout(() => {
console.log("onShow")
this.screendo(this.unshiftmsg.length - 1);
}, 100);
// 如果心跳包在发送,先停止,再启动
if(this.heartbeatInterval){
clearInterval(this.heartbeatInterval); // 停止心跳包发送
}
// socket接收实时消息
this.socketinit();
},
onBackPress(options) {
if (options.from === 'backbutton') {
// 来自顶部菜单的返回按钮
// 在这里处理你的逻辑
console.log('返回按钮被点击');
this.closeWebSocket();
uni.onSocketClose(function (res) {
console.log('WebSocket 已关闭!');
});
return false;
}
},
beforeDestroy() {
console.log('界面关闭socketbeforeDestroy');
// 在组件销毁前,确保关闭 WebSocket 连接
this.closeWebSocket();
clearInterval(this.heartbeatInterval); // 停止心跳包发送
},
methods: {
gotoDetail(item){
var send=item.send;
if(send){
if(send.type==1){
// 商品
uni.navigateTo({
url: `/pages/product/detail?id=${send.id}`
});
}
else if(send.type==2){
// 课程
uni.navigateTo({
url: `/pages/product/cdetail?id=${send.id}`
});
}
else if(send.type==3){
// 订单详情
uni.navigateTo({
url: `/pages/order/orderinfo?id=${send.orderId}`
});
}
}
},
// 关闭框
close(){
this.ifsend=false;
this.$forceUpdate();
},
// 发送服务信息
sendServer(){
let data = {
"fromname": this.userName,
"fromuser": this.userid,
"headimg": this.userheadimg,
"toname": this.info.chatName, // 接收人
"touser": this.info.friendId, // 接收人姓名
"content": this.sendinfo.id,
"time": 0,
"ifaudio":false,
"fromtime": new Date(),
"type": "product", // this.sendinfo.type==3?"5":"6" // 5订单 6 商品
"send":this.sendinfo
};
this.unshiftmsg.push(data);
var rindex=this.unshiftmsg.length-1;
// 消息发送
this.onSendWS(data,rindex);
},
// 发送消息跳转详情
gotoXQ(){
if(this.sendinfo.type==1){
// 1 商品
uni.navigateTo({
url: `/pages/product/detail?id=`+this.sendinfo.id
});
}
else if(this.sendinfo.type==2){
// 2 课程
uni.navigateTo({
url: `/pages/product/cdetail?id=`+this.sendinfo.id
});
}
else if(this.sendinfo.type==3){
// 3订单
uni.navigateTo({
url: `/pages/order/orderinfo?id=`+this.sendinfo.id
});
}
},
// 获取聊天记录
getchatstore(){
var that=this;
try{
// 先获取会话缓存
var data= myCache(this.info.chatId)?myCache(this.info.chatId):[];
console.log("data",data)
data.forEach((cell,i)=>{
cell["ifaudio"]=false;
//时间间隔处理
if (i < this.unshiftmsg.length - 1) {
//这里表示头部时间还是显示一下
let t = dateTime.spaceTime(this.oldTime, cell.fromtime);
if (t) {
this.oldTime = t;
}
cell.fromtime = t;
}
// 获取图片,为下面的预览做准备
if (cell.type == 'image') {
this.imgMsg.unshift(cell.content)
}
else if(cell.type=='txt'){
cell.content=decodeURIComponent(cell.content);
}
this.unshiftmsg.push(cell);
});
if(this.unshiftmsg.length<=0)
{
if(this.info.from=="yh"){
// 首次会话自动信息
var cont = 'Hi'+this.userName+',欢迎您!我是'+this.info.chatName+',请问有什么可以帮助您的呢?';
this.unshiftmsg = [
{
"fromname": this.info.chatName, // 发送人
"fromuser": this.info.friendId, // 发送人
"headimg": this.info.chatAvatar, // 发送人
"toname": this.userName, // 接收人
"touser": this.userid, // 接收人姓名
"content": cont,
"minId":this.info.minId,
"time": 0,
"ifaudio":false,
"fromtime": new Date(),
"type": 'txt'
}
];
this.$forceUpdate();
}
else{
// 首次会话自动信息
var cont = 'Hi'+this.userName+',欢迎您!我是'+this.info.chatName+',请问有什么可以帮助您的呢?';
this.unshiftmsg = [
{
"fromname": this.info.chatName, // 发送人
"fromuser": this.info.friendId, // 发送人
"headimg": this.info.chatAvatar, // 发送人
"toname": this.userName, // 接收人
"touser": this.userid, // 接收人姓名
"content": cont,
"minId":this.info.minId,
"time": 0,
"ifaudio":false,
"fromtime": new Date(),
"type": 'txt'
}
];
this.$forceUpdate();
}
// 如果是第一次接收消息没有缓存且有minId则拉取离线消息
if(this.info.minId){
this.readUp(1);
}
}
else{
// 跳转到最后一条数据 与前面的:id进行对照
setTimeout(() => {
that.screendo(that.unshiftmsg.length-1);
}, 100);
// 已经有缓存,则拉取离线消息
this.info.minId=this.unshiftmsg[this.unshiftmsg.length-1].id;
this.$forceUpdate();
// 请求服务器加载加载拉取离线聊天记录
if(this.info.minId&&this.info.minId>0){
this.readUp(1);
}
}
}
catch(err){
console.log(err);
}
},
// 定时心跳包
startHeartbeat() {
console.log("startHeartbeat")
this.heartbeatInterval = setInterval(() => {
if (this.socketTask) {
this.socketTask.send({
data: JSON.stringify({
'cmd': 1,//心跳
'data': {
'accessToken':uni.getStorageSync("token")
},
}) // 发送心跳包数据
});
}
}, this.heartbeatTimeout);
},
// ws接收消息
socketinit(){
var that = this;
if (!this.isConnected) {
this.socketTask=uni.connectSocket({
url: "wss://www.sanduolantoyoga.com/yoga-imserver/",
header: {
// 'content-type': 'application/json',
Authorization: uni.getStorageSync("token"),
},
success: (res) => {
console.log(res, 'socket连接成功success');
},
fail: (res) => {
console.log(res, 'socket连接失败')
},
complete: (res) => {
console.log(res,'socket连接成功complete');
}
});
uni.onSocketOpen(res => {
console.log('WebSocket连接已打开');
that.isConnected = true;
// 发送登录心跳包
uni.sendSocketMessage({
data: JSON.stringify({
"cmd": 0,//心跳
"data": {
"accessToken":uni.getStorageSync("token"),
},
}), // 发送心跳包数据 // 发送的消息内容
success(re) {
console.log(re);
console.log('消息发送成功!')
},
fail(err) {
console.log(err);
console.log('消息发送失败!')
}
});
// 发送心跳包
this.startHeartbeat();
});
uni.onSocketMessage(res => {
console.log('收到WebSocket服务器消息');
if(res.data){
let data=JSON.parse(res.data);
console.log(data);
if(data.data){
data=data.data;
if(data){
// 是发送者发送来的消息
if(data.recvId&&data.recvId.toString()==that.userid.toString()&&data.sendId.toString()==this.info.friendId.toString()){
// 加入聊天记录
// 消息类型 0:文字 1:图片 2:文件 3:语音 4:视频 5 订单 6 商品 10, "撤回" 11, "已读 "12, "消息已读回执 " 30,"加载中标记"
if(data.type==0||data.type==1||data.type==2||data.type==3||data.type==4||data.type==5||data.type==6){
if(data.type==0){
data.content=decodeURIComponent(data.content);
}
// 获取图片,为下面的预览做准备
if(data.type == 1) {
this.imgMsg.unshift(data.content)
}
let mdata = {
"fromname": this.info.chatName,
"fromuser": this.info.friendId,
"headimg": this.info.chatAvatar,
"toname": this.userName,
"touser": this.userid,
"content": data.content,
"time": data.type==3?5:0,
"ifaudio":data.type==3? true:false,
"fromtime": data.sendTime,
"type": data.type,
"id": data.id,
"recvId": data.recvId,
"sendId": data.sendId
};
this.setMsglist(mdata)
// 接收到socket信息后更新聊天列表记录
var chatlastinfo={
id: this.info.chatId,
content:data.content,
type:data.type,
minId: data.id,
datetime: data.sendTime,
name: this.info.chatName,
userid: this.userid,
fromuser: this.info.friendId,
img: this.info.chatAvatar,
sort:"privatechat"
};
this.updateChatList(chatlastinfo);
// 已读操作
this.readed();
}
else{
// 10, "撤回" 11, "已读 " 12, "消息已读回执 " 30,"加载中标记"
}
}
}
}
}
});
uni.onSocketClose(res => {
console.log('WebSocket连接已关闭');
that.isConnected = false;
clearInterval(that.heartbeatInterval); // 停止心跳包发送
});
uni.onSocketError(err => {
console.error('WebSocket连接打开失败请检查', err);
clearInterval(that.heartbeatInterval); // 停止心跳包发送
});
}
},
// 关闭WebSocket连接
closeWebSocket() {
if (this.socket) {
uni.closeSocket();
this.socket = null;
this.isConnected = false;
}
},
async setMsglist(data){
data.send=data.type==6?await this.getProduct(data.content):(data.type==5?await this.getOrder(data.content):null);
data.type=data.type==0?'txt':(data.type==1?'image':data.type==3?'audio':(data.type==4?'video':(data.type==5?'order':(data.type==6?'product':'')))),
console.log("setMsglist",data)
this.unshiftmsg.push(data);
this.$forceUpdate();
setTimeout(() => {
this.screendo(this.unshiftmsg.length-1);
}, 100);
// 缓存聊天
myCache(this.info.chatId,this.unshiftmsg);
},
async getProduct(id){
console.log("getProduct",id)
var rets=null;
const {data: res} = await uni.$http.post("/api/message/private/getProductForIm",{"productId":id});
if(res.data){
var data=res.data;
rets={
type:data.isCourse==0?1:2,// 1 商品2 课程3订单
id:data.id,
name:data.name,
pic:data.pic,
price:data.price,
unit: data.unit,
brandName:data.brandName,
isCourse:data.isCourse
}
console.log(rets)
return rets;
}
else{
return rets;
}
},
async getOrder(id){
var rets=null;
const {data: res} = await uni.$http.post("/api/message/private/getOrderForIm",{"orderItemId":id});
if(res.data){
var data=res.data;
rets={
type:3,// 1 商品2 课程3订单
id:data.id,
orderId:data.orderId,
name:data.productName,
pic:data.pic?data.pic:'/static/image/nopic.png',
price:data.totalAmount,
quantity:data.quantity,
spData: data.spData? JSON.parse(data.spData):null
}
return rets;
}
else{
return rets;
}
},
// 已读推送
async readed() {
const {data: res} = await uni.$http.put('/api/message/private/readed?friendId='+this.info.friendId);
},
// 已读推送
async readUp(ii) {
const {data: res} = await uni.$http.put('/api/message/private/readed?friendId='+this.info.friendId);
this.getList(ii);
},
// 加载对话
async getList(ii) {
var that=this;
const {data: res} = await uni.$http.get('/api/message/private/pullOfflineMessage',{minId: this.info.minId});
this.triggered = false;
if(res.data&&res.data.length>0){
const gotonum=res.data.length;
var type=0;
res.data.forEach((cell,i)=>{
type=cell.type;
cell["ifaudio"]=false;
//时间间隔处理
if (i < this.unshiftmsg.length - 1) {
//这里表示头部时间还是显示一下
let t = dateTime.spaceTime(this.oldTime, cell.fromtime);
if (t) {
this.oldTime = t;
}
cell.fromtime = t;
}
// 获取图片,为下面的预览做准备
if (cell.type == 1) {
this.imgMsg.unshift(cell.content)
}
else if(cell.type==0){
cell.content=decodeURIComponent(cell.content);
}
// // 消息类型 0:文字 1:图片 2:文件 3:语音 4:视频 5 订单 6 商品 10, "撤回" 11, "已读 "12, "消息已读回执 " 30,"加载中标记"
let mdata = {
"fromname": this.userName,
"fromuser": this.userid,
"headimg": cell.headImage?cell.headImage:'/static/image/kfr.png',
"toname": this.info.chatName, // 接收人
"touser": this.info.friendId, // 接收人姓名
"content": cell.content,
"time": cell.type==3?5:0,
"ifaudio":cell.type==3? true:false,
"fromtime": cell.sendTime,
"type": data.type==0?'txt':(data.type==1?'image':data.type==3?'audio':(data.type==4?'video':(data.type==5?'order':(data.type==6?'product':'')))),
"id": cell.id,
"recvId": cell.recvId,
"sendId": cell.sendId,
};
this.unshiftmsg.unshift(mdata);
});
if(ii==2){
// 跳转到加载数据的第一条 与前面的:id进行对照
setTimeout(() => {
that.screendo(gotonum -1);
}, 100);
}
else{
// 跳转到最后一条数据 与前面的:id进行对照
setTimeout(() => {
that.screendo(that.unshiftmsg.length-1);
}, 100);
}
// 缓存聊天
myCache(this.info.chatId,this.unshiftmsg);
this.info.minId=this.unshiftmsg[this.unshiftmsg.length-1].id;
this.$forceUpdate();
// 离线加载后更新聊天列表记录
var chatlastinfo={
id: this.info.chatId,
content:this.unshiftmsg[this.unshiftmsg.length-1].content,
type: type,
minId: this.unshiftmsg[this.unshiftmsg.length-1].id,
datetime: this.unshiftmsg[this.unshiftmsg.length-1].sendTime,
name: this.info.chatName,
userid: this.userid,
fromuser: this.info.friendId,
img: this.info.chatAvatar,
sort:"privatechat"
};
this.updateChatList(chatlastinfo);
}
},
screendo(scrindex){
this.scrollToView = '';
// 跳转到最后一条数据 与前面的:id进行对照
this.$nextTick(function() {
this.scrollToView = 'msg' + scrindex
});
},
// 自定义下拉刷新控件被下拉
onPulling(e) {
var that=this;
if (!this.triggered) {
//下拉刷新先变true再变false才能关闭
this.triggered = true;
//关掉圈圈,需要先执行完刷新操作
setTimeout(() => {
that.triggered = false;
}, 2000);
}
},
// 自定义下拉刷新被触发
onRefresh(event){
// 加载聊天记录
this.readUp(2);
},
// 自定义下拉刷新被复位
onRestore() {
this.triggered = 'restore'; // 需要重置
console.log("onRestore");
},
// 自定义下拉刷新被中止
onAbort() {
this.triggered = false;
console.log("onAbort");
},
changeTime(date) {
return dateTime.dateTime1(date);
},
// 进行图片的预览
previewImg(e) {
let index = 0;
for (let i = 0; i < this.imgMsg.length; i++) {
if (this.imgMsg[i] == e) {
index = i;
}
}
// 预览图片
uni.previewImage({
current: index,
urls: this.imgMsg,
longPressActions: {
itemList: ['发送给朋友', '保存图片', '收藏'],
success: function(data) {
console.log('选中了第' + (data.tapIndex + 1) + '个按钮,第' + (data.index + 1) + '张图片');
},
fail: function(err) {
console.log(err.errMsg);
}
}
});
},
//音频播放
playVoice(e,ifplay,index) {
var that=this;
// 先关闭停止所有
innerAudioContext.src = '';
innerAudioContext.stop();
that.unshiftmsg.forEach((cell,i)=>{
cell.ifaudio=false;
});
ifplay=!ifplay;
this.unshiftmsg[index].ifaudio=ifplay;
this.$forceUpdate();
if(ifplay){
innerAudioContext.src = e;
innerAudioContext.play(() => {
console.log('开始播放');
});
// 监听音频播放结束事件
innerAudioContext.onEnded((res) => {
console.log('音频播放结束');
that.unshiftmsg[index].ifaudio=!ifplay;
that.$forceUpdate();
// 在这里执行你想要的操作
});
// innerAudioContext.onPlay(() => {
// console.log('开始播放');
// });
}
else{
innerAudioContext.src = '';
innerAudioContext.stop();
}
},
//地图定位
covers(e) {
let map = [{
latitude: e.latitude,
longitude: e.longitude,
iconPath: '../../static/image/head.png'
}]
return (map);
},
//跳转地图信息
openLocation(e) {
uni.openLocation({
latitude: e.latitude,
longitude: e.longitude,
name: e.name,
address: e.address,
success: function() {
console.log('success');
}
});
},
fullscreenchange(e){
if(!e.detail.fullScreen){ // 退出全屏,锁定竖屏
plus.screen.lockOrientation('portrait-primary');
}
},
//接受输入内容
async inputs(e) {
console.log("inputs");
console.log(e);
var rindex=this.unshiftmsg.length-1;
let data = {
"fromname": this.userName,
"fromuser": this.userid,
"headimg": this.userheadimg,
"toname": this.info.chatName, // 接收人
"touser": this.info.friendId, // 接收人姓名
"content": e.type=='audio'?e.message.voice:e.message,
"time": e.type=='audio'?e.message.time:0,
"ifaudio":false,
"fromtime": new Date(),
"type": e.type
};
if(e.type!=='video'){
this.unshiftmsg.push(data);
rindex=this.unshiftmsg.length-1;
// 跳转到最后一条数据 与前面的:id进行对照
this.screendo(this.unshiftmsg.length - 1);
}
// 发送给服务器消息
var that = this;
if(e.type=='txt'){
// 文本
// 消息发送
this.onSendWS(data,rindex);
}
else if(e.type=='image'){
// 图片
// 先上传在传送消息
var token= uni.getStorageSync("token");
console.log('先上传在传送消息');
uni.showLoading({
title: '图片上传中...'
});
uni.uploadFile({
url: uni.$http.baseUrl+"/api/image/upload",
filePath: e.message,
name: 'file',
header: {
'Authorization': token
},
success: res => {
console.log(res);
uni.hideLoading();
var rdata=JSON.parse(res.data);
if(rdata.data&&rdata.data.originUrl){
var url=rdata.data&&rdata.data.originUrl?rdata.data.originUrl:'';
data.content= url;
// 图片放入集合
if (e.type == 'image'&&url) {
this.imgMsg.push(url);
}
// 消息发送
this.onSendWS(data,rindex);
}
else{
this.$refs.uToast.show({
title:rdata.msg?rdata.msg:"图片上传失败...",
type: "error",
duration: 2000,
});
}
},
fail: res => {
uni.hideLoading();
console.log(res)
}
});
}
else if(e.type=='audio'){
// 音频
// 先上传在传送消息
var token= uni.getStorageSync("token");
console.log('先上传在传送消息');
uni.showLoading({
title: '音频上传中...'
});
uni.uploadFile({
url: uni.$http.baseUrl+"/api/file/upload",
filePath: e.message.voice,
name: 'file',
header: {
'Authorization': token
},
success: res => {
console.log(res);
uni.hideLoading();
var rdata=JSON.parse(res.data);
console.log(rdata);
if(rdata.data&&rdata.data.originUrl){
var url=rdata.data&&rdata.data.originUrl?rdata.data.originUrl:'';
data.content= url;
console.log(data);
// 消息发送
this.onSendWS(data,rindex);
}
else{
this.$refs.uToast.show({
title:rdata.msg?rdata.msg:"音频上传失败...",
type: "error",
duration: 2000,
});
}
},
fail: res => {
uni.hideLoading();
console.log(res)
}
});
}
else if(e.type=='video'){
// 视频
// 先上传在传送消息
var token= uni.getStorageSync("token");
console.log('先上传在传送消息');
uni.showLoading({
title: '视频上传中...'
});
uni.uploadFile({
url: uni.$http.baseUrl+"/api/file/upload",
filePath: e.message,
name: 'file',
header: {
'Authorization': token
},
success: res => {
uni.hideLoading();
console.log(res);
var rdata=JSON.parse(res.data);
console.log(rdata);
if(rdata.data){
var url=rdata.data;
data.content= url;
// 信息发送聊天框
this.unshiftmsg.push(data);
rindex=this.unshiftmsg.length-1;
// 跳转到最后一条数据 与前面的:id进行对照
this.screendo(this.unshiftmsg.length - 1);
// 消息发送
this.onSendWS(data,rindex);
}
else{
this.$refs.uToast.show({
title:rdata.msg?rdata.msg:"视频上传失败...",
type: "error",
duration: 2000,
});
}
},
fail: res => {
uni.hideLoading();
console.log(res)
}
});
}
},
// 消息发送
async onSendWS(datamsg,rindex){
var message=JSON.stringify(datamsg);
var msssagebf=JSON.parse(message);
if(msssagebf.type=='txt'){
msssagebf.content=encodeURIComponent(msssagebf.content);
}
var mtype= '0'; // 消息类型 0:文字 1:图片 2:文件 3:语音 4:视频 5订单 6 商品
if(msssagebf.type=='txt'){
mtype='0';
}
else if(msssagebf.type=='image'){
mtype='1';
}
else if(msssagebf.type=='audio'){
mtype='3';
}
else if(msssagebf.type=='video'){
mtype='4';
}
else if(msssagebf.type=='product'){
// 发送服务
if(this.sendinfo.type==3){
mtype='5';// 5订单 6 商品
}
else{
mtype='6';// 5订单 6 商品
}
}
var param={
"recvId": this.info.friendId,
"content": msssagebf.content,
"type": mtype
}
// 发送消息
const {data: res} = await uni.$http.post('/api/message/private/send',param);
if(res.data){
var rrdata=res.data;
if(rrdata.type==0){
rrdata.content=decodeURIComponent(rrdata.content);
}
this.unshiftmsg[this.unshiftmsg.length-1]["content"]=rrdata.content;
this.unshiftmsg[this.unshiftmsg.length-1]["id"]=rrdata.id;
this.unshiftmsg[this.unshiftmsg.length-1]["recvId"]=rrdata.recvId; // 接收人的id
this.unshiftmsg[this.unshiftmsg.length-1]["sendId"]=rrdata.sendId; // 发送人的id
this.unshiftmsg[this.unshiftmsg.length-1]["fromtime"]=rrdata.sendTime;
this.$forceUpdate();
// 缓存聊天
myCache(this.info.chatId,this.unshiftmsg);
// 更新聊天列表记录
var chatlastinfo={
id:this.info.chatId,
content:rrdata.content,
type:mtype,
minId: rrdata.id,
datetime:rrdata.sendTime,
name: this.info.chatName,
userid: this.userid,
fromuser: this.info.friendId,
img: this.info.chatAvatar,
sort:"privatechat",
send:this.sendinfo
};
this.updateChatList(chatlastinfo);
if(mtype=='5'||mtype=='6'){
// 关闭发送服务窗口
this.ifsend=false;
this.sendinfo=null;
this.$forceUpdate();
}
}
else{
this.unshiftmsg.pop();
uni.showModal({
title: '提示',
content: res.msg?res.msg :'抱歉!信息发送失败..',
cancelText: '取消',
confirmText: '确定',
success: ress => {
}
});
}
},
updateChatList(chatlastinfo){
// 更新聊天列表记录
var chatlist = myCache("chatlist");
if(chatlist&&chatlist.length>0){
var ifexist=0;
chatlist.forEach((cell,i)=>{
if(cell.id==this.info.chatId){
ifexist++;
chatlist[i]=chatlastinfo;
}
});
if(ifexist==0){
// 新增的添加
chatlist.unshift(chatlastinfo);
}
// 重新保存聊天记录
myCache("chatlist",chatlist);
}
else{
chatlist=[];
chatlist.push(chatlastinfo);
myCache("chatlist",chatlist);
}
},
//输入框高度
heights(e) {
this.inputh = e;
this.goBottom();
},
// 滚动到底部
goBottom() {
console.log("goBottom")
this.scrollToView = '';
this.screendo(this.unshiftmsg.length - 1);
},
handleImageError(e,index){
console.log(e,index);
this.unshiftmsg[index]["headimg"]= require("@/static/image/girl.png");
this.$forceUpdate();
},
}
}
</script>
<style lang="scss">
page {
height: 100%;
}
.content {
height: 100%;
background-color: rgba(244, 244, 244, 1);
position: relative;
}
::v-deep .uni-noticebar{
margin-bottom: 0 !important;
padding: 10rpx 12rpx !important;
border-radius: 10rpx;
}
.chat {
height: 100%;
.chat-main {
padding-left: 20rpx;
padding-right: 20rpx;
padding-top: 20rpx;
// padding-bottom: 120rpx; //
display: flex;
flex-direction: column;
}
.chat-ls {
.chat-time {
font-size: 24rpx;
color: rgba(39, 40, 50, 0.3);
line-height: 34rpx;
padding: 10rpx 0rpx;
text-align: center;
}
.msg-m {
display: flex;
padding: 20rpx 0;
.user-img {
flex: none;
width: 92rpx;
height: 90rpx;
border-radius: 20rpx;
text-align: center;
.uimg{
width: 70rpx;
height: 70rpx;
margin: 0 auto;
border-radius: 35rpx;
}
.uname{
height: 30rpx;
display: block;
margin: 0 auto;
line-height: 30rpx;
color: rgba(39, 40, 50, 0.5);
font-size: 24rpx;
}
}
.message {
flex: none;
max-width: 480rpx;
}
.messagevideo {
max-width: 480rpx;
height: 300rpx;
}
.msg-text {
font-size: 32rpx;
color: rgba(39, 40, 50, 1);
line-height: 44rpx;
padding: 18rpx 24rpx;
}
.msg-img {
max-width: 400rpx;
border-radius: 20rpx;
}
.msg-video{
width: 400rpx;
height: 300rpx;
border-radius: 20rpx;
}
.msg-map {
background: #fff;
width: 464rpx;
height: 284rpx;
overflow: hidden;
margin: 0 20rpx;
.map-name {
font-size: 32rpx;
color: rgba(39, 40, 50, 1);
line-height: 44rpx;
padding: 18rpx 24rpx 0 24rpx;
//
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
overflow: hidden;
}
.map-address {
font-size: 24rpx;
color: rgba(39, 40, 50, 0.4);
padding: 0 24rpx;
//
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
overflow: hidden;
}
.map {
padding-top: 8rpx;
width: 464rpx;
height: 190rpx;
}
}
.voice {
// width: 200rpx;
min-width: 100rpx;
max-width: 400rpx;
}
.voice-img {
width: 36rpx;
height: 36rpx;
}
}
.msg-left {
flex-direction: row;
.feed-imgy{
display: flex;
flex-direction: column;
justify-content: center;
align-self: center;
margin-right: 0rpx;
width: 95rpx;
height: 75rpx;
}
.feed-img{
display: flex;
flex-direction: column;
justify-content: center;
align-self: center;
margin-right: 0rpx;
width: 75rpx;
height: 75rpx;
}
.msg-text {
margin-left: 16rpx;
background-color: #fff;
border-radius: 0rpx 20rpx 20rpx 20rpx;
}
.ms-img {
margin-left: 16rpx;
}
.msg-video{
margin-left: 16rpx;
}
.msh-map {
margin-left: 16rpx;
border-radius: 0rpx 20rpx 20rpx 20rpx;
}
.msg-img {
margin: 0 0 0 20rpx;
}
.voice {
text-align: left;
display: flex;
}
.voice-img {
transform: rotate(180deg);
width: 36rpx;
height: 36rpx;
padding-bottom: 4rpx;
margin-right: 10rpx;
}
.voicel{
height: 32rpx;
width: 32rpx;
}
.bg {
background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAAAYCAYAAAAF6fiUAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MEM0NzgwODc1MDY0MTFFRjk1QjhFRUUxQjYyOUQ5NDQiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MEM0NzgwODg1MDY0MTFFRjk1QjhFRUUxQjYyOUQ5NDQiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDowQzQ3ODA4NTUwNjQxMUVGOTVCOEVFRTFCNjI5RDk0NCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDowQzQ3ODA4NjUwNjQxMUVGOTVCOEVFRTFCNjI5RDk0NCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PqxjhsEAAANzSURBVHjazJlLaNRQFIaTVIcRQUELoggVKYIgQvGFr40giLMRBAtjXblwUSmIK1vBTQUREUFB8NGdGwUXgoIVFwq6EGSkOAguXKiUQQq6kKK0Gv+LJ+HkTpLJfYUc+DnJ3M436Tn3eeKHYeiZ2NDQkGfZfCj03Nka6DzUgqZMYa1WS45HzIf15C/xqmeuE7ATOs3up1zxRefslYSgggn465j/GLpJ13ehfS75SEIu36/AFCQ6wQHoBbTgIOBZfBGow9AvaIXBb8d89PYFFpcEn7e5GAG+wXfPQc+g91DNQQKy+A3oB1SnkWDMR9BrbG0oxLeVgNAgCeLhF6FN0CuLiS3CP07+BDTgko/kbHC9BugG6w20ja63QxNSYk0tj/8EatP1uOYuKMFHoCdYW09+kDKnT0Kz0KjGKChik9AsxPkz0FnWvtIgsar8y2wUBDp8BDrBR+zS+CP4PCgyApZDa6Eb+ELDQQJiPs3DkV2FOnQ9atDjVfkPyS+DduvykQQtfpAypM7A3aPbB0iC7bNCgi+dRW6RP2owDanyf0Lv6HqPKl+KTxcf8czlBxnz2gjcPGXtiIOdSRb/Ofmt1KY7DanyZ8gP2uIjMYX4eXPeNPm9jg5Eafwv7IS+rkT+N/Kry+bnJeA3+T5HCUjjhxa3oCr8UOM3rfDzEnCQ/Fu2Q7K5be3i0+IWWadEfj/572Xzg4zywhW4VWwhs128y+LvJ9+mxbEs/mbyn2zxafHtyU87B4yzPe1JgOZZ8x8LwU/waTGL7BT5RwZTkSq/Rge06NCmxJfi08Wn8kQmP20ErKc56xIvpQJUx72NBMR8L1kKbkIb6fq6FKDQIb9BI1v8by91+YiPFj+1GgpYP4I9x+593IcZ05VOEsScOMfuxUuMr/Sg4uHHWNtSjUqlCv81HZDuQ8OqfPFChl7CxHx8NsbiE/Px+XChBKiYhXL0IPUMsYB9lopiddpthI74O9i0sIXVbbT5CPIAi02Cj7a2y2KcrjXp4UXpdpfUtmihIJfHjxbQp5rBL8xPC77NXY2JXaOeOS1t3fooAa74t9loaNrgI8gd1vsL8f0KvpSPdj4u3wuLncxFuj4mbSWVTH4pz3aSMR9/k8mv4jthz3HwD7HgXDAJfkaHTPDzgl+VKahs+wjdgT54/0vUzvhUos61fwIMANiWariLn8/jAAAAAElFTkSuQmCC);
width: 32rpx;
height: 32rpx;
background-size: 400%;
}
.msg-product{
display: flex;
flex-direction: column;
width: 100%;
background-color: #FFFFFF;
padding: 10rpx;
border-radius: 16rpx;
width: 480rpx;
margin-left: 12rpx;
.zx{
display: flex;
justify-content: space-between;
width: 100%;
font-size: 28rpx;
margin: 10rpx;
.zxview{
color: darkgrey;
font-size: 26rpx;
margin-right: 20rpx;
}
}
.msg-con{
display: flex;
justify-content: space-between;
width: 100%;
padding: 10rpx;
border-radius: 16rpx;
}
.img{
width: 120rpx;
height: 120rpx;
}
.info{
display: flex;
flex-direction: column;
flex: 1;
padding: 6rpx 8rpx;
position: relative;
margin-left: 10rpx;
background-color: #f4f4f4;
border-radius: 0 10rpx 10rpx 0;
.name{
width: 330rpx;
// white-space: nowrap; /* */
// overflow: hidden; /* */
// text-overflow: ellipsis; /* */
.txt{
font-size: 26rpx;
color: darkgrey;
margin-left: 6rpx;
}
.ntxt{
font-size: 28rpx;
color: #000;
}
}
.sku{
display: flex;
flex-direction: row;
.txt{
font-size: 26rpx;
color: darkgrey;
margin-right: 6rpx;
}
}
.xq{
width: 100%;
display: flex;
flex-direction: row;
.list{
display: flex;
flex: 1;
}
.price{
display: flex;
align-items: center;
font-size: 28rpx;
color: #ff007f;
}
.ord{
display: flex;
align-items: center;
font-size: 26rpx;
color: #232323;
}
.qty{
display: flex;
align-items: center;
font-size: 26rpx;
color: darkgrey;
margin-left: 8rpx;
}
.btn{
font-size: 26rpx;
font-family: PingFang SC-Medium, PingFang SC;
font-weight: 500;
color: #FCFCFD;
width: 110rpx;
height: 50rpx;
line-height: 50rpx;
background: #ff007f;
box-shadow: 0rpx 10rpx 30rpx 2rpx rgba(255,0,127,0.2);
border-radius: 60rpx;
opacity: 1;
margin-right: 10rpx;
margin-top: 10rpx;
margin-bottom: 10rpx;
padding-left:0 !important;
padding-right:0 !important;
&::after{
border:none;
}
}
}
}
}
}
.msg-right {
flex-direction: row-reverse;
.feed-imgy{
display: flex;
flex-direction: column;
justify-content: center;
align-self: center;
margin-right: 0rpx;
width: 95rpx;
height: 75rpx;
}
.feed-img{
display: flex;
flex-direction: column;
justify-content: center;
align-self: center;
margin-right: 0rpx;
width: 75rpx;
height: 75rpx;
}
.msg-text {
margin-right: 16rpx;
background-color: #00a89b;
font-family: PingFang SC, PingFang SC;
font-weight: 400;
font-size: 32rpx;
color: #FFFFFF;
line-height: 48rpx;
border-radius: 20rpx 0rpx 20rpx 20rpx;
}
.ms-img {
margin-right: 16rpx;
}
.msg-img {
margin: 0 20rpx 0 0;
}
.msg-video{
margin: 0 20rpx 0 0;
}
.msh-map {
margin-left: 16rpx;
border-radius: 20rpx 0rpx 20rpx 20rpx;
}
.voice {
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-end;
}
.voice-img {
display: block;
width: 36rpx;
height: 36rpx;
margin-left: 10rpx;
}
.voicel{
height: 32rpx;
width: 32rpx;
}
.bg {
background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAAAYCAYAAAAF6fiUAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6REJBQzQ1RjQ1MDYzMTFFRjk5QjZEQkI5MDlENzE3RTQiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6REJBQzQ1RjU1MDYzMTFFRjk5QjZEQkI5MDlENzE3RTQiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpEQkFDNDVGMjUwNjMxMUVGOTlCNkRCQjkwOUQ3MTdFNCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpEQkFDNDVGMzUwNjMxMUVGOTlCNkRCQjkwOUQ3MTdFNCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pm5p+OoAAAKmSURBVHja1Jk/SBxBFMbdy6mHSEARNYIkhU0ICCEkEEynEYmkUEiTxmBtZZHCgGVsAgEhQozYaAo7G0GwjgemC1ZBgzbaKKnEIsb1HbwjH8PM7szdfEQffMzyzexvhn2zM/snSdO0wSOmRfdFc6JfDfGDzb++UUlAjmbTfzHi0T5UbP61Vl6DV3BxZggDYPNRyU1LQDtcnC9GXY/ojeh2HZ2z+ahbZD4lAZt6cQ4Mv1v0W+tm6+icza+qSOZTEvAAZudjo+5Q/SNRX40ds/m47JSIfFoC1nSQ24Y/r/4fUZdR1xHQMZtfVSOZH7LndPgmoEl0oQMdA/8OzNrXxjlzokvRgsfA2HxUM5nvUsmXbzt5CGZJE/jv1d832k8GPsmw+TgDEyLfd8PP5NsAM9q4bPi76r8FrwXgHzwHyOa7loDY/Kw73JtvAyzpCcvgtQLoKfgT6p0GDJDNtyWAwXepEMIvWF6O27Q8Aa8bjo/h+JGWWwEv32y+Ldh8jMsQvi0B1Y9DicUz/b9aNod8/SDzs/pk8V2Ry7cl4FTLTvCORBd63Av+Ny2HAwbF5tuCzXdFLt+WgD0t+8E7F/3Q40Hw17WuRbTqOSg23zbrGXyfyOdbNoYB2LBaLU8vx0b7UWj/0WOTYvNdGzGD76NMvu0OKGvWKjEO/ifY0KbB3xBN6eZ25jEr2HxXxOQnAf1m8x1ZW9SM7Rr+O8hmfx2z4jOZ71IsfoH9LegeDPSFUfcd3mSf1NjxXTI/64UsBj/av4WC47Y5EK3o8VejbkD0U1QUPa9xOTgk812bcSx+GrgM1fRLsvIl8Vxny4albqjOW5HNz+ubyY/2S/IZLBULhAGz+Tf+n7D5Ne8lYRBsPmXzjKWixyq1rOVD0Q7hZYXNz9oP/ntcCTAAHScbp0OSlTgAAAAASUVORK5CYII=);
width: 32rpx;
height: 32rpx;
background-size: 400%;
}
.msg-product{
display: flex;
flex-direction: column;
width: 100%;
background-color: #FFFFFF;
padding: 10rpx;
border-radius: 16rpx;
width: 480rpx;
margin-right: 12rpx;
.zx{
display: flex;
justify-content: space-between;
width: 100%;
font-size: 28rpx;
margin: 10rpx;
.zxview{
color: darkgrey;
font-size: 26rpx;
margin-right: 20rpx;
}
}
.msg-con{
display: flex;
justify-content: space-between;
width: 100%;
padding: 10rpx;
border-radius: 16rpx;
}
.img{
width: 120rpx;
height: 120rpx;
}
.info{
display: flex;
flex-direction: column;
flex: 1;
padding: 6rpx 8rpx;
position: relative;
margin-left: 10rpx;
background-color: #f4f4f4;
border-radius: 0 10rpx 10rpx 0;
.name{
width: 330rpx;
// white-space: nowrap; /* */
// overflow: hidden; /* */
// text-overflow: ellipsis; /* */
.txt{
font-size: 26rpx;
color: darkgrey;
margin-left: 6rpx;
}
.ntxt{
font-size: 28rpx;
color: #000;
}
}
.sku{
display: flex;
flex-direction: row;
.txt{
font-size: 26rpx;
color: darkgrey;
margin-right: 6rpx;
}
}
.xq{
width: 100%;
display: flex;
flex-direction: row;
.list{
display: flex;
flex: 1;
}
.price{
display: flex;
align-items: center;
font-size: 28rpx;
color: #ff007f;
}
.ord{
display: flex;
align-items: center;
font-size: 26rpx;
color: #232323;
}
.qty{
display: flex;
align-items: center;
font-size: 26rpx;
color: darkgrey;
margin-left: 8rpx;
}
.btn{
font-size: 26rpx;
font-family: PingFang SC-Medium, PingFang SC;
font-weight: 500;
color: #FCFCFD;
width: 110rpx;
height: 50rpx;
line-height: 50rpx;
background: #ff007f;
box-shadow: 0rpx 10rpx 30rpx 2rpx rgba(255,0,127,0.2);
border-radius: 60rpx;
opacity: 1;
margin-right: 10rpx;
margin-top: 10rpx;
margin-bottom: 10rpx;
padding-left:0 !important;
padding-right:0 !important;
&::after{
border:none;
}
}
}
}
}
}
}
}
.voicePlay {
animation-name: voicePlay;
animation-duration: 1s;
animation-direction: normal;
animation-iteration-count: infinite;
animation-timing-function: steps(3);
}
@keyframes voicePlay {
0% {
background-position: 0;
}
100% {
background-position: 100%;
}
}
.popup{
position: fixed;
bottom: 180rpx;
/* #ifdef H5 */
bottom: 100rpx;
/* #endif */
left: 0;
width: 100%;
padding: 18rpx;
border-radius: 16rpx;
.tipcon{
display: flex;
justify-content: space-between;
width: 100%;
background-color: #FFFFFF;
padding: 16rpx;
border-radius: 16rpx;
.img{
width: 100rpx;
height: 100rpx;
}
.info{
display: flex;
flex-direction: column;
flex: 1;
margin-left: 16rpx;
position: relative;
.name{
width: 550rpx;
// white-space: nowrap; /* */
// overflow: hidden; /* */
// text-overflow: ellipsis; /* */
margin-right: 50rpx;
.txt{
font-size: 26rpx;
color: darkgrey;
margin-left: 6rpx;
}
.ntxt{
font-size: 28rpx;
color: #000;
}
}
.sku{
display: flex;
flex-direction: row;
.txt{
font-size: 26rpx;
color: darkgrey;
margin-right: 6rpx;
}
}
.xq{
width: 100%;
display: flex;
flex-direction: row;
.list{
display: flex;
flex: 1;
align-items: flex-end;
}
.price{
font-size: 28rpx;
color: #ff007f;
}
.ord{
display: flex;
align-items: center;
font-size: 26rpx;
color: #232323;
}
.qty{
font-size: 26rpx;
color: darkgrey;
margin-left: 6rpx;
}
.btn{
font-size: 26rpx;
font-family: PingFang SC-Medium, PingFang SC;
font-weight: 500;
color: #FCFCFD;
width: 150rpx;
height: 50rpx;
line-height: 50rpx;
background: #ff007f;
box-shadow: 0rpx 10rpx 30rpx 2rpx rgba(255,0,127,0.2);
border-radius: 10rpx;
opacity: 1;
margin-right: 10rpx;
padding-left:0 !important;
padding-right:0 !important;
&::after{
border:none;
}
}
}
.close{
position: absolute;
top: 0;
right: 6rpx;
}
}
}
}
</style>