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.

1092 lines
33 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 !== friendcode">
<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>
<view class="msg-m msg-right" v-if="item.fromuser == friendcode">
<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 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>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>
</view>
</view>
</scroll-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,
friendName: "",
friendcode: "",
friendheadimg: "",
info:{},// 会话基本信息
imgurl:"",// uni.$http.baseUrl,
iftop:true,
msg: [
// {
// fromuser: "11",
// fromname: "Madeline 老师 (女)",
// fromtime:'2025-06-20 10:00:00',
// headimg:require("@/static/image/i1.png"),
// content:'Hixxx我是普拉提教练小a周日上午10点的课您可以准时参加吧',
// type:'txt'
// },
], // 排序用,暂不使用
// 反转数据接收
unshiftmsg: [
// {
// fromuser: "11",
// fromname: "Madeline 老师 (女)",
// fromtime:'2025-06-20 10:00:00',
// headimg:require("@/static/image/i1.png"),
// content:'Hixxx我是普拉提教练小a周日上午10点的课您可以准时参加吧',
// type:'txt'
// },
// {
// fromuser: "1",
// fromname: "测试人",
// fromtime:'2025-06-20 10:35:40',
// headimg:require("@/static/image/girl.jpg"),
// content:'没问题',
// type:'txt'
// },
], // chatrurn
imgMsg: [],
scrollToView: '',
oldTime: new Date(),
inputh: '90',
loadStatus:true,
ifaudio:false, // 是否音频
socket: null, // WebSocket实例
isConnected: false, // WebSocket连接状态
}
},
onLoad(options) {
var user = myCache('user');
// 本人聊天信息
this.friendName=user.nickName?user.nickName:"";
this.friendcode=user.userid?user.userid:"";
this.friendheadimg=user.avatar?user.avatar:require("@/static/image/girl.jpg");
if(options.data){
// 会话信息
this.info=JSON.parse(decodeURIComponent(options.data));
// 会话标题
var title =this.info.chatType=="teacher"?'教练'+this.info.chatName:this.info.chatName;
uni.setNavigationBarTitle({
title: title,
});
// 先获取缓存
this.getchatstore();
// socket接收信息
this.socketinit();
}
},
onShow() {
// 跳转到最后一条数据 与前面的:id进行对照
this.screendo(this.unshiftmsg.length - 1);
},
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();
},
//点击导航栏 buttons 时触发 添加任务
onNavigationBarButtonTap: async function(e) {
const _that = this;
const index = e.index;
if (index === 0) {
var data=encodeURIComponent(JSON.stringify(_that.info));
uni.navigateTo({
url: `/pages/chat/chatset?data=${data}`
});
}
},
methods: {
gotoset(){
var data=encodeURIComponent(JSON.stringify(this.info));
uni.navigateTo({
url: `/pages/chat/chatset?data=${data}`
});
},
tuclose(){
this.iftop=false;
},
handleImageError(e,index){
console.log(e,index);
this.unshiftmsg[index]["headimg"]= require("@/static/image/girl.jpg");
this.$forceUpdate();
},
// 获取聊天记录
getchatstore(){
var that=this;
try{
// 先获取会话缓存
console.log(this.info.chatId);
var data= myCache(this.info.chatId)?myCache(this.info.chatId):[];
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);
// 跳转到最后一条数据 与前面的:id进行对照
setTimeout(() => {
that.screendo(that.unshiftmsg.length-2);
}, 300);
});
if(this.unshiftmsg.length<=0)
{
// 首次教练会话自动信息
var cont = 'Hi'+this.friendName+',欢迎您!请问有什么可以帮助您的呢?';
if(this.info.chatType=="teacher"){
cont = 'Hi'+this.friendName+',欢迎您!我是'+this.info.chatName+'教练,请问有什么可以帮助您的呢?';
}
this.unshiftmsg = [
{
"fromname": this.info.chatName,
"fromuser": this.info.friendId,
"headimg": this.info.chatAvatar,
"toname": this.friendName, // 接收人
"touser": this.friendcode, // 接收人姓名
"content": cont,
"time": 0,
"ifaudio":false,
"fromtime": new Date(),
"type": 'txt'
}
];
this.$forceUpdate();
}
// 请求服务器加载加载拉取离线聊天记录
if(this.info.minId>0){
this.getList(1);
}
}
catch(err){
console.log(err);
}
},
// ws接收消息
socketinit(){
var that = this;
if (!this.isConnected) {
this.socket = uni.connectSocket({
url: "wss://www.sanduolantoyoga.com/yoga-imserver/",
});
uni.onSocketOpen(res => {
console.log('WebSocket连接已打开');
that.isConnected = true;
// 登录参数
let loginInfo = {
cmd: 0,//登录
data: {
accessToken: uni.getStorageSync("token")
}
};
// this.socket.send(JSON.stringify(loginInfo));
});
uni.onSocketMessage(res => {
console.log('收到WebSocket服务器消息', res.data);
if(res.data){
let data=JSON.parse(res.data);
console.log(data);
if(data){
// 加入聊天记录
// 消息类型 0:文字 1:图片 2:文件 3:语音 4:视频 10, "撤回" 11, "已读 "12, "消息已读回执 " 30,"加载中标记"
if(data.type=='0'){
data.content=decodeURIComponent(data.content);
}
let mdata = {
"fromname": this.friendName,
"fromuser": this.friendcode,
"headimg": this.friendheadimg,
"toname": this.info.chatName, // 接收人
"touser": this.info.friendId, // 接收人姓名
"content": data.content,
"time": data.type==3?5:0,
"ifaudio":data.type==3? true:false,
"fromtime": data.sendTime,
"type": data.type==0?'txt':(data.type==1?'image':data.type==3?'audio':(data.type==4?'video':'')),
"id": data.id,
"recvId": data.recvId,
"sendId": data.sendId,
};
if(data.type==0||data.type==1||data.type==3||data.type==4){
that.unshiftmsg.push(data);
that.$forceUpdate();
// 跳转到最后一条数据 与前面的:id进行对照
that.$nextTick(function() {
that.scrollToView = 'msg' + (that.unshiftmsg.length);
});
}
else{
// 10, "撤回" 11, "已读 "12, "消息已读回执 " 30,"加载中标记"
}
}
}
});
uni.onSocketClose(res => {
console.log('WebSocket连接已关闭');
that.isConnected = false;
});
uni.onSocketError(err => {
console.error('WebSocket连接打开失败请检查', err);
});
}
},
// 发送WebSocket消息
sendWebSocketMessage() {
if (this.socket && this.isConnected) {
uni.sendSocketMessage({
data: '这是一条测试消息' // 发送的消息内容
});
} else {
console.error('WebSocket未连接或未打开请先连接WebSocket');
}
},
// 关闭WebSocket连接
closeWebSocket() {
if (this.socket) {
uni.closeSocket();
this.socket = null;
this.isConnected = false;
}
},
// 加载对话
async getList(ii) {
var that=this;
if(this.loadStatus)
{
const {data: res} = await uni.$http.get('/api/message/private/pullOfflineMessage',{minId:this.info.minId});
this.triggered = false;
if(res.success){
if(res.data&&res.data.length>0){
const gotonum=res.data.length;
res.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') {
// cell.content=this.imgurl+'/images/'+cell.content;
this.imgMsg.unshift(cell.content)
}
else if(cell.type=='txt'){
cell.content=decodeURIComponent(cell.content);
}
this.unshiftmsg.unshift(cell);
});
if(ii==2){
// 跳转到加载数据的第一条 与前面的:id进行对照
setTimeout(() => {
that.screendo(gotonum -2);
}, 200);
}
else{
// 跳转到最后一条数据 与前面的:id进行对照
setTimeout(() => {
that.screendo(that.unshiftmsg.length-1);
}, 300);
}
// 缓存聊天
myCache(this.info.chatId);
}
else{
this.$refs.uToast.show({
title: "信息已加载完毕...",
type: "success",
duration: 2000,
});
this.loadStatus=false;
}
}
else{
this.$refs.uToast.show({
title: "信息加载失败...",
type: "error",
duration: 2000,
});
}
}
else{
this.triggered = false;
this.$refs.uToast.show({
title: "信息已加载完毕...",
type: "success",
duration: 2000,
});
}
},
screendo(scrindex){
this.scrollToView = '';
// 跳转到最后一条数据 与前面的:id进行对照
this.$nextTick(function() {
this.scrollToView = 'msg' + scrindex
});
},
// 自定义下拉刷新控件被下拉
onPulling(e) {
var that=this;
// console.log("onpulling", e);
if (!this.triggered) {
//下拉刷新先变true再变false才能关闭
this.triggered = true;
//关掉圈圈,需要先执行完刷新操作
setTimeout(() => {
that.triggered = false;
}, 2000);
}
},
// 自定义下拉刷新被触发
onRefresh(event){
console.log("下拉加载"+event);
// 加载聊天记录
this.getList(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;
console.log(this.imgMsg)
for (let i = 0; i < this.imgMsg.length; i++) {
if (this.imgMsg[i] == e) {
index = i;
}
}
console.log("index", index)
// 预览图片
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(e);
var rindex=this.unshiftmsg.length-1;
let data = {
"fromname": this.friendName,
"fromuser": this.friendcode,
"headimg": this.friendheadimg,
"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);
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);
// 图片放入集合
if (e.type == 'image'&&url) {
this.imgMsg.push(url);
}
// 消息发送
this.onSendWS(data,rindex);
}
},
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);
}
},
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&&rdata.data.originUrl){
var url=rdata.data&&rdata.data.originUrl?rdata.data.originUrl:'';
data.content= url;
console.log(data);
// 信息发送聊天框
this.unshiftmsg.push(data);
rindex=this.unshiftmsg.length-1;
// 跳转到最后一条数据 与前面的:id进行对照
this.screendo(this.unshiftmsg.length - 1);
// 消息发送
this.onSendWS(data,rindex);
}
},
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:视频
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';
}
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;
this.unshiftmsg[this.unshiftmsg.length-1]["sendId"]=rrdata.sendId;
this.unshiftmsg[this.unshiftmsg.length-1]["fromtime"]=rrdata.sendTime;
this.$forceUpdate();
// 缓存聊天
myCache(this.info.chatId,this.unshiftmsg);
console.log('this.unshiftmsg',this.unshiftmsg);
// 更新聊天记录列表
var chatlastinfo={
id:this.info.chatId,
content:rrdata.content,
minId:rrdata.id,
datetime:rrdata.sendTime,
chatType: "teacher",
name: this.info.chatName,
fromuser: this.info.friendId,
img: this.info.chatAvatar,
};
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() {
this.scrollToView = '';
this.screendo(this.unshiftmsg.length - 1);
}
}
}
</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-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: #89965f;
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%;
}
}
}
}
.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%;
}
}
</style>