perf: 对话顶部提示

This commit is contained in:
kuaifan 2023-02-19 08:47:14 +08:00
parent 66f0bef271
commit 42e54d8a6e
7 changed files with 102 additions and 53 deletions

View File

@ -1033,8 +1033,9 @@ class DialogController extends AbstractController
*
* @apiParam {Number} dialog_id 会话ID
* @apiParam {String} type 类型
* - read
* - unread
* - read: 已读
* - unread: 未读
* @apiParam {Number} [after_msg_id] 仅标记已读指定之后(含)的消息
*
* @apiSuccess {Number} ret 返回状态码1正确、0错误
* @apiSuccess {String} msg 返回信息(错误描述)
@ -1045,6 +1046,7 @@ class DialogController extends AbstractController
$user = User::auth();
$dialogId = intval(Request::input('dialog_id'));
$type = Request::input('type');
$afterMsgId = intval(Request::input('after_msg_id'));
$dialogUser = WebSocketDialogUser::whereUserid($user->userid)->whereDialogId($dialogId)->first();
if (!$dialogUser) {
return Base::retError("会话不存在");
@ -1054,27 +1056,31 @@ class DialogController extends AbstractController
];
switch ($type) {
case 'read':
$data['mark_unread'] = 0;
$data['unread'] = 0;
$data['first_umid'] = 0;
WebSocketDialogMsgRead::whereUserid($user->userid)
->whereReadAt(null)
->whereDialogId($dialogId)
->chunkById(100, function ($list) {
WebSocketDialogMsgRead::onlyMarkRead($list);
});
$dialogUser->mark_unread = 0;
$dialogUser->save();
$data['mention'] = 0;
$builder = WebSocketDialogMsgRead::whereUserid($user->userid)->whereReadAt(null)->whereDialogId($dialogId);
if ($afterMsgId > 0) {
$unBuilder = $builder->clone()->where('msg_id', '<', $afterMsgId);
$data['unread'] = $unBuilder->count();
$data['mention'] = $data['unread'] > 0 ? $unBuilder->whereMention(1)->count() : 0;
$builder->where('msg_id', '>=', $afterMsgId);
}
$builder->chunkById(100, function ($list) {
WebSocketDialogMsgRead::onlyMarkRead($list);
});
$data['position_msgs'] = WebSocketDialog::find($dialogId)?->getPositionMsgs($user->userid) ?: [];
break;
case 'unread':
$dialogUser->mark_unread = 1;
$dialogUser->save();
$data['mark_unread'] = 1;
break;
default:
return Base::retError("参数错误");
}
$data['mark_unread'] = $dialogUser->mark_unread;
$dialogUser->mark_unread = $data['mark_unread'];
$dialogUser->save();
return Base::retSuccess("success", $data);
}

View File

