From 66b7a00b5cc742c8d497d1f91b256d1138c4542b Mon Sep 17 00:00:00 2001 From: kuaifan Date: Tue, 28 Jun 2022 10:01:09 +0800 Subject: [PATCH] =?UTF-8?q?perf:=20=E6=94=AF=E6=8C=81=E6=9F=A5=E7=9C=8B?= =?UTF-8?q?=E5=9B=9E=E5=A4=8D=E5=88=97=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Http/Controllers/Api/DialogController.php | 21 +++- .../manage/components/ChatInput/index.vue | 2 +- .../js/pages/manage/components/DialogItem.vue | 21 +++- .../js/pages/manage/components/DialogView.vue | 14 ++- .../pages/manage/components/DialogWrapper.vue | 98 +++++++++++++++---- resources/assets/js/store/actions.js | 7 +- .../sass/pages/components/chat-input.scss | 1 - .../sass/pages/components/dialog-wrapper.scss | 23 +++++ 8 files changed, 156 insertions(+), 31 deletions(-) diff --git a/app/Http/Controllers/Api/DialogController.php b/app/Http/Controllers/Api/DialogController.php index 13816ddd8..ab61ef9e2 100755 --- a/app/Http/Controllers/Api/DialogController.php +++ b/app/Http/Controllers/Api/DialogController.php @@ -279,9 +279,11 @@ class DialogController extends AbstractController * @apiName msg__list * * @apiParam {Number} dialog_id 对话ID - * @apiParam {Number} [position_id] 此消息ID前后的数据,优先级1 - * @apiParam {Number} [prev_id] 此消息ID之前的数据,优先级2 - * @apiParam {Number} [next_id] 此消息ID之后的数据,优先级3 + * @apiParam {Number} msg_id 消息ID + * @apiParam {Number} [position_id] 此消息ID前后的数据 + * @apiParam {Number} [prev_id] 此消息ID之前的数据 + * @apiParam {Number} [next_id] 此消息ID之后的数据 + * - position_id、prev_id、next_id 只有一个有效,优先循序为:position_id > prev_id > next_id * * @apiParam {Number} [take] 获取条数,默认:50,最大:100 * @@ -295,6 +297,7 @@ class DialogController extends AbstractController $user = User::auth(); // $dialog_id = intval(Request::input('dialog_id')); + $msg_id = intval(Request::input('msg_id')); $position_id = intval(Request::input('position_id')); $prev_id = intval(Request::input('prev_id')); $next_id = intval(Request::input('next_id')); @@ -302,6 +305,7 @@ class DialogController extends AbstractController $data = []; // $dialog = WebSocketDialog::checkDialog($dialog_id); + $reDialog = true; // $builder = WebSocketDialogMsg::select([ 'web_socket_dialog_msgs.*', @@ -313,6 +317,11 @@ class DialogController extends AbstractController ->on('read.msg_id', '=', 'web_socket_dialog_msgs.id'); })->where('web_socket_dialog_msgs.dialog_id', $dialog_id); // + if ($msg_id > 0) { + $builder->whereReplyId($msg_id); + $reDialog = false; + } + // if ($position_id > 0) { $array = $builder->clone() ->where('web_socket_dialog_msgs.id', '>=', $position_id) @@ -325,11 +334,12 @@ class DialogController extends AbstractController $cloner = $builder->clone(); if ($prev_id > 0) { $cloner->where('web_socket_dialog_msgs.id', '<=', $prev_id)->orderByDesc('web_socket_dialog_msgs.id'); + $reDialog = false; } elseif ($next_id > 0) { $cloner->where('web_socket_dialog_msgs.id', '>=', $next_id)->orderBy('web_socket_dialog_msgs.id'); + $reDialog = false; } else { $cloner->orderByDesc('web_socket_dialog_msgs.id'); - $data['dialog'] = $dialog->formatData($user->userid); } $list = $cloner->take($take)->get()->sortByDesc('id', SORT_NUMERIC)->values(); // @@ -358,6 +368,9 @@ class DialogController extends AbstractController $isMarkDialogUser->save(); } // + if ($reDialog) { + $data['dialog'] = $dialog->formatData($user->userid); + } return Base::retSuccess('success', $data); } diff --git a/resources/assets/js/pages/manage/components/ChatInput/index.vue b/resources/assets/js/pages/manage/components/ChatInput/index.vue index a7491d478..eadec668f 100755 --- a/resources/assets/js/pages/manage/components/ChatInput/index.vue +++ b/resources/assets/js/pages/manage/components/ChatInput/index.vue @@ -75,7 +75,7 @@
  • - +
    diff --git a/resources/assets/js/pages/manage/components/DialogItem.vue b/resources/assets/js/pages/manage/components/DialogItem.vue index 8306c6aa9..9c45d0bad 100644 --- a/resources/assets/js/pages/manage/components/DialogItem.vue +++ b/resources/assets/js/pages/manage/components/DialogItem.vue @@ -7,12 +7,14 @@ :msg-data="source" :dialog-type="dialogData.type" :hide-percentage="hidePercentage" + :hide-reply="hideReply" :operate-visible="operateVisible" :operate-action="operateVisible && source.id === operateItem.id" @on-longpress="onLongpress" @on-view-reply="onViewReply" @on-view-text="onViewText" @on-view-file="onViewFile" + @on-reply-list="onReplyList" @on-emoji="onEmoji"/>
    @@ -41,6 +43,14 @@ export default { type: Boolean, default: false }, + hideReply: { + type: Boolean, + default: false + }, + isReply: { + type: Boolean, // 是否回复对象 + default: false + }, operateVisible: { type: Boolean, default: false @@ -65,7 +75,7 @@ export default { classArray() { return { 'dialog-item': true, - 'self': this.source.userid == this.userId, + 'self': !this.isReply && this.source.userid == this.userId, } } }, @@ -87,11 +97,20 @@ export default { this.dispatch("on-view-file", data) }, + onReplyList(data) { + this.dispatch("on-reply-list", data) + }, + onEmoji(data) { this.dispatch("on-emoji", data) }, dispatch(event, arg) { + if (this.isReply) { + this.$emit(event, arg) + return + } + let parent = this.$parent let name = parent.$options.name diff --git a/resources/assets/js/pages/manage/components/DialogView.vue b/resources/assets/js/pages/manage/components/DialogView.vue index 8346e3d76..c6151ae3a 100644 --- a/resources/assets/js/pages/manage/components/DialogView.vue +++ b/resources/assets/js/pages/manage/components/DialogView.vue @@ -10,7 +10,7 @@ :class="headClass" v-longpress="{callback: handleLongpress, delay: 300}"> -
    +
    {{formatMsgDesc(msgData.reply_data)}}
    @@ -83,7 +83,7 @@
    -
    +
    {{msgData.reply_num}}条回复
    @@ -154,6 +154,10 @@ export default { type: Boolean, default: false }, + hideReply: { + type: Boolean, + default: false + }, operateVisible: { type: Boolean, default: false @@ -393,6 +397,12 @@ export default { this.$emit("on-view-file", this.msgData) }, + replyList() { + this.$emit("on-reply-list", { + msg_id: this.msgData.id, + }) + }, + onEmoji(symbol) { this.$emit("on-emoji", { msg_id: this.msgData.id, diff --git a/resources/assets/js/pages/manage/components/DialogWrapper.vue b/resources/assets/js/pages/manage/components/DialogWrapper.vue index 30657e7da..77667f119 100644 --- a/resources/assets/js/pages/manage/components/DialogWrapper.vue +++ b/resources/assets/js/pages/manage/components/DialogWrapper.vue @@ -76,7 +76,7 @@ :data-component="msgItem" :item-class-add="itemClassAdd" - :extra-props="{dialogData, operateVisible, operateItem, hidePercentage: isMyDialog}" + :extra-props="{dialogData, operateVisible, operateItem, hidePercentage: isMyDialog, hideReply: msgId > 0}" :estimate-size="78" :keeps="70" @scroll="onScroll" @@ -87,6 +87,7 @@ @on-view-reply="onViewReply" @on-view-text="onViewText" @on-view-file="onViewFile" + @on-reply-list="onReplyList" @on-emoji="onEmoji"> @@ -271,6 +295,7 @@ import {textImagesInfo} from "../../../functions/utils"; export default { name: "DialogWrapper", components: { + DialogItem, VirtualList, ChatInput, DialogGroupInfo, @@ -284,6 +309,10 @@ export default { type: Number, default: 0 }, + msgId: { + type: Number, + default: 0 + }, autoFocus: { type: Boolean, default: false @@ -333,9 +362,12 @@ export default { preventMoreLoad: false, preventToBottom: false, - replyId: 0, + replyActiveId: 0, replyActiveIndex: -1, + replyListShow: false, + replyListId: 0, + scrollDirection: null, scrollAction: 0, scrollTmp: 0, @@ -372,8 +404,11 @@ export default { if (!this.isReady) { return []; } - return this.dialogMsgs.filter(({dialog_id}) => { - return dialog_id == this.dialogId; + return this.dialogMsgs.filter(item => { + if (this.msgId) { + return item.reply_id == this.msgId; + } + return item.dialog_id == this.dialogId; }).sort((a, b) => { return a.id - b.id; }); @@ -383,8 +418,11 @@ export default { if (!this.isReady) { return []; } - return this.tempMsgs.filter(({dialog_id}) => { - return dialog_id == this.dialogId; + return this.tempMsgs.filter(item => { + if (this.msgId) { + return item.reply_id == this.msgId; + } + return item.dialog_id == this.dialogId; }); }, @@ -400,7 +438,7 @@ export default { }, loadMsg() { - return this.isLoad(`msg::${this.dialogId}-0`) + return this.isLoad(`msg::${this.dialogId}-${this.msgId}`) }, prevId() { @@ -467,6 +505,18 @@ export default { isMyDialog() { const {dialogData, userId} = this; return dialogData.dialog_user && dialogData.dialog_user.userid == userId + }, + + replyId() { + return parseInt(this.msgId > 0 ? this.msgId : this.replyActiveId) + }, + + replyItem() { + return this.replyId ? this.dialogMsgs.find(({id}) => id === this.replyId) : null + }, + + replyListItem() { + return this.replyListId ? this.dialogMsgs.find(item => item.id == this.replyListId) : null } }, @@ -480,7 +530,10 @@ export default { this.allMsgs = this.allMsgList; requestAnimationFrame(this.onToBottom); } - this.$store.dispatch("getDialogMsgs", {dialog_id}).then(_ => { + this.$store.dispatch("getDialogMsgs", { + dialog_id, + msg_id: this.msgId + }).then(_ => { this.openId = dialog_id; setTimeout(this.onSearchMsgId, 100) }).catch(_ => {}); @@ -523,7 +576,8 @@ export default { wsOpenNum(num) { if (num <= 1) return this.$store.dispatch("getDialogMsgs", { - dialog_id: this.dialogId + dialog_id: this.dialogId, + msg_id: this.msgId, }).catch(_ => {}); }, @@ -594,7 +648,7 @@ export default { id: tempId, dialog_id: this.dialogData.id, reply_id: this.replyId, - reply_data: this.replyId ? this.dialogMsgs.find(({id}) => id === this.replyId) : null, + reply_data: this.replyItem, type: 'text', userid: this.userId, msg: { @@ -612,7 +666,6 @@ export default { data: { dialog_id: this.dialogId, reply_id: this.replyId, - reply_data: this.replyId ? this.dialogMsgs.find(({id}) => id === this.replyId) : null, text: msgText, }, method: 'post' @@ -638,7 +691,7 @@ export default { id: tempId, dialog_id: this.dialogData.id, reply_id: this.replyId, - reply_data: this.replyId ? this.dialogMsgs.find(({id}) => id === this.replyId) : null, + reply_data: this.replyItem, type: 'loading', userid: this.userId, msg, @@ -718,6 +771,7 @@ export default { this.preventToBottom = true; this.$store.dispatch("getDialogMsgs", { dialog_id: this.dialogId, + msg_id: this.msgId, position_id }).finally(_ => { const index = this.allMsgs.findIndex(item => item.id === position_id) @@ -949,6 +1003,7 @@ export default { } this.$store.dispatch('getDialogMsgs', { dialog_id: this.dialogId, + msg_id: this.msgId, prev_id: this.prevId }).then(({data}) => { const ids = data.list.map(item => item.id) @@ -1048,8 +1103,9 @@ export default { if (nearMsg && nearMsg.id != rangeValue) { this.preventMoreLoad = true this.$store.dispatch("getDialogMsgs", { - [key]: rangeValue, dialog_id: this.dialogId, + msg_id: this.msgId, + [key]: rangeValue, }).finally(_ => { this.preventMoreLoad = false }) @@ -1151,7 +1207,7 @@ export default { onReply() { const {tail} = this.scrollInfo() - this.replyId = this.operateItem.id + this.replyActiveId = this.operateItem.id this.inputFocus() if (tail <= 10) { requestAnimationFrame(this.onToBottom) @@ -1159,7 +1215,7 @@ export default { }, onCancelReply() { - this.replyId = 0; + this.replyActiveId = 0; }, onWithdraw() { @@ -1307,6 +1363,14 @@ export default { }); }, + onReplyList(data) { + if (this.operateVisible) { + return + } + this.replyListId = data.msg_id + this.replyListShow = true + }, + onEmoji(data) { if (!$A.isJson(data)) { data = { diff --git a/resources/assets/js/store/actions.js b/resources/assets/js/store/actions.js index 5d36d88e6..10454acca 100644 --- a/resources/assets/js/store/actions.js +++ b/resources/assets/js/store/actions.js @@ -2182,7 +2182,7 @@ export default { * @param state * @param dispatch * @param getters - * @param data {dialog_id, ?reply_id, ?position_id, ?prev_id, ?next_id} + * @param data {dialog_id, msg_id, ?position_id, ?prev_id, ?next_id} * @returns {Promise} */ getDialogMsgs({state, dispatch, getters}, data) { @@ -2192,11 +2192,8 @@ export default { reject({msg: 'Parameter error'}); return; } - if (!/^d+$/.test(data.reply_id)) { - data.reply_id = 0; - } // - const loadKey = `msg::${data.dialog_id}-${data.reply_id}` + const loadKey = `msg::${data.dialog_id}-${data.msg_id}` if (getters.isLoad(loadKey)) { reject({msg: 'Loading'}); return diff --git a/resources/assets/sass/pages/components/chat-input.scss b/resources/assets/sass/pages/components/chat-input.scss index 09bfa588a..cc4ec25d7 100755 --- a/resources/assets/sass/pages/components/chat-input.scss +++ b/resources/assets/sass/pages/components/chat-input.scss @@ -607,7 +607,6 @@ } .mention-item-name { - flex-shrink: 0; padding: 0 8px; font-size: 14px; overflow: hidden; diff --git a/resources/assets/sass/pages/components/dialog-wrapper.scss b/resources/assets/sass/pages/components/dialog-wrapper.scss index f845ac0dc..acbf14fd5 100644 --- a/resources/assets/sass/pages/components/dialog-wrapper.scss +++ b/resources/assets/sass/pages/components/dialog-wrapper.scss @@ -13,6 +13,29 @@ overflow: hidden; } + &.reply-list { + border-radius: 18px 0 0 18px; + + .dialog-nav { + position: relative; + + &:before { + content: ""; + position: absolute; + left: 0; + bottom: 0; + width: 100%; + height: 1px; + background-color: #f4f5f5; + } + + .dialog-scroller { + padding: 16px 16px 0; + } + + } + } + .vue-recycle-scroller.direction-vertical:not(.page-mode) { overflow-y: overlay; }