diff --git a/app/Http/Controllers/Api/DialogController.php b/app/Http/Controllers/Api/DialogController.php index e61775fd7..bc76c033f 100755 --- a/app/Http/Controllers/Api/DialogController.php +++ b/app/Http/Controllers/Api/DialogController.php @@ -708,7 +708,9 @@ class DialogController extends AbstractController $data[] = [ 'id' => $dialogUser->webSocketDialog->id, 'unread' => $dialogUser->webSocketDialog->unread, + 'unread_one' => $dialogUser->webSocketDialog->unread_one, 'mention' => $dialogUser->webSocketDialog->mention, + 'mention_ids' => $dialogUser->webSocketDialog->mention_ids, 'user_at' => Carbon::parse($dialogUser->updated_at)->toDateTimeString('millisecond'), 'user_ms' => Carbon::parse($dialogUser->updated_at)->valueOf() ]; @@ -751,7 +753,9 @@ class DialogController extends AbstractController return Base::retSuccess('success', [ 'id' => $dialogUser->webSocketDialog->id, 'unread' => $dialogUser->webSocketDialog->unread, + 'unread_one' => $dialogUser->webSocketDialog->unread_one, 'mention' => $dialogUser->webSocketDialog->mention, + 'mention_ids' => $dialogUser->webSocketDialog->mention_ids, 'user_at' => Carbon::parse($dialogUser->updated_at)->toDateTimeString('millisecond'), 'user_ms' => Carbon::parse($dialogUser->updated_at)->valueOf() ]); @@ -1340,6 +1344,7 @@ class DialogController extends AbstractController } switch ($type) { case 'read': + // 标记已读 $builder = WebSocketDialogMsgRead::whereDialogId($dialog_id)->whereUserid($user->userid)->whereReadAt(null); if ($after_msg_id > 0) { $builder->where('msg_id', '>=', $after_msg_id); @@ -1347,32 +1352,28 @@ class DialogController extends AbstractController $builder->chunkById(100, function ($list) { WebSocketDialogMsgRead::onlyMarkRead($list); }); - // - $dialogUser->webSocketDialog->generateUnread($user->userid); - $data = [ - 'id' => $dialogUser->webSocketDialog->id, - 'unread' => $dialogUser->webSocketDialog->unread, - 'mention' => $dialogUser->webSocketDialog->mention, - 'mark_unread' => 0, - ]; break; case 'unread': - $data = [ - 'id' => $dialogUser->webSocketDialog->id, - 'mark_unread' => 1, - ]; + // 标记未读 break; default: return Base::retError("参数错误"); } - $dialogUser->mark_unread = $data['mark_unread']; + $dialogUser->mark_unread = $type == 'unread' ? 1 : 0; $dialogUser->save(); - return Base::retSuccess("success", array_merge($data, [ + $dialogUser->webSocketDialog->generateUnread($user->userid); + return Base::retSuccess("success", [ + 'id' => $dialogUser->webSocketDialog->id, + 'unread' => $dialogUser->webSocketDialog->unread, + 'unread_one' => $dialogUser->webSocketDialog->unread_one, + 'mention' => $dialogUser->webSocketDialog->mention, + 'mention_ids' => $dialogUser->webSocketDialog->mention_ids, 'user_at' => Carbon::parse($dialogUser->updated_at)->toDateTimeString('millisecond'), 'user_ms' => Carbon::parse($dialogUser->updated_at)->valueOf(), - ])); + 'mark_unread' => $dialogUser->mark_unread, + ]); } /** diff --git a/app/Models/WebSocketDialog.php b/app/Models/WebSocketDialog.php index 03cfdb8c2..c3b1f618a 100644 --- a/app/Models/WebSocketDialog.php +++ b/app/Models/WebSocketDialog.php @@ -156,7 +156,7 @@ class WebSocketDialog extends AbstractModel $this->last_at = $this->last_msg?->created_at; } else { // 未读信息 - $this->generateUnread($userid, $hasData); + $this->generateUnread($userid); // 未读标记 $this->mark_unread = $this->mark_unread ?? $dialogUserFun('mark_unread'); // 是否免打扰 @@ -250,37 +250,19 @@ class WebSocketDialog extends AbstractModel /** * 生成未读数据 * @param $userid - * @param $positionData * @return $this */ - public function generateUnread($userid, $positionData = false) + public function generateUnread($userid) { $builder = WebSocketDialogMsgRead::whereDialogId($this->id)->whereUserid($userid)->whereReadAt(null); + // 未读消息 $this->unread = $builder->count(); + // 最早一条未读消息 + $this->unread_one = $this->unread > 0 ? intval($builder->clone()->orderBy('msg_id')->value('msg_id')) : 0; + // @我的消息 $this->mention = $this->unread > 0 ? $builder->clone()->whereMention(1)->count() : 0; - if ($positionData) { - $array = []; - // @我的消息 - if ($this->mention > 0) { - $list = $builder->clone()->whereMention(1)->orderByDesc('msg_id')->take(20)->get(); - foreach ($list as $item) { - $array[] = [ - 'msg_id' => $item->msg_id, - 'label' => Doo::translate('@我的消息'), - ]; - } - } - // 最早一条未读消息 - if ($this->unread > 0 - && $first_id = intval($builder->clone()->orderBy('msg_id')->value('msg_id'))) { - $array[] = [ - 'msg_id' => $first_id, - 'label' => '{UNREAD}' - ]; - } - // - $this->position_msgs = $array; - } + // @我的消息(id集合) + $this->mention_ids = $this->mention > 0 ? $builder->clone()->whereMention(1)->orderByDesc('msg_id')->take(20)->pluck('msg_id')->toArray() : []; return $this; } diff --git a/resources/assets/js/pages/manage.vue b/resources/assets/js/pages/manage.vue index 2a213b96e..7ce7444f8 100644 --- a/resources/assets/js/pages/manage.vue +++ b/resources/assets/js/pages/manage.vue @@ -1002,6 +1002,7 @@ export default { } const notificationFuncB = (title) => { if (this.__notificationId === id) { + this.__notificationId = null if (this.$isEEUiApp) { this.$refs.mobileNotification.open({ userid: userid, diff --git a/resources/assets/js/pages/manage/components/DialogItem.vue b/resources/assets/js/pages/manage/components/DialogItem.vue index e7bd8d313..9af87baf7 100644 --- a/resources/assets/js/pages/manage/components/DialogItem.vue +++ b/resources/assets/js/pages/manage/components/DialogItem.vue @@ -101,7 +101,7 @@ export default { type: Number, default: 0 }, - unreadMsgId: { + unreadOne: { type: Number, default: 0 }, @@ -131,7 +131,7 @@ export default { }, isUnreadStart() { - return this.unreadMsgId === this.source.id + return this.unreadOne === this.source.id }, hidePercentage() { diff --git a/resources/assets/js/pages/manage/components/DialogWrapper.vue b/resources/assets/js/pages/manage/components/DialogWrapper.vue index 1ca82ab0f..0475592f5 100644 --- a/resources/assets/js/pages/manage/components/DialogWrapper.vue +++ b/resources/assets/js/pages/manage/components/DialogWrapper.vue @@ -181,7 +181,7 @@ :data-component="msgItem" :item-class-add="itemClassAdd" - :extra-props="{dialogData, operateVisible, operateItem, isMyDialog, msgId, unreadMsgId, scrollIng, readEnabled}" + :extra-props="{dialogData, operateVisible, operateItem, isMyDialog, msgId, unreadOne, scrollIng, readEnabled}" :estimate-size="dialogData.type=='group' ? 105 : 77" :keeps="keeps" :disabled="scrollDisabled" @@ -765,13 +765,13 @@ export default { observers: [], - unreadMsgId: 0, // 最早未读消息id + unreadOne: 0, // 最早未读消息id topPosLoad: false, // 置顶跳转加载中 positionLoad: 0, // 定位跳转加载中 positionShow: false, // 定位跳转显示 renderMsgNum: 0, // 渲染消息数量 renderMsgSizes: new Map(), // 渲染消息尺寸 - msgPreparedStatus: false, // 消息准备完成 + msgActivityStatus: false, // 消息准备完成 listPreparedStatus: false, // 列表准备完成 selectedTextStatus: false, // 是否选择文本 scrollToBottomAndRefresh: false, // 滚动到底部重新获取消息 @@ -830,7 +830,11 @@ export default { }, dialogData() { - return this.cacheDialogs.find(({id}) => id == this.dialogId) || {}; + const data = this.cacheDialogs.find(({id}) => id == this.dialogId) || {} + if (this.unreadOne === 0) { + this.unreadOne = data.unread_one || 0 + } + return data }, dialogList() { @@ -1082,20 +1086,29 @@ export default { }, positionMsg({msgNew, dialogData, allMsgs}) { - const {mention, unread, position_msgs} = dialogData - if (!position_msgs || position_msgs.length === 0 || (unread - msgNew) <= 0 || allMsgs.length === 0) { + const {unread, unread_one, mention, mention_ids} = dialogData + const not = unread - msgNew + const array = [] + if (unread_one) { + array.push({ + type: 'unread', + label: this.$L(`未读消息${not}条`), + msg_id: unread_one + }) + } + if (mention_ids && mention_ids.length > 0) { + array.push(...mention_ids.map(msg_id => { + return { + type: 'mention', + label: this.$L(`@我的消息`), + msg_id + } + })) + } + if (not <= 0 || array.length === 0 || allMsgs.length === 0) { return null } - const item = $A.cloneJSON(position_msgs.find(item => { - if (mention === 0) { - return item.label === '{UNREAD}' - } - return true - })) - if (item.label === '{UNREAD}') { - item.label = this.$L(`未读消息${unread - msgNew}条`) - } - return item + return array.find(item => item.type === (mention === 0 ? 'unread' : 'mention')) || array[0] }, operateEmojis({cacheEmojis}) { @@ -1115,8 +1128,8 @@ export default { return 1024000 }, - readEnabled({msgPreparedStatus, listPreparedStatus}) { - return msgPreparedStatus && listPreparedStatus + readEnabled({msgActivityStatus, listPreparedStatus}) { + return msgActivityStatus === 0 && listPreparedStatus }, }, @@ -1143,7 +1156,7 @@ export default { if (dialog_id) { this.msgNew = 0 this.msgType = '' - this.unreadMsgId = 0 + this.unreadOne = 0 this.searchShow = false this.positionShow = false this.listPreparedStatus = false @@ -1164,11 +1177,6 @@ export default { this.openId = dialog_id this.listPreparedStatus = true // - const {position_msgs} = this.dialogData - if ($A.isArray(position_msgs)) { - this.unreadMsgId = position_msgs.find(item => item.label === '{UNREAD}')?.msg_id || 0 - } - // const tmpMsgB = this.allMsgList.map(({id, msg, emoji}) => { return {id, msg, emoji} }) @@ -1328,10 +1336,11 @@ export default { const {tail} = this.scrollInfo(); if ($A.isIos() && newList.length !== oldList.length) { // 隐藏区域,让iOS断触 - this.$refs.scroller.$el.style.visibility = 'hidden' + const scrollEl = this.$refs.scroller.$el + scrollEl.style.visibility = 'hidden' this.allMsgs = newList; this.$nextTick(_ => { - this.$refs.scroller.$el.style.visibility = 'visible' + scrollEl.style.visibility = 'visible' }) } else { this.allMsgs = newList; @@ -1339,7 +1348,7 @@ export default { // if (!this.windowActive || (tail > 55 && oldList.length > 0)) { const lastId = oldList[oldList.length - 1] ? oldList[oldList.length - 1].id : 0 - const tmpList = newList.filter(item => item.id && item.id > lastId) + const tmpList = newList.filter(item => item.id && item.id > lastId && !item.read_at) this.msgNew += tmpList.length } else { !this.preventToBottom && this.$nextTick(this.onToBottom) @@ -1741,6 +1750,7 @@ export default { this.todoViewData = {} this.todoViewMid = 0 this.todoViewId = 0 + this.onFooterResize() }, onPosTodo() { @@ -2128,6 +2138,7 @@ export default { setTimeout(_ => { scroller.scrollToOffset(offset) scroller.virtual.handleFront() + // scroller.virtual.handleBehind() }, 10) // 预防出现白屏的情况 } }, @@ -2518,7 +2529,17 @@ export default { }, onActivity(activity) { - this.msgPreparedStatus = !activity + if (this.msgActivityStatus === false) { + if (activity) { + this.msgActivityStatus = 1 + } + return + } + if (activity) { + this.msgActivityStatus++ + } else { + this.msgActivityStatus-- + } }, onScroll(event) { diff --git a/resources/assets/js/store/actions.js b/resources/assets/js/store/actions.js index f1e80b9e4..44ef92294 100644 --- a/resources/assets/js/store/actions.js +++ b/resources/assets/js/store/actions.js @@ -2331,7 +2331,9 @@ export default { const originalTime = original.user_ms || 0 if (nowTime < originalTime) { typeof data.unread !== "undefined" && delete data.unread + typeof data.unread_one !== "undefined" && delete data.unread_one typeof data.mention !== "undefined" && delete data.mention + typeof data.mention_ids !== "undefined" && delete data.mention_ids } state.cacheDialogs.splice(index, 1, Object.assign({}, original, data)); } else { @@ -3059,11 +3061,21 @@ export default { state.readWaitData[data.id] = data.id; // const dialog = state.cacheDialogs.find(({id}) => id == data.dialog_id); - if (dialog && $A.isArray(dialog.position_msgs)) { - const index = dialog.position_msgs.findIndex(({msg_id}) => msg_id == data.id); - if (index > -1) { + if (dialog) { + let mark = false + if (data.id == dialog.unread_one) { + dialog.unread_one = 0 + mark = true + } + if ($A.isArray(dialog.mention_ids)) { + const index = dialog.mention_ids.findIndex(id => id == data.id) + if (index > -1) { + dialog.mention_ids.splice(index, 1) + mark = true + } + } + if (mark) { state.readEndMark[data.dialog_id] = Math.max(data.id, $A.runNum(state.readEndMark[data.dialog_id])) - dialog.position_msgs.splice(index, 1); dispatch("saveDialog", dialog) } } @@ -3120,6 +3132,13 @@ export default { url: 'dialog/msg/mark', data, }).then(result => { + if (typeof data.after_msg_id !== "undefined") { + state.dialogMsgs.some(item => { + if (item.dialog_id == data.dialog_id && item.id >= data.after_msg_id) { + item.read_at = $A.formatDate() + } + }) + } dispatch("saveDialog", result.data) resolve(result) }).catch(e => {