mirror of
https://github.com/kuaifan/dootask.git
synced 2026-02-28 04:40:37 +00:00
perf: 优化消息分页加载
This commit is contained in:
parent
17ce620abf
commit
58856c6620
@ -214,10 +214,11 @@ class DialogController extends AbstractController
|
||||
* @apiName msg__lists
|
||||
*
|
||||
* @apiParam {Number} dialog_id 对话ID
|
||||
* @apiParam {String} [position_id] 定位消息ID(填写时page无效)
|
||||
* @apiParam {String} [position_id] 此消息ID前后的数据,优先级1
|
||||
* @apiParam {Number} [prev_id] 此消息ID之前的数据,优先级2
|
||||
* @apiParam {Number} [next_id] 此消息ID之后的数据,优先级3
|
||||
*
|
||||
* @apiParam {Number} [page] 当前页,默认:1
|
||||
* @apiParam {Number} [pagesize] 每页显示数量,默认:50,最大:100
|
||||
* @apiParam {Number} [take] 获取条数,默认:50,最大:100
|
||||
*
|
||||
* @apiSuccess {Number} ret 返回状态码(1正确、0错误)
|
||||
* @apiSuccess {String} msg 返回信息(错误描述)
|
||||
@ -229,6 +230,9 @@ class DialogController extends AbstractController
|
||||
//
|
||||
$dialog_id = intval(Request::input('dialog_id'));
|
||||
$position_id = intval(Request::input('position_id'));
|
||||
$prev_id = intval(Request::input('prev_id'));
|
||||
$next_id = intval(Request::input('next_id'));
|
||||
$take = Base::getPaginate(100, 50, 'take');
|
||||
//
|
||||
$dialog = WebSocketDialog::checkDialog($dialog_id);
|
||||
//
|
||||
@ -240,16 +244,40 @@ class DialogController extends AbstractController
|
||||
$leftJoin
|
||||
->on('read.userid', '=', DB::raw($user->userid))
|
||||
->on('read.msg_id', '=', 'web_socket_dialog_msgs.id');
|
||||
})->where('web_socket_dialog_msgs.dialog_id', $dialog_id)->orderByDesc('web_socket_dialog_msgs.id');
|
||||
})->where('web_socket_dialog_msgs.dialog_id', $dialog_id);
|
||||
//
|
||||
$perPage = Base::getPaginate(100, 50);
|
||||
if ($position_id > 0) {
|
||||
$position_count = $builder->clone()->where('web_socket_dialog_msgs.id', '>=', $position_id)->count();
|
||||
$list = $builder->paginate($perPage, [], 'page', ceil($position_count / $perPage));
|
||||
} else {
|
||||
$list = $builder->paginate($perPage);
|
||||
$array = $builder->clone()
|
||||
->where('web_socket_dialog_msgs.id', '>=', $position_id)
|
||||
->orderBy('web_socket_dialog_msgs.id')
|
||||
->take(intval($take / 2))
|
||||
->get();
|
||||
$prev_id = intval($array->last()?->id);
|
||||
}
|
||||
//
|
||||
$cloner = $builder->clone();
|
||||
if ($prev_id > 0) {
|
||||
$cloner->where('web_socket_dialog_msgs.id', '<=', $prev_id)->orderByDesc('web_socket_dialog_msgs.id');
|
||||
} elseif ($next_id > 0) {
|
||||
$cloner->where('web_socket_dialog_msgs.id', '>=', $next_id)->orderBy('web_socket_dialog_msgs.id');
|
||||
} else {
|
||||
$cloner->orderByDesc('web_socket_dialog_msgs.id');
|
||||
}
|
||||
$list = $cloner->take($take)->get()->sortByDesc('id', SORT_NUMERIC)->values();
|
||||
//
|
||||
if ($list->isNotEmpty()) {
|
||||
$first = $list->first();
|
||||
$first->next_id = intval($builder->clone()
|
||||
->where('web_socket_dialog_msgs.id', '>', $first->id)
|
||||
->orderBy('web_socket_dialog_msgs.id')
|
||||
->value('id'));
|
||||
$last = $list->last();
|
||||
$last->prev_id = intval($builder->clone()
|
||||
->where('web_socket_dialog_msgs.id', '<', $last->id)
|
||||
->orderByDesc('web_socket_dialog_msgs.id')
|
||||
->value('id'));
|
||||
}
|
||||
// 记录当前打开的任务对话
|
||||
if ($dialog->type == 'group' && $dialog->group_type == 'task') {
|
||||
$user->task_dialog_id = $dialog->id;
|
||||
$user->save();
|
||||
@ -261,8 +289,9 @@ class DialogController extends AbstractController
|
||||
$isMarkDialogUser->save();
|
||||
}
|
||||
//
|
||||
$data = $list->toArray();
|
||||
if ($list->currentPage() === 1) {
|
||||
$data = [];
|
||||
$data['list'] = $list;
|
||||
if ($prev_id === 0 && $next_id === 0) {
|
||||
$data['dialog'] = $dialog->formatData($user->userid);
|
||||
}
|
||||
return Base::retSuccess('success', $data);
|
||||
|
||||
@ -81,7 +81,7 @@
|
||||
:keeps="70"
|
||||
@scroll="onScroll"
|
||||
@range="onRange"
|
||||
@totop="onNextPage"
|
||||
@totop="onPrevPage"
|
||||
|
||||
@on-longpress="onLongpress"
|
||||
@on-view-reply="onViewReply"
|
||||
@ -89,7 +89,7 @@
|
||||
@on-view-file="onViewFile"
|
||||
@on-emoji="onEmoji">
|
||||
<template slot="header">
|
||||
<div v-if="(allMsgs.length === 0 && dialogData.loading > 0) || nextPage > 0" class="dialog-item loading"><Loading/></div>
|
||||
<div v-if="loadMsg || prevId > 0" class="dialog-item loading"><Loading/></div>
|
||||
<div v-else-if="allMsgs.length === 0" class="dialog-item nothing">{{$L('暂无消息')}}</div>
|
||||
</template>
|
||||
</VirtualList>
|
||||
@ -256,7 +256,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {mapState} from "vuex";
|
||||
import {mapGetters, mapState} from "vuex";
|
||||
import DialogItem from "./DialogItem";
|
||||
import DialogUpload from "./DialogUpload";
|
||||
import UserInput from "../../../components/UserInput";
|
||||
@ -335,6 +335,10 @@ export default {
|
||||
|
||||
replyId: 0,
|
||||
replyActiveIndex: -1,
|
||||
|
||||
scrollDirection: null,
|
||||
scrollAction: 0,
|
||||
scrollTmp: 0,
|
||||
}
|
||||
},
|
||||
|
||||
@ -354,6 +358,8 @@ export default {
|
||||
'windowActive',
|
||||
]),
|
||||
|
||||
...mapGetters(['isLoad']),
|
||||
|
||||
isReady() {
|
||||
return this.dialogId > 0 && this.dialogData.id > 0
|
||||
},
|
||||
@ -393,13 +399,13 @@ export default {
|
||||
return dialogMsgList;
|
||||
},
|
||||
|
||||
nextPage() {
|
||||
loadMsg() {
|
||||
return this.isLoad(`msg::${this.dialogId}-0`)
|
||||
},
|
||||
|
||||
prevId() {
|
||||
if (this.allMsgs.length > 0) {
|
||||
let topMsgPage = $A.runNum(this.allMsgs[0]._page);
|
||||
let {lastPage} = this.dialogData;
|
||||
if (topMsgPage < lastPage && lastPage > 1) {
|
||||
return topMsgPage + 1
|
||||
}
|
||||
return $A.runNum(this.allMsgs[0].prev_id)
|
||||
}
|
||||
return 0
|
||||
},
|
||||
@ -466,22 +472,22 @@ export default {
|
||||
|
||||
watch: {
|
||||
dialogId: {
|
||||
handler(id) {
|
||||
if (id) {
|
||||
handler(dialog_id) {
|
||||
if (dialog_id) {
|
||||
this.msgNew = 0;
|
||||
//
|
||||
if (this.allMsgList.length > 0) {
|
||||
this.allMsgs = this.allMsgList;
|
||||
requestAnimationFrame(this.onToBottom);
|
||||
}
|
||||
this.$store.dispatch("getDialogMsgs", id).then(_ => {
|
||||
this.openId = id;
|
||||
this.$store.dispatch("getDialogMsgs", {dialog_id}).then(_ => {
|
||||
this.openId = dialog_id;
|
||||
setTimeout(this.onSearchMsgId, 100)
|
||||
}).catch(_ => {});
|
||||
//
|
||||
this.$store.dispatch('saveInDialog', {
|
||||
uid: this._uid,
|
||||
dialog_id: id,
|
||||
dialog_id,
|
||||
})
|
||||
//
|
||||
if (this.autoFocus) {
|
||||
@ -516,7 +522,9 @@ export default {
|
||||
|
||||
wsOpenNum(num) {
|
||||
if (num <= 1) return
|
||||
this.$store.dispatch("getDialogMsgs", this.dialogId).catch(_ => {});
|
||||
this.$store.dispatch("getDialogMsgs", {
|
||||
dialog_id: this.dialogId
|
||||
}).catch(_ => {});
|
||||
},
|
||||
|
||||
allMsgList(newList, oldList) {
|
||||
@ -708,7 +716,7 @@ export default {
|
||||
})
|
||||
}
|
||||
this.preventToBottom = true;
|
||||
this.$store.dispatch("getDialogMoreMsgs", {
|
||||
this.$store.dispatch("getDialogMsgs", {
|
||||
dialog_id: this.dialogId,
|
||||
position_id
|
||||
}).finally(_ => {
|
||||
@ -935,16 +943,15 @@ export default {
|
||||
this.$store.dispatch("openTask", this.dialogData.group_info.id);
|
||||
},
|
||||
|
||||
onNextPage() {
|
||||
if (this.nextPage === 0) {
|
||||
onPrevPage() {
|
||||
if (this.prevId === 0) {
|
||||
return
|
||||
}
|
||||
this.$store.dispatch('getDialogMoreMsgs', {
|
||||
this.$store.dispatch('getDialogMsgs', {
|
||||
dialog_id: this.dialogId,
|
||||
page: this.nextPage
|
||||
}).then(result => {
|
||||
const resData = result.data;
|
||||
const ids = resData.data.map(item => item.id)
|
||||
prev_id: this.prevId
|
||||
}).then(({data}) => {
|
||||
const ids = data.list.map(item => item.id)
|
||||
this.$nextTick(() => {
|
||||
const scroller = this.$refs.scroller
|
||||
const offset = ids.reduce((previousValue, currentId) => {
|
||||
@ -952,7 +959,7 @@ export default {
|
||||
return {size: previousSize + scroller.getSize(currentId)}
|
||||
})
|
||||
let size = scroller.getOffset() + offset.size;
|
||||
if (this.nextPage === 0) {
|
||||
if (this.prevId === 0) {
|
||||
size -= 36
|
||||
}
|
||||
this.onToOffset(size);
|
||||
@ -1015,7 +1022,7 @@ export default {
|
||||
}
|
||||
},
|
||||
|
||||
onScroll() {
|
||||
onScroll(event) {
|
||||
this.operateVisible = false;
|
||||
//
|
||||
const {tail} = this.scrollInfo();
|
||||
@ -1023,25 +1030,31 @@ export default {
|
||||
if (this.scrollTail <= 10) {
|
||||
this.msgNew = 0;
|
||||
}
|
||||
//
|
||||
this.scrollAction = event.target.scrollTop;
|
||||
this.scrollDirection = this.scrollTmp <= this.scrollAction ? 'down' : 'up';
|
||||
setTimeout(_ => this.scrollTmp = this.scrollAction, 0);
|
||||
},
|
||||
|
||||
onRange(range) {
|
||||
if (this.preventMoreLoad) {
|
||||
return
|
||||
}
|
||||
let tmpPage = 0;
|
||||
const key = this.scrollDirection === 'down' ? 'next_id' : 'prev_id';
|
||||
for (let i = range.start; i <= range.end; i++) {
|
||||
if (tmpPage - parseInt(this.allMsgs[i]._page) > 1) {
|
||||
this.preventMoreLoad = true
|
||||
this.$store.dispatch("getDialogMoreMsgs", {
|
||||
dialog_id: this.dialogId,
|
||||
page: tmpPage - 1
|
||||
}).finally(_ => {
|
||||
this.preventMoreLoad = false
|
||||
})
|
||||
break;
|
||||
const rangeValue = this.allMsgs[i][key]
|
||||
if (rangeValue) {
|
||||
const nearMsg = this.allMsgs[i + (key === 'next_id' ? 1 : -1)]
|
||||
if (nearMsg && nearMsg.id != rangeValue) {
|
||||
this.preventMoreLoad = true
|
||||
this.$store.dispatch("getDialogMsgs", {
|
||||
[key]: rangeValue,
|
||||
dialog_id: this.dialogId,
|
||||
}).finally(_ => {
|
||||
this.preventMoreLoad = false
|
||||
})
|
||||
}
|
||||
}
|
||||
tmpPage = parseInt(this.allMsgs[i]._page);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
83
resources/assets/js/store/actions.js
vendored
83
resources/assets/js/store/actions.js
vendored
@ -2181,88 +2181,45 @@ export default {
|
||||
* 获取会话消息
|
||||
* @param state
|
||||
* @param dispatch
|
||||
* @param dialog_id
|
||||
* @param getters
|
||||
* @param data {dialog_id, ?reply_id, ?position_id, ?prev_id, ?next_id}
|
||||
* @returns {Promise<unknown>}
|
||||
*/
|
||||
getDialogMsgs({state, dispatch}, dialog_id) {
|
||||
return new Promise(resolve => {
|
||||
if (!dialog_id) {
|
||||
resolve()
|
||||
return;
|
||||
}
|
||||
let dialog = state.cacheDialogs.find(({id}) => id == dialog_id);
|
||||
if (!dialog) {
|
||||
dialog = {
|
||||
id: dialog_id,
|
||||
};
|
||||
state.cacheDialogs.push(dialog);
|
||||
}
|
||||
if (dialog.loading) {
|
||||
resolve()
|
||||
return;
|
||||
}
|
||||
dialog.loading = true;
|
||||
//
|
||||
dispatch("call", {
|
||||
url: 'dialog/msg/lists',
|
||||
data: {
|
||||
dialog_id: dialog_id,
|
||||
page: 1
|
||||
},
|
||||
complete: _ => dialog.loading = false
|
||||
}).then(result => {
|
||||
const resData = result.data;
|
||||
dialog.lastPage = resData.last_page;
|
||||
dialog = Object.assign(dialog, resData.dialog)
|
||||
//
|
||||
const ids = resData.data.map(({id}) => id)
|
||||
state.dialogMsgs = state.dialogMsgs.filter((item) => item.dialog_id != dialog_id || ids.includes(item.id));
|
||||
//
|
||||
dispatch("saveDialogMsg", resData.data.map(item => Object.assign(item, {_page: resData.current_page})));
|
||||
resolve()
|
||||
}).catch(e => {
|
||||
console.warn(e);
|
||||
resolve()
|
||||
}).finally(_ => {
|
||||
dispatch("saveDialog", dialog);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取更多会话消息(指定页|定位页)
|
||||
* @param state
|
||||
* @param dispatch
|
||||
* @param data {dialog_id, ?page, ?position_id}
|
||||
*/
|
||||
getDialogMoreMsgs({state, dispatch}, data) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
getDialogMsgs({state, dispatch, getters}, data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const dialog = state.cacheDialogs.find(({id}) => id == data.dialog_id);
|
||||
if (!dialog) {
|
||||
reject({msg: 'Parameter error'});
|
||||
return;
|
||||
}
|
||||
if (dialog.loading) {
|
||||
reject({msg: 'Loading'});
|
||||
return;
|
||||
if (!/^d+$/.test(data.reply_id)) {
|
||||
data.reply_id = 0;
|
||||
}
|
||||
dialog.loading = true;
|
||||
const loadKey = `msg::${data.dialog_id}-${data.reply_id}`
|
||||
if (getters.isLoad(loadKey)) {
|
||||
reject({msg: 'Loading'});
|
||||
return
|
||||
}
|
||||
dispatch("setLoad", loadKey)
|
||||
//
|
||||
dispatch("call", {
|
||||
url: 'dialog/msg/lists',
|
||||
data,
|
||||
complete: _ => dialog.loading = false
|
||||
complete: _ => dispatch("cancelLoad", loadKey)
|
||||
}).then(result => {
|
||||
const resData = result.data;
|
||||
dialog.lastPage = resData.last_page;
|
||||
if ($A.isJson(resData.dialog)) {
|
||||
dispatch("saveDialog", resData.dialog);
|
||||
//
|
||||
const ids = resData.list.map(({id}) => id)
|
||||
state.dialogMsgs = state.dialogMsgs.filter(item => item.dialog_id != data.dialog_id || ids.includes(item.id));
|
||||
}
|
||||
//
|
||||
dispatch("saveDialogMsg", resData.data.map(item => Object.assign(item, {_page: resData.current_page})));
|
||||
dispatch("saveDialogMsg", resData.list);
|
||||
resolve(result)
|
||||
}).catch(e => {
|
||||
console.warn(e);
|
||||
reject(e)
|
||||
}).finally(_ => {
|
||||
dispatch("saveDialog", dialog);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
12
resources/assets/js/store/getters.js
vendored
12
resources/assets/js/store/getters.js
vendored
@ -1,4 +1,16 @@
|
||||
export default {
|
||||
/**
|
||||
* 是否加载中
|
||||
* @param state
|
||||
* @returns {function(*)}
|
||||
*/
|
||||
isLoad(state) {
|
||||
return function (key) {
|
||||
const load = state.loads.find(item => item.key === key);
|
||||
return load && load.num > 0
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 当前打开的项目
|
||||
* @param state
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user