mirror of
https://github.com/kuaifan/dootask.git
synced 2025-12-11 18:42:54 +00:00
308 lines
12 KiB
Vue
308 lines
12 KiB
Vue
<template>
|
|
<div class="page-dashboard">
|
|
<PageTitle :title="$L('仪表盘')"/>
|
|
<Alert v-if="warningMsg" class="dashboard-warning" type="warning" show-icon>
|
|
<span @click="goForward({name: 'manage-setting-license'})">{{warningMsg}}</span>
|
|
</Alert>
|
|
<div class="dashboard-wrapper" :style="wrapperStyle">
|
|
<div class="dashboard-hello">
|
|
<h2>{{dashboardHello}}</h2>
|
|
<div class="dashboard-search" :class="{'min-search': windowPortrait}" @click="openSearch">
|
|
<Icon type="ios-search"/>
|
|
<span>{{$L('搜索')}} ({{mateName}}+F)</span>
|
|
</div>
|
|
</div>
|
|
<div v-if="systemConfig.timezoneDifference" class="dashboard-time">
|
|
<span>{{$L('服务器时间')}}:</span>
|
|
<span>{{$A.daytz().format('YYYY-MM-DD HH:mm:ss')}}</span>
|
|
</div>
|
|
<div class="dashboard-desc">
|
|
<span>{{$L('以下是你当前的任务统计数据')}}</span>
|
|
<transition name="dashboard-load">
|
|
<div v-if="loadDashboardTasks" class="dashboard-load"><Loading/></div>
|
|
</transition>
|
|
</div>
|
|
<ul class="dashboard-block">
|
|
<li @click="scrollTo('today')">
|
|
<div class="block-title">{{getTitle('today')}}</div>
|
|
<div class="block-data">
|
|
<div class="block-num">{{dashboardTask.today_count}}</div>
|
|
<i class="taskfont"></i>
|
|
</div>
|
|
</li>
|
|
<li @click="scrollTo('overdue')">
|
|
<div class="block-title">{{getTitle('overdue')}}</div>
|
|
<div class="block-data">
|
|
<div class="block-num">{{dashboardTask.overdue_count}}</div>
|
|
<i class="taskfont"></i>
|
|
</div>
|
|
</li>
|
|
<li @click="scrollTo('todo')">
|
|
<div class="block-title">{{getTitle('todo')}}</div>
|
|
<div class="block-data">
|
|
<div class="block-num">{{dashboardTask.todo_count}}</div>
|
|
<i class="taskfont"></i>
|
|
</div>
|
|
</li>
|
|
</ul>
|
|
<Scrollbar class="dashboard-list">
|
|
<template
|
|
v-for="column in columns"
|
|
v-if="column.list.length > 0">
|
|
<div :ref="`type_${column.type}`" class="dashboard-ref"></div>
|
|
<div class="dashboard-title" :class="{'title-close': column.hidden}" @click="onDashboardHidden(column.type)">
|
|
<span>
|
|
{{column.title}}
|
|
<template v-if="column.hidden">
|
|
({{column.count}})
|
|
</template>
|
|
</span>
|
|
<i class="taskfont"></i>
|
|
</div>
|
|
<ul class="dashboard-ul" :class="{'ul-hidden': column.hidden}">
|
|
<li
|
|
v-for="(item, index) in column.list"
|
|
:key="index"
|
|
:class="{complete: item.complete_at}"
|
|
:style="$A.generateColorVarStyle(item.flow_item_color, [10], 'flow-item-custom-color', item.color ? {backgroundColor: item.color} : {})"
|
|
@click="openTask(item)">
|
|
<em
|
|
v-if="item.p_name"
|
|
class="priority-color"
|
|
:style="{backgroundColor:item.p_color}"></em>
|
|
<div class="item-select" @click.stop="openMenu($event, item)">
|
|
<i class="taskfont" v-html="item.complete_at ? '' : ''"></i>
|
|
</div>
|
|
<div class="item-title">
|
|
<!--工作流状态-->
|
|
<span v-if="item.flow_item_name" :class="item.flow_item_status" @click.stop="openMenu($event, 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"></i>
|
|
</div>
|
|
<div v-if="item.sub_num > 0" class="item-icon">
|
|
<i class="taskfont"></i>
|
|
<em>{{item.sub_complete}}/{{item.sub_num}}</em>
|
|
</div>
|
|
<ETooltip v-if="item.end_at" :disabled="$isEEUIApp || windowTouch" :content="item.end_at" placement="right">
|
|
<div :class="['item-icon', item.today ? 'today' : '', item.overdue ? 'overdue' : '']">
|
|
<i class="taskfont"></i>
|
|
<em>{{expiresFormat(item.end_at)}}</em>
|
|
</div>
|
|
</ETooltip>
|
|
</li>
|
|
</ul>
|
|
</template>
|
|
</Scrollbar>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import {mapGetters, mapState} from "vuex";
|
|
import TaskMenu from "./components/TaskMenu";
|
|
import emitter from "../../store/events";
|
|
|
|
const hiddenCaches = []
|
|
export default {
|
|
components: {TaskMenu},
|
|
data() {
|
|
return {
|
|
nowTime: $A.dayjs().unix(),
|
|
nowInter: null,
|
|
|
|
licenseTimer: null,
|
|
|
|
loadIng: 0,
|
|
dashboard: 'today',
|
|
|
|
mateName: /macintosh|mac os x/i.test(navigator.userAgent) ? '⌘' : 'Ctrl',
|
|
|
|
warningMsg: '',
|
|
|
|
hiddenColumns: hiddenCaches,
|
|
}
|
|
},
|
|
|
|
async beforeRouteEnter(to, from, next) {
|
|
hiddenCaches.push(...(await $A.IDBArray("dashboardHiddenColumns")))
|
|
next()
|
|
},
|
|
|
|
activated() {
|
|
this.$store.dispatch("getTaskForDashboard", 600);
|
|
this.loadInterval(true);
|
|
this.loadLicense(true);
|
|
},
|
|
|
|
deactivated() {
|
|
this.$store.dispatch("forgetTaskCompleteTemp", true);
|
|
this.loadInterval(false);
|
|
this.loadLicense(false);
|
|
},
|
|
|
|
computed: {
|
|
...mapState(['systemConfig', 'userInfo', 'userIsAdmin', 'cacheTasks', 'taskCompleteTemps', 'loadDashboardTasks']),
|
|
...mapGetters(['dashboardTask', 'assistTask', 'transforTasks']),
|
|
|
|
columns({hiddenColumns, dashboardTask, assistTask}) {
|
|
const list = [];
|
|
['today', 'overdue', 'todo'].some(type => {
|
|
let data = this.transforTasks(dashboardTask[type]);
|
|
list.push({
|
|
type,
|
|
title: this.getTitle(type),
|
|
hidden: hiddenColumns.includes(type),
|
|
count: dashboardTask[`${type}_count`],
|
|
list: data.sort((a, b) => {
|
|
return $A.sortDay(a.end_at || "2099-12-31 23:59:59", b.end_at || "2099-12-31 23:59:59");
|
|
})
|
|
})
|
|
})
|
|
list.push({
|
|
type: 'assist',
|
|
title: this.getTitle('assist'),
|
|
hidden: hiddenColumns.includes('assist'),
|
|
count: assistTask.length,
|
|
list: assistTask.sort((a, b) => {
|
|
return $A.sortDay(a.end_at || "2099-12-31 23:59:59", b.end_at || "2099-12-31 23:59:59");
|
|
})
|
|
})
|
|
return list;
|
|
},
|
|
|
|
total() {
|
|
const {dashboardTask} = this;
|
|
return dashboardTask.today_count + dashboardTask.overdue_count + dashboardTask.todo_count;
|
|
},
|
|
|
|
wrapperStyle({warningMsg}) {
|
|
return warningMsg ? {
|
|
'max-height': 'calc(100% - 50px)'
|
|
} : null
|
|
},
|
|
|
|
dashboardHello({systemConfig, userInfo}) {
|
|
let hello = '欢迎您,{username}';
|
|
if (systemConfig.system_welcome) {
|
|
hello = systemConfig.system_welcome
|
|
}
|
|
return this.$L(hello.replace(/\{username}/g, userInfo.nickname))
|
|
}
|
|
},
|
|
|
|
watch: {
|
|
windowActive(active) {
|
|
if (this.routeName !== 'manage-dashboard') {
|
|
return
|
|
}
|
|
this.loadInterval(active)
|
|
this.loadLicense(active)
|
|
if (active) {
|
|
this.$store.dispatch("getTaskForDashboard", 600)
|
|
}
|
|
}
|
|
},
|
|
|
|
methods: {
|
|
getTitle(type) {
|
|
switch (type) {
|
|
case 'today':
|
|
return this.$L('今日到期');
|
|
case 'overdue':
|
|
return this.$L('超期任务');
|
|
case 'todo':
|
|
return this.$L('待完成任务');
|
|
case 'assist':
|
|
return this.$L('协助的任务');
|
|
default:
|
|
return '';
|
|
}
|
|
},
|
|
|
|
scrollTo(type) {
|
|
const refs = this.$refs[`type_${type}`]
|
|
if (refs) {
|
|
const index = this.hiddenColumns.indexOf(type);
|
|
if (index !== -1) {
|
|
this.hiddenColumns.splice(index, 1)
|
|
}
|
|
this.$nextTick(_ => {
|
|
$A.scrollToView(refs[0], {
|
|
behavior: 'smooth',
|
|
inline: 'end',
|
|
});
|
|
})
|
|
}
|
|
},
|
|
|
|
onDashboardHidden(type) {
|
|
const index = this.hiddenColumns.indexOf(type);
|
|
if (index === -1) {
|
|
this.hiddenColumns.push(type)
|
|
} else {
|
|
this.hiddenColumns = this.hiddenColumns.filter(item => item !== type)
|
|
}
|
|
$A.IDBSave("dashboardHiddenColumns", this.hiddenColumns)
|
|
},
|
|
|
|
openSearch() {
|
|
emitter.emit('openSearch', null);
|
|
},
|
|
|
|
openTask(task) {
|
|
this.$store.dispatch("openTask", task)
|
|
},
|
|
|
|
openMenu(event, task) {
|
|
this.$store.state.taskOperation = {event, task}
|
|
},
|
|
|
|
expiresFormat(date) {
|
|
return $A.countDownFormat(this.nowTime, date)
|
|
},
|
|
|
|
loadInterval(load) {
|
|
if (this.nowInter) {
|
|
clearInterval(this.nowInter)
|
|
this.nowInter = null;
|
|
}
|
|
if (load === false) {
|
|
return
|
|
}
|
|
this.nowInter = setInterval(_ => {
|
|
this.nowTime = $A.dayjs().unix()
|
|
}, 1000)
|
|
},
|
|
|
|
loadLicense(load) {
|
|
if (this.licenseTimer) {
|
|
clearTimeout(this.licenseTimer)
|
|
this.licenseTimer = null;
|
|
}
|
|
if (load === false || !this.userIsAdmin) {
|
|
return
|
|
}
|
|
this.licenseTimer = setTimeout(_ => {
|
|
this.$store.dispatch("call", {
|
|
url: 'system/license',
|
|
data: {
|
|
type: 'error',
|
|
}
|
|
}).then(({data}) => {
|
|
this.warningMsg = data.error.length > 0 ? data.error[0] : '';
|
|
}).catch(_ => {
|
|
this.warningMsg = '';
|
|
})
|
|
}, 1500)
|
|
}
|
|
}
|
|
}
|
|
</script>
|