perf: 优化项目面板

This commit is contained in:
kuaifan 2024-12-15 22:27:05 +08:00
parent a1ce6e6928
commit 783c21ad18
2 changed files with 211 additions and 142 deletions

View File

@ -81,7 +81,7 @@
</div> </div>
<div class="project-switch"> <div class="project-switch">
<div v-if="completedCount > 0" class="project-checkbox"> <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>
<div class="project-select"> <div class="project-select">
<Cascader ref="flow" :data="flowData" @on-change="flowChange" transfer-class-name="project-panel-flow-cascader" transfer> <Cascader ref="flow" :data="flowData" @on-change="flowChange" transfer-class-name="project-panel-flow-cascader" transfer>
@ -249,7 +249,12 @@
</li> </li>
</Draggable> </Draggable>
</div> </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"> <div class="project-table-head">
<Row class="task-row"> <Row class="task-row">
<Col span="12"> <Col span="12">
@ -294,7 +299,13 @@
<Col span="3"></Col> <Col span="3"></Col>
<Col span="3"></Col> <Col span="3"></Col>
</Row> </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>
<!--协助的任务--> <!--协助的任务-->
<div v-if="helpList.length" :class="['project-table-body', !projectData.cacheParameter.showHelp ? 'project-table-hide' : '']"> <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>
<Col span="3"></Col> <Col span="3"></Col>
</Row> </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>
<!--未完成任务--> <!--未完成任务-->
<div v-if="projectData.task_num > 0" :class="['project-table-body', !projectData.cacheParameter.showUndone ? 'project-table-hide' : '']"> <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>
<Col span="3"></Col> <Col span="3"></Col>
</Row> </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>
<!--已完成任务--> <!--已完成任务-->
<div v-if="projectData.task_num > 0" :class="['project-table-body', !projectData.cacheParameter.showCompleted ? 'project-table-hide' : '']"> <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> <div class="ellipsis">{{projectData.task_num > 0 && projectData.cacheParameter.showCompleted ? $L('完成时间') : ''}}</div>
</Col> </Col>
</Row> </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> </div>
</Scrollbar> </Scrollbar>
<div v-else-if="tabTypeActive === 'gantt'" class="project-gantt"> <div v-else-if="tabTypeActive === 'gantt'" class="project-gantt">
@ -624,8 +651,9 @@ export default {
flowInfo: {}, flowInfo: {},
flowList: [], flowList: [],
columnVisibility: {}, columnVisibilitys: {},
taskVisibility: {}, taskVisibilitys: {},
taskRowVisibilitys: {},
} }
}, },
@ -971,6 +999,21 @@ export default {
}, },
watch: { watch: {
projectId: {
handler(id) {
if (id > 0) {
this.getFlowData();
this.handleColumnDebounce();
}
},
immediate: true,
},
'allTask.length'() {
this.handleColumnDebounce();
},
windowWidth() {
this.handleColumnDebounce();
},
projectData() { projectData() {
this.sortData = this.getSort(); this.sortData = this.getSort();
}, },
@ -984,24 +1027,6 @@ export default {
this.loading = false; 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: { methods: {
@ -1507,8 +1532,9 @@ export default {
}); });
}, },
flowChange(value, data) { flowChange(_, data) {
this.flowInfo = data.pop() || {}; this.flowInfo = data.pop() || {};
this.handleColumnDebounce();
}, },
inviteCopy() { inviteCopy() {
@ -1525,10 +1551,6 @@ export default {
}); });
}, },
toggleCompleted() {
this.toggleParameter('completedTask');
},
workflowBeforeClose() { workflowBeforeClose() {
return new Promise(resolve => { return new Promise(resolve => {
if (!this.$refs.workflow) { if (!this.$refs.workflow) {
@ -1629,15 +1651,16 @@ export default {
}, },
toggleParameter(data) { toggleParameter(data) {
if (data === 'completedTask') { if (data === 'chat') {
this.$store.dispatch("forgetTaskCompleteTemp", true);
} else if (data === 'chat') {
if (this.windowPortrait) { if (this.windowPortrait) {
this.$store.dispatch('openDialog', this.projectData.dialog_id) this.$store.dispatch('openDialog', this.projectData.dialog_id)
return; return;
} }
} else if (data === 'completedTask') {
this.$store.dispatch("forgetTaskCompleteTemp", true);
} }
this.$store.dispatch('toggleProjectParameter', data); this.$store.dispatch('toggleProjectParameter', data);
this.handleColumnDebounce();
}, },
onBack() { onBack() {
@ -1654,7 +1677,7 @@ export default {
}, },
taskItemVisible({id, column_id}) { 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}) { taskItemStyle({id, column_id, color}) {
@ -1663,7 +1686,7 @@ export default {
style.backgroundColor = color; style.backgroundColor = color;
} }
if (!this.taskItemVisible({id, column_id})) { if (!this.taskItemVisible({id, column_id})) {
style.height = (this.taskVisibility[id]?.height || 146) + 'px'; style.height = (this.taskVisibilitys[id]?.height || 146) + 'px';
} }
return style; return style;
}, },
@ -1671,9 +1694,16 @@ export default {
handleColumnDebounce() { handleColumnDebounce() {
if (!this.columnDebounceInvoke) { if (!this.columnDebounceInvoke) {
this.columnDebounceInvoke = debounce(_ => { this.columnDebounceInvoke = debounce(_ => {
if (this.tabTypeActive === 'column') { this.$nextTick(_ => {
this.$nextTick(this.handleColumnScroll) switch (this.tabTypeActive) {
case 'column':
this.handleColumnScroll()
break;
case 'table':
this.handleTaskScroll({target: this.$refs.projectTableScroll?.$el})
break;
} }
})
}, 10); }, 10);
} }
this.columnDebounceInvoke(); this.columnDebounceInvoke();
@ -1690,8 +1720,8 @@ export default {
if (!columnContainer) { if (!columnContainer) {
return return
} }
const columnId = parseInt(columnContainer.getAttribute('data-id')) const dataId = columnContainer.getAttribute('data-id')
if (!columnId) { if (!dataId) {
return return
} }
const mainContainer = this.$refs.projectColumn; const mainContainer = this.$refs.projectColumn;
@ -1711,11 +1741,9 @@ export default {
columnRect.bottom > mainRect.top columnRect.bottom > mainRect.top
) )
if (visible) { if (visible) {
this.handleTaskScroll({ this.handleTaskScroll({target: columnContainer.querySelector('.task-scrollbar')})
target: columnContainer.querySelector('.task-scrollbar')
})
} }
this.$set(this.columnVisibility, columnId, visible) this.$set(this.columnVisibilitys, dataId, visible)
}, },
async handleTaskScroll({target}) { async handleTaskScroll({target}) {
@ -1726,14 +1754,25 @@ export default {
if (!targetItem.length) { if (!targetItem.length) {
return return
} }
let visibleType = null;
switch (this.tabTypeActive) {
case 'column':
visibleType = 'taskVisibilitys'
break;
case 'table':
visibleType = 'taskRowVisibilitys'
break;
default:
return
}
const targetRect = target.getBoundingClientRect(); const targetRect = target.getBoundingClientRect();
for (const item of targetItem) { for (const item of targetItem) {
const taskId = parseInt(item.getAttribute('data-id')); const dataId = item.getAttribute('data-id');
if (!taskId) { if (!dataId) {
continue; continue;
} }
const taskRect = item.getBoundingClientRect(); const taskRect = item.getBoundingClientRect();
const originalVisible = this.taskVisibility[taskId]?.visible || false; const originalVisible = this[visibleType][dataId]?.visible || false;
const currentVisible = ( const currentVisible = (
taskRect.top >= targetRect.top - taskRect.height && taskRect.top >= targetRect.top - taskRect.height &&
taskRect.bottom <= targetRect.bottom + taskRect.height taskRect.bottom <= targetRect.bottom + taskRect.height
@ -1741,8 +1780,8 @@ export default {
if (currentVisible === originalVisible) { if (currentVisible === originalVisible) {
continue; continue;
} }
const firstVisible = this.taskVisibility[taskId] === undefined && currentVisible; const firstVisible = this[visibleType][dataId] === undefined && currentVisible;
this.$set(this.taskVisibility, taskId, { this.$set(this[visibleType], dataId, {
visible: currentVisible, visible: currentVisible,
height: taskRect.height height: taskRect.height
}); });
@ -1750,7 +1789,7 @@ export default {
await this.$nextTick(); await this.$nextTick();
} }
} }
} },
} }
} }
</script> </script>

View File

@ -1,7 +1,15 @@
<template> <template>
<div class="task-rows"> <div class="task-rows">
<div v-for="(item, key) in list" :key="key" :ref="`task_${item.id}`"> <div
<Row class="task-row" :style="item.color ? {backgroundColor: item.color, borderBottomColor: item.color} : {}"> 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> <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' : '']"> <Col span="12" :class="['row-name', item.complete_at ? 'complete' : '']">
<Icon <Icon
@ -93,6 +101,7 @@
</ETooltip> </ETooltip>
<div v-else-if="showCompleteAt && item.complete_at" :title="item.complete_at">{{completeAtFormat(item.complete_at)}}</div> <div v-else-if="showCompleteAt && item.complete_at" :title="item.complete_at">{{completeAtFormat(item.complete_at)}}</div>
</Col> </Col>
</template>
</Row> </Row>
<TaskRow <TaskRow
v-if="taskOpen[item.id]===true" v-if="taskOpen[item.id]===true"
@ -139,6 +148,10 @@ export default {
type: Boolean, type: Boolean,
default: false default: false
}, },
taskVisibilitys: {
type: Object,
default: () => ({})
}
}, },
data() { data() {
return { return {
@ -279,6 +292,23 @@ export default {
} else { } else {
return time.format('YYYY-MM-DD') 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;
} }
} }
} }