merchapp/java-mall-app-shop-admin/pages/IM/IMmsgContent.vue
2025-06-24 18:44:20 +08:00

1282 lines
34 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view
:class="[
'IMmsgContent-container',
{ isIos: 'IMmsgContent-ios-container' },
{ 'disable-scroll': showVoiceMask },
]"
>
<u-navbar
:title="ImItemInfo.username"
:autoBack="true"
:placeholder="true"
></u-navbar>
<view class="tui-chat-content" id="tui-chat-content">
<!-- <tui-loadmore
v-if="loadding"
:index="3"
type="primary"
text=" "
></tui-loadmore> -->
<view>
<!-- <view class="tui-label">对方已通过您的好友请求</view> -->
<view v-for="(item, index) of msgList" :key="index">
<view class="tui-chat-center">
{{ formatTime(item.message_time) }}
</view>
<view class="tui-chat-right" v-if="item.message_kind == 1">
<view
v-if="item.msg.type == 'text' || item.msg.type == 'user'"
class="tui-chatbox tui-chatbox-right"
>
<u-parse
:content="item.msg.content.text"
class="parse-content"
></u-parse>
</view>
<view
v-if="item.msg.type == 'img'"
class="tui-chatbox tui-chatbox-right img"
>
<image
:src="item.msg.content.url"
:style="{
width: item.msg.content.w,
height: item.msg.content.h,
}"
@click="showImgPreview(item)"
class=""
></image>
</view>
<view
class="tui-flex-center tui-flex-end"
v-if="item.msg.type == 'voice'"
>
<view
class="tui-chatbox tui-chatbox-right tui-chat-flex tui-ml tui-flex-reverse"
@click="playVoice(item)"
>
<image
:src="
isPlayVoice && item.msg.id == playMsgid
? '/static/images/chat/voice.gif'
: '/static/images/chat/voice.png'
"
class="tui-chat-voice tui-rotate tui-ml"
></image>
<view :style="{ width: calculateVoiceWidth(item.mp3Time) }">
{{ item.mp3Time }}"
</view>
</view>
</view>
<image
:src="item.msg.userinfo.face"
class="tui-user-pic tui-left"
></image>
</view>
<view class="tui-chat-left" v-if="item.message_kind == 2">
<image
:src="item.msg.userinfo.face"
class="tui-user-pic tui-right"
></image>
<view class="tui-flex-center" v-if="item.msg.type == 'voice'">
<view
class="tui-chatbox tui-chatbox-left tui-chat-flex tui-mr"
@click="playVoice(item)"
>
<image
:src="
isPlayVoice && item.msg.id == playMsgid
? '/static/images/chat/voice.gif'
: '/static/images/chat/voice.png'
"
class="tui-chat-voice tui-mr"
></image>
<view :style="{ width: calculateVoiceWidth(item.mp3Time) }">
{{ item.mp3Time }}"
</view>
</view>
<!-- <tui-badge :dot="true" type="danger"></tui-badge> -->
</view>
<view
v-if="item.msg.type == 'text'"
class="tui-chatbox tui-chatbox-left"
>
<u-parse :content="item.msg.content.text"></u-parse>
</view>
<view
v-if="item.msg.type == 'img'"
class="tui-chatbox tui-chatbox-right"
>
<!-- <image
:src="formatImg(item)"
@click="showImgPreview(item)"
class="tui-user-pic tui-left img"
></image> -->
</view>
</view>
</view>
</view>
</view>
<t-chat-bar
@sendMsg="chatBarSendMsg"
paddingBottom
@uploadPictures="uploadPictures"
@photograph="photograph"
@uploadVideo="selectVideo"
@showVoicePopup="showVoicePopup"
@voiceEnd="voiceEnd"
:isHideKeyBoard="isHideKeyBoard"
></t-chat-bar>
</view>
</template>
<script>
import {
GetImConfig,
GetImMsgList,
GetSendMsgAdd,
SetMsgRead,
} from "../../api/im";
import { UploadFilePromise } from "../../api/upload";
import { toDayTime } from "../../utils/date";
import tChatBar from "@/components/t-chat-bar/t-chat-bar";
import tuiBadge from "@/components/tui-badge/tui-badge.vue";
import emoji from "../../static/im/emojiData.js";
import { mapState } from "vuex";
export default {
components: {
tChatBar,
tuiBadge,
},
data() {
return {
loadding: false,
show: true,
bottom: 0,
myUserId: 2,
chatList: [
{
type: 1, //1-文字 2-图片 3-语音4-时间 5-提醒 ...
userId: 1, //用户标识 不一定是userid
text: "",
src: "",
read: false,
success: false,
},
],
ImItemInfo: {
friend_id: 0,
},
msgList: [],
msgImgList: [],
pcEmoji: [],
pcEmojiObj: {},
//播放语音相关参数
AUDIO: uni.createInnerAudioContext(),
// 录音
RECORDER: uni.getRecorderManager(),
playMsgid: "",
isPlayVoice: false,
// socket: {},
chattype: "user",
isHideKeyBoard: false,
emojiPath: "https://res.wx.qq.com/mpres/htmledition/images/icon/emotion/",
isIos: false,
showVoiceMask: false,
};
},
onLoad: function (options) {
if (options.item) {
this.ImItemInfo = JSON.parse(options.item);
console.log(this.ImItemInfo);
}
this.faceList = emoji.imgArr[1].emojiList;
},
onShow() {
// this.socketServer();
this.getPcEmoji();
// this.getImConfig();
this.getImMsgList();
// #ifdef APP-PLUS
const platform = uni.getSystemInfoSync().platform;
if (platform == "ios") {
this.isIos = true;
}
// #endif
},
watch: {
getMsg: function (val) {
let that = this;
let cacheid = 0;
console.log("获取到数据");
console.log(val);
var nowDate = new Date();
let lastid = val.message_id;
let tempmy = this.userInfo.im;
let msg_type = val.msg_type;
var nowDate = new Date();
let msg = {
type: "user",
sendmethod: this.chattype,
avatar: val.avatar,
needload: false,
fromid: this.ImItemInfo.id,
toid: tempmy.puid,
message_kind: 2,
msg: {
id: lastid,
type: msg_type,
userinfo: {
uid: this.ImItemInfo.id,
username: this.ImItemInfo.username,
face: val.avatar,
},
content: {
text: val.content,
},
},
mp3Time: msg_type == "voice" ? val.length : 0,
message_time: nowDate,
};
// 用户消息
switch (msg_type) {
case "text":
msg.msg.content.text = val.content;
break;
case "voice":
msg.msg.content.url = val.content;
break;
case "img":
msg.msg.content.url = val.content;
break;
case "video":
msg.msg.content.url = val.content;
break;
case "redEnvelope":
msg.msg.content.blessing = val.content;
break;
case "rtc":
msg.msg.content.text = val.content;
break;
}
if (that.chattype == "user" && val.type == "friend") {
if (that.ImItemInfo.id == val.id) {
console.log("screened");
console.log(msg);
that.screened(msg);
// //发起视频聊天
// if (msg_type == "rtc") {
// // #ifdef MP-WEIXIN
// this.$.gotopage("/rtc/room/1v1wx?to_user_id=" + that.options.uid);
// // #endif
// // #ifdef APP-PLUS
// this.$.gotopage("/rtc/room/1v1?to_user_id=" + that.options.uid);
// // #endif
// }
}
cacheid = msg.fromid;
} else if (that.chattype == "group" && val.type == "group") {
if (that.ImItemInfo.id == val.toid) {
that.screened(msg);
}
cacheid = msg.toid;
///群聊
} else {
///不让在当前页面显示内容
}
if (that.ImItemInfo.id == val.id) {
this.setMsgRead(lastid);
//设为已读
}
this.$nextTick(() => {
const query = uni.createSelectorQuery().in(this);
query.select(".IMmsgContent-container").boundingClientRect();
query.selectAll(".IMmsgContent-container view").boundingClientRect();
query.exec((res) => {
const scrollViewHeight = res[0].height;
const scrollContentHeight = res[1].reduce(
(total, item) => total + item.height,
0
);
// const scrollTop = scrollContentHeight - scrollViewHeight;
uni.pageScrollTo({
scrollTop: scrollViewHeight,
duration: 0,
});
});
});
// this.$apiconfig.cacheMessage(val, val.sendmethod, cacheid, tempmy);
this.$store.commit("user/REMOVE_IM_KEY", this.ImItemInfo.id.toString());
// //新消息数归零
// this.$store.commit("resetWeidu", {
// type: this.chattype,
// val: this.chat_to_puid,
// });
},
},
computed: {
...mapState("user", ["uid", "userInfo", "socket", "getMsg"]),
},
methods: {
async setMsgRead(lastid) {
await SetMsgRead({ message_id: lastid });
},
voiceEnd(voiceMP3Info) {
console.log('"voiceEnd"', voiceMP3Info);
if (voiceMP3Info) {
uni.uploadFile({
url: "https://mall.gpxscs.cn/mobile/shop/oss/upload", //仅为示例,非真实的接口地址
filePath: voiceMP3Info.voice,
header: {
merchcode: "cb0ac353f02a73a7c45885a862fe4de1",
},
name: "upfile",
formData: {
user: "test",
},
success: (uploadFileRes) => {
console.log(voiceMP3Info);
let tmpres = JSON.parse(uploadFileRes.data);
let msg = {
length: voiceMP3Info.length,
url: tmpres.data.url,
mp3Time: voiceMP3Info.length,
};
// let min = parseInt(this.recordLength / 60);
// let sec = this.recordLength % 60;
// min = min < 10 ? "0" + min : min;
// sec = sec < 10 ? "0" + sec : sec;
// msg.length = min + ":" + sec;
///上传录音到服务器
this.sendMsg(msg, "voice");
},
});
}
this.showVoiceMask = false;
console.log("结束录音");
},
showVoicePopup() {
this.AUDIO.stop();
this.showVoiceMask = true;
},
uploadPictures() {
this.isHideKeyBoard = true;
this.selectPhotoOrTakeShot("album");
setTimeout(() => {
this.isHideKeyBoard = false;
}, 100);
},
photograph() {
this.isHideKeyBoard = true;
this.selectPhotoOrTakeShot("camera");
setTimeout(() => {
this.isHideKeyBoard = false;
}, 100);
},
selectVideo() {
this.isHideKeyBoard = true;
this.upLoadVideo();
setTimeout(() => {
this.isHideKeyBoard = false;
}, 100);
},
upLoadVideo() {
uni.chooseVideo({
count: 1,
sourceType: ["camera", "album"],
success: async (res) => {
uni.showLoading({
title: "视频上传中..",
mask: true,
});
let result = await UploadFilePromise(res.tempFilePath);
if (result && result.status == 200) {
let msg = {
url: res.tempFilePath,
w: result.data.width,
h: result.data.height,
};
msg.url = result.data.url;
this.sendMsg(msg, "video");
}
uni.hideLoading();
},
});
},
selectPhotoOrTakeShot(type) {
let that = this;
uni.chooseImage({
sourceType: [type],
sizeType: ["original", "compressed"], //可以指定是原图还是压缩图,默认二者都有
success: (res) => {
for (let i = 0; i < res.tempFilePaths.length; i++) {
uni.getImageInfo({
src: res.tempFilePaths[i],
success: async (image) => {
var msg = {
url: res.tempFilePaths[i],
w: image.width,
h: image.height,
};
console.log(res);
let result = await UploadFilePromise(res.tempFilePaths[i], {
user: "test",
});
if (result && result.status == 200) {
msg.url = result.data.url;
this.sendMsg(msg, "img");
}
},
});
}
},
});
},
// 添加文字消息到列表
addTextMsg(msg) {
this.msgList.push(msg);
},
// 添加语音消息到列表
addVoiceMsg(msg) {
this.msgList.push(msg);
},
// 添加图片消息到列表
addImgMsg(msg) {
msg.msg.content = this.setPicSize(msg.msg.content);
this.msgImgList.push(msg.msg.content.url);
this.msgList.push(msg);
},
addRedEnvelopeMsg(msg) {
this.msgList.push(msg);
},
// 添加系统文字消息到列表
addSystemTextMsg(msg) {
this.msgList.push(msg);
},
// 添加系统红包消息到列表
addSystemRedEnvelopeMsg(msg) {
this.msgList.push(msg);
},
screened(msg) {
if (msg.type == "system") {
// 系统消息
switch (msg.msg.type) {
case "text":
this.addSystemTextMsg(msg);
break;
case "redEnvelope":
this.addSystemRedEnvelopeMsg(msg);
break;
}
} else if (msg.type == "user" || msg.type == "friend") {
// 用户消息
switch (msg.msg.type) {
case "text":
this.addTextMsg(msg);
break;
case "voice":
this.addVoiceMsg(msg);
break;
case "img":
this.addImgMsg(msg);
break;
case "video":
this.addTextMsg(msg);
break;
case "redEnvelope":
this.addRedEnvelopeMsg(msg);
break;
}
// console.log('用户消息');
//非自己的消息震动
// if (msg.msg.userinfo.uid != this.myuid) {
// // console.log('振动');
// uni.vibrateLong();
// }
}
},
// socketServer() {
// console.log(this.userInfo.im.node_site_url);
// this.socket = new this.$Socket({
// url: this.userInfo.im.node_site_url,
// maxInterValCount: 5,
// interValTime: 2000,
// onClose: (res) => {
// console.log("socket关闭");
// },
// onOpen: (res) => {
// console.log("socket连接成功");
// },
// onMsg: (res) => {
// console.log("onMsg", res);
// },
// });
// this.socket.connectserver(this.userInfo.im);
// },
processTimeString(timeStr) {
const parts = timeStr.split(":");
// If there's no colon or format is invalid, return as-is
if (parts.length !== 2) return timeStr;
const minutes = parseInt(parts[0], 10);
const seconds = parseInt(parts[1], 10);
// Case 1: "00:60" or "01:00" → return "60"
if (
(minutes === 0 && seconds === 60) ||
(minutes === 1 && seconds === 0)
) {
return "60";
}
// Case 2: "00:XX" where XX < 60 → return "XX"
if (minutes === 0 && seconds < 60) {
return parts[1]; // Return the original seconds part to preserve leading zero
}
// For all other cases, return the original string
return timeStr;
},
playVoice(item) {
this.playMsgid = item.msg.id;
if (this.isPlayVoice == true) {
this.AUDIO.stop();
this.isPlayVoice = false;
return;
}
if (item.message_length) {
this.AUDIO.src = item.message_content;
} else {
this.AUDIO.src = item.msg.content.url;
}
this.$nextTick(function () {
this.isPlayVoice = true;
this.AUDIO.play();
});
this.$nextTick(() => {
this.AUDIO.onEnded((res) => {
this.isPlayVoice = false;
});
});
},
im_decode(content) {
let that = this;
//支持的html标签
var html = function (end) {
return new RegExp(
"\\n*\\[" +
(end || "") +
"(code|pre|div|span|p|table|thead|th|tbody|tr|td|ul|li|ol|li|dl|dt|dd|h2|h3|h4|h5)([\\s\\S]*?)\\]\\n*",
"g"
);
};
content = (content || "")
.replace(/&(?!#?[a-zA-Z0-9]+;)/g, "&amp;")
//.replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/'/g, '&#39;').replace(/"/g, '&quot;') //XSS
.replace(/@(\S+)(\s+?|$)/g, '@<a href="javascript:;">$1</a>$2') //转义@
.replace(/face\[([^\s\[\]]+?)\]/g, function (face) {
//转义表情
var alt = face.replace(/^face/g, "");
return (
'<img alt="' +
alt +
'" title="' +
alt +
'" src="' +
that.pcEmojiObj[alt] +
'">'
);
})
.replace(/img\[([^\s]+?)\]/g, function (img) {
//转义图片
//return '<img class="layui-layim-photos" style="width: 100%;height: 100%;" src="' + img.replace(/(^img\[)|(\]$)/g, '') + '">';
return (
'<div><img class="chatimg single-img" src="' +
img.replace(/(^img\[)|(\]$)/g, "") +
'" /><span style="min-width: 240px;">&nbsp;</span></div>'
);
})
.replace(/file\([\s\S]+?\)\[[\s\S]*?\]/g, function (str) {
//转义文件
var href = (str.match(/file\(([\s\S]+?)\)\[/) || [])[1];
var text = (str.match(/\)\[([\s\S]*?)\]/) || [])[1];
if (!href) return str;
return $.__("不支持该格式:file");
// #ifdef H5
return (
'<a class="layui-layim-file" href="' +
href +
'" download target="_blank"><i class="iconfont zc zc-xiangqing im-file"></i><cite>' +
$.sprintf($.__("不支持该格式,请复制网址到浏览器打开 %s"), href) +
"</cite></a>"
);
// #endif
// #ifndef H5
return (
'<a class="layui-layim-file" href="' +
href +
'" download target="_blank"><i class="iconfont zc zc-xiangqing im-file"></i><cite>' +
$.sprintf($.__("不支持该格式,请复制网址到浏览器打开 %s"), href) +
"</cite></a>"
);
// #endif
})
.replace(/audio\[([^\s]+?)\]/g, function (audio) {
//转义音频
return $.__("不支持该格式:audio");
return (
'<div class="layui-unselect layui-layim-audio" layim-event="playAudio" data-src="' +
audio.replace(/(^audio\[)|(\]$)/g, "") +
'"><i class="layui-icon">&#xe652;</i><p>音频消息</p></div>'
);
})
.replace(/video\[([^\s]+?)\]/g, function (video) {
//转义音频
return $.__("不支持该格式:video");
return (
'<div class="layui-unselect layui-layim-video" layim-event="playVideo" data-src="' +
video.replace(/(^video\[)|(\]$)/g, "") +
'"><i class="layui-icon">&#xe652;</i></div>'
);
})
.replace(/\[pre([\s\S]*)\]([\s\S]*)\[\/pre\]/g, function (video) {
//转义音频
return $.__("不支持该格式:code");
return (
'<div class="layui-unselect layui-layim-video" layim-event="playVideo" data-src="' +
video.replace(/(^video\[)|(\]$)/g, "") +
'"><i class="layui-icon">&#xe652;</i></div>'
);
})
.replace(/a\([\s\S]+?\)\[[\s\S]*?\]/g, function (str) {
//转义链接
var href = (str.match(/a\(([\s\S]+?)\)\[/) || [])[1];
var text = (str.match(/\)\[([\s\S]*?)\]/) || [])[1];
if (!href) return str;
return (
'<a href="' + href + '" target="_blank">' + (text || href) + "</a>"
);
});
//.replace(html(), '\<$1 $2\>').replace(html('/'), '\</$1\>') //转移HTML代码
//.replace(/\n/g, '<br>') //转义换行
return content;
},
replaceEmoji(str) {
// 正则表达式匹配内容
let replacedStr = str.replace(/\[([^(\]|\[)]*)\]/g, (item, index) => {
// console.log("item: " + item);
for (let i = 0; i < this.faceList.length; i++) {
let row = this.faceList[i];
for (let j = 0; j < row.length; j++) {
let EM = row[j];
if (EM.alt == item) {
//在线表情路径,图文混排必须使用网络路径,请上传一份表情到你的服务器后再替换此路径
//比如你上传服务器后你的100.gif路径为https://www.xxx.com/emoji/100.gif 则替换onlinePath填写为https://www.xxx.com/emoji/
// let onlinePath = 'https://s2.ax1x.com/2019/04/12/'
// let imgstr = '<image src="'+onlinePath+this.onlineEmoji[EM.url]+'">';
let onlinePath = this.emojiPath;
let imgstr =
'<img style="width:24px;height:24px;" src="' +
onlinePath +
EM.url +
'">';
// console.log("imgstr: " + imgstr);
return imgstr;
}
}
}
});
return replacedStr;
},
chatBarSendMsg(content) {
content = this.replaceEmoji(content);
let msg = {
text: content,
};
this.sendMsg(msg, "text");
},
sendMsgText() {
this.sendMsg(msg, "text");
if (!this.textMsg) {
return;
}
let content = this.replaceEmoji(this.textMsg);
let msg = {
text: content,
};
},
async sendMsg(content, type, needload = false) {
console.info("--------------");
console.info(content);
console.info(content.text);
console.info(type);
console.info(needload);
let message_id = 1001;
var mine = {
username: this.userInfo.user_nickname,
avatar: this.userInfo.user_avatar,
id: this.userInfo.im.puid,
user_id: this.userInfo.user_id,
content: content.text || content.url,
length: type == "voice" ? content.length : 0,
w: type == "img" ? content.w : 0,
h: type == "img" ? content.h : 0,
item_id: typeof content.item_id != "undefined" ? content.item_id : 0,
type: type,
mine: true,
};
console.log(mine.avatar);
var to = {
id: this.ImItemInfo.id,
friend_id: this.ImItemInfo.user_id,
user_id: this.ImItemInfo.user_id,
name: this.ImItemInfo.user_nickname,
avatar: this.ImItemInfo.user_avatar,
type: this.chattype,
};
let maxLength = 50;
if (mine.content.replace(/\s/g, "") !== "") {
if (mine.content.length > maxLength) {
//return layer.msg('内容最长不能超过' + maxLength + '个字符')
}
}
var chat_data = {
mine: mine,
to: to,
};
let params = {
user_other_id: this.ImItemInfo.friend_id,
message_content: mine.content,
item_id: typeof content.item_id != "undefined" ? content.item_id : 0,
length: mine.length,
w: mine.w,
h: mine.h,
type: type,
};
let res = await GetSendMsgAdd(params);
if (res && res.status == 200) {
chat_data.mine.message_id = res.data.message_other_id;
this.socket.nsend(chat_data);
let lastid = res.data.message_other_id;
let tempmy = this.userInfo.im;
///TOID现在是模拟的
var nowDate = new Date();
let msg = {
type: "user",
sendmethod: this.chattype,
needload: needload,
fromid: tempmy.puid,
toid: this.ImItemInfo.user_id,
message_kind: 1,
msg: {
id: lastid,
type: type,
userinfo: {
uid: tempmy.puid,
username: this.userInfo.user_nickname,
face: this.userInfo.user_avatar,
},
content: content,
},
mp3Time: type == "voice" ? content.length : 0,
message_time: nowDate,
};
this.screened(msg);
this.$nextTick(() => {
const query = uni.createSelectorQuery().in(this);
query.select(".IMmsgContent-container").boundingClientRect();
query.selectAll(".IMmsgContent-container view").boundingClientRect();
query.exec((res) => {
const scrollViewHeight = res[0].height;
const scrollContentHeight = res[1].reduce(
(total, item) => total + item.height,
0
);
// const scrollTop = scrollContentHeight - scrollViewHeight;
uni.pageScrollTo({
scrollTop: scrollViewHeight,
duration: 0,
});
});
});
}
},
calculateVoiceWidth(seconds) {
// 微信语音最大宽度限制(根据实际情况调整)
const MAX_WIDTH = 400; // rpx
const MIN_WIDTH = 100; // rpx
const MAX_DURATION = 60; // 微信语音最大60秒
// 确保秒数在合理范围内
seconds = Math.min(Math.max(seconds, 1), MAX_DURATION);
// 计算宽度(线性增长)
const width =
MIN_WIDTH + (seconds / MAX_DURATION) * (MAX_WIDTH - MIN_WIDTH);
// 返回rpx单位的值取整
return Math.round(width) + "rpx";
},
getPcEmoji() {
this.pcEmoji = [
"[微笑]",
"[嘻嘻]",
"[哈哈]",
"[可爱]",
"[可怜]",
"[挖鼻]",
"[吃惊]",
"[害羞]",
"[挤眼]",
"[闭嘴]",
"[鄙视]",
"[爱你]",
"[泪]",
"[偷笑]",
"[亲亲]",
"[生病]",
"[太开心]",
"[白眼]",
"[右哼哼]",
"[左哼哼]",
"[嘘]",
"[衰]",
"[委屈]",
"[吐]",
"[哈欠]",
"[抱抱]",
"[怒]",
"[疑问]",
"[馋嘴]",
"[拜拜]",
"[思考]",
"[汗]",
"[困]",
"[睡]",
"[钱]",
"[失望]",
"[酷]",
"[色]",
"[哼]",
"[鼓掌]",
"[晕]",
"[悲伤]",
"[抓狂]",
"[黑线]",
"[阴险]",
"[怒骂]",
"[互粉]",
"[心]",
"[伤心]",
"[猪头]",
"[熊猫]",
"[兔子]",
"[ok]",
"[耶]",
"[good]",
"[NO]",
"[赞]",
"[来]",
"[弱]",
"[草泥马]",
"[神马]",
"[囧]",
"[浮云]",
"[给力]",
"[围观]",
"[威武]",
"[奥特曼]",
"[礼物]",
"[钟]",
"[话筒]",
"[蜡烛]",
"[蛋糕]",
];
let obj = {};
this.pcEmoji.forEach((item, index) => {
obj[item] =
"https://media-mall-prod-1259811287.cos.ap-guangzhou.myqcloud.com/static/xcxfile/appicon/im/face/" +
index +
".gif";
});
this.pcEmojiObj = obj;
},
async getImMsgList() {
let params = {
typ: "json",
user_other_id: this.ImItemInfo.friend_id,
type: "friend",
page: 1,
};
let res = await GetImMsgList(params);
if (res && res.status == 200) {
this.msgList = res.data.items.reverse();
this.msgList.forEach((item) => {
item.msg.content.text = this.im_decode(item.msg.content.text);
if (item.msg.type == "voice") {
item.mp3Time = this.processTimeString(item.message_length);
}
if (item.msg.type == "img") {
item.msg.content = this.setPicSize(item.msg.content);
this.msgImgList.push(item.msg.content.url);
}
});
}
this.$nextTick(() => {
setTimeout(() => {
// 增加延迟确保渲染完成
const query = uni.createSelectorQuery().in(this);
query.select(".IMmsgContent-container").boundingClientRect();
query.selectAll(".IMmsgContent-container view").boundingClientRect();
query.exec((res) => {
if (!res[0] || !res[1]) return; // 容错处理
const scrollViewHeight = res[0].height; // 容器可视高度
const scrollContentHeight = res[1].reduce(
(total, item) => total + item.height + 10, // 加上间距
0
);
// 关键修正:滚动到内容底部
const targetScrollTop = Math.max(
0,
scrollContentHeight - scrollViewHeight
);
uni.pageScrollTo({
scrollTop: scrollViewHeight,
duration: 0, // 适当动画时长
success: () => console.log("滚动到底部成功"),
fail: (err) => console.error("滚动失败:", err),
});
});
}, 100); // 安卓/iOS可能需要更长延迟
});
},
formatTime(time) {
return toDayTime(time);
},
//处理图片尺寸,如果不处理宽高,新进入页面加载图片时候会闪
setPicSize(content) {
// 让图片最长边等于设置的最大长度短边等比例缩小图片控件真实改变区别于aspectFit方式。
let maxW = uni.upx2px(250); //350是定义消息图片最大宽度
let maxH = uni.upx2px(250); //350是定义消息图片最大高度
if (content.w > maxW || content.h > maxH) {
let scale = content.w / content.h;
content.w = scale > 1 ? maxW : maxH * scale;
content.h = scale > 1 ? maxW / scale : maxH;
}
return content;
},
showImgPreview(item) {
uni.previewImage({
indicator: "none",
current: item.msg.content.url,
urls: this.msgImgList,
});
},
},
onPageScroll(e) {
if (e.scrollTop == 0 && !this.loadding) {
this.loadding = true;
setTimeout(() => {
this.show = true;
this.loadding = false;
}, 1000);
}
},
};
</script>
<style lang="scss">
.IMmsgContent-container {
padding-left: 20rpx;
padding-right: 20rpx;
padding-bottom: 146rpx;
box-sizing: border-box;
background-color: #fafafa;
font-size: 1rem;
font-family: -apple-system-font, Helvetica Neue, Helvetica, sans-serif;
min-height: 100vh;
&.disable-scroll {
height: 100vh;
overflow: hidden;
}
.u-navbar {
height: 88rpx;
margin-bottom: 20rpx;
}
.tui-chat-content {
width: 100%;
/* 阻止默认触摸行为 */
pointer-events: auto;
/* 阻止滚动传递 */
overscroll-behavior: contain;
/* 当显示语音面板时添加的类 */
}
.penetrate-touch {
pointer-events: none;
}
.tui-chatbox {
max-width: 66%;
border-radius: 10rpx;
position: relative;
padding: 20rpx 22rpx;
font-size: 32rpx;
color: #333;
word-break: break-all;
word-wrap: break-word;
}
.tui-chatbox::before {
content: "";
position: absolute;
width: 0;
height: 0;
top: 20rpx;
border: 16rpx solid;
}
.tui-chatbox-left {
background: #fff;
border: 1rpx solid #fff;
display: inline-block;
}
.tui-chatbox-left::before {
right: 100%;
border-color: transparent #fff transparent transparent;
}
.tui-chatbox-right {
background: #a0d5f3;
border: 1rpx solid #a0d5f3;
}
.tui-chatbox-right::before {
left: 100%;
border-color: transparent transparent transparent #a0d5f3;
}
/*chatbox*/
.tui-chatbox ::v-deep {
.chat-bubble-box {
display: flex;
align-items: center;
.chatimg {
width: 200rpx;
height: 200rpx;
margin-right: 20rpx;
}
}
}
.tui-chat-left,
.tui-chat-right {
display: flex;
align-items: flex-start;
padding-top: 36rpx;
}
.tui-user-pic {
width: 80rpx;
height: 80rpx;
flex-shrink: 0;
border-radius: 50%;
display: block;
}
.tui-left {
margin-left: 26rpx;
}
.tui-right {
margin-right: 26rpx;
}
.tui-chat-right {
justify-content: flex-end;
}
.tui-chat-center {
display: flex;
align-items: center;
justify-content: center;
height: 28rpx;
font-size: 28rpx;
color: #666;
padding-top: 36rpx;
}
.tui-label {
display: inline-block;
background: rgba(0, 0, 0, 0.4);
color: #fff;
font-size: 24rpx;
line-height: 24rpx;
margin-top: 36rpx;
padding: 12rpx 16rpx;
text-align: center;
border-radius: 8rpx;
margin-left: 50%;
transform: translateX(-50%);
}
.tui-img-chatbox {
position: relative;
}
.tui-img-chatbox::after {
content: "";
position: absolute;
height: 200%;
width: 200%;
border: 1rpx solid #eaeef1;
transform-origin: 0 0;
-webkit-transform-origin: 0 0;
-webkit-transform: scale(0.5);
transform: scale(0.5);
left: 0;
top: 0;
border-radius: 20rpx;
}
.tui-chat-img {
max-width: 200rpx;
/* min-height: 80rpx; */
display: block;
border-radius: 10rpx;
}
.tui-chat-flex {
display: flex;
align-items: center;
}
.tui-flex-center {
display: flex;
align-items: center;
}
.tui-chat-voice {
width: 40rpx;
height: 40rpx;
display: block;
flex-shrink: 0;
}
.tui-rotate {
transform: rotate(180deg);
}
.tui-chat-fail {
width: 50rpx;
height: 50rpx;
display: block;
flex-shrink: 0;
}
.tui-mr {
margin-right: 16rpx;
}
.tui-ml {
margin-left: 16rpx;
}
.tui-flex-end {
justify-content: flex-end;
}
.tui-flex-reverse {
flex-direction: row-reverse;
}
._root ::v-deep {
.chat-bubble-box {
display: flex;
align-items: center;
.chatimg {
width: 200rpx;
height: 200rpx;
margin-right: 20rpx;
}
}
.single-img {
width: 300rpx;
height: 300rpx;
}
}
.img {
image {
flex: 1;
max-width: 350upx;
max-height: 350upx;
}
}
}
.IMmsgContent-ios-container {
padding-bottom: 220rpx;
}
</style>