ufutx_love_mp/src/pages/news/groupChitchat.wpy
2024-10-23 16:30:51 +08:00

1518 lines
44 KiB
Plaintext

<style lang="less" scoped>
@import url(../../styles/theme.less);
page {
background-color: #f5f5f5;
}
.m_tips_icon {
width: 140rpx;
height: 140rpx;
position: fixed;
top: 32rpx;
right: -4rpx;
z-index: 999;
}
.ui-scroll-view{
-webkit-overflow-scrolling: touch;
will-change: transform;
background: #f2f2f2;
}
.ui-top-placeholder {
width: 100vw;
height: 30rpx;
}
.ui-tips-box{
display: inline-block;
padding: 20rpx;
border-radius: 16rpx;
width: 76%;
margin: 0 50rpx 30rpx 50rpx;
background: #ffffff;
.ui-tips_icon{
width: 28rpx;
height: 28rpx;
vertical-align: middle;
margin-top: -8rpx;
margin-right: 6rpx;
}
.ui-tips_text{
text-align: justify;
text-align-last: left;
line-height: 1.6;
margin-top: 10rpx;
}
}
.ui-msg-data-box {
padding: 0 30rpx 160rpx 30rpx;
.ui-msg-data {
overflow: hidden;
padding-bottom: 36rpx;
}
.ui-left-msg-box {
float: left;
}
.ui-right-msg-box {
float: right;
}
.ui-user-pic {
width: 86rpx;
height: 86rpx;
border: 2rpx solid #eaeaea;
box-shadow: 0 0 12rpx #cccccc;
border-radius: 50%;
display: block;
vertical-align: top;
}
.ui-user-name {
color: #86889a;
letter-spacing: 2rpx;
}
.ui-msg-left,
.ui-msg-right {
max-width: 480rpx;
padding: 20rpx 24rpx;
background: #ffffff;
line-height: 42rpx;
letter-spacing: 2rpx;
word-wrap: break-word;
word-break: break-all;
.emoji_small {
width: 42rpx;
height: 42rpx;
vertical-align: middle;
}
}
.ui-msg-left-pic, .ui-msg-right-pic{
border: 2rpx solid #eaeaea;
max-width: 200rpx;
max-height: 200rpx;
border-radius: 20rpx;
display: block;
vertical-align: top;
}
.ui-right-audio{
background: #ff7d9f;
}
.ui-left-audio{
background: #ffffff;
}
.ui-audio-box{
padding: 10rpx 24rpx;
box-sizing: content-box;
height: 100%;
justify-content: space-between;
overflow-x: hidden;
.ui-audio-icon,.ui-audio-icon-l-play,.ui-audio-icon-r-play{
position: relative;
width: 28rpx;
height: 36rpx;
overflow: hidden;
}
.ui-audio-icon-l-play:before,.ui-audio-icon-r-play:before{
content: '';
position: absolute;
top:0;
width: 28rpx;
height: 36rpx;
}
.ui-audio-icon-l-play:before {
left: 0;
background: #ffffff;
animation: volumeLPlay 1.5s linear infinite;
}
.ui-audio-icon-r-play:before{
right:0;
background: #ff7d9f;
animation: volumeRPlay 1.5s linear infinite;
}
@keyframes volumeLPlay{
0%{
left: 8rpx;
}
25%{
left: 8rpx;
}
50%{
left: 20rpx;
}
75%{
left: 28rpx;
}
100%{
left: 28rpx;
}
}
@keyframes volumeRPlay{
0%{
right: 8rpx;
}
25%{
right: 8rpx;
}
50%{
right: 20rpx;
}
75%{
right: 28rpx;
}
100%{
right: 28rpx;
}
}
}
.liveImg {
position: relative;
border-radius: 20rpx;
.ui-video-box, .ui-video-r-box{
position: relative;
.ui-vide-poster{
position: absolute;
top:50%;
left:50%;
transform: translate(-50%,-50%);
text-align: center;
}
.ui-video_play_icon{
width: 52rpx;
height:52rpx;
}
.ui-video_play-text{
width: 120rpx;
}
}
.ui-video-box{
width: auto;
border-radius: 16rpx;
}
.ui-video-r-box{
width: auto;
border-radius: 16rpx;
}
}
.ui-source-text {
width: fit-content;
border-radius: 0 8rpx 8rpx 0;
background: linear-gradient(90deg, rgba(221, 216, 250, 0.14) 0%, rgba(221, 216, 250, 1) 100%);
padding: 4rpx 16rpx 4rpx 36rpx;
margin-top: 10rpx;
float: right;
}
.ui-msg-right {
background: #FF7D9F;
}
.ui-copy-icon-box {
width: 54rpx;
height: 54rpx;
background: #ffffff;
border-radius: 50%;
position: absolute;
right: -70rpx;
top: 0;
.ui-copy-icon {
width: 32rpx;
height: 32rpx;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
}
.ui-left-msg-radius {
border-radius: 0 32rpx 32rpx 32rpx;
}
.ui-right-msg-radius {
border-radius: 32rpx 0 32rpx 32rpx;
}
}
.ui-bottom-input-box {
width: 100vw;
padding: 32rpx 30rpx 72rpx 30rpx;
box-sizing: border-box;
background: #ffffff;
border-radius: 42rpx 42rpx 0 0;
box-shadow: 0 0 12rpx #f8f8f8;
position: fixed;
bottom: 0;
left: 50%;
transform: translateX(-50%);
z-index: 999;
.replyView{
width: 100vw;
position: fixed;
bottom: 180rpx;
left: 0;
padding: 32rpx;
z-index: 9999999;
.replyContent{
border-radius: 32rpx;
max-height: 78vh;
overflow: auto;
padding: 16rpx 26rpx;
background: #FFFFFF;
line-height: 42rpx;
letter-spacing: 4rpx;
word-break: break-all;
}
.main-content-box {
display: inline-block;
white-space: pre-line;
vertical-align: center;
align-items: center;
margin-top: 4rpx;
word-break: break-all; // 纯数字、单词换行
.m_rich {
margin-right: -4rpx;
}
.emoji_text {
align-items: center;
padding: 4rpx;
line-height: 40rpx;
.emoji_small {
width: 42rpx;
height: 42rpx;
vertical-align: middle;
}
}
}
}
}
.ui-input-box {
width: 85vw;
height: 72rpx;
line-height: 72rpx;
padding: 20rpx 76rpx 20rpx 26rpx;
margin-right: 20rpx;
background: #f5f5f7;
border-radius: 100rpx;
position: relative;
.ui-emoji-icon{
width: 44rpx;
height: 44rpx;
position: absolute;
right: 20rpx;
z-index: 9;
}
.ui-input {
width: 100%;
position: relative;
z-index: 3;
background: initial;
word-break: break-all;
}
}
.ui-send-box {
.ui-send-icon{
width: 0;
height: 66rpx;
transition: width .2s;
transition-timing-function: linear;
}
.ui-send-icon.active {
width: 90rpx;
height: 90rpx;
color: white;
border-radius: 12rpx;
}
.ui_add_icon{
width: 44rpx;
height: 44rpx;
transition-delay: .2s;
}
.ui_add_icon.active {
width: 0;
height: 44rpx;
transition-delay: 0s;
}
}
.ui-microphone-box{
margin-right: 20rpx;
width: 36rpx;
height: 44rpx;
.ui-microphone-image{
width: 36rpx;
height: 44rpx;
}
}
.ui-microphone-close,
.ui-microphone-open{
width: 100%;
text-align: center;
height: 72rpx;
line-height: 72rpx;
border-radius: 36rpx;
}
.ui-microphone-open{
background: #FFFFFF;
border: 2rpx solid #E8E8E8;
}
.ui-microphone-close{
background: #E8E8E8;
}
.ui-microphone-message{
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
width: 320rpx;
height: 320rpx;
background: #757575;
border-radius: 24rpx;
text-align: center;
.ui-icon-change-stop .ui-icon-change:before{
animation-play-state: paused!important;
}
.ui-icon-box{
margin:86rpx 0 0 88rpx;
display: flex;
align-items: flex-end;
.ui-icon-microphone{
margin-right: 20rpx;
width: 76rpx;
height: 110rpx;
}
.ui-icon-change{
margin-bottom: 12rpx;
position: relative;
width: 52rpx;
height: 88rpx;
background-size: cover;
background-repeat: no-repeat;
background-image: url("https://image.fulllinkai.com/202308/15/f5461afc6ade909fa61a6be0b8e2a084.png");
overflow: hidden;
}
.ui-icon-change:before{
content: '';
position: absolute;
bottom: 0;
left: 0;
width: 52rpx;
height: 88rpx;
background: #757575;
animation: volumeChange 2.5s linear infinite;
}
@keyframes volumeChange {
0%{
bottom: 0rpx;
}
16%{
bottom: 14rpx;
}
32%{
bottom: 28rpx;
}
48%{
bottom: 42rpx;
}
64%{
bottom: 56rpx;
}
78%{
bottom: 70rpx;
}
94%{
bottom: 88rpx;
}
100%{
bottom: 88rpx;
}
}
}
.ui-icon-text{
margin: 52rpx auto;
}
}
.m_inp_ct {
border: 0;
width: 100%;
height: 0rpx;
transition: height .2s;
-moz-transition: height .2s; /* Firefox 4 */
-webkit-transition: height .2s; /* Safari 和 Chrome */
-o-transition: height .2s; /* Opera */
transition-timing-function: linear;
overflow: hidden;
padding-top: 0rpx;
.u_xi {
width: 100%;
height: 2rpx;
background-color: #f5f5f7;
}
.u_imp_lst {
padding: 30rpx;
.m_impLst_img {
width: 100rpx;
height: 100rpx;
border-radius: 20rpx;
background-color: white;
margin-bottom: 8rpx;
}
}
}
.m_inp_ct.sel {
height: 200rpx;
padding-top: 30rpx;
}
.m_inp_ct.emojiSel {
height: 400rpx;
padding-top: 30rpx;
overflow: hidden;
}
.m_prog {
background-color: #a8a8a8;
border-radius: 30rpx;
width: 200rpx;
.conic-progress {
margin: 50rpx auto;
position: relative;
width: 100rpx;
height: 100rpx;
border-radius: 50%;
}
.conic-progress::before {
content: "";
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 86%;
height: 86%;
border-radius: 50%;
background-color: #a8a8a8;
overflow: hidden;
}
}
</style>
<template>
<view class="ui-groupChitchat">
<image class="m_tips_icon" @tap="jumpDetailPath" src="https://image.fulllinkai.com/202307/24/8c9d68ecf83230ea5e394aa98ef1765d.png" mode="aspectFit"></image>
<scroll-view class="ui-scroll-view" style="height: {{windowHeight - bottomBoxH}}rpx;" :scroll-y="scrollY" upper-threshold="50" bindscrolltoupper="getHistoryMsg" scroll-into-view="{{toView}}" enable-flex="{{true}}">
<view class="ui-top-placeholder"></view>
<view class="ui-tips-box" v-show="loading">
<view class="font_28 color333 bold">
<image src="https://images.ufutx.com/202012/24/dcf6c6454e7bb280c07346dcdceef767.png" mode="widthFix" class="ui-tips_icon"></image>
聊天小贴士
</view>
<view class="font_24 ui-tips_text">
请各位会员自觉遵守法律法规,<span class="color-theme">遇到转款切勿相信,谨防上当受骗,</span>未实名认证的会员保持警惕;交友期保持必要的界限,保证自身安全,请勿轻易委身于人,<span class="color-theme">请勿和用户发生借贷关系,</span>否则后果自己承担。
</view>
</view>
<view class="ui-msg-data-box" v-show="msgList.length > 0">
<view v-for="(item, index) in msgList" :key="index" class="ui-msg-data" id="{{item.id}}">
<block v-if="item.msgType == '7' || item.msgType == 'notification' && item.tips">
<!--群消息通知-->
<view class="text-center color999 font_24">{{item.tips}}</view>
</block>
<block v-else>
<view class="text-center color999 font_24 ui-pb-16" v-if="item.showTime">{{item.time}}</view>
<view class="{{!item.isSelf ? 'ui-left-msg-box f-fl' : 'ui-right-msg-box f-fr'}}">
<image v-if="!item.isSelf" class="ui-user-pic" :src="item.avatar" mode="aspectFill"></image>
<view class="{{!item.isSelf ? 'ui-pl-12' : 'ui-pr-12'}}">
<view class="ui-relative">
<view v-if="membersData.user_team.show_other_nick" class="font_26 color999 ui-pb-8 {{!item.isSelf ? 'text-left' : 'text-right'}}">{{item.name}}</view>
<!--文本加表情信息-->
<view class="{{!item.isSelf ? 'ui-left-msg-radius ui-msg-left color3' : 'ui-right-msg-radius ui-msg-right white'}} font_28" v-if="item.msgType == '0' || item.msgType == 'text'">
<rich-text nodes="{{item.text}}"></rich-text>
</view>
<!--图片信息-->
<image v-if="item.msgType == '1' || item.msgType == 'image'" class="ui-msg-left-pic" :style="{maxWidth: item.attach.w + 'rpx', maxHeight: item.attach.h + 'rpx'}" :src="item.attach.url" mode="aspectFill" @tap.stop="previewImage(item.attach.url)"></image>
<!--音频信息-->
<view v-if="item.msgType == '2' || item.msgType == 'audio'" class="{{!item.isSelf ? 'ui-left-msg-radius ui-left-audio' : 'ui-right-msg-radius ui-right-audio white' }} ui-audio-box font_36 f-fc" :style="{width: item.audioDur < 20 ? '120rpx' :item.audioDur < 40 ? '180rpx' : '320rpx', maxWidth: '320rpx!important', minWidth: '120rpx!important'}" @tap.stop="playAudio(item.attach, index)">
<image v-if="!item.isSelf" class="{{!audioState || playAudioIndex != index ? 'ui-audio-icon' : 'ui-audio-icon-l-play'}}" src="https://image.fulllinkai.com/202308/09/a0e320ef4f498309745d35f6798e970f.png" mode="aspectFit" lazy-load="false"></image>
<image v-else class="{{!audioState || playAudioIndex != index ? 'ui-audio-icon' : 'ui-audio-icon-r-play'}}" src="https://image.fulllinkai.com/202308/09/5514071f2d388102b5672e46ea1922f4.png" mode="aspectFit" lazy-load="false"></image>
<view v-if="!audioState || playAudioIndex != index">{{item.audioDur+ '"'}}</view>
<view v-else>{{audioTime + '"'}}</view>
</view>
<!--视频信息-->
<view v-if="item.msgType == '3' || item.msgType == 'video'" :style="{width: item.attach.w + 'rpx', height: item.attach.h + 'rpx'}" class="liveImg" mode="widthFix" @tap.stop="playVideo(index)">
<image v-if="videoIndex != index" class="ui-video-box" :src="item.attach.poster" :style="{width: item.attach.w + 'rpx', height: item.attach.h + 'rpx'}">
<view class="ui-vide-poster">
<image class="ui-video_play_icon" src="https://image.fulllinkai.com/202308/17/42c88bf039bb56f85cfcb9af0392ffb6.png"></image>
<view class="ui-video_play-text font_20 white">{{item.videoDur}}</view>
</view>
</image>
<video id="groupChatVideo-{{index}}" :src="item.attach.url" v-if="videoIndex == index" play-btn-position="center" show-fullscreen-btn="{{false}}" controls custom-cache="{{true}}" direction="0" object-fit="{{videoIndex == index ? 'contain' : 'cover'}}" referrer-policy="origin" bindfullscreenchange="leaveVideo" class="videoCenter ui-video-r-box" :style="{width: item.attach.w + 'rpx', height: item.attach.h + 'rpx'}" :key="index">
</video>
</view>
</view>
</view>
<image v-if="item.isSelf" class="ui-user-pic" :src="item.avatar" mode="aspectFill"></image>
</view>
</block>
</view>
</view>
</scroll-view>
<view class="ui-bottom-input-box">
<!--输入文本加表情预览信息-->
<view class="replyView f-fcc animation-slide-bottom" v-if="msg.length > 17 && showReplyView" style="bottom: {{inputBoxH}}px;">
<view class="replyContent main-content-box" bindlongpress="copy" data-text="{{msg}}">
<rich-text nodes="{{replyContent}}"></rich-text>
</view>
</view>
<view class="f-fbc">
<view class="ui-microphone-box">
<image class="ui-microphone-image" @tap.stop="changeMicrophone" src="https://image.fulllinkai.com/202308/05/a6adc00602e0b26aa642c2551c84bf03.png" mode="aspectFit" lazy-load="false"></image>
</view>
<block v-if="!microphoneShow">
<view class="ui-input-box f-fcl">
<image class="ui-emoji-icon" src="https://images.ufutx.com/202108/03/2f4661c8d19e56faa068ffac52ac9762.png" mode="widthFix" @tap="changeSelectEmoji"></image>
<input class="ui-input font_28 color3 text-left" confirm-hold="{{true}}" v-model="msg" type="text" maxlength="-1" placeholder="真诚一些,收获好感..." confirm-type="send" cursorSpacing="26" bindinput="changeMsg" bindenter="changeMsg" bindfocus="InputFocus" @confirm="send">
</view>
<view class="ui-send-box f-fcr">
<image class="font_32 ui-send-icon f-fcc {{msg ? 'active' : ''}}" @tap="send" src="https://image.fulllinkai.com/202305/05/4a47a0db6e60853dedfcfdf08a5ca249.png" mode="aspectFit" lazy-load="false"></image>
<image class="ui_add_icon {{msg ? 'active' : ''}}" @tap="changeSelectPic" src="https://images.ufutx.com/202107/20/055e2a820dd94b6eb9fcb09db3622ec7.png" mode="aspectFit" lazy-load="false"></image>
</view>
</block>
<block v-else>
<view class="{{microphoneType ? 'ui-microphone-close' : 'ui-microphone-open color-333 font_32'}}" @longpress="handleRecordStart" @touchmove="handleTouchMove" @touchend.stop="handleRecordStop">{{ mircrophoneType ? '松开结束' :'按住说话' }}</view>
</block>
</view>
<view class="m_inp_ct {{emojiShow ? 'emojiSel' : ''}}">
<block v-if="emojiShow">
<chatEmoji :emojiArray="emojiList.emoji" @selectEmoji="selectEmoji"></chatEmoji>
</block>
</view>
<view class="m_inp_ct {{openShow ? 'sel' : ''}}">
<view class="u_xi"></view>
<view class="f-fc">
<view class="u_imp_lst" v-for="(item,index) in operationList" :key="index" @tap="changeOperation(item.title)">
<view class="m_impLst_img f-fcc">
<image src="{{item.icon}}" mode="aspectFit" lazy-load="false"></image>
</view>
<view class="color-333 text-center font_22">{{ item.title }}</view>
</view>
</view>
</view>
</view>
</view>
<!--长按录音-->
<view v-if="microphoneType" class="ui-microphone-message">
<view class="{{sendLock ? 'ui-icon-change-stop' : ''}} ui-icon-box">
<image class="ui-icon-microphone" @tap="changeMicrophone" src="https://image.fulllinkai.com/202308/05/97e1aa711ec3bf688f0853ea8d3444f0.png" mode="aspectFit" lazy-load="false"></image>
<view class="ui-icon-change"></view>
</view>
<view class="ui-icon-text white font_24">{{sendLock ? '松开手指,取消发送' : '手指上滑,取消发送'}}</view>
</view>
<!--上传进度展示-->
<view class="cu-modal {{uploadState ? 'show' : ''}}" style="background: rgba(0,0,0,0);">
<view class="cu-dialog m_prog">
<view class="conic-progress" style="background-image: conic-gradient(#fff {{progressValue}}%,#a8a8a8 0%);">
</view>
</view>
</view>
</template>
<script>
import wepy from '@wepy/core'
import https from '../../mixins/https'
import base from '../../mixins/base'
import {service} from '../../config'
import {getTime, format, timeContrast, getVideoTime} from '../../mixins/plugins'
import emojiObj from '../../components/chatEmojiFile/emoji'
const app = getApp().$wepy.$options
wepy.page({
config: {},
mixins: [https, base],
data: {
loading: false,
myAvatar: '',
myUserId: '',
myName: '',
myType: '',
otherAvatar: '',
otherUserId: '',
otherUserName: '',
recorderManager: wx.getRecorderManager(),
startPoint: 0,
scrollY: true,
sendLock: true, // audio发送锁
microphoneShow: false,
microphoneType: false, // 按住或松开
openShow: false,
emojiList: [],
emojiShow: false,
emojiType: 'session',
operationList: [
{
icon: 'https://image.fulllinkai.com/202308/09/ef0d4e64d4f6fdfbe0f0ef21723e4d7b.png',
title: '图片'
},
{
icon: 'https://image.fulllinkai.com/202308/09/05550f0306f9b6057ea42ed3e4246a0e.png',
title: '相机'
},
{
icon: 'https://image.fulllinkai.com/202308/09/5154e58fe8f46a7a26a8bf6c507c6def.png',
title: '视频'
}
],
videoIndex: -1,
videoContext: null,
videoState: null,
playAudioIndex: -1,
audioTime: null,
audioState: null,
toView: '',
uploadState: false,
progressValue: 0, // 上传进度
lastId: '', // 历史记录分页数据最后一条id
firstTime: '', // 历史记录分页数据第一条的时间戳
lastTime: '', // 历史记录分页数据最后一条的时间戳
lastMsgId: '', // 历史记录分页数据最后一条的id
beginTime: '', // 历史记录分页数据最后一条的时间
finished: false, // 数据已全部获取完成
msgList: [],
membersData: {},
showReplyView: true,
inputBoxH: 86,
bottomBoxH: 0,
windowHeight: 0,
replyContent: '',
msg: ''
},
methods: {
// 获取群成员信息
getMembers() {
let vm = this
vm.$get({url: `${service.host}/team/${vm.otherUserId}/detail`}).then(({code, data}) => {
if (code === 0) {
// 第一次进入页面的时候才请求历史消息
if (!vm.membersData.user_team) {
vm.$nextTick(() => {
// 获取历史消息
vm.getHistoryMsg()
// 实时获取对方发送的消息
app.globalData.nim.on('msg', function (e) {
vm.reception(e)
})
})
}
vm.membersData = data
}
}).catch(err => {
wx.hideLoading()
console.log(err)
})
},
// 标记群消息已读
groupIsRead() {
let vm = this
let data = {
team_id: vm.otherUserId
}
vm.$post({url: `${service.host}/chat/group/read`, data}).then(() => {
}).catch(err => {
console.log(err)
})
},
// 标记消息已读
teamsSessions() {
let vm = this
let groupSessionsCount = wx.getStorageSync('teamsSessionsCount') || []
let newTeamSessions = groupSessionsCount.map(item => {
if (item.id == vm.otherUserId) {
item.unread = 0
}
return item
})
wx.setStorageSync('teamsSessionsCount', newTeamSessions)
},
// 发送文本和表情包消息
send() {
let vm = this
let timeData = new Date().getTime()
if (!vm.msg) {
vm.$showToast('请输入聊天内容')
return
}
if (/\[[^\]]+\]/.test(vm.msg)) {
vm.msg = vm.transitionMsg(vm.msg)
}
vm.msgList.push({
text: vm.msg,
attach: '',
id: `id_${timeData}`,
isSelf: true,
avatar: vm.myAvatar,
timestamp: timeData,
name: vm.myName,
userId: vm.myUserId,
isSend: 0,
msgType: '0'
})
vm.toView = `id_${timeData}`
let msgIndex = 0
let msgNewObj = {}
msgIndex = vm.msgList.findIndex((e) => e.timestamp == timeData)
app.globalData.nim.msg.sendTextMsg({
scene: 'team',
to: vm.otherUserId,
body: vm.msg,
isSend: 0,
onSendBefore: function (msg) {
console.log('get msg before', msg)
if (/\[[^\]]+\]/.test(vm.msg)) {
vm.msg = vm.transitionMsg(vm.msg)
}
msgNewObj = {
text: vm.msg,
attach: '',
id: `id_${msg.time}`,
isSelf: true,
avatar: vm.myAvatar,
time: getTime(format(msg.time)),
showTime: timeContrast(vm.firstTime, format(msg.time)),
name: vm.myName,
userId: msg.from,
isSend: 1,
msgType: '0'
}
setTimeout(() => {
vm.msgList.splice(msgIndex, 1, msgNewObj)
vm.firstTime = format(msg.time)
vm.lastTime = format(msg.time)
vm.callbackSend('text')
})
}
})
},
// 发送图片消息
sendPictures(file) {
let vm = this
vm.openShow = false
vm.uploadState = true
vm.progressValue = 5
app.globalData.nim.msg.sendImageMsg({
scene: 'team',
to: vm.otherUserId,
type: 'image',
filePath: file,
onUploadProgress: function (progress) {
console.log(progress, '上传进度')
vm.progressValue = progress.percentage
},
onSendBefore: function (msg) {
console.log(msg, '上传完成, 图片信息')
vm.msgList.push({
text: '',
attach: vm.calculatePic(msg.attach, msg.type),
id: `id_${msg.time}`,
isSelf: true,
avatar: vm.myAvatar,
time: getTime(format(msg.time)),
showTime: timeContrast(vm.firstTime, format(msg.time)),
name: msg.fromNick,
userId: msg.from,
isSend: 1,
msgType: '1'
})
vm.firstTime = format(msg.time)
vm.lastTime = format(msg.time)
vm.callbackSend('picture')
vm.$nextTick(() => {
vm.toView = `id_${msg.time}`
})
// 防止图片撑开触发加载历史数据
vm.$nextTick(() => {
setTimeout(() => {
vm.uploadState = false
}, 500)
})
}
})
},
// 发送视频
sendVideos(file) {
let vm = this
vm.openShow = false
vm.uploadState = true
vm.progressValue = 5
app.globalData.nim.msg.sendVideoMsg({
scene: 'team',
to: vm.otherUserId,
type: 'video',
filePath: file,
onUploadProgress: function (progress) {
console.log(progress, '上传进度')
vm.progressValue = progress.percentage
},
onSendBefore: function (msg) {
console.log(msg, '上传完成,视频信息')
vm.msgList.push({
text: '',
attach: vm.calculatePic(msg.attach, msg.type),
id: `id_${msg.time}`,
timestamp: msg.time,
isSelf: true,
avatar: vm.myAvatar,
time: getTime(format(msg.time)),
showTime: timeContrast(vm.firstTime, format(msg.time)),
videoDur: getVideoTime(msg.attach.dur),
name: msg.fromNick,
userId: msg.from,
isSend: 1,
msgType: '3'
})
vm.firstTime = format(msg.time)
vm.lastTime = format(msg.time)
vm.callbackSend('video')
vm.$nextTick(() => {
vm.toView = `id_${msg.time}`
})
// 防止视频撑开触发加载历史数据
vm.$nextTick(() => {
setTimeout(() => {
vm.uploadState = false
}, 500)
})
}
})
},
sendAudio(file) {
let vm = this
vm.openShow = false
vm.uploadState = true
vm.progressValue = 5
app.globalData.nim.msg.sendAudioMsg({
scene: 'team',
to: vm.otherUserId,
type: 'video',
filePath: file,
onUploadProgress: function (progress) {
console.log(progress, '上传进度')
vm.progressValue = progress.percentage
},
onSendBefore: function (msg) {
console.log(msg, '上传完成,音频信息')
vm.msgList.push({
text: '',
attach: msg.attach,
id: `id_${msg.time}`,
timestamp: msg.time,
isSelf: true,
avatar: vm.myAvatar,
time: getTime(format(msg.time)),
showTime: timeContrast(vm.firstTime, format(msg.time)),
videoDur: getVideoTime(msg.attach.dur),
audioDur: (msg.attach.dur / 1000).toFixed(0),
name: msg.fromNick,
userId: msg.from,
isSend: 1,
msgType: '2'
})
vm.firstTime = format(msg.time)
vm.lastTime = format(msg.time)
vm.callbackSend('audio')
vm.$nextTick(() => {
vm.toView = `id_${msg.time}`
})
// 防止音频撑开触发加载历史数据
vm.$nextTick(() => {
setTimeout(() => {
vm.uploadState = false
}, 500)
})
}
})
},
// 发送信息后回调
callbackSend(type) {
let vm = this
let data = {
team_id: vm.otherUserId * 1,
content: vm.msg,
type: type
}
vm.$post({url: `${service.host}/chat/team/message/send`, data}).then(() => {
wx.hideLoading()
vm.msg = ''
vm.emojiShow = false
vm.replyContent = ''
}).catch(() => {
vm.uploadState = false
wx.hideLoading()
})
},
// 标记IM信息已读
sendMsgReceipt() {
let vm = this
app.globalData.nim.session.resetSessionUnreadCount({
id: `team-${vm.otherUserId}`
}).then((res) => {
console.log(res, '标记IM信息已读---------')
})
},
// 在当前页面接收到别人发送过来的消息
reception(e) {
let vm = this
if (e.to != vm.otherUserId) {
return
}
// 标记IM消息已读
vm.sendMsgReceipt()
if (e.type == 'text' && /\[[^\]]+\]/.test(e.body)) {
e.body = vm.transitionMsg(e.body)
}
app.globalData.nim.user.getUsersNameCardFromServer({
accounts: [e.from]
}).then((res) => {
vm.msgList.push({
text: e.body,
attach: vm.calculatePic(e.attach, e.type),
id: `id_${e.time}`,
timestamp: e.time,
isSelf: false,
avatar: res[0].avatar,
time: getTime(format(e.time)),
showTime: timeContrast(vm.firstTime, format(e.time)),
videoDur: e.type == 'video' ? getVideoTime(e.attach.dur) : '',
audioDur: e.type == 'audio' ? (e.attach.dur / 1000).toFixed(0) : '',
name: e.fromNick,
userId: e.from,
isSend: 1,
msgType: e.type,
tips: vm.groupNotification(e)
})
vm.toView = `id_${e.time}`
vm.firstTime = format(e.time)
vm.lastTime = format(e.time)
// 标记消息已读
vm.teamsSessions()
})
},
// 获取历史消息数据
getHistoryMsg() {
let vm = this
let data = {
min_id: vm.lastId
}
if (vm.uploadState || vm.videoState) {
return
}
if (vm.finished) {
return
}
vm.$showLoading('')
vm.$get({url: `${service.host}/chat/team/${vm.otherUserId}/message/list`, data}).then(({code, data}) => {
if (code === 0) {
console.log(data, '-------------------')
vm.sendMsgReceipt()
if (data && data.length > 0) {
data.forEach((item, index) => {
item.time = new Date(item.create_time.replace(/[-]/g, '/').replace(/[-]/, '')).getTime()
item.avatar = 'https://image.fulllinkai.com/202307/18/449c3253ca2bbed9314d39977a486d0e.png'
item.showTime = timeContrast(format(item.time), vm.lastTime)
item.timing = getTime(format(item.time))
if (item.showTime && index > 0) {
data[index].showTime = false
data[index - 1].showTime = true
}
if (item.type == '0' && /\[[^\]]+\]/.test(item.body_arr.msg)) {
item.body = vm.transitionMsg(item.body_arr.msg)
} else {
item.body = item.body_arr.msg
}
if (!vm.lastId) {
vm.firstTime = format(data[0].time)
}
vm.lastTime = format(item.time)
// 获取成员头像后再循环获取数据
app.globalData.nim.user.getUsersNameCardFromServer({
accounts: [`${item.id}`]
}).then((res) => {
if (index + 1 == data.length) {
vm.lastMsgId = data[data.length - 1].id
vm.beginTime = data[data.length - 1].time
setTimeout(() => {
data.forEach((item) => {
vm.msgList.unshift({
text: item.body,
attach: vm.calculatePic(item.body_arr, item.type),
id: `id_${item.time}`,
timestamp: item.time,
isSelf: item.is_mine == 0 ? false : true,
avatar: item.is_mine == 0 ? item.photo : vm.myAvatar,
time: item.timing,
showTime: item.showTime,
videoDur: item.type == '3' && item.body_arr.dur ? getVideoTime(item.body_arr.dur) : '',
audioDur: item.type == '2' && item.body_arr.dur ? (item.body_arr.dur / 1000).toFixed(0) : '',
name: item.from_nick,
userId: item.from,
msgType: item.type,
tips: vm.groupNotification(item)
})
})
console.log(vm.msgList, '88888888888888888')
vm.$nextTick(() => {
vm.toView = `id_${data[0].time}`
if (vm.msgList.length > 15) {
vm.scrollY = false
}
vm.lastId = `${data[data.length - 1].id}`
vm.loading = true
// 防止撑开触发加载历史数据
setTimeout(() => {
vm.uploadState = false
vm.scrollY = true
}, 500)
})
})
}
})
})
} else {
vm.loading = true
vm.scrollY = true
}
if (data && data.length < 15) {
vm.finished = true
}
}
}).catch(err => {
wx.hideLoading()
console.log(err)
})
},
// 监听底部输入框的高度
changeInputHeight(e) {
let vm = this
let query = wx.createSelectorQuery()
query.select('.ui-bottom-input-box').boundingClientRect((res) => {
if (res) {
vm.inputBoxH = res.height
}
if (e) {
vm.bottomBoxH = res.height * 2
}
}).exec()
},
// 监听输入框内容
changeMsg(e) {
console.log(e, '8888')
let vm = this
if (/\[[^\]]+\]/.test(e.$wx.detail.value)) {
vm.replyContent = vm.transitionMsg(e.$wx.detail.value)
} else {
vm.replyContent = e.$wx.detail.value
}
vm.changeInputHeight()
},
// 输入框聚焦事件
InputFocus() {
let vm = this
vm.emojiShow = false
vm.openShow = false
vm.showReplyView = false
setTimeout(() => {
vm.changeInputHeight()
vm.showReplyView = true
}, 500)
},
// 录音授权
changeMicrophone() {
let vm = this
wx.authorize({
scope: 'scope.record',
success() {
console.log('录音授权成功')
// 第一次成功授权后
vm.microphoneShow = !vm.microphoneShow
},
fail() {
wx.showModal({
title: '提示',
content: '您未授权录音,功能将无法使用',
showCancel: true,
confirmText: '授权',
confirmColor: '#52a2d8',
success: function (res) {
if (res.confirm) {
wx.openSetting({
success: (res) => {
if (!res.authSetting['scope.record']) {
// 未设置录音授权
wx.showModal({
title: '提示',
content: '您未授权录音,功能将无法使用',
showCancel: false,
success: function (res) {
}
})
} else {
// 第二次成功授权
vm.microphoneShow = !vm.microphoneShow
}
},
fail: function () {
console.log('授权设置录音失败')
}
})
} else if (res.cancel) {
console.log('cancel')
}
}
})
}
})
},
handleRecordStart(e) { // 长按语音
let vm = this
const options = {
sampleRate: 16000, // 采样率
numberOfChannels: 1, // 录音通道数
encodeBitRate: 96000, // 编码码率
format: 'mp3', // 音频格式,有效值 aac/mp3
frameSize: 50// 指定帧大小,单位 KB
}
vm.recorderManager.start(options)
vm.startPoint = e.touches[0]// 记录长按时开始点信息,后面用于计算上划取消时手指滑动的距离。
vm.microphoneType = true
vm.sendLock = false // 长按时是不上锁的。
vm.recorderManager.onStart(() => {
console.log('recorder start')
})
vm.recorderManager.onError((err) => {
console.log(err, 'err--')
})
},
handleTouchMove(e) { // 上滑取消
let vm = this
let moveLenght = e.touches[e.touches.length - 1].clientY - vm.startPoint.clientY // 移动距离
vm.sendLock = Math.abs(moveLenght) > 50
},
// 松开发送语音
handleRecordStop() {
let vm = this
vm.microphoneType = false
vm.recorderManager.stop()
vm.recorderManager.onStop((res) => {
console.log(res, 'res----')
console.log(res.tempFilePath, 'res----')
if (!vm.sendLock) {
vm.sendAudio(res.tempFilePath)
}
})
vm.recorderManager.onError((err) => {
console.log(err, 'err--')
})
},
// 展示/关闭弹出表情包
changeSelectEmoji() {
let vm = this
vm.showReplyView = false
vm.openShow = false
vm.emojiShow = !vm.emojiShow
setTimeout(() => {
vm.changeInputHeight()
vm.showReplyView = true
}, 500)
},
// 展示/关闭弹出选择图片
changeSelectPic() {
let vm = this
vm.emojiShow = false
vm.openShow = !vm.openShow
setTimeout(() => {
vm.changeInputHeight()
}, 500)
},
// 选择表情包
selectEmoji(e) {
let vm = this
vm.msg = vm.msg + e
if (/\[[^\]]+\]/.test(vm.msg)) {
vm.replyContent = vm.transitionMsg(vm.msg)
}
vm.changeInputHeight()
},
// 转换msg表情数据
transitionMsg(e) {
let vm = this
let emojiItems = e.match(/\[[^\]]+\]/g)
emojiItems.forEach(text => {
let emojiCnt = vm.emojiList.emoji.list
emojiCnt.forEach(emItem => {
if (emItem.key == text) {
e = e.replace(text, `<img class="emoji_small" src="${emItem.img}" />`)
}
})
})
e = '<div class="emoji_text">' + e + '</div>'
return e
},
// 获取emoji表情包数据
emojiCts() {
return this.genEmojiList('emoji', emojiObj.emojiList)
},
// 获取表情包
genEmojiList(type, emojiList) {
let result = {}
for (let name in emojiList) {
let emojiMap = emojiList[name]
let list = []
for (let key in emojiMap) {
list.push({
type,
name,
key,
img: emojiMap[key].img
})
}
if (list.length > 0) {
result[name] = {
type,
name,
list,
album: list[0].img
}
}
}
return result
},
// 群通知消息判断
groupNotification (e) {
let text = ``
if (e.type == '7' && e.attach.type == 'addTeamMembers') {
text = `${e.attach.users[1].nick}邀请${e.attach.users[0].nick}加入群`
}
if (e.type == '7' && e.attach.type == 'leaveTeam') {
text = `${e.attach.users[0].nick}离开群`
}
return text
},
// 图片大小计算
calculatePic(e, type) {
if (!e || !e.url) {
return ''
}
let wRatio = 0
if (type == '3' && e.url && e.url.includes('?')) {
e.poster = `${e.url}&vframe`
} else if (type == '3' && e.url) {
e.poster = `${e.url}?vframe`
}
if (e.w > e.h) {
wRatio = e.w / 200
e.w = 200
e.h = e.h / wRatio
} else {
wRatio = e.h / 200
e.w = e.w / wRatio
e.h = 200
}
return e
},
// 更多操作
changeOperation(title) {
let vm = this
if (title == '图片') {
vm.onAlbum(['album'])
} else if (title == '相机') {
vm.onAlbum(['camera'])
} else {
vm.chooseVideo()
}
},
// 选择图片发送
onAlbum(sourceType) {
let vm = this
wx.chooseMedia({
count: 1,
mediaType: ['image'],
sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
sourceType, // 可以指定来源是相册还是相机,默认二者都有
success: (res) => {
console.log('res--------------------------', res)
let imgSrc = res.tempFiles[0].tempFilePath
vm.sendPictures(imgSrc)
}
})
},
// 选择视频
chooseVideo() {
let vm = this
wx.chooseMedia({
count: 1,
mediaType: ['video'],
sizeType: ['compressed'],
sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
success: (res) => {
console.log('res--------------------------', res)
let imgSrc = res.tempFiles[0].tempFilePath
vm.sendVideos(imgSrc)
}
})
},
// 播放视频
playVideo(index) {
let vm = this
vm.videoState = true
vm.videoIndex = index
vm.videoContext = wx.createVideoContext('groupChatVideo-' + index, vm)
vm.videoContext.requestFullScreen({direction: 0})
setTimeout(function() {
// 将点击视频进行播放
vm.videoContext.play()
}, 500)
},
// 关闭视频
leaveVideo(e, row) {
let vm = this
let fullScreen = e.$wx.detail.fullScreen
vm.videoState = true
if (!fullScreen) {
vm.toView = `${row}`
vm.videoContext.stop()
vm.videoContext = null
vm.videoIndex = -1
setTimeout(() => {
vm.videoState = false
}, 500)
}
},
// 播放音频
playAudio(row, index) {
let vm = this
vm.audioState = !vm.audioState
vm.playAudioIndex = index
const innerAudioContext = wx.createInnerAudioContext({
useWebAudioImplement: false // 是否使用 WebAudio 作为底层音频驱动,默认关闭。对于短音频、播放频繁的音频建议开启此选项,开启后将获得更优的性能表现。由于开启此选项后也会带来一定的内存增长,因此对于长音频建议关闭此选项
})
let myTime = null
if (vm.audioState) {
innerAudioContext.src = row.url
innerAudioContext.play() // 播放
vm.audioTime = 0
myTime = setInterval(() => {
vm.audioTime += 1
if (vm.audioTime * 1000 > row.dur) {
clearInterval(myTime)
vm.audioState = false
vm.playAudioIndex = -1
}
}, 1000)
} else {
clearInterval(myTime)
vm.audioState = false
vm.playAudioIndex = -1
}
},
// 预览图片
previewImage(imge) {
let vm = this
let imageArr = []
vm.msgList.forEach((item) => {
if (item.msgType == '1') {
imageArr.push(item.attach.url)
}
})
// 倒序处理阅览顺序不对的问题
imageArr = imageArr.reverse()
vm.$previewImages(imge, imageArr)
},
jumpDetailPath() {
let vm = this
wx.navigateTo({url: `/pages/news/groupChitchatDetail?id=${vm.otherUserId}`})
}
},
onShow() {
let vm = this
vm.myUserId = wx.getStorageSync('user_id')
vm.myType = wx.getStorageSync('userInfo').type
vm.myName = wx.getStorageSync('userInfo').name
vm.myAvatar = wx.getStorageSync('userInfo').avatar
vm.getMembers()
},
onLoad(e) {
let vm = this
vm.otherAvatar = e.pic
vm.otherUserId = e.id
vm.otherUserName = decodeURIComponent(e.name)
// 获取表情包数据
vm.emojiList = vm.emojiCts()
// 获取手机屏幕高度
wx.getSystemInfo({
success: (res) => {
vm.windowHeight = res.windowHeight * 2
}
})
// 底部输入框高度
vm.changeInputHeight(true)
// 标记消息已读
vm.teamsSessions()
wx.setNavigationBarTitle({
title: vm.otherUserName,
success: function () {}
})
},
created() {
}
})
</script>
<config>
{
navigationBarTitleText: '聊天',
enablePullDownRefresh: false,
backgroundColorTop: '#f2f2f2',
backgroundColorBottom: '#f2f2f2',
usingComponents: {
chatEmoji: '~@/components/chatEmojiFile/ChatEmoji'
}
}
</config>