@ -76,16 +76,16 @@ class WebSocketDialog extends AbstractModel
// 最后消息
$this->last_msg = WebSocketDialogMsg::whereDialogId($this->id)->orderByDesc('id')->first();
// 未读信息
$unreadBuilder = WebSocketDialogMsgRead::whereDialogId($this->id)->whereUserid($userid)->whereReadAt(null);
$this->unread = $unreadBuilder->count();
$unBuilder = WebSocketDialogMsgRead::whereDialogId($this->id)->whereUserid($userid)->whereReadAt(null);
$this->unread = $unBuilder->count();
$this->mention = 0;
$this->last_umid = 0;
$this->first_umid = 0; // 第一条未读消息
$this->position_msgs = [];
if ($this->unread > 0) {
$this->mention = $unreadBuilder->clone()->whereMention(1)->count();
$this->last_umid = intval($unreadBuilder->clone()->orderByDesc('msg_id')->value('msg_id'));
$this->mention = $unBuilder->clone()->whereMention(1)->count();
$this->last_umid = intval($unBuilder->clone()->orderByDesc('msg_id')->value('msg_id'));
if ($hasData === true) {
$this->first_umid = intval($unreadBuilder->clone()->orderBy('msg_id')->value('msg_id'));
$this->position_msgs = $this->getPositionMsgs($userid);
}
}
$this->mark_unread = $this->mark_unread ?? $dialogUserFun('mark_unread');
@ -156,6 +156,34 @@ class WebSocketDialog extends AbstractModel
return $this;
}
/**
* 获取定位消息
* @param $userid
* @return array[]
*/
public function getPositionMsgs($userid)
{
$builder = WebSocketDialogMsgRead::whereDialogId($this->id)->whereUserid($userid)->whereReadAt(null);
$array = [];
// @我的消息
$mention_id = intval($builder->clone()->whereMention(1)->orderByDesc('msg_id')->value('msg_id'));
if ($mention_id > 0) {
$array[] = [
'msg_id' => $mention_id,
'label' => Base::Lang('@我的消息'),
];
}
// 最早一条未读消息
$first_id = intval($builder->clone()->orderBy('msg_id')->value('msg_id'));
if ($first_id > 0) {
$array[] = [
'msg_id' => $first_id,
'label' => 'unread'
];
}
return $array;
}
/**
* 加入聊天室
* @param int|array $userid 加入的会员ID或会员ID组

View File

@ -99,10 +99,11 @@
</div>
<!--顶部提示-->
<div v-if="beforeUnread > 0" class="dialog-top" :class="{'down': tagShow}">
<div class="top-unread" @click="goBeforeUnread">
<Icon v-if="beforeLoad" type="ios-loading" class="icon-loading"></Icon>
<span>{{$L(`未读消息${beforeUnread}`)}}</span>
<div v-if="positionMsg" class="dialog-position" :class="{'down': tagShow}">
<div class="position-label" @click="onPositionMark">
<Icon v-if="positionLoad > 0" type="ios-loading" class="icon-loading"></Icon>
<i v-else class="taskfont">&#xe624;</i>
{{positionMsg.label}}
</div>
</div>
@ -543,7 +544,7 @@ export default {
scrollAction: 0,
scrollTmp: 0,
beforeLoad: false,
positionLoad: 0,
}
},
@ -775,16 +776,24 @@ export default {
return null
},
beforeUnread() {
const {unread, first_umid} = this.dialogData
if (unread > 0
&& first_umid > 0
&& this.allMsgs.length > 0
&& this.allMsgs.findIndex(({id}) => id == first_umid) === -1) {
return unread
positionMsg() {
const {unread, position_msgs} = this.dialogData
if (unread === 0 || this.allMsgs.length === 0 ||position_msgs.length === 0) {
return null
}
return 0
}
const item = position_msgs.sort((a, b) => {
return b.msg_id - a.msg_id
})[0]
if (this.allMsgs.findIndex(({id}) => id == item.msg_id) === -1) {
if (item.label === 'unread') {
return Object.assign(item, {
'label': this.$L(`未读消息${unread}`)
})
}
return item
}
return null
},
},
watch: {
@ -2256,22 +2265,26 @@ export default {
}
},
goBeforeUnread() {
if (this.beforeUnread === 0 || this.beforeLoad) {
onPositionMark() {
if (this.positionLoad > 0) {
return;
}
//
this.beforeLoad = true
const {first_umid} = this.dialogData
this.positionLoad++
const {msg_id} = this.positionMsg;
this.$store.dispatch("dialogMsgMark", {
dialog_id: this.dialogId,
type: 'read'
type: 'read',
after_msg_id: msg_id,
}).then(_ => {
this.onPositionId(first_umid)
this.positionLoad++
this.onPositionId(msg_id).finally(_ => {
this.positionLoad--
})
}).catch(({msg}) => {
$A.modalError(msg)
}).finally(_ => {
this.beforeLoad = false
this.positionLoad--
})
},

View File

@ -1086,26 +1086,29 @@
}
}
.dialog-top {
.dialog-position {
position: absolute;
top: 78px;
left: 0;
top: 100px;
right: 0;
z-index: 1;
display: flex;
align-items: center;
justify-content: center;
.top-unread {
justify-content: flex-end;
.position-label {
display: flex;
align-items: center;
justify-content: center;
padding: 6px 12px;
border-radius: 4px;
box-shadow: 0 2px 8px 0 rgba($primary-text-color, 0.33);
background: #fff;
padding: 5px 10px;
border-radius: 18px 0 0 18px;
color: #ffffff;
background-color: $primary-color;
cursor: pointer;
> i {
margin-right: 4px;
width: 14px;
height: 14px;
font-size: 14px;
line-height: 14px;
}
}
}
@ -1625,10 +1628,9 @@
}
}
}
.dialog-top {
top: 68px;
.dialog-position {
&.down {
top: 98px;
top: 130px;
}
}
.dialog-footer {