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-desc">{{$L('以下是你当前的任务统计数据')}}</div>
<ul class="dashboard-block">
<li @click="dashboard='today'">
<div class="block-title">{{$L('今日待完成')}}</div>
<li @click="scrollTo('today')">
<div class="block-title">{{getTitle('today')}}</div>
<div class="block-data">
<div class="block-num">{{dashboardTask.today.length}}</div>
<i class="taskfont">&#xe6f4;</i>
</div>
</li>
<li @click="dashboard='overdue'">
<div class="block-title">{{$L('超期未完成')}}</div>
<li @click="scrollTo('overdue')">
<div class="block-title">{{getTitle('overdue')}}</div>
<div class="block-data">
<div class="block-num">{{dashboardTask.overdue.length}}</div>
<i class="taskfont">&#xe603;</i>
</div>
</li>
<li @click="dashboard='all'">
<div class="block-title">{{$L('待完成任务')}}</div>
<li @click="scrollTo('all')">
<div class="block-title">{{getTitle('all')}}</div>
<div class="block-data">
<div class="block-num">{{dashboardTask.all.length}}</div>
<i class="taskfont">&#xe6f9;</i>
</div>
</li>
</ul>
<template v-if="list.length > 0">
<div class="dashboard-title">{{title}}</div>
<ul class="dashboard-list overlay-y">
<li
v-for="(item, index) in list"
:key="index"
:class="{complete: item.complete_at}"
:style="item.color ? {backgroundColor: item.color} : {}"
@click="openTask(item)">
<em
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 class="dashboard-list overlay-y">
<div
:ref="`type_${column.type}`"
v-for="(column, index) in columns"
v-if="column.list.length > 0"
:key="index">
<div class="dashboard-title">{{column.title}}</div>
<ul class="dashboard-li">
<li
v-for="(item, index) in column.list"
:key="index"
:class="{complete: item.complete_at}"
:style="item.color ? {backgroundColor: item.color} : {}"
@click="openTask(item)">
<em
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>
</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 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 v-if="item.desc" class="item-icon">
<i class="taskfont">&#xe71a;</i>
</div>
</ETooltip>
</li>
</ul>
</template>
<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>
</ETooltip>
</li>
</ul>
</div>
</div>
</div>
</div>
</template>
@ -110,13 +116,34 @@ export default {
},
computed: {
...mapState(['userInfo', 'cacheProjects', 'taskId']),
...mapState(['userInfo']),
...mapGetters(['dashboardTask', 'transforTasks']),
title() {
const {dashboard} = this;
switch (dashboard) {
columns() {
let list = [];
['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':
return this.$L('今日任务');
case 'overdue':
@ -128,27 +155,20 @@ export default {
}
},
list() {
const {dashboard} = this;
let data = [];
switch (dashboard) {
case 'today':
data = this.transforTasks(this.dashboardTask.today);
break
case 'overdue':
data = this.transforTasks(this.dashboardTask.overdue);
break
case 'all':
data = this.transforTasks(this.dashboardTask.all);
break
scrollTo(type) {
try {
this.$refs[`type_${type}`][0].scrollIntoView({
behavior: 'instant',
inline: 'end',
});
} catch (e) {
scrollIntoView(this.$refs[`type_${type}`][0], {
behavior: 'instant',
inline: 'end',
})
}
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) {
this.$store.dispatch("openTask", task)
},

View File

@ -5,13 +5,22 @@
flex-direction: column;
align-items: center;
justify-content: center;
background-color: #ffffff;
.dashboard-wrapper {
width: 664px;
max-width: 80%;
width: 100%;
max-height: 80%;
margin-bottom: 2%;
display: flex;
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 {
padding: 0 12px;
color: #333333;
@ -41,10 +50,7 @@
flex-direction: column;
justify-content: center;
cursor: pointer;
transition: box-shadow 0.3s;
&:hover {
box-shadow: 0 0 10px #cccccc;
}
transition: transform 0.5s ease-out 0s, box-shadow 0.3s ease-out 0s;
&:first-child {
background-color: #6f9ef6;
}
@ -52,6 +58,16 @@
background-color: #98de6e;
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 {
color: rgba(255, 255, 255, 0.6);
font-size: 12px;
@ -74,114 +90,130 @@
}
}
}
.dashboard-title {
margin-top: 60px;
padding: 0 12px;
font-weight: 600;
font-size: 15px;
}
.dashboard-list {
margin-top: 4px;
padding: 0 12px;
width: 100%;
margin-top: 48px;
overflow: auto;
> li {
position: relative;
list-style: none;
display: flex;
background: #F9FAFB;
margin-top: 12px;
padding: 8px 12px;
border-radius: 6px;
cursor: pointer;
transition: box-shadow 0.3s;
&:hover {
box-shadow: 0 0 6px #dfdfdf;
}
&:last-child {
margin-bottom: 12px;
}
&.complete {
.dashboard-title {
position: sticky;
top: 0;
z-index: 1;
margin: 0 auto;
padding: 0 12px;
height: 46px;
line-height: 46px;
font-weight: 600;
font-size: 15px;
background-color: #ffffff;
}
.dashboard-li {
margin: 0 auto;
padding: 0 12px;
overflow: hidden;
> 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 {
opacity: 0.5;
text-decoration: line-through;
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: 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 {
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 {
display: flex;
align-items: center;
font-size: 13px;
}
> em {
font-style: normal;
margin-left: 4px;
}
&.overdue {
color: #ed4014;
}
&.today {
color: #ff9900;
margin-left: 16px;
height: 22px;
color: #aaaaaa;
cursor: pointer;
.taskfont {
font-size: 13px;
}
> em {
font-style: normal;
margin-left: 4px;
}
&.overdue {
color: #ed4014;
}
&.today {
color: #ff9900;
}
}
}
}
@ -217,8 +249,14 @@
.page-dashboard {
.dashboard-wrapper {
display: block;
max-width: 86%;
max-height: 86%;
.dashboard-hello,
.dashboard-desc ,
.dashboard-block ,
.dashboard-list .dashboard-title,
.dashboard-list .dashboard-li {
max-width: 86%;
}
.dashboard-block {
display: block;
margin-top: 10px;
@ -227,16 +265,17 @@
padding: 8px 12px;
}
}
.dashboard-title {
margin-top: 36px;
}
.dashboard-list {
padding-bottom: 22px;
> li {
.item-title {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap
overflow: visible !important;
padding-bottom: 2px;
> ul {
margin-bottom: 36px;
> li {
.item-title {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap
}
}
}
}