提交 d6e6c02d 编写于 作者: DCloud_JSON's avatar DCloud_JSON 提交者: DCloud_JSON

更新 uni-im-msg-reader 为 1.0.2

上级 c4007b41
## 1.0.0(2024-05-06)
第一版
## 1.0.1(2024-06-21)
更新:在移动端点击未读详情时,以独立页面展示
## 1.0.2(2024-11-06)
更新:兼容 uni-im 3.4.x
\ No newline at end of file
<template>
<view v-if="!msg.is_revoke" :class="{'self':currentUid == msg.from_uid}">
<text
v-if="readerList"
class="read-state"
:class="{'active-color':isGroupMsg && unreadUserList.length}"
@click="showReaderList"
>
{{isGroupMsg ? unreadUserCountTip : (readerList.length?'已读':'未读') }}
</text>
<view
v-if="showPopup && isGroupMsg"
class="popup"
@click="closePopup"
>
<view
class="reader-list-box"
:class="{'show':showTransition}"
@click.stop
<view v-if="!msg.is_revoke && !msg.revoke_ing" :class="{'self':currentUid == msg.from_uid}" class="uni-im-msg-reader">
<text
v-if="readerList && !hiddenState"
class="read-state"
:class="{'active-color':unreadUserList.length || readerList.length,isGroupMsg}"
@click="clickHandler"
>
<text class="title">消息接收人列表</text>
<uni-segmented-control
v-if="!isWidescreen"
:current="currentIndex"
:values="[`未读(${memberUids.length - readerList.length})`, `已读(${readerList.length})`]"
style-type="text"
active-color="black"
@clickItem="e => currentIndex = e.currentIndex"
/>
<view class="content">
<view v-if="isWidescreen || currentIndex == 0" class="reader-list">
<text v-if="isWidescreen" class="title">
{{ memberUids.length - readerList.length }}人未读
</text>
<scroll-view class="user-list" scroll-y>
<view
v-for="(item,index) in unreadUserList"
:key="index"
class="users"
>
<cloud-image
:src=" item.avatar_file&&item.avatar_file.url||'/uni_modules/uni-im/static/avatarUrl.png'"
mode="widthFix"
width="36px"
height="36px"
border-radius="15px"
/>
<text class="nickname">
{{ item.nickname }}
{{ isGroupMsg ? (isReady ? unreadUserCountTip : '') : (readerList.length?'已读':'未读') }}
</text>
<!-- #ifdef H5 -->
<teleport to="body" :disabled="!isWidescreen">
<!-- #endif -->
<view
v-if="showPopup && isGroupMsg"
class="uni-im-msg-reader-popup"
@click="closePopup"
>
<view
class="reader-list-box"
:class="{'show':showTransition}"
@click.stop
>
<text class="title">消息接收人列表</text>
<uni-segmented-control class="segmented-control"
v-if="!isWidescreen"
:current="currentIndex"
:values="[`未读(${unreadUserList.length})`, `已读(${readerList.length})`]"
style-type="text"
active-color="black"
@clickItem="e => currentIndex = e.currentIndex"
/>
<view class="content">
<view v-if="isWidescreen || currentIndex == 0" class="reader-list">
<text v-if="isWidescreen" class="title">
{{ unreadUserList.length }}人未读
</text>
<scroll-view class="user-list" scroll-y>
<view
v-for="(item,index) in unreadUserList"
:key="index"
class="users"
>
<cloud-image
:src=" item.avatar_file&&item.avatar_file.url||'/uni_modules/uni-im/static/avatarUrl.png'"
mode="widthFix"
width="36px"
height="36px"
border-radius="15px"
/>
<text class="nickname">
{{ item.nickname }}
</text>
</view>
</scroll-view>
</view>
</scroll-view>
</view>
<view v-if="isWidescreen || currentIndex == 1" class="reader-list">
<text v-if="isWidescreen" class="title">
{{ readerList.length }}人已读
</text>
<scroll-view class="user-list" scroll-y>
<view
v-for="(item,index) in readerUserlist"
:key="index"
class="users"
>
<cloud-image
:src=" item.avatar_file&&item.avatar_file.url||'/uni_modules/uni-im/static/avatarUrl.png'"
mode="widthFix"
width="36px"
height="36px"
border-radius="15px"
/>
<text class="nickname">
{{ item.nickname }}
<view v-if="isWidescreen || currentIndex == 1" class="reader-list">
<text v-if="isWidescreen" class="title">
{{ readerList.length }}人已读
</text>
<scroll-view class="user-list" scroll-y>
<view
v-for="(item,index) in readerUserlist"
:key="index"
class="users"
>
<cloud-image
:src=" item.avatar_file&&item.avatar_file.url||'/uni_modules/uni-im/static/avatarUrl.png'"
mode="widthFix"
width="36px"
height="36px"
border-radius="15px"
/>
<text class="nickname">
{{ item.nickname }}
</text>
</view>
</scroll-view>
</view>
</scroll-view>
</view>
</view>
</view>
</view>
<!-- #ifdef H5 -->
</teleport>
<!-- #endif -->
</view>
</view>
</template>
<script>
......@@ -92,6 +98,10 @@ export default {
msg: {
type: Object,
default: () => {}
},
hiddenState: {
type: Boolean,
default: false
}
},
data() {
......@@ -99,26 +109,34 @@ export default {
showPopup: false,
showTransition: false,
conversation: {},
currentIndex: 0,
currentIndex: 0
}
},
// 计算属性
computed: {
...uniIm.mapState(['isWidescreen','systemInfo']),
currentUid() {
return uniCloud.getCurrentUserInfo().uid
return uniIm.currentUser._id
},
isReady() {
// 群会话需要等待群成员数据,全部加载完毕
return !this.conversation.group?.member?.hasMore
},
memberUids() {
const groupMember = this.conversation && this.conversation.group_member || {}
// 成员uid不包含消息发送者
return Object.keys(groupMember).filter(uid => uid != this.msg.from_uid)
const groupMember = this.conversation.group?.member
if(groupMember){
// 成员uid不包含消息发送者
return groupMember.dataList.filter(item => item.users._id != this.msg.from_uid).map(item => item.users._id)
}else{
return []
}
},
unreadUserList() {
const unreadUserList = this.memberUids.filter(item => !this.readerList.find(reader => reader.user_id == item))
return unreadUserList.map(item => uniIm.users[item])
},
unreadUserCountTip() {
let unreadUserCount = this.memberUids.length - this.readerList.length
let unreadUserCount = this.unreadUserList.length
// 大于99人显示99+
unreadUserCount = unreadUserCount > 99 ? '99+' : unreadUserCount
return unreadUserCount > 0 ? `${unreadUserCount}人未读` : '全部已读'
......@@ -141,15 +159,26 @@ export default {
}
},
mounted() {
this.conversation = uniIm.conversation.dataList.find(conversation => conversation.id == this.msg.conversation_id)
this.conversation = uniIm.conversation.find(this.msg.conversation_id)
},
methods: {
showReaderList() {
if (this.isGroupMsg) {
// this.$refs.popup.open()
this.showPopup = true
clickHandler() {
if(this.isGroupMsg){
if(uniIm.isWidescreen){
this.showReaderList()
}else {
uni.navigateTo({
url: `/uni_modules/uni-im-msg-reader/pages/reader-list/reader-list?msgId=${this.msg._id}&conversationId=${this.msg.conversation_id}`,
// animationType: 'slide-in-bottom'
})
}
}
},
showReaderList() {
this.showPopup = true
// this.$refs.popup.open()
},
closePopup() {
this.showPopup = false
}
......@@ -157,133 +186,129 @@ export default {
}
</script>
<style lang="scss" scoped>
.self {
align-items: flex-end;
}
.read-state {
font-size: 12px;
flex-direction: row;
color: #999;
margin: 0 60px;
width: 65px;
}
.self .read-state {
text-align: right;
}
.active-color {
color: #0b65ff;
}
/* #ifdef H5 */
.active-color{
cursor: pointer;
}
/* #endif */
.reader-list-box {
background-color: #fff;
border-radius: 10px;
overflow: hidden;
/* 显示隐藏的过度动画 */
transition: transform 0.1s,opacity 0.1s;
transform: scale(0.7);
opacity: 0;
}
.show {
transform: scale(1);
opacity: 1;
}
.reader-list-box>.title {
font-size: 18px;
font-weight: bold;
color: #333;
padding: 10px;
background-color: #f5f5f5;
}
.reader-list-box .content {
flex-direction: row;
padding: 10px;
width: 550rpx;
}
.reader-list {
flex-direction: column;
padding: 0 10px;
<style lang="scss">
.uni-im-msg-reader {
display: flex;
width: 100%;
flex: 1;
/* #ifndef APP-NVUE */
width: 50%;
min-width: 260px;
max-height: 80vh !important;
/* #endif */
}
.reader-list .title {
font-size: 16px;
font-weight: bold;
color: #333;
margin-bottom: 10px;
}
.reader-list .user-list {
height: 750rpx;
overflow: hidden;
.read-state {
font-size: 12px;
flex-direction: row;
color: #555;
margin: 0 60px;
width: 65px;
height: 16px;
}
.active-color {
color: #aaa;
&.isGroupMsg {
/* #ifdef H5 */
cursor: pointer;
/* #endif */
color: #0b65ff;
}
}
&.self {
align-items: flex-end;
.read-state {
text-align: right;
}
}
}
.uni-im-msg-reader-popup {
height: 100%;
.reader-list-box {
width: 750rpx;
height: 100%;
.segmented-control {
flex-shrink: 0;
}
&>.title {
display: none;
}
.content {
height: 100%;
overflow: hidden;
.reader-list {
flex-direction: column;
overflow: hidden;
.title {
padding: 15px;
background-color: #FFF;
font-size: 20px;
}
.user-list {
flex: 1;
overflow: hidden;
.users {
flex-direction: row;
align-items: center;
padding: 10px;
.nickname {
font-size: 16px;
color: #333;
margin-left: 6px;
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
/* #ifndef APP-NVUE */
white-space: nowrap;
/* #endif */
}
}
}
}
}
}
}
/* #ifdef H5 */
@media screen and (min-device-width:960px) {
.reader-list:last-child {
border-left: 1px solid #eee;
}
.reader-list .user-list {
flex: 1;
}
.reader-list-box .content {
width: auto;
.uni-im-msg-reader-popup {
position: fixed !important;
top: 0;
left: 0;
z-index: 9999;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.3);
display: flex;
justify-content: center;
align-items: center !important;
.reader-list-box {
background-color: #fff;
border-radius: 10px;
overflow: hidden;
/* 显示隐藏的过度动画 */
transition: transform 0.1s,opacity 0.1s;
transform: scale(0.7);
opacity: 0;
width: 600px;
margin-top: 44px;
height: 50%;
flex-direction: column;
&.show {
transform: scale(1);
opacity: 1;
}
&>.title {
display: flex;
font-size: 18px;
font-weight: bold;
color: #333;
padding: 15px;
background-color: #f5f5f5;
}
.content {
flex-direction: row;
padding: 5px 15px;
.reader-list {
flex: 1;
}
}
}
}
}
/* #endif */
.reader-list .users {
flex-direction: row;
align-items: center;
margin-bottom: 10px;
}
.reader-list .users:last-child {
margin-bottom: 0;
}
.reader-list .users .nickname {
font-size: 16px;
color: #333;
margin-left: 6px;
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
/* #ifndef APP-NVUE */
white-space: nowrap;
/* #endif */
}
.popup {
position: fixed;
top: 0;
left: 0;
/* #ifdef APP-NVUE */
width: 750rpx;
bottom: 0;
/* #endif */
/* #ifndef APP-NVUE */
z-index: 9999;
width: 100%;
height: 100%;
/* #endif */
background-color: rgba(0, 0, 0, 0.3);
display: flex;
justify-content: center;
align-items: center;
}
</style>
\ No newline at end of file
import uniIm from '@/uni_modules/uni-im/sdk/index.js'
import UniImMsgReader from '@/uni_modules/uni-im-msg-reader/components/uni-im-msg-reader/uni-im-msg-reader.vue'
function install() {
// 配置在什么情况下启用已读功能
uniIm.extensions.installExt('msg-extra', (msg, currentUser) => {
// 仅限“我”发送的消息
if (msg.from_uid !== uniIm.currentUser._id) return
// 仅限内部用户
if (!uniIm.currentUser.role.includes('staff')) return
// 排除特殊消息
if (msg.type == 'system' || msg.is_revoke) return
// 仅限私聊会话
let conversation = uniIm.conversation.find(msg.conversation_id)
if (!conversation?.friend_uid) return
return {
component: UniImMsgReader,
props: {
msg
}
}
})
// 注册 read_msg 消息类型
uniIm.extensions.installExt('msg-type-register', () => {
return {
......@@ -18,38 +39,39 @@ function install() {
from_uid,
create_time,
} = msgData
const msg = conversation.msgList.find(msg => msg._id === msgId)
// debugger
const msg = conversation.msg.find(msgId)
if (msg) {
let reader = {
user_id: from_uid,
create_time
}
msg.reader_list ? msg.reader_list.push(reader) : msg.reader_list = [reader]
conversation.msgManager.localMsg.update(msg.unique_id, msg)
}
},
}
})
// 监听每条消息的显示状态,报送 read_msg 消息
uniIm.extensions.installExt('msg-appear', (msg, currentUser) => {
uniIm.extensions.installExt('msg-appear', msg => {
const currentUid = uniIm.currentUser._id
// 特殊消息不用处理
if (msg.type === 'system' || msg.is_revoke) return
// 如果是我发送的消息则不处理
if (msg.from_uid == currentUser.user_id) return
if (msg.from_uid == currentUid) return
// 如果我已经在已读列表里则不再处理
if (msg.reader_list?.some(u => u.user_id == currentUser.user_id)) return
if (msg.reader_list?.some(u => u.user_id == currentUid)) return
// 如果是群聊消息且没有 @我,则不用处理
let conversation = uniIm.conversation.getCached(msg.conversation_id)
if (conversation.group_id && !msg.call_uid?.includes(currentUser.user_id)) return
let conversation = uniIm.conversation.find(msg.conversation_id)
if (conversation.group_id && !msg.call_uid?.includes(currentUid)) return
// 把自己记入已读列表
msg.reader_list = msg.reader_list || []
msg.reader_list.push({
user_id: currentUser.user_id,
user_id: currentUid,
create_time: Date.now()
})
......@@ -64,7 +86,7 @@ function install() {
}
}).catch(e => {
// 提交失败,把自己从已读列表里去掉
msg.reader_list = msg.reader_list.filter(u => u.user_id !== currentUser.user_id)
msg.reader_list = msg.reader_list.filter(u => u.user_id !== currentUid)
})
})
}
......
{
"id": "uni-im-msg-reader",
"displayName": "uni-im-msg-reader",
"version": "1.0.0",
"version": "1.0.2",
"description": "uni-im的消息已读未读状态展示插件",
"keywords": [
"uni-im-msg-reader"
],
"repository": "",
"engines": {
"HBuilderX": "^4.14"
"HBuilderX": "^4.29"
},
"dcloudext": {
"type": "component-vue",
......@@ -25,7 +25,7 @@
},
"declaration": {
"ads": "无",
"data": "插件不采集任何数据",
"data": "",
"permissions": "无"
},
"npmurl": ""
......@@ -46,17 +46,17 @@
},
"App": {
"app-vue": "y",
"app-nvue": "y",
"app-nvue": "n",
"app-uvue": "n"
},
"H5-mobile": {
"Safari": "n",
"Android Browser": "n",
"微信浏览器(Android)": "n",
"QQ浏览器(Android)": "n"
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "n",
"Chrome": "y",
"IE": "n",
"Edge": "n",
"Firefox": "n",
......
<template>
<view class="reader-list-page">
<uni-im-msg-reader ref="msg-reader" :msg="msg" :hiddenState="true"></uni-im-msg-reader>
</view>
</template>
<script>
import uniIm from '@/uni_modules/uni-im/sdk/index.js';
export default {
data() {
return {
msg: {}
}
},
onLoad(param) {
// console.log('onload', param);
this.msg = uniIm.conversation.find(param.conversationId).msg.find(param.msgId)
this.$nextTick(() => {
const msgReader = this.$refs['msg-reader']
msgReader.readStateCanShow = false;
msgReader.showReaderList();
if(msgReader.unreadUserList.length === 0){
msgReader.currentIndex = 1
}
});
},
methods: {
}
}
</script>
<style lang="scss">
@import "@/uni_modules/uni-im/common/baseStyle.scss";
page,.reader-list-page {
width: 100%;
height: 100%;
}
</style>
{
"name": "uni-im-ext-msg-reader",
"version": "1.0.0",
"version": "1.0.2",
"description": "",
"main": "index.js",
"keywords": [],
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册