完成第一版已读未读功能

This commit is contained in:
wangyifeng 2025-04-18 17:17:13 +08:00
parent 29dcfac775
commit 3898c637b4
3 changed files with 288 additions and 45 deletions

View File

@ -221,3 +221,12 @@ export const ServeReadConditionList = (data) => {
data,
})
}
// 获取消息已读未读详情
export const ServeMessageReadDetail = (data) => {
return request({
url: '/api/v1/talk/my-records/read/condition',
method: 'POST',
data,
})
}

View File

@ -215,6 +215,17 @@
</div> -->
</div>
<div
class="talk-tools have_read_num"
v-if="item.user_id === talkParams.uid"
@click="toShowMessageReadDetail(item)"
>
<span v-if="talkParams.type === 1">未读</span>
<span v-if="talkParams.type === 2">
已读 (0/{{ talkParams.num }})
</span>
</div>
<div
v-if="item.extra.reply"
class="talk-reply pointer"
@ -530,6 +541,101 @@
@getMentionSelectLists="getMentionSelectLists"
></selectMemberByAlphabet>
</tm-drawer>
<tm-drawer
placement="bottom"
v-model:show="state.isShowMessageReadDetail"
:hideHeader="true"
:round="5"
:height="state.mentionSelectHeight"
>
<div
class="mention-select-drawer flex flex-row flex-1 flex-row flex-row-center-between"
>
<div
class="cancel-btns flex-row flex flex-row-center-start"
style="width: 210rpx;"
@click="hideMessageReadDetail"
>
<span
style="flex-shrink: 0; display: block;"
class="text-[32rpx] font-regular text-[#191919]"
>
{{ $t('cancel') }}
</span>
</div>
<div
class="flex flex-row-center-center flex-col"
style="padding: 6rpx 0;"
>
<text>{{ $t('chat.msgRead.list') }}</text>
</div>
<div
class="flex-row flex flex-row-center-end"
style="width: 210rpx;"
></div>
</div>
<div class="msg-read-detail-tabs">
<tm-sheet>
<tm-tabs
:list="state.msgReadDetailTabs"
showTabsLineAni
activeFontColor="#7A58DE"
tabsLineAniColor="#7A58DE"
:item-width="375"
:width="750"
@change="msgReadDetailTabsChange"
:default-name="state.msgReadDetailTabs[0].key"
></tm-tabs>
<div class="msg-read-detail">
<ZPaging
ref="zPaging"
:show-scrollbar="false"
:fixed="false"
:height="state.readDetailHeight"
:safe-area-inset-bottom="true"
:inside-more="true"
:hide-no-more-inside="true"
@scrolltolower="loadMoreReadDetails"
>
<div
class="msg-read-detail-each"
v-for="(item, index) in state.msgReadOrNotDetail"
:key="index"
>
<div class="msg-read-detail-each-avatar">
<avatarModule
:mode="2"
:groupType="item?.group_type"
:avatar="item?.avatar"
:userName="item?.nickName"
:customStyle="{ width: '72rpx', height: '72rpx' }"
:customTextStyle="{
fontSize: '24rpx',
fontWeight: 'bold',
color: '#fff',
lineHeight: '34rpx',
}"
></avatarModule>
</div>
<div class="msg-read-detail-each-info">
<span>{{ item.nickName }}</span>
<span
style="
font-size: 20rpx;
color: #747474;
font-weight: 400;
line-height: 28rpx;
"
>
{{ item.jobNum }}
</span>
</div>
</div>
</ZPaging>
</div>
</tm-sheet>
</div>
</tm-drawer>
</div>
</template>
<script setup>
@ -579,6 +685,7 @@ import {
ServeClearTalkUnreadNum,
ServeTalkRecords,
ServeReadConditionList,
ServeMessageReadDetail,
} from '@/api/chat'
import copy07 from '@/static/image/chatList/copy07@2x.png'
import multipleChoices from '@/static/image/chatList/multipleChoices@2x.png'
@ -676,6 +783,24 @@ const state = ref({
visibleOutElements: new Set(), //
setOutMessageReadInterval: null, //
tempWaitDoCheck: [], //
isShowMessageReadDetail: false, //
msgReadDetailTabs: [
{
key: '1',
title: '未读',
},
{
key: '0',
title: '已读',
},
],
msgReadOrNotDetail: [], //
currentMsgReadOrNotDetail: null, //
readNumPage: 1, //
hasMoreReadDetail: true, //
currentIsUnread: 1, //
readDetailHeight: 400, //
isFirstEnter: true, //
})
// Map
@ -685,28 +810,27 @@ const recordReadsMap = ref(new Map())
watch(
recordReadsMap,
(newMap) => {
console.error(newMap, 'newMap')
requestAnimationFrame(() => {
console.error('requestAnimationFrame')
newMap.forEach((readNum, msgId) => {
console.error(readNum, 'readNum')
console.error(msgId, 'msgId')
const element = document.getElementById(`zp-id-${msgId}`)
if (element) {
console.error(element, 'element')
element.dataset.readNum = readNum
// const readNumElement = element.querySelector('.read-num')
// if (readNumElement) {
// console.error(readNumElement, 'readNumElement')
// readNumElement.textContent = readNum
// }
const readNumElement = element.querySelector('.have_read_num')
if (readNumElement) {
if (talkParams.type === 1) {
readNumElement.textContent = readNum > 0 ? '已读' : '未读'
} else {
readNumElement.textContent =
'已读 (' + readNum + '/' + talkParams.num + ')'
}
}
}
})
})
},
{
deep: true
}
deep: true,
},
)
uniOnload(async (options) => {
@ -1447,7 +1571,6 @@ watch(
},
)
const onScrollToLower = async () => {
if (state.value.useCustomLoadMore) {
const tempVirtualList = lodash.cloneDeep(virtualList.value).reverse()
@ -1935,6 +2058,9 @@ onMounted(async () => {
state.value.selectAreaHeight =
rpxToPx(state.value.mentionSelectHeight) - rpxToPx(90) + 'px'
state.value.readDetailHeight =
rpxToPx(state.value.mentionSelectHeight) - rpxToPx(300) + 'px'
})
//
@ -2088,36 +2214,40 @@ const checkVisibleOutElements = () => {
// !prevItem ||
// !doCheckItem.msg_ids.every((id) => prevItem.msg_ids.includes(id))
// ) {
console.error('====调用了已读回执查询接口=====', doCheckItem)
let params = Object.assign({}, doCheckItem, {
talkType: doCheckItem.talk_type, //12
receiverId: doCheckItem.talk_type === 1 ? talkParams.uid : talkParams.receiver_id, //idid
msgIds: doCheckItem.msg_ids,
type: 'list', //listdetail
})
console.error('====调用了已读回执查询接口=====', doCheckItem)
let params = Object.assign({}, doCheckItem, {
talkType: doCheckItem.talk_type, //12
receiverId:
doCheckItem.talk_type === 1
? talkParams.uid
: talkParams.receiver_id, //idid
msgIds: doCheckItem.msg_ids,
type: 'list', //listdetail
})
const resp = ServeReadConditionList(params)
// console.log(resp)
resp.then(({ code, data }) => {
const resp = ServeReadConditionList(params)
// console.log(resp)
resp
.then(({ code, data }) => {
// console.log(data)
if (code == 200) {
//
if (Array.isArray(data.data)) {
console.error('处理批量更新', data.data)
data.data.forEach(item => {
data.data.forEach((item) => {
if (item.msgId && item.readNum !== undefined) {
console.error('修改recordReadsMap', item)
recordReadsMap.value.set(item.msgId, item.readNum)
}
})
} else if (data.data && data.data.readNum !== undefined) {
console.error('处理单个更新', data.data)
doCheckItem.msg_ids.forEach(msgId => {
doCheckItem.msg_ids.forEach((msgId) => {
recordReadsMap.value.set(msgId, data.data.readNum)
})
}
}
}).catch(() => {})
})
.catch(() => {})
// }
})
}
@ -2160,6 +2290,12 @@ const handleIntersection = (entries) => {
state.value.visibleOutElements.delete(entry.target)
}
})
if (state.value.isFirstEnter) {
state.value.isFirstEnter = false
//
// checkVisibleElements()
// checkVisibleOutElements()
}
}
const pxTorPx = (px) => {
@ -2265,6 +2401,82 @@ const onTextAreaMention = (user) => {
state.value.isShowMentionSelect = false
}
}
//
const hideMessageReadDetail = () => {
state.value.isShowMessageReadDetail = false
}
//
const toShowMessageReadDetail = (item) => {
console.log(item)
if (talkParams.type === 1) {
return
}
state.value.isShowMessageReadDetail = true
state.value.currentMsgReadOrNotDetail = item
getMessageReadDetail(1)
}
///
const msgReadDetailTabsChange = (e) => {
// console.log(e)
if (Number(e) !== Number(state.value.currentIsUnread)) {
state.value.readNumPage = 1
}
state.value.currentIsUnread = Number(e)
getMessageReadDetail(e)
}
//
const getMessageReadDetail = (isUnread) => {
let params = {
page: state.value.readNumPage,
pageSize: 10,
type: 'detail', //listdetail
talkType: state.value.currentMsgReadOrNotDetail.talk_type, //12
receiverId: state.value.currentMsgReadOrNotDetail.receiver_id, //idid
msgId: state.value.currentMsgReadOrNotDetail.msg_id,
isUnread: Number(isUnread), //01
}
const resp = ServeMessageReadDetail(params)
// console.log(resp)
resp
.then(({ code, data }) => {
console.log(data)
if (code == 200) {
if (Number(isUnread) === 0) {
state.value.msgReadDetailTabs[0].title =
'未读 ' + (talkParams.num - data.count) + ''
state.value.msgReadDetailTabs[1].title = '已读 ' + data.count + ''
} else if (Number(isUnread) === 1) {
state.value.msgReadDetailTabs[0].title = '未读 ' + data.count + ''
state.value.msgReadDetailTabs[1].title =
'已读 ' + (talkParams.num - data.count) + ''
}
if (state.value.readNumPage === 1) {
state.value.msgReadOrNotDetail = data.data
} else {
state.value.msgReadOrNotDetail = [
...state.value.msgReadOrNotDetail,
...data.data,
]
}
if (!data?.data || data?.data?.length < 10) {
state.value.hasMoreReadDetail = false
} else {
state.value.hasMoreReadDetail = true
}
}
})
.catch(() => {})
}
//
const loadMoreReadDetails = () => {
if (!state.value.hasMoreReadDetail) {
return
}
state.value.readNumPage += 1
getMessageReadDetail(state.value.currentIsUnread)
}
</script>
<style scoped lang="less">
.dialog-page {
@ -2454,6 +2666,15 @@ const onTextAreaMention = (user) => {
}
}
.have_read_num {
text-align: right;
color: #7a58de;
font-size: 22rpx;
font-weight: 400;
line-height: 34rpx;
margin: 5rpx 0 0;
}
.talk-reply {
display: flex;
align-items: flex-start;
@ -2661,25 +2882,37 @@ const onTextAreaMention = (user) => {
color: #1890ff;
}
//
[data-msgid] {
position: relative;
&::after {
content: attr(data-read-num);
position: absolute;
right: 10px;
bottom: 5px;
font-size: 12px;
color: #999;
background: rgba(0, 0, 0, 0.1);
padding: 2px 6px;
border-radius: 10px;
display: none;
.msg-read-detail-tabs {
padding: 32rpx 0 0;
:deep(.noNvueBorder) {
padding: 0 !important;
margin: 0 !important;
}
&[data-read-num]:not([data-read-num=""])::after {
display: block;
.msg-read-detail {
padding: 28rpx 32rpx;
.msg-read-detail-each {
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-start;
padding: 20rpx 32rpx;
border-bottom: 1rpx solid #f8f8f8;
.msg-read-detail-each-avatar {
margin: 0 20rpx 0 0;
}
.msg-read-detail-each-info {
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: center;
span {
font-size: 28rpx;
color: #191919;
font-weight: 500;
line-height: 40rpx;
}
}
}
}
}
</style>

View File

@ -156,6 +156,7 @@
"popup.title.phone": "电话",
"pageTitle.view.deps": "查看部门",
"group.dismiss.confirm": "确定解散本群",
"chat.msgRead.list": "消息接收人列表",
"chat.settings.report": "投诉",
"complaint": {
"title": "投诉举报",