...
 
Commits (11)
    https://gitcode.net/dcloud/uni-im/-/commit/55b80ed05184005e005ddf54b6a5fd4b1e7ccc77 修复 代码错误导致云对象报错的问题 2024-05-08T14:25:58+08:00 DCloud_MQ maquan@dcloud.io https://gitcode.net/dcloud/uni-im/-/commit/937e18bf7781941768e0f7cd34ff0a35c58e6df6 修复 代码错误导致云端扩展框架缓存无效的问题 2024-05-08T14:43:02+08:00 DCloud_MQ maquan@dcloud.io https://gitcode.net/dcloud/uni-im/-/commit/0ff902d687cec2e37071f721cd32d3450f2f5e1c 3.0.3 changelog 2024-05-08T14:46:13+08:00 DCloud_JSON linju@dcloud.io https://gitcode.net/dcloud/uni-im/-/commit/2f990b7f7f763af6334c46e1a23656da69fd7ba5 优化 消息列表滚动到底时,自动隐藏“有新消息”提示 2024-05-08T14:56:00+08:00 DCloud_MQ maquan@dcloud.io https://gitcode.net/dcloud/uni-im/-/commit/89a778eea7c57de900a5700721b2c0b367455def Update package.json 2024-05-08T15:06:19+08:00 DCloud_JSON linju@dcloud.io https://gitcode.net/dcloud/uni-im/-/commit/075e41b5ed397311910d0e9d35bf970dc2776bb1 优化 微调“有新消息”提示的样式 2024-05-08T16:01:57+08:00 DCloud_MQ maquan@dcloud.io https://gitcode.net/dcloud/uni-im/-/commit/e1b28dd3b2ada6582e172b2eaa93431979777a66 优化 微调“有新消息”提示的样式 2024-05-08T16:18:09+08:00 DCloud_MQ maquan@dcloud.io https://gitcode.net/dcloud/uni-im/-/commit/cd02a5f0b4b8f4b8cc8e8e2052e142e9add47fed 更新 优化多个会话切换的草稿功能,提升性能 2024-05-08T19:58:08+08:00 DCloud_JSON linju@dcloud.io https://gitcode.net/dcloud/uni-im/-/commit/1b28d936c5272f9efc71bbb5337cf0453e42cea6 Update uni-im-msg-list.vue 2024-05-08T21:00:27+08:00 DCloud_JSON linju@dcloud.io https://gitcode.net/dcloud/uni-im/-/commit/3c73c32fbf5021f9c6cf6d01a972575c300e74dc 更新:对于含有图片的消息数据,新增了图片的宽高值,使图片加载前可以固定容器高度,从而避免列表抖动。 2024-05-09T20:37:13+08:00 DCloud_JSON linju@dcloud.io https://gitcode.net/dcloud/uni-im/-/commit/7dd5069d9e5ee640b22239e4641563783d4122cc 3.0.4 2024-05-09T20:54:16+08:00 DCloud_JSON linju@dcloud.io
