perf: 优化搜索加载提示

This commit is contained in:
kuaifan 2022-05-25 14:36:21 +08:00
parent c5a0e04242
commit 0911bc2dc9
7 changed files with 165 additions and 68 deletions

View File

@ -3,15 +3,21 @@
<PageTitle :title="$L('项目')"/>
<div class="list-search">
<div class="search-wrapper">
<Input v-model="projectKeyValue" :placeholder="$L(loadProjects || projectKeyLoading ? '读取中...' : '搜索...')" clearable>
<Input v-model="projectKeyValue" :placeholder="$L(loadProjects ? '更新中...' : '搜索项目')" clearable>
<div class="search-pre" slot="prefix">
<Loading v-if="loadProjects || projectKeyLoading"/>
<Loading v-if="loadProjects"/>
<Icon v-else type="ios-search" />
</div>
</Input>
</div>
</div>
<ul>
<template v-if="projectLists.length === 0">
<li v-if="projectKeyLoading > 0" class="loading"><Loading/></li>
<li v-else class="nothing">
{{$L(projectLists ? `没有任何与"${projectKeyValue}"相关的项目` : `没有任何项目`)}}
</li>
</template>
<li
v-for="(item, key) in projectLists"
:key="key"
@ -49,7 +55,6 @@ export default {
data() {
return {
projectKeyValue: '',
projectKeyAlready: {},
projectKeyLoading: 0,
}
},
@ -89,31 +94,25 @@ export default {
if (val == '') {
return;
}
this.projectKeyLoading++;
setTimeout(() => {
if (this.projectKeyValue == val) {
this.searchProject();
}
this.projectKeyLoading--;
}, 600);
},
},
methods: {
searchProject() {
if (this.projectKeyAlready[this.projectKeyValue] === true) {
return;
}
this.projectKeyAlready[this.projectKeyValue] = true;
//
setTimeout(() => {
this.projectKeyLoading++;
}, 1000)
this.projectKeyLoading++;
this.$store.dispatch("getProjects", {
keys: {
name: this.projectKeyValue
}
}).then(() => {
this.projectKeyLoading--;
}).catch(() => {
},
hideLoad: true,
}).finally(_ => {
this.projectKeyLoading--;
});
},

View File

@ -5,7 +5,9 @@
<div class="dashboard-hello">{{$L('欢迎您,' + userInfo.nickname)}}</div>
<div class="dashboard-desc">
{{$L('以下是你当前的任务统计数据')}}
<div v-if="loadDashboardTasks" class="dashboard-load"><Loading/></div>
<transition name="dashboard-load">
<div v-if="loadDashboardTasks" class="dashboard-load"><Loading/></div>
</transition>
</div>
<ul class="dashboard-block">
<li @click="scrollTo('today')">

View File

