功能:基础功能群聊 文件上传 图片上传 表情发送 超链接跳转
注:里面涉及到诸多函数依赖,请忽略,只看主要功能即可

html
<template>
<div class="container" :style="{'top':'calc('+marginTop+' + 0.16rem)'}">
<div class="chart-message display-flex" :style="{'height':'calc(100vh - '+marginTop+' - '+(KEYBOARD_H+0.16)+'rem)'}">
<div class="chart-header">
<h2>{{groupChatInfo.groupName}}({{chatGroupList.length}})</h2>
<div @click="handleGroupUser" class="more-user display-flex hvc">
<i class="icon icon-more"></i>
</div>
</div>
<div class="chart-message-cont flex-1" @touchstart="handleMessageInputBlur">
<div class="chart-message-cont-wrap">
<div class="load-more" v-if="hasMore">
<span @click="getHistoryMessage({type:'loadMore'})">加载更多</span>
</div>
<template v-for="(item,index) in historyMessageList">
<!--加入者信息-->
<div v-if="item.messageType == 'RC:InfoNtf'" class="chart-message-item message-time">
<p>{{item.content.message}}</p>
</div>
<!--接收者-->
<div v-if="item.messageDirection == '2'&&item.messageType != 'RC:InfoNtf'" class="chart-message-item message-receive display-flex">
<div class="user-avatar" @click="handleAvatar({type:'2',data:item.content.extra})">
<img v-if="item.content.extra" :src="item.content.extra.avatar" alt="">
<img v-else src="./../../assets/images/industry/icon-avatar.png" alt="">
</div>
<div>
<p v-if="item.content.extra" style="color: #555;font-size: 0.2rem;line-height: 1.5;">{{item.content.extra.name}}</p>
<div @click="handleDownloadFile({type:item.messageType,data:item})" class="user-msg " :class="{'display-flex':item.messageType == 'RC:FileMsg'}">
<template v-if="item.messageType == 'RC:TxtMsg'">
<p @contextmenu.stop.prevent="handleCopyText({data:item.content.content,eType:'contextmenu'})" @click="handleCopyText({data:item.content.content,eType:'click'})" v-html="chatMessageFormat({data:item.content.content,type:2})"></p>
</template>
<template v-else-if="item.messageType=='RC:ImgMsg'">
<img @click="handleImagePreview({url:item.content.imageUri})" :src="item.content.imageUri" alt="">
</template>
<template v-else-if="item.messageType == 'RC:FileMsg'">
<div class="file-info">
<p class="file-name">{{item.content.name}}</p>
<p class="file-size">{{item.content.size>1024*1024?(item.content.size/1024/1024).toFixed(2)+'MB':(item.content.size/1024).toFixed(2)+'KB'}}</p>
</div>
<div class="file-icon">
<img src="./../../assets/images/chat/icon-file.png" style="height: 0.68rem; 0.68rem;" alt="">
</div>
</template>
</div>
</div>
</div>
<!--发送者-->
<div v-if="item.messageDirection == '1'&&item.messageType != 'RC:InfoNtf'" class="chart-message-item message-send display-flex">
<div>
<p v-if="item.content.extra" style="text-align: right;color: #555;font-size: 0.2rem;line-height: 1.5;">{{item.content.extra.name}}</p>
<div @click="handleDownloadFile({type:item.messageType,data:item})" class="user-msg" :class="{'user-msg--file display-flex':item.messageType == 'RC:FileMsg'}">
<template v-if="item.messageType == 'RC:TxtMsg'">
<p @contextmenu.stop.prevent="handleCopyText({data:item.content.content,eType:'contextmenu'})" @click="handleCopyText({data:item.content.content,eType:'click'})" v-html="chatMessageFormat({data:item.content.content,type:1})"></p>
</template>
<template v-else-if="item.messageType=='RC:ImgMsg'">
<img @click="handleImagePreview({url:item.content.imageUri})" :src="item.content.imageUri" alt="">
</template>
<template v-else-if="item.messageType == 'RC:FileMsg'">
<div class="file-icon">
<img src="./../../assets/images/chat/icon-file.png" style="height: 0.68rem; 0.68rem;" alt="">
</div>
<div class="file-info">
<p class="file-name">{{item.content.name}}</p>
<p class="file-size">{{item.content.size>1024*1024?(item.content.size/1024/1024).toFixed(2)+'MB':(item.content.size/1024).toFixed(2)+'KB'}}</p>
</div>
</template>
</div>
</div>
<div @click="handleAvatar({type:'1',data:item.content.extra})" class="user-avatar">
<img v-if="item.content.extra" :src="item.content.extra.avatar" alt="">
<img v-else src="./../../assets/images/industry/icon-avatar.png" alt="">
</div>
</div>
<!--时间类型-->
<div v-if="index < historyMessageList.length-1 &&historyMessageList[index+1].sentTime-historyMessageList[index].sentTime>10*60*1000" class="chart-message-item message-time">
<p v-html="chatMessageTimeFormat({data:historyMessageList[index+1]})"></p>
</div>
</template>
</div>
</div>
<div class="chart-message-footer" v-if="sendMsgState">
<div class="btn-group display-flex">
<div class="btn-industry-map display-flex hvc">
<i v-if="browser.mobile" @touchstart="handleIndustryMap" class="icon icon-industryMap"></i>
<i v-else @click="handleIndustryMap" class="icon icon-industryMap"></i>
</div>
<textarea @blur="messageBlur" ref="messageContent" @focus="messageFocus" @keydown.enter="handleSendMessage({event:$event,sendType:'text'})" v-model.trim="messageContent" placeholder="请输入内容" :class="messageContent?'message-val':'message-placeholder'" class="message-input flex-1"></textarea>
<div class="btn-smile display-flex hvc">
<i class="icon icon-smile" v-if="browser.mobile" @touchstart="handleTogglePanelEmtion({event:$event})"></i>
<i class="icon icon-smile" v-else @click="handleTogglePanelEmtion({event:$event})"></i>
</div>
<template v-if="messageContent">
<div class="btn-send display-flex hvc">
<span v-if="browser.mobile" @touchstart="handleSendMessage({event:$event,sendType:'text'})">发送</span>
<span v-else @click="handleSendMessage({event:$event,sendType:'text'})">发送</span>
</div>
</template>
<template v-else>
<div class="btn-add display-flex hvc">
<i class="icon icon-add" v-if="browser.mobile" @touchstart="handleTogglePanelImage({event:$event})"></i>
<i class="icon icon-add" v-else @click="handleTogglePanelImage({event:$event})"></i>
</div>
</template>
</div>
<div class="multi-fun-panel">
<div v-show="panelImageState" class="panel-image">
<ul>
<li>
<label for="uploadImage">
<input @change.prevent="handleUploadImg({event: $event})" style="display: none" accept="image/*" type="file" ref="uploadImage" id="uploadImage">
<img style=" 1.16rem;" src="./../../assets/images/chat/icon-upload-images.png" alt="">
<p>照片</p>
</label>
</li>
<li>
<label for="uploadFile">
<input @change.prevent="handleUploadFile({event: $event})" style="display: none" type="file" ref="uploadFile" id="uploadFile">
<img style=" 1.16rem;" src="./../../assets/images/chat/icon-upload-file.png" alt="">
<p>文件</p>
</label>
</li>
</ul>
</div>
<div v-show="panelEmtionState" class="panel-emtion display-flex">
<template v-if="browser.mobile">
<Emotion class="emotion-item" v-for="(item, i) in emoticon" :key="i" @touchend.native="handleEmotion({data:item})">{{item}}</Emotion>
</template>
<template v-else>
<Emotion class="emotion-item" v-for="(item, i) in emoticon" :key="i" @click.native="handleEmotion({event:$event,data:item})">{{item}}</Emotion>
</template>
</div>
</div>
</div>
</div>
</div>
</template>
js
<script>
import {ImagePreview} from 'vant'
import {formatDate,browser,getOpenId,emotionParams ,addEvent,regularExpression,copyText,globalStatistics} from "../../../static/js/help";
import {getByToken,groupBoardChat,setMessageRead,groupChatInfo,getWechatInfoByUnionId ,attachUpload,chatAutoQuote,groupChatMembers} from "../../../static/js/api";
import {mapGetters} from 'vuex';
import Emotion from './../../components/chat/emotion'
const avatar = require('./../../assets/images/industry/icon-avatar.png');
import {Dialog} from 'vant'
window.vueThis = null;
export default {
name: "chatMessage",
components:{
Emotion
},
data() {
return {
userInfo:{
name:'',
icon:'',
appUserId:''
},//自己的用户信息
receiveTargetId:'',//接送消息的userId
messageContent:'',//消息内容
historyMessageList:[],//历史消息
scrollDirection:'down',//down 向下,up向上
timestrap:new Date().getTime(),//历史消息limit
hasMore:false,//是否展示加载更多
beforeScrollHeight:0,//滚动之前高度
sentTime:localStorage.sentTime,//记录已读消息时间
groupChatInfo:{},//群聊信息
wxUserInfo:{},//微信用户信息
emoticon:emotionParams.list,
panelImageState:false,//图片上传面板
panelEmtionState:false,//表情面板
sendImage:'',//图片发送
chatGroupList:[],
chatFilter:process.env.CHAT_FILTER,//聊天用户过滤列表
browser:browser.versions,
KEYBOARD_H:0,//软盘高度
}
},
watch:{
'historyMessageList'(){
this.$nextTick(()=>{
this.scrollView();
})
},
'im'(){
this.creatRongIMConnect();
},
},
computed:{
...mapGetters ([
'im',
'sysUserInfo'
]),
deviceInfo() {
return this.$store.getters.deviceInfo;
},
marginTop() {
if (this.deviceInfo.grade == '1.3' || this.deviceInfo.grade == '1.4') {//App
return '0rem'
} else if (this.deviceInfo.grade == '2') {//PC
return '1.78rem'
} else {//手机微信
return '0.9rem'
}
},
//发送框状态
sendMsgState(){
let state = true;
for(let i = 0;i<this.chatFilter.length;i++){
if(this.chatFilter[i].id == this.receiveTargetId){
return false
continue
}
}
return state
}
},
methods: {
//让input失去焦点
handleMessageInputBlur(){
this.$refs.messageContent.blur();
},
//点击头像
handleAvatar({type,data} = {}){
if(type == '1'){
this.$router.push({
name:'industrySetting'
})
}else if(type == '2'){
this.$router.push({
name:'industryContacts',
query:{
clientId:data.clientId
}
})
}
},
//图片面板切换
handleTogglePanelImage({event} = {}){
this.panelImageState = !this.panelImageState;
this.panelEmtionState = false;
if(this.panelImageState){
this.$refs.messageContent.blur();
}else {
this.$refs.messageContent.focus();
}
event.preventDefault();
},
//表情面板切换
handleTogglePanelEmtion({event} = {}){
this.panelEmtionState = !this.panelEmtionState;
this.panelImageState = false;
if(this.panelEmtionState){
this.$refs.messageContent.blur();
}else {
this.$refs.messageContent.focus();
}
event.preventDefault();
},
//图片预览
handleImagePreview({url} = {}){
ImagePreview({
images: [url],
closeable: true,
});
},
//图片上传
handleUploadImg({event} = {}){
let file = event.target.files[0];
if(file.size>10*1024*1024){
this.$_toast('图片大小需小于1OMB')
this.$refs.uploadImage.value = '';
return
}
attachUpload({
multipartFile:file
}).then((res)=>{
if(res.data.state == 'SUCCESS'){
let url = res.data.url;
this.sendImage = url;
this.handleSendMessage({event:event,sendType:'image'});
this.$refs.uploadImage.value = '';
}
})
event.preventDefault();
},
//文件上传
handleUploadFile({event} = {}){
let file = event.target.files[0];
let fileInfo = {
name: file.name,
size: file.size,
type: file.type,
}
if(file.size>10*1024*1024){
this.$_toast('文件大小需小于1OMB')
this.$refs.uploadFile.value = '';
return
}
attachUpload({
multipartFile:file
}).then((res)=>{
if(res.data.state == 'SUCCESS'){
let url = res.data.url;
this.sendImage = url;
fileInfo.fileUrl = url;
this.handleSendMessage({event:event,sendType:'file',fileInfo});
this.$refs.uploadFile.value = '';
}
})
event.preventDefault();
},
//文件下载
handleDownloadFile({type,data} = {}){
if(type == 'RC:FileMsg'){
let {fileUrl,name,size} = data.content;
this.$router.push({
name:'downloadFile',
query:{
params:JSON.stringify({
fileUrl,
name,
size,
})
}
})
}
},
//聊天消息格式化
chatMessageFormat({data,type} = {}){
if(type == 1){
var style = "color:#232323;text-decoration: underline"
}else if(type == 2){
var style = "color:#333;text-decoration: underline"
}
let _html = data.replace(regularExpression.http, (res)=> {
let url = res;
if(res.indexOf('http')=='-1'){
url ='http://'+url;
}
return `<a style="${style}" onclick="handleCopyTextByMiniProgarm({event:event,url:'${url}'})" href="javascript:;">${res}</a>`;
return this.deviceInfo.terminalType == 'MINIPROGRAM'?`<a style="${style}" onclick="handleCopyTextByMiniProgarm(event,'${res}')" href="javascript:;">${res}</a>`:`<a onclick="handleCopyTextByMiniProgarm(event,'${res}')" style="${style}" target="_blank" href="${url}">${res}</a>`
})
_html = _html.replace(/#[u4E00-u9FA5]{1,3};/gi, this.emotionFormat)
return _html
},
//表情格式化
emotionFormat (res) {
let word = res.replace(/#|;/gi,'')
const list = emotionParams.list
let index = list.indexOf(word)
return `<img style=" 0.343rem;height: 0.343rem;display: inline-block;vertical-align: -4px" src="${emotionParams.url}${index}.gif" align="middle">`
},
//选择表情
handleEmotion({event,data} ={}){
let emotion = `#${data};`;
this.messageContent +=emotion;
let h = this.$refs.messageContent.scrollHeight;
let fontSize = 100/parseFloat($('html').css('font-size'));//px换算rem
this.$refs.messageContent.scrollTop =h*fontSize*2;
//event.preventDefault();
},
//切换到地图
handleIndustryMap(){
this.handleMessageInputBlur();
this.$parent.type = 1;
localStorage.industryType = 1;
globalStatistics({
eventType:'E_033',
clickType:'C_032_0002'
})
},
//聊天用户
getGroupChatMembers(){
groupChatMembers({
groupId:this.$route.query.groupId
}).then((res)=>{
if(res.data.code == '0000'){
let data = res.data.data;
this.chatGroupList = data;
}
})
},
//获取微信用户信息
getWechatInfoByUnionId(){
getWechatInfoByUnionId({
unionId:getOpenId()
}).then((res)=>{
if(res.data.code == '0000'){
let data = res.data.data;
this.wxUserInfo = data;
}
})
},
//input失去焦点滚动到可视区域 https://cdn.ronghub.com/RongIMLib-3.0.6-dev.min.js
handleScrolltoView() {
document.querySelector(".chart-message").scrollIntoView(true);
},
//与建立融云连接
creatRongIMConnect(){
//只有获取到了targetId才能做其他操作
this.getGroupChatInfo().then(()=>{
this.watchRongIMLib();//监测
this.getHistoryMessage();//历史消息
this.clearnUnReadConvert() //清除未读
})
},
//设置监听
watchRongIMLib(){
this.im.watch({
conversation: ()=>{
console.log('消息列表更新');
},
message: (event)=>{
if(this.$route.name !='industry') return
var message = event.message;
let {messageUId,sentTime,type} = message;
if(message.messageType !='RC:ReadNtf'){
if(message.type == 3){
message.receivedStatus = 0;
this.historyMessageList.push(message);
this.setMessageRead({
messageUId,
lastMessageSendTime:sentTime,
type});
this.clearnUnReadConvert() //清除未读
}
console.log('我已接收到新消息');
}else {
this.sentTime = localStorage.sentTime = message.sentTime;
this.SetServerMessageRead();//服务器已读
console.log('我已接收到已读通知')
}
}
});
},
//message失去焦点
messageBlur(){
this.handleScrolltoView();
},
//message获取焦点
messageFocus(){
this.panelImageState = false;
this.panelEmtionState = false;
},
//消息发送
handleSendMessage({event,sendType,fileInfo} = {}){
//手机回车不发消息
var conversation = this.im.Conversation.get({
targetId: this.receiveTargetId,//接收方USERID
type: RongIMLib.CONVERSATION_TYPE.GROUP
});
//发送文本
if(sendType == 'text'){
if(this.browser.mobile&&event.keyCode == '13'){
return
}
if(!this.messageContent) {
this.$_toast('请输入内容');
return
}
//发送文本
var sendParams = {
messageType: RongIMLib.MESSAGE_TYPE.TEXT, // 填写开发者定义的 messageType
content: { // 填写开发者定义的消息内容
content:this.messageContent,
extra:{
avatar:this.wxUserInfo.headImgUrl,
name:this.sysUserInfo.name,
clientId:this.sysUserInfo.client_id
},
},
isPersited: true,// 是否存储在服务端,默认为 true
isCounted: true, // 是否计数. 计数消息接收端接收后未读数加 1,默认为 true
pushContent:'user 发送了一条消息', // Push 显示内容
pushData: 'Push 通知时附加信息', // Push 通知时附加信息, 可不填
isStatusMessage: false, // 设置为 true 后 isPersited 和 isCounted 属性失效
disableNotification: false, // 设置为 true 后移动端不会收到 Push 信息和本地通知提醒
}
}else if(sendType == 'image'){
//发送图片
var sendParams = {
messageType: RongIMLib.MESSAGE_TYPE.IMAGE, // 填写开发者定义的 messageType
content: { // 填写开发者定义的消息内容
content:'',//base64图片地址
imageUri:this.sendImage,//图片url
extra:{
avatar:this.wxUserInfo.headImgUrl,
name:this.sysUserInfo.name,
clientId:this.sysUserInfo.client_id
},
},
isPersited: true,// 是否存储在服务端,默认为 true
isCounted: true, // 是否计数. 计数消息接收端接收后未读数加 1,默认为 true
pushContent:'user 发送了一条消息', // Push 显示内容
pushData: 'Push 通知时附加信息', // Push 通知时附加信息, 可不填
isStatusMessage: false, // 设置为 true 后 isPersited 和 isCounted 属性失效
disableNotification: false, // 设置为 true 后移动端不会收到 Push 信息和本地通知提醒
}
}else if(sendType == 'file'){
//发文件
var sendParams = {
messageType: RongIMLib.MESSAGE_TYPE.FILE, // 填写开发者定义的 messageType
content: {
...fileInfo,
extra:{
avatar:this.wxUserInfo.headImgUrl,
name:this.sysUserInfo.name,
clientId:this.sysUserInfo.client_id
}
},
isPersited: true,// 是否存储在服务端,默认为 true
isCounted: true, // 是否计数. 计数消息接收端接收后未读数加 1,默认为 true
pushContent:'user 发送了一条消息', // Push 显示内容
pushData: 'Push 通知时附加信息', // Push 通知时附加信息, 可不填
isStatusMessage: false, // 设置为 true 后 isPersited 和 isCounted 属性失效
disableNotification: false, // 设置为 true 后移动端不会收到 Push 信息和本地通知提醒
}
}
conversation.send(sendParams).then((message)=>{
this.scrollDirection = 'down';
this.historyMessageList.push(message);
if(sendType == 'text'){
//自动报单
chatAutoQuote({
wechatNickName:this.wxUserInfo.nickname,
content:this.messageContent
})
}
this.messageContent = '';
});
groupBoardChat({
targetToken:this.receiveTargetId,
content:this.messageContent
})
event.preventDefault();
},
//告诉对方,该消息已读过了
setMessageRead({messageUId,lastMessageSendTime,type}){
var conversation = this.im.Conversation.get({
targetId:this.receiveTargetId,
type: RongIMLib.CONVERSATION_TYPE.GROUP
});
// 以上 3 个属性在会话的最后一条消息中可以获得
conversation.send({
messageType: 'RC:ReadNtf',
content: {
messageUId: messageUId,
lastMessageSendTime: lastMessageSendTime,
type: type
}
}).then((message)=>{
console.log('消息我已经读了,发了通知给你');
});
},
//获取历史消息
getHistoryMessage({type}={}){
if(type == 'loadMore'){
this.scrollDirection = 'up'
}else {
this.scrollDirection = 'down'
}
var conversation = this.im.Conversation.get({
targetId: this.receiveTargetId,//接收方的 userId
type: RongIMLib.CONVERSATION_TYPE.GROUP
});
conversation.getMessages({
timestrap:this.timestrap,
count: 20
}).then((result)=>{
console.log(result.list)
this.scrollDirection = 'up';
this.beforeScrollHeight = $('.chart-message-cont-wrap').height();
this.historyMessageList = [...result.list,...this.historyMessageList]; // 历史消息列表
this.hasMore = result.hasMore;
if(result.list.length){
this.timestrap = result.list[0].sentTime;
}
});
},
//滚动到可视区域
scrollView({animate}={animate:true}){
let scrollHeight = $('.chart-message-cont-wrap').height();
if(this.scrollDirection == 'down'){
if(animate){
$('.chart-message-cont').animate({scrollTop: scrollHeight+'px'}, 500);
}else {
$('.chart-message-cont').scrollTop(scrollHeight)
}
}else if(this.scrollDirection == 'up'){
$('.chart-message-cont').animate({scrollTop: (scrollHeight- this.beforeScrollHeight)+'px'}, 0);
}
},
//时间格式化
chatMessageTimeFormat({data}={}){
let currentDate = formatDate({date:data.sentTime});
let nowDate = formatDate();
if(currentDate == nowDate){
return formatDate({
date:data.sentTime,
fmt:'hh:mm',
})
}else {
return formatDate({
date:data.sentTime,
fmt:'yyyy-MM-dd hh:mm'
})
}
},
//清除未读数
clearnUnReadConvert(){
this.im.Conversation.get({
targetId:this.receiveTargetId,
type: RongIMLib.CONVERSATION_TYPE.GROUP
}).read().then(()=>{
console.log('清除未读数成功'); // im.watch conversation 将被触发
});
},
getUserInfo(){
getByToken({
targetId:this.receiveTargetId
}).then((res)=>{
if(res.data.code == '0000'){
let data = res.data.data;
if(data){
this.userInfo = data;
}
}
})
},
//服务器已读
SetServerMessageRead(){
setMessageRead({
targetToken:this.receiveTargetId
})
},
//获取群聊信息
getGroupChatInfo(){
return new Promise((resolve,reject)=>{
groupChatInfo({}).then((res)=>{
if(res.data.code == '0000'){
let data = res.data.data;
this.groupChatInfo = data;
this.receiveTargetId = data.groupId;
document.title = data.groupName
resolve();
}
})
})
},
//查看群组用户
handleGroupUser(){
this.$router.push({
name:'chatGroupUser',
query:{
groupId:this.receiveTargetId
}
})
},
//复制
handleCopyText({data,eType} ={}){
if(!this.browser.mobile&&eType =='click') return
if(this.deviceInfo.grade == '2.1') {
this.$_toast('请使用ctrl+c复制')
return;
}
copyText({text:data})
},
stopEvent(event) { //阻止冒泡事件
//取消事件冒泡
var e = event; //若省略此句,下面的e改为event,IE运行可以,但是其他浏览器就不兼容
if (e && e.stopPropagation) {
// this code is for Mozilla and Opera
e.stopPropagation();
} else if (window.event) {
// this code is for IE
window.event.cancelBubble = true;
}
}
},
created(){
this.getGroupChatMembers();
window.vueThis = this;
},
activated(){
this.scrollView();
this.getGroupChatMembers();
if(this.im){
this.clearnUnReadConvert() //清除未读
}
},
mounted() {
this.SetServerMessageRead();
this.getWechatInfoByUnionId();
if(this.im){
this.creatRongIMConnect();
}
addEvent({ele:'.panel-emtion'})
}
}
window.handleCopyTextByMiniProgarm = function(data){
if(window.vueThis.deviceInfo.terminalType == 'MINIPROGRAM'){
copyText({text:data.url,isTip:false})
Dialog.alert({
message: '小程序不支持打开链接,链接已复制请在浏览器中打开',
})
}else {
window.open(data.url,'_blank')
}
window.vueThis.stopEvent(event);
}
</script>
css
<style lang="scss" scoped>
.container{ 7.5rem;margin: auto;position: relative;
-moz-user-select:text;
-webkit-user-select:text;
}
.chart-header{height: 0.93rem; 7.5rem;background: #fff;
h2{font-size: 0.3rem;color: #2C2C2C;text-align: center;line-height: 0.93rem;font-weight: 700}
.more-user{
0.93rem;
height: 0.93rem;
position: absolute;right: 0;top: 0;
.icon-more{ 0.36rem;height: 0.09rem;background: url("././../../assets/images/chat/icon-more.png") no-repeat;background-size: contain;}
}
}
.chart-message{flex-direction: column;height: 100vh;
.load-more{text-align: center;padding: 0.3rem 0;cursor: pointer;
span{color: #555;}
}
.chart-message{
&-item{margin: 0.7rem 0;
.user-avatar{ 0.88rem;
img{ 0.88rem;height: 0.88rem;background: #fff;border-radius: 0.88rem;overflow: hidden;border: 0.01rem solid #eee;}
}
}
&-cont{padding: 0 0.18rem;overflow: scroll;background: #f5f5f5;
.message-time{color: #888888;font-size: 0.26rem;text-align: center;margin: 0.2rem 0;
p{display: inline-block;
background: rgba(0,0,0,0.2);
padding: 2px 5px;
color: #fff;
border-radius: 2px;}
}
.message-receive{margin-right: 1.2rem;
.user-avatar{margin-right: 0.2rem;}
.user-msg {background: #fff;padding: 0.25rem 0.3rem;border: 0.01rem solid #DDDDDD;border-radius: 0.04rem 0.2rem 0.2rem 0.2rem;
img{ auto;height: auto;max- 1.8rem;}
.href{color: #333;text-decoration: underline}
}
.file-info{margin-right: 0.6rem;}
.file-size{color: #999;font-size: 0.24rem;}
p{font-size:0.28rem;color: #333;line-height: 0.45rem;word-break: break-all;}
}
.message-send{margin-left: 1.2rem;justify-content: flex-end;
.user-avatar{margin-left: 0.2rem;}
.user-msg {background: #9eea6a;padding: 0.25rem 0.3rem;border: 0.01rem solid #9eea6a;border-radius: 0.2rem 0.04rem 0.2rem 0.2rem;position: relative;
img{ auto;height: auto;max- 1.8rem;}
}
.user-msg.user-msg--file{background: #fff;border: 0.01rem solid #DDDDDD;}
.file-info{margin-left: 0.6rem;}
.file-size{color: #232323;font-size: 0.24rem;}
.href{color: #232323;text-decoration: underline;border: 1px solid red;}
.read-state{position: absolute;font-size: 0.24rem; 0.6rem;text-align: center;right: 0;bottom: -0.4rem;background: rgba(0,0,0,0.1);border-radius: 0.05rem;color: #555;}
p{font-size:0.28rem;color: #232323;line-height: 0.45rem;word-break: break-all;}
}
}
&-footer{
.btn-group{
background: #fff;padding: 0.15rem 0.25rem;box-sizing: border-box;padding-bottom: 0.4rem;
}
.btn-industry-map{ 0.68rem;margin-right: 0.34rem;
.icon-industryMap{ 0.68rem;height: 0.68rem;display: inline-block;background: url("./../../assets/images/industry/icon-industryMap.png") no-repeat;background-size: contain;cursor: pointer}
}
.btn-smile{ 0.56rem;margin-right: 0.24rem;margin-left: 0.24rem;
.icon-smile{ 0.56rem;height: 0.56rem;display: inline-block;background: url("./../../assets/images/industry/icon-smile.png") no-repeat;background-size: contain;cursor: pointer}
}
.btn-add{ 0.56rem;
.icon-add{ 0.56rem;height: 0.56rem;display: inline-block;background: url("./../../assets/images/industry/icon-add.png") no-repeat;background-size: contain;;cursor: pointer}
}
.btn-send{ 0.56rem;
span{color: #5C86F7;font-size: 0.3rem;background: transparent;border: none;text-align: center;font-weight: bold;min- 1rem;white-space: nowrap;cursor: pointer}
}
.message-input{padding: 0;margin: 0;border: none;height: 0.8rem;border-radius: 0.12rem;background:#F1F3FA;box-sizing: border-box;font-size: 0.28rem;color: #555;
&::-webkit-scrollbar {
0.05rem;
height: 0.1rem
}
&::-webkit-scrollbar-thumb {
min-height: 0.05rem;
background: #c4c6cc;
border-radius: 0.02rem;
}
&::-webkit-scrollbar-track-piece {
background: #fff
}
&::placeholder{color: #999;}
}
.message-placeholder{
padding: 0.2rem 0.1rem;
line-height: 0.4rem;
}
.message-val{
padding: 0.1rem 0.1rem;
line-height: 0.35rem;
}
}
}
.multi-fun-panel{background: #F7F7F7;
.panel-image{
ul{
li{text-align: center;display: inline-block;margin:0.3rem 0.33rem;
p{text-align: center;color: #4C4C4C;font-size: 0.24rem;margin-top: 0.1rem;}
}
}
}
}
.panel-emtion{flex-direction: row;flex-wrap: wrap;max-height: 3rem;overflow: scroll;padding: 0.1rem ;box-sizing: border-box;}
}
</style>