## 3.0.4(2024-05-09)
- 优化 对于含有图片的消息数据,新增了图片的宽高值,使图片加载前可以固定容器高度,从而避免列表抖动
- 优化 多个会话切换的草稿功能,提升性能消息输入的性能
- 优化 消息列表滚动到底时,自动隐藏“有新消息”提示
- 优化 微调“有新消息”提示的样式
## 3.0.3(2024-05-08)
- 修复 代码错误导致云端扩展框架缓存无效的问题
## 3.0.2(2024-05-08) ## 3.0.2(2024-05-08)
- 修复 解决部分云厂商的uniCloud环境不支持写缓存文件引起的问题 - 修复 解决部分云厂商的uniCloud环境不支持写缓存文件引起的问题
## 3.0.1(2024-05-08) ## 3.0.1(2024-05-08)
......
<template> <template>
<image @load="load" :src="url" :mode="mode" :style="{width,height}" @click="handleClick"></image> <image @load="load" :src="url" :mode="mode" :style='{"width":viewWidth,"height":viewHeight}' @click="handleClick"></image>
</template> </template>
<script> <script>
...@@ -16,15 +16,50 @@ import uniIm from '@/uni_modules/uni-im/sdk/index.js'; ...@@ -16,15 +16,50 @@ import uniIm from '@/uni_modules/uni-im/sdk/index.js';
default: '' default: ''
}, },
maxWidth: { maxWidth: {
type: [String,Boolean], type: [String,Number],
default: false default: false
}, },
maxHeight: {
type: [String,Number],
default: ''
},
width: {
type: [String,Number],
default: ''
},
height: {
type: [String,Number],
default: ''
}
}, },
data() { data() {
return { return {
width:"1px", url: '',
height:"1px", viewWidth: '',
url: '' viewHeight: ''
}
},
mounted() {
// console.log('beforeCreate')
if( this.width && this.height){
// 根据maxWidth 和 maxWidth,在保持宽高比例不变的情况下 计算viewWidth 和 viewHeight
const maxWidth = this.toPx(this.maxWidth)
const maxHeight = this.toPx(this.maxHeight)
let width = this.toPx(this.width)
let height = this.toPx(this.height)
// 如果宽超过最大宽度,高度按比例缩小
if(width > maxWidth){
height = height * maxWidth / width
width = maxWidth
}
// 如果高超过最大高度,宽度按比例缩小
if(height > maxHeight){
width = width * maxHeight / height
height = maxHeight
}
this.viewWidth = width + 'px'
this.viewHeight = height + 'px'
} }
}, },
watch: { watch: {
...@@ -37,7 +72,7 @@ import uniIm from '@/uni_modules/uni-im/sdk/index.js'; ...@@ -37,7 +72,7 @@ import uniIm from '@/uni_modules/uni-im/sdk/index.js';
this.url += '?imageMogr2/thumbnail/400x400>' this.url += '?imageMogr2/thumbnail/400x400>'
}else if(src.indexOf('http') === 0){ }else if(src.indexOf('http') === 0){
// 因为还可能是 base64 blob 的本地图片,所以这里判断是不是http开头的 // 因为还可能是 base64 blob 的本地图片,所以这里判断是不是http开头的
this.url += '?x-oss-process=image/resize,w_100/quality,q_80' this.url += '?x-oss-process=image/resize,w_200/quality,q_80'
} }
} }
}, },
...@@ -47,24 +82,29 @@ import uniIm from '@/uni_modules/uni-im/sdk/index.js'; ...@@ -47,24 +82,29 @@ import uniIm from '@/uni_modules/uni-im/sdk/index.js';
methods: { methods: {
load(e){ load(e){
// console.log('img load',e) // console.log('img load',e)
this.width = e.detail.width // TODO:渲染后再设置宽高,为兼容旧版系统,图片消息中没有带宽高的情况
// 如果以rpx为单位,转换为px if(!this.width || !this.height){
let maxWidth = parseInt(this.maxWidth) let width = e.detail.width
if(this.maxWidth && this.maxWidth.indexOf('rpx') > -1){ let maxWidth = this.toPx(this.maxWidth)
maxWidth = parseInt(this.maxWidth) * uniIm.systemInfo.windowWidth / 750 if(maxWidth && width > maxWidth){
} this.viewWidth = maxWidth + 'px'
// console.log('maxWidth',maxWidth) this.viewHeight = maxWidth * e.detail.height / e.detail.width + 'px'
if(maxWidth && this.width > maxWidth){
this.width = maxWidth + 'px'
this.height = maxWidth * e.detail.height / e.detail.width + 'px'
// console.error('超了',this.width,this.height) // console.error('超了',this.width,this.height)
}else{ }else{
this.width = e.detail.width + 'px' this.viewWidth = e.detail.width + 'px'
this.height = e.detail.height + 'px' this.viewHeight = e.detail.height + 'px'
}
} }
}, },
handleClick(){ handleClick(){
this.$emit('click') this.$emit('click')
},
// 如果是rpx单位,转换为px
toPx(val){
if(typeof val === 'string' && val.indexOf('rpx') > -1){
return parseInt(val) * uniIm.systemInfo.windowWidth / 750
}
return parseInt(val)
} }
} }
} }
......
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
</template> </template>
<template v-slot:floating-block> <template v-slot:floating-block>
<view v-if="hasNewMsg" class="new-msg-bar" @click="showLast"> <view v-if="hasNewMsg" class="new-msg-bar" @click="showLast">
<uni-icons type="arrow-down" size="16"></uni-icons> <uni-icons type="pulldown" size="18" color="#007fff"></uni-icons>
<text>有新消息</text> <text>有新消息</text>
</view> </view>
</template> </template>
...@@ -372,6 +372,7 @@ ...@@ -372,6 +372,7 @@
}, },
async onScrollToLower() { async onScrollToLower() {
this.scrollTracker.reachBottom() this.scrollTracker.reachBottom()
this.hasNewMsg = false
}, },
async canHoldScrollDo(fn){ async canHoldScrollDo(fn){
return new Promise((resolve) => { return new Promise((resolve) => {
...@@ -740,13 +741,14 @@ ...@@ -740,13 +741,14 @@
position: absolute; position: absolute;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
right: 25px; align-items: flex-start;
right: 40px;
bottom: 10px; bottom: 10px;
font-size: 12px; font-size: 12px;
background-color: white; background-color: white;
border: 1px solid silver; color: #007fff;
padding: 5px 8px 5px 5px; padding: 5px 8px 5px 5px;
border-radius: 5px; border-radius: 15px 15px 15px 15px;
/* #ifdef H5 */ /* #ifdef H5 */
pointer-events: auto; pointer-events: auto;
cursor: pointer; cursor: pointer;
......
<template> <template>
<view> <view>
<!-- 注意:根节点都view不能去掉,否则鼠标右键出不来菜单 --> <!-- 注意:根节点都view不能去掉,否则鼠标右键出不来菜单 -->
<uni-im-img max-width="100px" :src="msg.body.url" mode="widthFix" @click="previewImage" class="img" /> <uni-im-img max-width="200px" :src="msg.body.url" :width="msg.body.width" :height="msg.body.height" mode="widthFix" @click="previewImage" class="img" />
</view> </view>
</template> </template>
......
...@@ -16,8 +16,8 @@ ...@@ -16,8 +16,8 @@
size="14px" :color="item.isRead?'#25882a':'#bbb'"></uni-im-icons> size="14px" :color="item.isRead?'#25882a':'#bbb'"></uni-im-icons>
</template> </template>
<text class="text" v-else-if="item.type == 'text'" :decode="true" space="ensp">{{item.text}}</text> <text class="text" v-else-if="item.type == 'text'" :decode="true" space="ensp">{{item.text}}</text>
<uni-im-img v-else-if="item.name == 'img'" max-width="100px" @click="previewImage(item.attrs.src)" <uni-im-img v-else-if="item.name == 'img'" max-width="200px" @click="previewImage(item.attrs.src)"
:src="item.attrs.src" mode="widthFix" class="img" /> :src="item.attrs.src" :width="item.attrs.width" :height="item.attrs.height" mode="widthFix" class="img" />
<uni-link class="link" v-else-if="item.name == 'a'" :href="item.attrs.href" color="#007fff" <uni-link class="link" v-else-if="item.name == 'a'" :href="item.attrs.href" color="#007fff"
:text="item.children[0].text"></uni-link> :text="item.children[0].text"></uni-link>
</template> </template>
......
{ {
"id": "uni-im", "id": "uni-im",
"displayName": "uni-im", "displayName": "uni-im",
"version": "3.0.2", "version": "3.0.4",
"description": "uni-im是云端一体的、全平台的、免费的、开源即时通讯系统", "description": "uni-im是云端一体的、全平台的、免费的、开源即时通讯系统",
"keywords": [ "keywords": [
"im,即时通讯,客服,聊天" "im,即时通讯,客服,聊天"
......
...@@ -253,7 +253,9 @@ ...@@ -253,7 +253,9 @@
aboutUserKeyword: '', aboutUserKeyword: '',
memberListScrollTop: 0, memberListScrollTop: 0,
chooseMoreMsg: false, chooseMoreMsg: false,
checkedMsgList: [] checkedMsgList: [],
// 聊天输入框内容
chatInputContent: '',
}; };
}, },
props: { props: {
...@@ -319,24 +321,6 @@ ...@@ -319,24 +321,6 @@
}) })
}, },
//聊天数据 //聊天数据
//当前会话的聊天框文字内容
chatInputContent: {
get() {
// console.log('this.conversation',this.conversation);
return this.conversation?.chatInputContent || '';
},
set(chatInputContent) {
// #ifdef APP-NVUE
if(this.nvueSetChatInputContent){
clearTimeout(this.nvueSetChatInputContent)
}
this.nvueSetChatInputContent = setTimeout(()=>this.conversation.chatInputContent = chatInputContent,1000)
// #endif
// #ifndef APP-NVUE
this.conversation.chatInputContent = chatInputContent
// #endif
}
},
canSend() { canSend() {
if(typeof this.chatInputContent === 'string'){ if(typeof this.chatInputContent === 'string'){
return this.chatInputContent.trim() != '' return this.chatInputContent.trim() != ''
...@@ -660,9 +644,15 @@ ...@@ -660,9 +644,15 @@
async load(param) { async load(param) {
this.answerMsg = false this.answerMsg = false
// conversation_id = "single_eff0518ad35e16a8a025cc8af03e0388" // conversation_id = "single_eff0518ad35e16a8a025cc8af03e0388"
if(this.conversation.id){
// 设置(含清空)上一个会话的chatInputContent 实现多个会话之间的草稿功能
this.conversation.chatInputContent = this.chatInputContent
}
// console.log('conversation_id',conversation_id); // console.log('conversation_id',conversation_id);
this.conversation = await uniIm.conversation.get(param) this.conversation = await uniIm.conversation.get(param)
// 初始化会话的chatInputContent
this.chatInputContent = this.conversation.chatInputContent
// this.conversation.call_list = [] // this.conversation.call_list = []
// console.log('this.conversation',this.conversation) // console.log('this.conversation',this.conversation)
...@@ -863,13 +853,12 @@ ...@@ -863,13 +853,12 @@
// console.log('this.uploadFileAndSendMsg res',res); // console.log('this.uploadFileAndSendMsg res',res);
tempFiles.forEach(async tempFile => { tempFiles.forEach(async tempFile => {
// console.log('tempFile~',tempFile); // console.log('tempFile~',tempFile);
let { const {
path:url, path:url,
name, name,
size size
} = tempFile; } = tempFile;
const {fileType} = tempFile
let {fileType} = tempFile
if (!['image', 'video'].includes(fileType)) { if (!['image', 'video'].includes(fileType)) {
fileType = 'file' fileType = 'file'
} }
...@@ -888,13 +877,18 @@ ...@@ -888,13 +877,18 @@
}); });
} }
let data = {}; const data = {};
data[fileType] = { const fileInfo = {
url, url,
size, size,
name name
}; };
if(fileType == 'image'){
const {width,height} = await uni.getImageInfo({src:url});
fileInfo.width = width
fileInfo.height = height
}
data[fileType] = fileInfo
let msg = await this.beforeSendMsg(data,false) let msg = await this.beforeSendMsg(data,false)
// console.log('~~~beforeSendMsg',msg); // console.log('~~~beforeSendMsg',msg);
try{ try{
...@@ -907,7 +901,7 @@ ...@@ -907,7 +901,7 @@
await this.updateMsg(msg) await this.updateMsg(msg)
this.sendMsg(msg) this.sendMsg(msg)
}catch(e){ }catch(e){
console.error(777,e) console.error('uploadFile error:',e)
} }
}); });
...@@ -1045,13 +1039,11 @@ ...@@ -1045,13 +1039,11 @@
} }
if (typeof this.chatInputContent == 'object'){ if (typeof this.chatInputContent == 'object'){
// 富文本(图文混排、@某人)消息 // 富文本(图文混排、@某人)消息
// 把字符串中带url的链接转为html的a标签的形式。1.将字符串,按是否为标签,切割为数组 // 把字符串中带url的链接转为html的a标签的形式。1.将字符串,按是否为标签,切割为数组
const htmlStr = this.chatInputContent.html.split(/(<[^>]+>)/) const htmlStr = this.chatInputContent.html.split(/(<[^>]+>)/)
// 2.找到不以<开头的字符串内的url并替换为 html的a // 2.找到不以<开头的字符串内的url并替换为 html的a
.map(str=>str.startsWith('<') ? str : uniIm.utils.replaceUrlToLink(str)) .map(str=>str.startsWith('<') ? str : uniIm.utils.replaceUrlToLink(str))
.join(' ') .join('')
// 先插到消息列表 // 先插到消息列表
let msg = await this.beforeSendMsg({ let msg = await this.beforeSendMsg({
"rich-text":uniIm.utils.parseHtml(htmlStr) "rich-text":uniIm.utils.parseHtml(htmlStr)
...@@ -1062,7 +1054,20 @@ ...@@ -1062,7 +1054,20 @@
msg.body.forEach(async item=>{ msg.body.forEach(async item=>{
if(item.type === 'text'){ if(item.type === 'text'){
item.text = item.text.trim(); item.text = item.text.trim();
}else if(item.name === 'img' && item.attrs.src.indexOf('data:image/png;base64,') === 0){ }else if(item.name === 'img'){
promiseArr.push(new Promise((resolve,reject)=>{
uni.getImageInfo({
src:item.attrs.src,
success:res=>{
item.attrs.width = res.width
item.attrs.height = res.height
resolve()
},
fail:reject
});
}))
if(item.attrs.src.indexOf('data:image/png;base64,') === 0){
promiseArr.push(new Promise((resolve,reject)=>{ promiseArr.push(new Promise((resolve,reject)=>{
uniCloud.uploadFile({ uniCloud.uploadFile({
filePath: item.attrs.src, filePath: item.attrs.src,
...@@ -1072,16 +1077,13 @@ ...@@ -1072,16 +1077,13 @@
// console.log('上传成功',res); // console.log('上传成功',res);
resolve() resolve()
}).catch(e=>{ }).catch(e=>{
console.error(777,e,item.attrs.src);
reject() reject()
}) })
})) }))
} }
}
}) })
await Promise.all(promiseArr) await Promise.all(promiseArr)
// console.log('msg',msg);
// 传完更新 // 传完更新
await this.updateMsg(msg) await this.updateMsg(msg)
// 执行发送 // 执行发送
...@@ -1118,10 +1120,7 @@ ...@@ -1118,10 +1120,7 @@
msg.body = msg.body.trim(); msg.body = msg.body.trim();
// 阻止发送空消息 // 阻止发送空消息
if (!msg.body.length) { if (!msg.body.length) {
this.$nextTick(() => { this.resetChatInput()
this.chatInputContent = '';
this.textareaHeight = 26;
});
return uni.showToast({ return uni.showToast({
title: '不能发送空消息', title: '不能发送空消息',
icon: 'none' icon: 'none'
...@@ -1163,12 +1162,6 @@ ...@@ -1163,12 +1162,6 @@
} }
} }
this.$nextTick(e => {
this.chatInputContent = '';
this.textareaHeight = 26;
this.answerMsg = false
});
//如果是回复某一条消息,需要带上相关id //如果是回复某一条消息,需要带上相关id
if (this.answerMsg !== false) { if (this.answerMsg !== false) {
msg.about_msg_id = this.answerMsg._id msg.about_msg_id = this.answerMsg._id
...@@ -1177,6 +1170,8 @@ ...@@ -1177,6 +1170,8 @@
// 消息列表追加此消息。此时消息状态值为0,表示发送中 // 消息列表追加此消息。此时消息状态值为0,表示发送中
let resMsg = this.conversation.msgList.push(msg) let resMsg = this.conversation.msgList.push(msg)
this.resetChatInput()
this.$nextTick(() => { this.$nextTick(() => {
this.showLast() this.showLast()
// #ifdef APP-NVUE // #ifdef APP-NVUE
...@@ -1197,6 +1192,12 @@ ...@@ -1197,6 +1192,12 @@
return msg; return msg;
} }
}, },
resetChatInput() {
this.chatInputContent = ''
this.textareaHeight = 26
// 关闭引用的消息
this.answerMsg = false
},
getCallUid(param){ getCallUid(param){
let aboutNicknameList = [] let aboutNicknameList = []
if( this.isWidescreen){ if( this.isWidescreen){
......
...@@ -200,7 +200,8 @@ let _registeredExtensionPointsPromise ...@@ -200,7 +200,8 @@ let _registeredExtensionPointsPromise
* @returns {any[]} 该扩展点上挂接的所有扩展程序各自的返回值拼装在一个数组里。 * @returns {any[]} 该扩展点上挂接的所有扩展程序各自的返回值拼装在一个数组里。
*/ */
async function invokeExts(extensionPointName, ...args) { async function invokeExts(extensionPointName, ...args) {
isFsWritable = (this.getCloudInfo().provider === 'aliyun') const [{ provider }] = uniCloud.getCloudInfos()
isFsWritable = (provider === 'aliyun')
// 尝试从生成的缓存文件中加载 // 尝试从生成的缓存文件中加载
let registeredExtensionPoints let registeredExtensionPoints
......