@ -5,16 +5,16 @@
<div class="messenger-select">
<div class="messenger-search">
<div class="search-wrapper">
<Input v-if="tabActive==='dialog'" v-model="dialogKey" :placeholder="$L(loadDialogs ? '读取中...' : '搜索...')" clearable >
<Input v-if="tabActive==='dialog'" v-model="dialogKey" :placeholder="$L(loadDialogs ? '更新中...' : '搜索消息')" clearable >
<div class="search-pre" slot="prefix">
<Loading v-if="loadDialogs"/>
<Icon v-else type="ios-search" />
</div>
</Input>
<Input v-else prefix="ios-search" v-model="contactsKey" :placeholder="$L('搜索...')" clearable />
<Input v-else prefix="ios-search" v-model="contactsKey" :placeholder="$L('搜索联系人')" clearable />
</div>
</div>
<div v-if="tabActive==='dialog'" class="messenger-nav">
<div v-if="tabActive==='dialog' && !dialogKey" class="messenger-nav">
<p
v-for="(item, key) in dialogType"
:key="key"
@ -34,7 +34,11 @@
v-if="tabActive==='dialog'"
ref="dialogWrapper"
class="dialog" >
<li v-if="dialogList.length === 0" class="nothing">
{{$L(dialogKey ? `没有任何与"${dialogKey}"相关的对话` : `没有任何对话`)}}
</li>
<li
v-else
v-for="(dialog, key) in dialogList"
:ref="`dialog_${dialog.id}`"
:key="key"
@ -76,17 +80,24 @@
</li>
</ul>
<ul v-else class="contacts">
<li v-for="(users, label) in contactsData">
<div class="label">{{label}}</div>
<ul>
<li v-for="(user, index) in users" :key="index" @click="openContacts(user)">
<div class="avatar"><UserAvatar :userid="user.userid" :size="30"/></div>
<div class="nickname">{{user.nickname}}</div>
</li>
</ul>
</li>
<li v-if="contactsLoad > 0" class="loading"><Loading/></li>
<li v-else-if="!contactsHasMorePages" class="loaded">{{$L('共' + contactsList.length + '位联系人')}}</li>
<template v-if="contactsFilter.length === 0">
<li v-if="contactsLoad > 0" class="loading"><Loading/></li>
<li v-else class="nothing">
{{$L(contactsKey ? `没有任何与"${contactsKey}"相关的联系人` : `没有任何联系人`)}}
</li>
</template>
<template v-else>
<li v-for="items in contactsList">
<div class="label">{{items.az}}</div>
<ul>
<li v-for="(user, index) in items.list" :key="index" @click="openContacts(user)">
<div class="avatar"><UserAvatar :userid="user.userid" :size="30"/></div>
<div class="nickname">{{user.nickname}}</div>
</li>
</ul>
</li>
<li class="loaded">{{$L('共' + contactsFilter.length + '位联系人')}}</li>
</template>
</ul>
<div class="top-operate" :style="topOperateStyles">
<Dropdown
@ -156,7 +167,6 @@ export default {
contactsKey: '',
contactsLoad: 0,
contactsList: [],
contactsData: null,
contactsCurrentPage: 1,
contactsHasMorePages: false,
@ -200,7 +210,13 @@ export default {
if (!this.filterDialog(dialog)) {
return false;
}
if (dialogActive) {
if (dialogKey) {
let existName = $A.strExists(dialog.name, dialogKey);
let existMsg = dialog.last_msg && dialog.last_msg.type === 'text' && $A.strExists(dialog.last_msg.msg.text, dialogKey);
if (!existName && !existMsg) {
return false;
}
} else if (dialogActive) {
switch (dialogActive) {
case 'project':
case 'task':
@ -217,13 +233,6 @@ export default {
return false;
}
}
if (dialogKey) {
let existName = $A.strExists(dialog.name, dialogKey);
let existMsg = dialog.last_msg && dialog.last_msg.type === 'text' && $A.strExists(dialog.last_msg.msg.text, dialogKey);
if (!existName && !existMsg) {
return false;
}
}
return true;
}).sort((a, b) => {
if (a.top_at || b.top_at) {
@ -233,6 +242,36 @@ export default {
})
},
contactsFilter() {
const {contactsData, contactsKey} = this;
if (contactsData === null) {
return [];
}
if (contactsKey) {
return contactsData.filter(item => $A.strExists(item.email, contactsKey) || $A.strExists(item.nickname, contactsKey))
}
return contactsData;
},
contactsList() {
let list = [];
this.contactsFilter.some(user => {
let az = user.az ? user.az.toUpperCase() : "#";
let item = list.find(item => item.az = az);
if (item) {
if (item.list.findIndex(({userid}) => userid == user.userid) === -1) {
item.list.push(user)
}
} else {
list.push({
az,
list: [user]
})
}
})
return list;
},
msgUnread() {
return function (type) {
let num = 0;
@ -285,11 +324,15 @@ export default {
}
},
contactsKey(val) {
if (val == '') {
return;
}
this.contactsLoad++;
setTimeout(() => {
if (this.contactsKey == val) {
this.contactsData = null;
this.getContactsList(1);
}
this.contactsLoad--;
}, 600);
},
tabActive: {
@ -399,9 +442,6 @@ export default {
},
getContactsList(page) {
if (this.contactsData === null) {
this.contactsData = {};
}
this.contactsLoad++;
this.$store.dispatch("call", {
url: 'users/search',
@ -416,19 +456,15 @@ export default {
pagesize: 50
},
}).then(({data}) => {
if (this.contactsData === null) {
this.contactsData = [];
}
data.data.some((user) => {
if (user.userid === this.userId) {
return false;
}
let az = user.az ? user.az.toUpperCase() : "#";
if (typeof this.contactsData[az] === "undefined") this.contactsData[az] = [];
//
let index = this.contactsData[az].findIndex(({userid}) => userid === user.userid);
if (index > -1) {
this.contactsData[az].splice(index, 1, user);
} else {
this.contactsData[az].push(user);
this.contactsList.push(user);
if (this.contactsData.findIndex(item => item.userid = user.userid) === -1) {
this.contactsData.push(user)
}
});
this.contactsCurrentPage = data.current_page;

View File

@ -711,7 +711,12 @@ export default {
reject({msg: 'Parameter error'});
return;
}
state.loadProjects++;
let showLoad = true;
if (data.hideLoad !== undefined) {
showLoad = !data.hideLoad;
delete data.hideLoad;
}
showLoad && state.loadProjects++;
dispatch("call", {
url: 'project/lists',
data: data || {}
@ -723,7 +728,7 @@ export default {
console.warn(e);
reject(e)
}).finally(_ => {
state.loadProjects--;
showLoad && state.loadProjects--;
});
});
},

View File

@ -24,14 +24,14 @@
overflow: hidden;
.search-pre {
width: 32px;
height: 32px;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
.common-loading {
width: 16px;
height: 16px;
width: 14px;
height: 14px;
margin: 0;
}
}
@ -60,6 +60,25 @@
border-radius: 12px;
background-color: #ffffff;
list-style: none;
&.nothing,
&.loading {
text-align: center;
height: 100%;
margin: 0;
padding: 24px;
border-radius: 0;
line-height: 22px;
}
&.loading {
display: flex;
align-items: flex-start;
justify-content: center;
.common-loading {
width: 20px;
height: 20px;
margin: 1px;
}
}
.project-h1 {
font-size: 16px;
line-height: 22px;

View File

@ -261,6 +261,22 @@
}
}
// 加载状态延时显示立即隐藏
.dashboard-load-enter-active {
transition: opacity 0.3s ease;
transition-delay: 1s;
}
.dashboard-load-leave-active {
transition: opacity 0.2s ease;
transition-delay: 0s;
}
.dashboard-load-enter,
.dashboard-load-leave-to {
opacity: 0;
}
@media (max-width: 768px) {
.page-dashboard {
.dashboard-wrapper {

View File

@ -37,14 +37,14 @@
border-radius: 12px;
overflow: hidden;
.search-pre {
width: 32px;
height: 32px;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
.common-loading {
width: 16px;
height: 16px;
width: 14px;
height: 14px;
margin: 0;
}
}
@ -262,6 +262,13 @@
}
}
}
&.nothing {
justify-content: center;
padding: 24px;
margin: 0;
border: 0;
line-height: 22px;
}
}
}
&.contacts {
@ -277,18 +284,31 @@
line-height: 34px;
border-bottom: 1px solid #efefef;
}
&.loading,
&.nothing,
&.loading {
text-align: center;
height: 100%;
margin: 0;
padding: 24px;
border-radius: 0;
line-height: 22px;
}
&.loading {
display: flex;
align-items: flex-start;
justify-content: center;
.common-loading {
width: 20px;
height: 20px;
margin: 1px;
}
}
&.loaded {
margin: 0;
height: 52px;
display: flex;
align-items: center;
justify-content: center;
.common-loading {
width: 20px;
height: 20px;
margin: 0;
}
}
> ul {
> li {