37 changed files with 2153 additions and 1555 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,67 @@ |
|||||
|
<template> |
||||
|
<div class="chat-group-member" :style="{'height':height+'px'}"> |
||||
|
<div class="member-avatar"> |
||||
|
<head-image :size="headImageSize" :name="member.aliasName" :url="member.headImage"> </head-image> |
||||
|
</div> |
||||
|
<div class="member-name" :style="{'line-height':height+'px'}"> |
||||
|
<div>{{ member.aliasName }}</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
import HeadImage from "../common/HeadImage.vue"; |
||||
|
export default { |
||||
|
name: "groupMember", |
||||
|
components: { HeadImage }, |
||||
|
data() { |
||||
|
return {}; |
||||
|
}, |
||||
|
props: { |
||||
|
member: { |
||||
|
type: Object, |
||||
|
required: true |
||||
|
}, |
||||
|
height:{ |
||||
|
type: Number, |
||||
|
default: 50 |
||||
|
} |
||||
|
}, |
||||
|
computed:{ |
||||
|
headImageSize(){ |
||||
|
return Math.ceil(this.height * 0.75) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style lang="scss"> |
||||
|
.chat-group-member { |
||||
|
display: flex; |
||||
|
margin-bottom: 1px; |
||||
|
position: relative; |
||||
|
padding: 0 5px; |
||||
|
align-items: center; |
||||
|
background-color: #fafafa; |
||||
|
white-space: nowrap; |
||||
|
box-sizing: border-box; |
||||
|
|
||||
|
&:hover { |
||||
|
background-color: #eeeeee; |
||||
|
} |
||||
|
|
||||
|
&.active { |
||||
|
background-color: #eeeeee; |
||||
|
} |
||||
|
|
||||
|
.member-name { |
||||
|
padding-left: 10px; |
||||
|
height: 100%; |
||||
|
text-align: left; |
||||
|
white-space: nowrap; |
||||
|
overflow: hidden; |
||||
|
font-size: 14px; |
||||
|
font-weight: 600; |
||||
|
} |
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1,186 @@ |
|||||
|
<template> |
||||
|
<div v-show="show"> |
||||
|
<div class="chat-group-readed-mask" @click.self="close()"> |
||||
|
<div class="chat-group-readed" :style="{ 'left': pos.x + 'px', 'top': pos.y + 'px' }" @click.prevent=""> |
||||
|
<el-tabs type="border-card" :stretch="true"> |
||||
|
<el-tab-pane :label="`已读(${readedMembers.length})`"> |
||||
|
<el-scrollbar class="scroll-box"> |
||||
|
<div v-for="(member) in readedMembers" :key="member.id"> |
||||
|
<chat-group-member :member="member"></chat-group-member> |
||||
|
</div> |
||||
|
</el-scrollbar> |
||||
|
</el-tab-pane> |
||||
|
<el-tab-pane :label="`未读(${unreadMembers.length})`"> |
||||
|
<el-scrollbar class="scroll-box"> |
||||
|
<div v-for="(member) in unreadMembers" :key="member.id"> |
||||
|
<chat-group-member :member="member"></chat-group-member> |
||||
|
</div> |
||||
|
</el-scrollbar> |
||||
|
</el-tab-pane> |
||||
|
</el-tabs> |
||||
|
<div v-show="msgInfo.selfSend" class="arrow-right" :style="{ 'top': pos.arrowY + 'px' }"> |
||||
|
<div class="arrow-right-inner"> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div v-show="!msgInfo.selfSend" class="arrow-left" :style="{ 'top': pos.arrowY + 'px' }"> |
||||
|
<div class="arrow-left-inner"> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
|
||||
|
<script> |
||||
|
import ChatGroupMember from "./ChatGroupMember.vue"; |
||||
|
|
||||
|
export default { |
||||
|
name: "chatGroupReaded", |
||||
|
components: { |
||||
|
ChatGroupMember |
||||
|
}, |
||||
|
data() { |
||||
|
return { |
||||
|
show: false, |
||||
|
pos: { |
||||
|
x: 0, |
||||
|
y: 0, |
||||
|
arrowY: 0 |
||||
|
}, |
||||
|
msgInfo: {}, |
||||
|
readedMembers: [], |
||||
|
unreadMembers: [] |
||||
|
} |
||||
|
}, |
||||
|
props: { |
||||
|
groupMembers: { |
||||
|
type: Array |
||||
|
} |
||||
|
}, |
||||
|
methods: { |
||||
|
close() { |
||||
|
this.show = false; |
||||
|
}, |
||||
|
open(msgInfo, rect) { |
||||
|
this.show = true; |
||||
|
this.msgInfo = msgInfo; |
||||
|
this.pos.arrowY = 200; |
||||
|
// 计算窗口位置 |
||||
|
if (this.msgInfo.selfSend) { |
||||
|
// 自己发的消息弹出在消息的左边 |
||||
|
this.pos.x = rect.left - 310; |
||||
|
} else { |
||||
|
// 别人发的消息弹窗在消息右边 |
||||
|
this.pos.x = rect.right + 20; |
||||
|
} |
||||
|
this.pos.y = rect.top + rect.height / 2 - 215; |
||||
|
// 防止窗口溢出 |
||||
|
if (this.pos.y < 0) { |
||||
|
this.pos.arrowY += this.pos.y |
||||
|
this.pos.y = 0; |
||||
|
} |
||||
|
this.loadReadedUser() |
||||
|
}, |
||||
|
loadReadedUser() { |
||||
|
this.readedMembers = []; |
||||
|
this.unreadMembers = []; |
||||
|
this.$http({ |
||||
|
url: "/message/group/findReadedUsers", |
||||
|
method: 'get', |
||||
|
params: { groupId: this.msgInfo.groupId, messageId: this.msgInfo.id } |
||||
|
}).then(userIds => { |
||||
|
this.groupMembers.forEach(member => { |
||||
|
// 发送者和已退群的不显示 |
||||
|
if (member.userId == this.msgInfo.sendId && member.quit) { |
||||
|
return; |
||||
|
} |
||||
|
// 区分已读还是未读 |
||||
|
if (userIds.find(userId => member.userId == userId)) { |
||||
|
this.readedMembers.push(member); |
||||
|
} else { |
||||
|
this.unreadMembers.push(member); |
||||
|
} |
||||
|
}) |
||||
|
// 更新已读人数 |
||||
|
this.$store.commit("updateMessage", { |
||||
|
id: this.msgInfo.id, |
||||
|
groupId: this.msgInfo.groupId, |
||||
|
readedCount: this.readedMembers.length |
||||
|
}) |
||||
|
}) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style lang="scss"> |
||||
|
.chat-group-readed-mask { |
||||
|
position: fixed; |
||||
|
left: 0; |
||||
|
top: 0; |
||||
|
right: 0; |
||||
|
bottom: 0; |
||||
|
width: 100%; |
||||
|
height: 100%; |
||||
|
z-index: 9999; |
||||
|
} |
||||
|
|
||||
|
.chat-group-readed { |
||||
|
position: fixed; |
||||
|
box-shadow: 0px 0px 10px #ccc; |
||||
|
width: 300px; |
||||
|
background-color: #fafafa; |
||||
|
border-radius: 8px; |
||||
|
|
||||
|
.scroll-box { |
||||
|
height: 400px; |
||||
|
} |
||||
|
|
||||
|
.arrow-left { |
||||
|
|
||||
|
position: absolute; |
||||
|
left: -15px; |
||||
|
width: 0; |
||||
|
height: 0; |
||||
|
border-top: 15px solid transparent; |
||||
|
border-bottom: 15px solid transparent; |
||||
|
border-right: 15px solid #ccc; |
||||
|
|
||||
|
.arrow-left-inner { |
||||
|
position: absolute; |
||||
|
top: -12px; |
||||
|
left: 3px; |
||||
|
width: 0; |
||||
|
height: 0; |
||||
|
overflow: hidden; |
||||
|
border-top: 12px solid transparent; |
||||
|
border-bottom: 12px solid transparent; |
||||
|
border-right: 12px solid white; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.arrow-right { |
||||
|
position: absolute; |
||||
|
right: -15px; |
||||
|
width: 0; |
||||
|
height: 0; |
||||
|
border-top: 15px solid transparent; |
||||
|
border-bottom: 15px solid transparent; |
||||
|
border-left: 15px solid #ccc; |
||||
|
|
||||
|
.arrow-right-inner { |
||||
|
position: absolute; |
||||
|
top: -12px; |
||||
|
right: 3px; |
||||
|
width: 0; |
||||
|
height: 0; |
||||
|
overflow: hidden; |
||||
|
border-top: 12px solid transparent; |
||||
|
border-bottom: 12px solid transparent; |
||||
|
border-left: 12px solid white; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1,131 @@ |
|||||
|
<template> |
||||
|
<uni-popup ref="popup" type="bottom"> |
||||
|
<view class="chat-group-readed"> |
||||
|
<view class="uni-padding-wrap uni-common-mt"> |
||||
|
<uni-segmented-control :current="current" :values="items" style-type="button" active-color="#587ff0" @clickItem="onClickItem"/> |
||||
|
</view> |
||||
|
<view class="content"> |
||||
|
<view v-if="current === 0"> |
||||
|
<scroll-view class="scroll-bar" scroll-with-animation="true" scroll-y="true"> |
||||
|
<view v-for="m in readedMembers" :key="m.userId"> |
||||
|
<view class="member-item"> |
||||
|
<head-image :name="m.aliasName" :online="m.online" :url="m.headImage" |
||||
|
:size="90"></head-image> |
||||
|
<view class="member-name">{{ m.aliasName}}</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
</scroll-view> |
||||
|
</view> |
||||
|
<view v-if="current === 1"> |
||||
|
<scroll-view class="scroll-bar" scroll-with-animation="true" scroll-y="true"> |
||||
|
<view v-for="m in unreadMembers" :key="m.userId"> |
||||
|
<view class="member-item"> |
||||
|
<head-image :name="m.aliasName" :online="m.online" :url="m.headImage" |
||||
|
:size="90"></head-image> |
||||
|
<view class="member-name">{{ m.aliasName}}</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
</scroll-view> |
||||
|
</view> |
||||
|
</view> |
||||
|
</view> |
||||
|
</uni-popup> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
export default { |
||||
|
name: "chat-group-readed", |
||||
|
data() { |
||||
|
return { |
||||
|
items: ['已读', '未读'], |
||||
|
current: 0, |
||||
|
readedMembers: [], |
||||
|
unreadMembers: [] |
||||
|
}; |
||||
|
}, |
||||
|
props: { |
||||
|
msgInfo: { |
||||
|
type: Object, |
||||
|
required: true |
||||
|
}, |
||||
|
groupMembers: { |
||||
|
type: Array |
||||
|
} |
||||
|
}, |
||||
|
methods: { |
||||
|
open() { |
||||
|
this.$refs.popup.open(); |
||||
|
this.loadReadedUser(); |
||||
|
}, |
||||
|
loadReadedUser() { |
||||
|
this.readedMembers = []; |
||||
|
this.unreadMembers = []; |
||||
|
this.$http({ |
||||
|
url: `/message/group/findReadedUsers?groupId=${this.msgInfo.groupId}&messageId=${this.msgInfo.id}`, |
||||
|
method: 'Get' |
||||
|
}).then(userIds => { |
||||
|
this.groupMembers.forEach(member => { |
||||
|
// 发送者和已退群的不显示 |
||||
|
if (member.userId == this.msgInfo.sendId && member.quit) { |
||||
|
return; |
||||
|
} |
||||
|
// 区分已读还是未读 |
||||
|
if (userIds.find(userId => member.userId == userId)) { |
||||
|
this.readedMembers.push(member); |
||||
|
} else { |
||||
|
this.unreadMembers.push(member); |
||||
|
} |
||||
|
}) |
||||
|
this.items[0] = `已读(${this.readedMembers.length})`; |
||||
|
this.items[1] = `未读(${this.unreadMembers.length})`; |
||||
|
// 更新已读人数 |
||||
|
this.$store.commit("updateMessage", { |
||||
|
id: this.msgInfo.id, |
||||
|
groupId: this.msgInfo.groupId, |
||||
|
readedCount: this.readedMembers.length |
||||
|
}) |
||||
|
}) |
||||
|
}, |
||||
|
onClickItem(e){ |
||||
|
this.current = e.currentIndex; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style lang="scss" scoped> |
||||
|
.chat-group-readed { |
||||
|
position: relative; |
||||
|
border: #dddddd solid 1rpx; |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
background-color: white; |
||||
|
padding: 10rpx; |
||||
|
border-radius: 15rpx; |
||||
|
.scroll-bar { |
||||
|
height: 800rpx; |
||||
|
} |
||||
|
|
||||
|
.member-item { |
||||
|
height: 120rpx; |
||||
|
display: flex; |
||||
|
position: relative; |
||||
|
padding: 0 30rpx; |
||||
|
align-items: center; |
||||
|
background-color: white; |
||||
|
white-space: nowrap; |
||||
|
|
||||
|
.member-name { |
||||
|
flex: 1; |
||||
|
padding-left: 20rpx; |
||||
|
font-size: 30rpx; |
||||
|
font-weight: 600; |
||||
|
line-height: 60rpx; |
||||
|
white-space: nowrap; |
||||
|
overflow: hidden; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
} |
||||
|
</style> |
||||
Binary file not shown.
Loading…
Reference in new issue