mirror of
https://github.com/kuaifan/dootask.git
synced 2026-01-05 20:10:26 +00:00
perf: 优化项目面板
This commit is contained in:
parent
a1ce6e6928
commit
783c21ad18
@ -81,7 +81,7 @@
|
||||
</div>
|
||||
<div class="project-switch">
|
||||
<div v-if="completedCount > 0" class="project-checkbox">
|
||||
<Checkbox :value="projectData.cacheParameter.completedTask" @on-change="toggleCompleted">{{$L('显示已完成')}}</Checkbox>
|
||||
<Checkbox :value="projectData.cacheParameter.completedTask" @on-change="toggleParameter('completedTask')">{{$L('显示已完成')}}</Checkbox>
|
||||
</div>
|
||||
<div class="project-select">
|
||||
<Cascader ref="flow" :data="flowData" @on-change="flowChange" transfer-class-name="project-panel-flow-cascader" transfer>
|
||||
@ -249,7 +249,12 @@
|
||||
</li>
|
||||
</Draggable>
|
||||
</div>
|
||||
<Scrollbar v-else-if="tabTypeActive === 'table'" class="project-table" enable-x>
|
||||
<Scrollbar
|
||||
v-else-if="tabTypeActive === 'table'"
|
||||
ref="projectTableScroll"
|
||||
class="project-table"
|
||||
enable-x
|
||||
@on-scroll="handleTaskScroll">
|
||||
<div class="project-table-head">
|
||||
<Row class="task-row">
|
||||
<Col span="12">
|
||||
@ -294,7 +299,13 @@
|
||||
<Col span="3"></Col>
|
||||
<Col span="3"></Col>
|
||||
</Row>
|
||||
<TaskRow v-if="projectData.cacheParameter.showMy" :list="transforTasks(myList)" open-key="my" @on-priority="addTaskOpen" fast-add-task/>
|
||||
<TaskRow
|
||||
v-if="projectData.cacheParameter.showMy"
|
||||
:list="transforTasks(myList)"
|
||||
:task-visibilitys="taskRowVisibilitys"
|
||||
open-key="my"
|
||||
@on-priority="addTaskOpen"
|
||||
fast-add-task/>
|
||||
</div>
|
||||
<!--协助的任务-->
|
||||
<div v-if="helpList.length" :class="['project-table-body', !projectData.cacheParameter.showHelp ? 'project-table-hide' : '']">
|
||||
@ -309,7 +320,12 @@
|
||||
<Col span="3"></Col>
|
||||
<Col span="3"></Col>
|
||||
</Row>
|
||||
<TaskRow v-if="projectData.cacheParameter.showHelp" :list="helpList" open-key="help" @on-priority="addTaskOpen"/>
|
||||
<TaskRow
|
||||
v-if="projectData.cacheParameter.showHelp"
|
||||
:list="helpList"
|
||||
:task-visibilitys="taskRowVisibilitys"
|
||||
open-key="help"
|
||||
@on-priority="addTaskOpen"/>
|
||||
</div>
|
||||
<!--未完成任务-->
|
||||
<div v-if="projectData.task_num > 0" :class="['project-table-body', !projectData.cacheParameter.showUndone ? 'project-table-hide' : '']">
|
||||
@ -324,7 +340,12 @@
|
||||
<Col span="3"></Col>
|
||||
<Col span="3"></Col>
|
||||
</Row>
|
||||
<TaskRow v-if="projectData.cacheParameter.showUndone" :list="unList" open-key="undone" @on-priority="addTaskOpen"/>
|
||||
<TaskRow
|
||||
v-if="projectData.cacheParameter.showUndone"
|
||||
:list="unList"
|
||||
:task-visibilitys="taskRowVisibilitys"
|
||||
open-key="undone"
|
||||
@on-priority="addTaskOpen"/>
|
||||
</div>
|
||||
<!--已完成任务-->
|
||||
<div v-if="projectData.task_num > 0" :class="['project-table-body', !projectData.cacheParameter.showCompleted ? 'project-table-hide' : '']">
|
||||
@ -341,7 +362,13 @@
|
||||
<div class="ellipsis">{{projectData.task_num > 0 && projectData.cacheParameter.showCompleted ? $L('完成时间') : ''}}</div>
|
||||
</Col>
|
||||
</Row>
|
||||
<TaskRow v-if="projectData.cacheParameter.showCompleted" :list="completedList" open-key="completed" @on-priority="addTaskOpen" showCompleteAt/>
|
||||
<TaskRow
|
||||
v-if="projectData.cacheParameter.showCompleted"
|
||||
:list="completedList"
|
||||
:task-visibilitys="taskRowVisibilitys"
|
||||
open-key="completed"
|
||||
@on-priority="addTaskOpen"
|
||||
showCompleteAt/>
|
||||
</div>
|
||||
</Scrollbar>
|
||||
<div v-else-if="tabTypeActive === 'gantt'" class="project-gantt">
|
||||
@ -624,8 +651,9 @@ export default {
|
||||
flowInfo: {},
|
||||
flowList: [],
|
||||
|
||||
columnVisibility: {},
|
||||
taskVisibility: {},
|
||||
columnVisibilitys: {},
|
||||
taskVisibilitys: {},
|
||||
taskRowVisibilitys: {},
|
||||
}
|
||||
},
|
||||
|
||||
@ -971,6 +999,21 @@ export default {
|
||||
},
|
||||
|
||||
watch: {
|
||||
projectId: {
|
||||
handler(id) {
|
||||
if (id > 0) {
|
||||
this.getFlowData();
|
||||
this.handleColumnDebounce();
|
||||
}
|
||||
},
|
||||
immediate: true,
|
||||
},
|
||||
'allTask.length'() {
|
||||
this.handleColumnDebounce();
|
||||
},
|
||||
windowWidth() {
|
||||
this.handleColumnDebounce();
|
||||
},
|
||||
projectData() {
|
||||
this.sortData = this.getSort();
|
||||
},
|
||||
@ -984,24 +1027,6 @@ export default {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
projectId: {
|
||||
handler(val) {
|
||||
if (val > 0) {
|
||||
this.getFlowData();
|
||||
this.handleColumnDebounce();
|
||||
}
|
||||
},
|
||||
immediate: true,
|
||||
},
|
||||
'allTask.length'() {
|
||||
this.handleColumnDebounce();
|
||||
},
|
||||
'projectData.cacheParameter.completedTask'() {
|
||||
this.handleColumnDebounce();
|
||||
},
|
||||
windowWidth() {
|
||||
this.handleColumnDebounce();
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
@ -1507,8 +1532,9 @@ export default {
|
||||
});
|
||||
},
|
||||
|
||||
flowChange(value, data) {
|
||||
flowChange(_, data) {
|
||||
this.flowInfo = data.pop() || {};
|
||||
this.handleColumnDebounce();
|
||||
},
|
||||
|
||||
inviteCopy() {
|
||||
@ -1525,10 +1551,6 @@ export default {
|
||||
});
|
||||
},
|
||||
|
||||
toggleCompleted() {
|
||||
this.toggleParameter('completedTask');
|
||||
},
|
||||
|
||||
workflowBeforeClose() {
|
||||
return new Promise(resolve => {
|
||||
if (!this.$refs.workflow) {
|
||||
@ -1629,15 +1651,16 @@ export default {
|
||||
},
|
||||
|
||||
toggleParameter(data) {
|
||||
if (data === 'completedTask') {
|
||||
this.$store.dispatch("forgetTaskCompleteTemp", true);
|
||||
} else if (data === 'chat') {
|
||||
if (data === 'chat') {
|
||||
if (this.windowPortrait) {
|
||||
this.$store.dispatch('openDialog', this.projectData.dialog_id)
|
||||
return;
|
||||
}
|
||||
} else if (data === 'completedTask') {
|
||||
this.$store.dispatch("forgetTaskCompleteTemp", true);
|
||||
}
|
||||
this.$store.dispatch('toggleProjectParameter', data);
|
||||
this.handleColumnDebounce();
|
||||
},
|
||||
|
||||
onBack() {
|
||||
@ -1654,7 +1677,7 @@ export default {
|
||||
},
|
||||
|
||||
taskItemVisible({id, column_id}) {
|
||||
return this.columnVisibility[column_id] && this.taskVisibility[id]?.visible
|
||||
return this.columnVisibilitys[column_id] && this.taskVisibilitys[id]?.visible
|
||||
},
|
||||
|
||||
taskItemStyle({id, column_id, color}) {
|
||||
@ -1663,7 +1686,7 @@ export default {
|
||||
style.backgroundColor = color;
|
||||
}
|
||||
if (!this.taskItemVisible({id, column_id})) {
|
||||
style.height = (this.taskVisibility[id]?.height || 146) + 'px';
|
||||
style.height = (this.taskVisibilitys[id]?.height || 146) + 'px';
|
||||
}
|
||||
return style;
|
||||
},
|
||||
@ -1671,9 +1694,16 @@ export default {
|
||||
handleColumnDebounce() {
|
||||
if (!this.columnDebounceInvoke) {
|
||||
this.columnDebounceInvoke = debounce(_ => {
|
||||
if (this.tabTypeActive === 'column') {
|
||||
this.$nextTick(this.handleColumnScroll)
|
||||
}
|
||||
this.$nextTick(_ => {
|
||||
switch (this.tabTypeActive) {
|
||||
case 'column':
|
||||
this.handleColumnScroll()
|
||||
break;
|
||||
case 'table':
|
||||
this.handleTaskScroll({target: this.$refs.projectTableScroll?.$el})
|
||||
break;
|
||||
}
|
||||
})
|
||||
}, 10);
|
||||
}
|
||||
this.columnDebounceInvoke();
|
||||
@ -1690,8 +1720,8 @@ export default {
|
||||
if (!columnContainer) {
|
||||
return
|
||||
}
|
||||
const columnId = parseInt(columnContainer.getAttribute('data-id'))
|
||||
if (!columnId) {
|
||||
const dataId = columnContainer.getAttribute('data-id')
|
||||
if (!dataId) {
|
||||
return
|
||||
}
|
||||
const mainContainer = this.$refs.projectColumn;
|
||||
@ -1711,11 +1741,9 @@ export default {
|
||||
columnRect.bottom > mainRect.top
|
||||
)
|
||||
if (visible) {
|
||||
this.handleTaskScroll({
|
||||
target: columnContainer.querySelector('.task-scrollbar')
|
||||
})
|
||||
this.handleTaskScroll({target: columnContainer.querySelector('.task-scrollbar')})
|
||||
}
|
||||
this.$set(this.columnVisibility, columnId, visible)
|
||||
this.$set(this.columnVisibilitys, dataId, visible)
|
||||
},
|
||||
|
||||
async handleTaskScroll({target}) {
|
||||
@ -1726,14 +1754,25 @@ export default {
|
||||
if (!targetItem.length) {
|
||||
return
|
||||
}
|
||||
let visibleType = null;
|
||||
switch (this.tabTypeActive) {
|
||||
case 'column':
|
||||
visibleType = 'taskVisibilitys'
|
||||
break;
|
||||
case 'table':
|
||||
visibleType = 'taskRowVisibilitys'
|
||||
break;
|
||||
default:
|
||||
return
|
||||
}
|
||||
const targetRect = target.getBoundingClientRect();
|
||||
for (const item of targetItem) {
|
||||
const taskId = parseInt(item.getAttribute('data-id'));
|
||||
if (!taskId) {
|
||||
const dataId = item.getAttribute('data-id');
|
||||
if (!dataId) {
|
||||
continue;
|
||||
}
|
||||
const taskRect = item.getBoundingClientRect();
|
||||
const originalVisible = this.taskVisibility[taskId]?.visible || false;
|
||||
const originalVisible = this[visibleType][dataId]?.visible || false;
|
||||
const currentVisible = (
|
||||
taskRect.top >= targetRect.top - taskRect.height &&
|
||||
taskRect.bottom <= targetRect.bottom + taskRect.height
|
||||
@ -1741,8 +1780,8 @@ export default {
|
||||
if (currentVisible === originalVisible) {
|
||||
continue;
|
||||
}
|
||||
const firstVisible = this.taskVisibility[taskId] === undefined && currentVisible;
|
||||
this.$set(this.taskVisibility, taskId, {
|
||||
const firstVisible = this[visibleType][dataId] === undefined && currentVisible;
|
||||
this.$set(this[visibleType], dataId, {
|
||||
visible: currentVisible,
|
||||
height: taskRect.height
|
||||
});
|
||||
@ -1750,7 +1789,7 @@ export default {
|
||||
await this.$nextTick();
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -1,98 +1,107 @@
|
||||
<template>
|
||||
<div class="task-rows">
|
||||
<div v-for="(item, key) in list" :key="key" :ref="`task_${item.id}`">
|
||||
<Row class="task-row" :style="item.color ? {backgroundColor: item.color, borderBottomColor: item.color} : {}">
|
||||
<em v-if="item.p_name" class="priority-color" :style="{backgroundColor:item.p_color}"></em>
|
||||
<Col span="12" :class="['row-name', item.complete_at ? 'complete' : '']">
|
||||
<Icon
|
||||
v-if="(item.sub_num > 0 && item.sub_top !== true) || (item.parent_id === 0 && fastAddTask)"
|
||||
:class="['sub-icon', taskOpen[item.id] ? 'active' : '']"
|
||||
type="ios-arrow-forward"
|
||||
@click="getSublist(item)"/>
|
||||
<TaskMenu :ref="`taskMenu_${item.id}`" :task="item"/>
|
||||
<div class="item-title" @click="openTask(item)">
|
||||
<!--工作流状态-->
|
||||
<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 class="item-icons" @click="openTask(item)">
|
||||
<div v-if="item.desc" class="item-icon">
|
||||
<i class="taskfont"></i>
|
||||
<div
|
||||
v-for="(item, key) in list"
|
||||
:key="key"
|
||||
:ref="`task_${item.id}`"
|
||||
:data-id="`${openKey}_${item.id}`"
|
||||
class="task-item">
|
||||
<Row
|
||||
class="task-row"
|
||||
:style="taskItemStyle(item)">
|
||||
<template v-if="taskItemVisible(`${openKey}_${item.id}`)">
|
||||
<em v-if="item.p_name" class="priority-color" :style="{backgroundColor:item.p_color}"></em>
|
||||
<Col span="12" :class="['row-name', item.complete_at ? 'complete' : '']">
|
||||
<Icon
|
||||
v-if="(item.sub_num > 0 && item.sub_top !== true) || (item.parent_id === 0 && fastAddTask)"
|
||||
:class="['sub-icon', taskOpen[item.id] ? 'active' : '']"
|
||||
type="ios-arrow-forward"
|
||||
@click="getSublist(item)"/>
|
||||
<TaskMenu :ref="`taskMenu_${item.id}`" :task="item"/>
|
||||
<div class="item-title" @click="openTask(item)">
|
||||
<!--工作流状态-->
|
||||
<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.file_num > 0" class="item-icon">
|
||||
<i class="taskfont"></i>
|
||||
<em>{{item.file_num}}</em>
|
||||
<div class="item-icons" @click="openTask(item)">
|
||||
<div v-if="item.desc" class="item-icon">
|
||||
<i class="taskfont"></i>
|
||||
</div>
|
||||
<div v-if="item.file_num > 0" class="item-icon">
|
||||
<i class="taskfont"></i>
|
||||
<em>{{item.file_num}}</em>
|
||||
</div>
|
||||
<div v-if="item.msg_num > 0" class="item-icon">
|
||||
<i class="taskfont"></i>
|
||||
<em>{{item.msg_num}}</em>
|
||||
</div>
|
||||
<div v-if="item.sub_num > 0" class="item-icon" @click.stop="getSublist(item)">
|
||||
<i class="taskfont"></i>
|
||||
<em>{{item.sub_complete}}/{{item.sub_num}}</em>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="item.msg_num > 0" class="item-icon">
|
||||
<i class="taskfont"></i>
|
||||
<em>{{item.msg_num}}</em>
|
||||
</div>
|
||||
<div v-if="item.sub_num > 0" class="item-icon" @click.stop="getSublist(item)">
|
||||
<i class="taskfont"></i>
|
||||
<em>{{item.sub_complete}}/{{item.sub_num}}</em>
|
||||
</div>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span="3" class="row-column">
|
||||
<EDropdown
|
||||
trigger="click"
|
||||
size="small"
|
||||
placement="bottom"
|
||||
:disabled="item.sub_top === true"
|
||||
@command="dropTask(item, $event)">
|
||||
<div class="task-column">{{columnName(item.column_id)}}</div>
|
||||
<EDropdownMenu slot="dropdown">
|
||||
<EDropdownItem v-for="column in columnList(item.project_id)" :key="column.id" :command="'column::' + column.id">
|
||||
{{column.name}}
|
||||
</EDropdownItem>
|
||||
</EDropdownMenu>
|
||||
</EDropdown>
|
||||
</Col>
|
||||
<Col span="3" class="row-priority">
|
||||
<EDropdown
|
||||
trigger="click"
|
||||
size="small"
|
||||
placement="bottom"
|
||||
:disabled="item.sub_top === true"
|
||||
@command="dropTask(item, $event)">
|
||||
<TaskPriority :backgroundColor="item.p_color">{{item.p_name || $L('未设置')}}</TaskPriority>
|
||||
<EDropdownMenu slot="dropdown">
|
||||
<EDropdownItem v-for="(item, key) in taskPriority" :key="key" :command="'priority::' + key">
|
||||
<i
|
||||
class="taskfont"
|
||||
:style="{color:item.color}"
|
||||
v-html="item.p_name == item.name ? '' : ''"></i>
|
||||
{{item.name}}
|
||||
</EDropdownItem>
|
||||
</EDropdownMenu>
|
||||
</EDropdown>
|
||||
</Col>
|
||||
<Col span="3" class="row-user">
|
||||
<ul @click="openTask(item)">
|
||||
<li v-for="(user, keyu) in ownerUser(item.task_user)" :key="keyu" v-if="keyu < 3">
|
||||
<UserAvatar :userid="user.userid" size="32" :borderWitdh="2" :borderColor="item.color" :showName="ownerUser(item.task_user).length === 1"/>
|
||||
</li>
|
||||
<li v-if="ownerUser(item.task_user).length === 0" class="no-owner">
|
||||
<Button type="primary" size="small" @click.stop="openTask(item, true)">{{$L('领取任务')}}</Button>
|
||||
</li>
|
||||
</ul>
|
||||
</Col>
|
||||
<Col span="3" class="row-time">
|
||||
<ETooltip
|
||||
v-if="!item.complete_at && item.end_at"
|
||||
:class="['task-time', item.today ? 'today' : '', item.overdue ? 'overdue' : '']"
|
||||
:disabled="$isEEUiApp || windowTouch"
|
||||
:open-delay="600"
|
||||
:content="item.end_at">
|
||||
<div @click="openTask(item)">{{expiresFormat(item.end_at)}}</div>
|
||||
</ETooltip>
|
||||
<div v-else-if="showCompleteAt && item.complete_at" :title="item.complete_at">{{completeAtFormat(item.complete_at)}}</div>
|
||||
</Col>
|
||||
</Col>
|
||||
<Col span="3" class="row-column">
|
||||
<EDropdown
|
||||
trigger="click"
|
||||
size="small"
|
||||
placement="bottom"
|
||||
:disabled="item.sub_top === true"
|
||||
@command="dropTask(item, $event)">
|
||||
<div class="task-column">{{columnName(item.column_id)}}</div>
|
||||
<EDropdownMenu slot="dropdown">
|
||||
<EDropdownItem v-for="column in columnList(item.project_id)" :key="column.id" :command="'column::' + column.id">
|
||||
{{column.name}}
|
||||
</EDropdownItem>
|
||||
</EDropdownMenu>
|
||||
</EDropdown>
|
||||
</Col>
|
||||
<Col span="3" class="row-priority">
|
||||
<EDropdown
|
||||
trigger="click"
|
||||
size="small"
|
||||
placement="bottom"
|
||||
:disabled="item.sub_top === true"
|
||||
@command="dropTask(item, $event)">
|
||||
<TaskPriority :backgroundColor="item.p_color">{{item.p_name || $L('未设置')}}</TaskPriority>
|
||||
<EDropdownMenu slot="dropdown">
|
||||
<EDropdownItem v-for="(item, key) in taskPriority" :key="key" :command="'priority::' + key">
|
||||
<i
|
||||
class="taskfont"
|
||||
:style="{color:item.color}"
|
||||
v-html="item.p_name == item.name ? '' : ''"></i>
|
||||
{{item.name}}
|
||||
</EDropdownItem>
|
||||
</EDropdownMenu>
|
||||
</EDropdown>
|
||||
</Col>
|
||||
<Col span="3" class="row-user">
|
||||
<ul @click="openTask(item)">
|
||||
<li v-for="(user, keyu) in ownerUser(item.task_user)" :key="keyu" v-if="keyu < 3">
|
||||
<UserAvatar :userid="user.userid" size="32" :borderWitdh="2" :borderColor="item.color" :showName="ownerUser(item.task_user).length === 1"/>
|
||||
</li>
|
||||
<li v-if="ownerUser(item.task_user).length === 0" class="no-owner">
|
||||
<Button type="primary" size="small" @click.stop="openTask(item, true)">{{$L('领取任务')}}</Button>
|
||||
</li>
|
||||
</ul>
|
||||
</Col>
|
||||
<Col span="3" class="row-time">
|
||||
<ETooltip
|
||||
v-if="!item.complete_at && item.end_at"
|
||||
:class="['task-time', item.today ? 'today' : '', item.overdue ? 'overdue' : '']"
|
||||
:disabled="$isEEUiApp || windowTouch"
|
||||
:open-delay="600"
|
||||
:content="item.end_at">
|
||||
<div @click="openTask(item)">{{expiresFormat(item.end_at)}}</div>
|
||||
</ETooltip>
|
||||
<div v-else-if="showCompleteAt && item.complete_at" :title="item.complete_at">{{completeAtFormat(item.complete_at)}}</div>
|
||||
</Col>
|
||||
</template>
|
||||
</Row>
|
||||
<TaskRow
|
||||
v-if="taskOpen[item.id]===true"
|
||||
@ -139,6 +148,10 @@ export default {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
taskVisibilitys: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@ -279,6 +292,23 @@ export default {
|
||||
} else {
|
||||
return time.format('YYYY-MM-DD')
|
||||
}
|
||||
},
|
||||
|
||||
taskItemVisible(key) {
|
||||
return this.parentId > 0 || this.taskVisibilitys[key]?.visible
|
||||
},
|
||||
|
||||
taskItemStyle({id, color}) {
|
||||
const style = {}
|
||||
if (color) {
|
||||
style.backgroundColor = color;
|
||||
style.borderBottomColor = color;
|
||||
}
|
||||
const key = `${this.openKey}_${id}`;
|
||||
if (!this.taskItemVisible(key)) {
|
||||
style.height = (this.taskVisibilitys[key]?.height || 49) + 'px';
|
||||
}
|
||||
return style;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user