perf: 优化仪表盘使用sticky方式

This commit is contained in:
kuaifan 2022-03-05 10:59:18 +08:00
parent 8e0a684a9a
commit e969b5b7e4
2 changed files with 248 additions and 189 deletions

View File

@ -5,72 +5,78 @@
<div class="dashboard-hello">{{$L('欢迎您,' + userInfo.nickname)}}</div> <div class="dashboard-hello">{{$L('欢迎您,' + userInfo.nickname)}}</div>
<div class="dashboard-desc">{{$L('以下是你当前的任务统计数据')}}</div> <div class="dashboard-desc">{{$L('以下是你当前的任务统计数据')}}</div>
<ul class="dashboard-block"> <ul class="dashboard-block">
<li @click="dashboard='today'"> <li @click="scrollTo('today')">
<div class="block-title">{{$L('今日待完成')}}</div> <div class="block-title">{{getTitle('today')}}</div>
<div class="block-data"> <div class="block-data">
<div class="block-num">{{dashboardTask.today.length}}</div> <div class="block-num">{{dashboardTask.today.length}}</div>
<i class="taskfont">&#xe6f4;</i> <i class="taskfont">&#xe6f4;</i>
</div> </div>
</li> </li>
<li @click="dashboard='overdue'"> <li @click="scrollTo('overdue')">
<div class="block-title">{{$L('超期未完成')}}</div> <div class="block-title">{{getTitle('overdue')}}</div>
<div class="block-data"> <div class="block-data">
<div class="block-num">{{dashboardTask.overdue.length}}</div> <div class="block-num">{{dashboardTask.overdue.length}}</div>
<i class="taskfont">&#xe603;</i> <i class="taskfont">&#xe603;</i>
</div> </div>
</li> </li>
<li @click="dashboard='all'"> <li @click="scrollTo('all')">
<div class="block-title">{{$L('待完成任务')}}</div> <div class="block-title">{{getTitle('all')}}</div>
<div class="block-data"> <div class="block-data">
<div class="block-num">{{dashboardTask.all.length}}</div> <div class="block-num">{{dashboardTask.all.length}}</div>
<i class="taskfont">&#xe6f9;</i> <i class="taskfont">&#xe6f9;</i>
</div> </div>
</li> </li>
</ul> </ul>
<template v-if="list.length > 0"> <div class="dashboard-list overlay-y">
<div class="dashboard-title">{{title}}</div> <div
<ul class="dashboard-list overlay-y"> :ref="`type_${column.type}`"
<li v-for="(column, index) in columns"
v-for="(item, index) in list" v-if="column.list.length > 0"
:key="index" :key="index">
:class="{complete: item.complete_at}" <div class="dashboard-title">{{column.title}}</div>
:style="item.color ? {backgroundColor: item.color} : {}" <ul class="dashboard-li">
@click="openTask(item)"> <li
<em v-for="(item, index) in column.list"
v-if="item.p_name" :key="index"
class="priority-color" :class="{complete: item.complete_at}"
:style="{backgroundColor:item.p_color}"></em> :style="item.color ? {backgroundColor: item.color} : {}"
<TaskMenu :ref="`taskMenu_${item.id}`" :task="item"> @click="openTask(item)">
<div slot="icon" class="drop-icon" @click.stop=""> <em
<i class="taskfont" v-html="item.complete_at ? '&#xe627;' : '&#xe625;'"></i> v-if="item.p_name"
class="priority-color"
:style="{backgroundColor:item.p_color}"></em>
<TaskMenu :ref="`taskMenu_${item.id}`" :task="item">
<div slot="icon" class="drop-icon" @click.stop="">
<i class="taskfont" v-html="item.complete_at ? '&#xe627;' : '&#xe625;'"></i>
</div>
</TaskMenu>
<div class="item-title">
<!--工作流状态-->
<span v-if="item.flow_item_name" :class="item.flow_item_status" @click.stop="openMenu(item)">{{item.flow_item_name}}</span>
<!--是否子任务-->
<span v-if="item.sub_top === true">{{$L('子任务')}}</span>
<!--有多少个子任务-->
<span v-if="item.sub_my && item.sub_my.length > 0">+{{item.sub_my.length}}</span>
<!--任务描述-->
{{item.name}}
</div> </div>
</TaskMenu> <div v-if="item.desc" class="item-icon">
<div class="item-title"> <i class="taskfont">&#xe71a;</i>
<!--工作流状态-->
<span v-if="item.flow_item_name" :class="item.flow_item_status" @click.stop="openMenu(item)">{{item.flow_item_name}}</span>
<!--是否子任务-->
<span v-if="item.sub_top === true">{{$L('子任务')}}</span>
<!--有多少个子任务-->
<span v-if="item.sub_my && item.sub_my.length > 0">+{{item.sub_my.length}}</span>
<!--任务描述-->
{{item.name}}
</div>
<div v-if="item.desc" class="item-icon">
<i class="taskfont">&#xe71a;</i>
</div>
<div v-if="item.sub_num > 0" class="item-icon">
<i class="taskfont">&#xe71f;</i>
<em>{{item.sub_complete}}/{{item.sub_num}}</em>
</div>
<ETooltip v-if="item.end_at" :content="item.end_at" placement="right">
<div :class="['item-icon', item.today ? 'today' : '', item.overdue ? 'overdue' : '']">
<i class="taskfont">&#xe71d;</i>
<em>{{expiresFormat(item.end_at)}}</em>
</div> </div>
</ETooltip> <div v-if="item.sub_num > 0" class="item-icon">
</li> <i class="taskfont">&#xe71f;</i>
</ul> <em>{{item.sub_complete}}/{{item.sub_num}}</em>
</template> </div>
<ETooltip v-if="item.end_at" :content="item.end_at" placement="right">
<div :class="['item-icon', item.today ? 'today' : '', item.overdue ? 'overdue' : '']">
<i class="taskfont">&#xe71d;</i>
<em>{{expiresFormat(item.end_at)}}</em>
</div>
</ETooltip>
</li>
</ul>
</div>
</div>
</div> </div>
</div> </div>
</template> </template>
@ -110,13 +116,34 @@ export default {
}, },
computed: { computed: {
...mapState(['userInfo', 'cacheProjects', 'taskId']), ...mapState(['userInfo']),
...mapGetters(['dashboardTask', 'transforTasks']), ...mapGetters(['dashboardTask', 'transforTasks']),
title() { columns() {
const {dashboard} = this; let list = [];
switch (dashboard) { ['today', 'overdue', 'all'].some(type => {
let data = this.transforTasks(this.dashboardTask[type]);
list.push({
type,
title: this.getTitle(type),
list: data.sort((a, b) => {
return $A.Date(a.end_at || "2099-12-31 23:59:59") - $A.Date(b.end_at || "2099-12-31 23:59:59");
})
})
})
return list;
},
total() {
const {dashboardTask} = this;
return dashboardTask.today.length + dashboardTask.overdue.length + dashboardTask.all.length;
},
},
methods: {
getTitle(type) {
switch (type) {
case 'today': case 'today':
return this.$L('今日任务'); return this.$L('今日任务');
case 'overdue': case 'overdue':
@ -128,27 +155,20 @@ export default {
} }
}, },
list() { scrollTo(type) {
const {dashboard} = this; try {
let data = []; this.$refs[`type_${type}`][0].scrollIntoView({
switch (dashboard) { behavior: 'instant',
case 'today': inline: 'end',
data = this.transforTasks(this.dashboardTask.today); });
break } catch (e) {
case 'overdue': scrollIntoView(this.$refs[`type_${type}`][0], {
data = this.transforTasks(this.dashboardTask.overdue); behavior: 'instant',
break inline: 'end',
case 'all': })
data = this.transforTasks(this.dashboardTask.all);
break
} }
return data.sort((a, b) => {
return $A.Date(a.end_at || "2099-12-31 23:59:59") - $A.Date(b.end_at || "2099-12-31 23:59:59");
});
}, },
},
methods: {
openTask(task) { openTask(task) {
this.$store.dispatch("openTask", task) this.$store.dispatch("openTask", task)
}, },

View File

@ -5,13 +5,22 @@
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
background-color: #ffffff;
.dashboard-wrapper { .dashboard-wrapper {
width: 664px; width: 100%;
max-width: 80%;
max-height: 80%; max-height: 80%;
margin-bottom: 2%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center;
.dashboard-hello,
.dashboard-desc ,
.dashboard-block ,
.dashboard-list .dashboard-title,
.dashboard-list .dashboard-li {
width: 660px;
max-width: 80%;
margin: 0 auto;
}
.dashboard-hello { .dashboard-hello {
padding: 0 12px; padding: 0 12px;
color: #333333; color: #333333;
@ -41,10 +50,7 @@
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: center;
cursor: pointer; cursor: pointer;
transition: box-shadow 0.3s; transition: transform 0.5s ease-out 0s, box-shadow 0.3s ease-out 0s;
&:hover {
box-shadow: 0 0 10px #cccccc;
}
&:first-child { &:first-child {
background-color: #6f9ef6; background-color: #6f9ef6;
} }
@ -52,6 +58,16 @@
background-color: #98de6e; background-color: #98de6e;
margin-right: 0; margin-right: 0;
} }
&:hover {
transform: translateY(-3px);
box-shadow: 0 2px 10px 0 #fa8e8c;
&:first-child {
box-shadow: 0 2px 10px 0 #6f9ef6;
}
&:last-child {
box-shadow: 0 2px 10px 0 #98de6e;
}
}
.block-title { .block-title {
color: rgba(255, 255, 255, 0.6); color: rgba(255, 255, 255, 0.6);
font-size: 12px; font-size: 12px;
@ -74,114 +90,130 @@
} }
} }
} }
.dashboard-title {
margin-top: 60px;
padding: 0 12px;
font-weight: 600;
font-size: 15px;
}
.dashboard-list { .dashboard-list {
margin-top: 4px; width: 100%;
padding: 0 12px; margin-top: 48px;
overflow: auto; overflow: auto;
> li { .dashboard-title {
position: relative; position: sticky;
list-style: none; top: 0;
display: flex; z-index: 1;
background: #F9FAFB; margin: 0 auto;
margin-top: 12px; padding: 0 12px;
padding: 8px 12px; height: 46px;
border-radius: 6px; line-height: 46px;
cursor: pointer; font-weight: 600;
transition: box-shadow 0.3s; font-size: 15px;
&:hover { background-color: #ffffff;
box-shadow: 0 0 6px #dfdfdf; }
} .dashboard-li {
&:last-child { margin: 0 auto;
margin-bottom: 12px; padding: 0 12px;
} overflow: hidden;
&.complete { > li {
position: relative;
list-style: none;
display: flex;
background: #F9FAFB;
padding: 12px;
cursor: pointer;
transition: box-shadow 0.3s,transform 0.2s;
border-bottom: 1px solid #f1f2f4;
&:hover {
transform: translateX(-2px);
}
&:first-child {
border-top-right-radius: 6px;
border-top-left-radius: 6px;
}
&:last-child {
border-bottom-right-radius: 6px;
border-bottom-left-radius: 6px;
border-bottom: 0;
}
&.complete {
.item-title {
opacity: 0.5;
text-decoration: line-through;
}
.item-icon {
display: none;
}
}
.priority-color {
position: absolute;
top: 50%;
transform: translateY(-50%);
left: 0;
height: 12px;
width: 2px;
}
.el-dropdown {
flex-shrink: 0;
width: 22px;
height: 22px;
line-height: 22px;
.taskfont {
color: #bbbbbb;
font-size: 18px;
}
}
.item-title { .item-title {
opacity: 0.5; flex: 1;
text-decoration: line-through; padding-left: 6px;
line-height: 22px;
> span {
font-size: 12px;
height: 18px;
min-width: 20px;
line-height: 16px;
padding: 0 2px;
border-radius: 3px;
color: #8bcf70;
border: 1px solid #8bcf70;
display: inline-block;
vertical-align: top;
margin-top: 3px;
margin-right: 3px;
text-align: center;
&.start {
background-color: rgba(38, 38, 38, 0.05);
border-color: rgba(38, 38, 38, 0.05);
color: #595959;
}
&.progress {
background-color: rgba(27, 154, 238, 0.1);
border-color: rgba(27, 154, 238, 0.1);
color: #0171c2;
}
&.end {
background-color: rgba(21, 173, 49, 0.1);
border-color: rgba(21, 173, 49, 0.1);
color: #038a24;
}
}
} }
.item-icon { .item-icon {
display: none; display: flex;
} align-items: center;
}
.priority-color {
position: absolute;
top: 50%;
transform: translateY(-50%);
left: 0;
height: 12px;
width: 2px;
}
.el-dropdown {
flex-shrink: 0;
width: 22px;
height: 22px;
line-height: 22px;
.taskfont {
color: #bbbbbb;
font-size: 18px;
}
}
.item-title {
flex: 1;
padding-left: 6px;
line-height: 22px;
> span {
font-size: 12px;
height: 18px;
min-width: 20px;
line-height: 16px;
padding: 0 2px;
border-radius: 3px;
color: #8bcf70;
border: 1px solid #8bcf70;
display: inline-block;
vertical-align: top;
margin-top: 3px;
margin-right: 3px;
text-align: center;
&.start {
background-color: rgba(38, 38, 38, 0.05);
border-color: rgba(38, 38, 38, 0.05);
color: #595959;
}
&.progress {
background-color: rgba(27, 154, 238, 0.1);
border-color: rgba(27, 154, 238, 0.1);
color: #0171c2;
}
&.end {
background-color: rgba(21, 173, 49, 0.1);
border-color: rgba(21, 173, 49, 0.1);
color: #038a24;
}
}
}
.item-icon {
display: flex;
align-items: center;
font-size: 13px;
margin-left: 16px;
height: 22px;
color: #aaaaaa;
cursor: pointer;
.taskfont {
font-size: 13px; font-size: 13px;
} margin-left: 16px;
> em { height: 22px;
font-style: normal; color: #aaaaaa;
margin-left: 4px; cursor: pointer;
} .taskfont {
&.overdue { font-size: 13px;
color: #ed4014; }
} > em {
&.today { font-style: normal;
color: #ff9900; margin-left: 4px;
}
&.overdue {
color: #ed4014;
}
&.today {
color: #ff9900;
}
} }
} }
} }
@ -217,8 +249,14 @@
.page-dashboard { .page-dashboard {
.dashboard-wrapper { .dashboard-wrapper {
display: block; display: block;
max-width: 86%;
max-height: 86%; max-height: 86%;
.dashboard-hello,
.dashboard-desc ,
.dashboard-block ,
.dashboard-list .dashboard-title,
.dashboard-list .dashboard-li {
max-width: 86%;
}
.dashboard-block { .dashboard-block {
display: block; display: block;
margin-top: 10px; margin-top: 10px;
@ -227,16 +265,17 @@
padding: 8px 12px; padding: 8px 12px;
} }
} }
.dashboard-title {
margin-top: 36px;
}
.dashboard-list { .dashboard-list {
padding-bottom: 22px; overflow: visible !important;
> li { padding-bottom: 2px;
.item-title { > ul {
overflow: hidden; margin-bottom: 36px;
text-overflow: ellipsis; > li {
white-space: nowrap .item-title {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap
}
} }
} }
} }