Merge 2745487987 into b866ba3f58
This commit is contained in:
commit
5eeb23cad7
|
|
@ -17,6 +17,14 @@
|
|||
:project-id="projectId"
|
||||
@update:modelValue="loadTasks()"
|
||||
/>
|
||||
<button
|
||||
class="collapse-all-btn"
|
||||
:class="{ 'is-collapsed': collapseAll }"
|
||||
@click="toggleCollapseAll"
|
||||
:title="collapseAll ? 'Expand all subtasks' : 'Collapse all subtasks'"
|
||||
>
|
||||
<Icon icon="chevron-down" />
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
@ -101,7 +109,7 @@
|
|||
|
||||
|
||||
<script setup lang="ts">
|
||||
import {ref, computed, nextTick, onMounted, onBeforeUnmount, watch, toRef} from 'vue'
|
||||
import {ref, computed, nextTick, onMounted, onBeforeUnmount, watch, toRef, provide} from 'vue'
|
||||
import draggable from 'zhyswan-vuedraggable'
|
||||
|
||||
import ProjectWrapper from '@/components/project/ProjectWrapper.vue'
|
||||
|
|
@ -143,6 +151,14 @@ const ctaVisible = ref(false)
|
|||
|
||||
const drag = ref(false)
|
||||
|
||||
// Collapse all subtasks
|
||||
const collapseAll = ref(false)
|
||||
provide('collapseAll', collapseAll)
|
||||
|
||||
function toggleCollapseAll() {
|
||||
collapseAll.value = !collapseAll.value
|
||||
}
|
||||
|
||||
const {
|
||||
tasks: allTasks,
|
||||
loading,
|
||||
|
|
@ -368,6 +384,32 @@ onBeforeUnmount(() => {
|
|||
}
|
||||
}
|
||||
|
||||
.collapse-all-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
inline-size: 32px;
|
||||
block-size: 32px;
|
||||
border: 1px solid var(--grey-300);
|
||||
background: var(--white);
|
||||
color: var(--grey-500);
|
||||
cursor: pointer;
|
||||
border-radius: $radius;
|
||||
transition: all 0.2s ease;
|
||||
|
||||
&:hover {
|
||||
color: var(--grey-700);
|
||||
background: var(--grey-100);
|
||||
border-color: var(--grey-400);
|
||||
}
|
||||
|
||||
&.is-collapsed {
|
||||
color: var(--primary);
|
||||
border-color: var(--primary);
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
}
|
||||
|
||||
.tasks {
|
||||
padding: .5rem;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,15 @@
|
|||
@click="openTaskDetail"
|
||||
@keyup.enter="openTaskDetail"
|
||||
>
|
||||
<button
|
||||
v-if="task.relatedTasks?.subtask?.length"
|
||||
class="collapse-toggle collapse-toggle-left"
|
||||
:class="{ 'is-collapsed': isCollapsed }"
|
||||
@click.stop="toggleCollapse"
|
||||
:aria-label="isCollapsed ? 'Expand subtasks' : 'Collapse subtasks'"
|
||||
>
|
||||
<Icon icon="chevron-down" />
|
||||
</button>
|
||||
<span
|
||||
v-tooltip="!canMarkAsDone ? $t('task.readOnlyCheckbox') : ''"
|
||||
class="is-inline-flex is-align-items-center"
|
||||
|
|
@ -178,8 +187,17 @@
|
|||
/>
|
||||
</BaseButton>
|
||||
<slot />
|
||||
<button
|
||||
v-if="task.relatedTasks?.subtask?.length"
|
||||
class="collapse-toggle"
|
||||
:class="{ 'is-collapsed': isCollapsed }"
|
||||
@click.stop="toggleCollapse"
|
||||
:aria-label="isCollapsed ? 'Expand subtasks' : 'Collapse subtasks'"
|
||||
>
|
||||
<Icon icon="chevron-down" />
|
||||
</button>
|
||||
</div>
|
||||
<template v-if="typeof task.relatedTasks?.subtask !== 'undefined'">
|
||||
<template v-if="task.relatedTasks?.subtask?.length && !isCollapsed">
|
||||
<template v-for="subtask in task.relatedTasks.subtask">
|
||||
<template v-if="getTaskById(subtask.id)">
|
||||
<single-task-in-project
|
||||
|
|
@ -197,7 +215,7 @@
|
|||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import {ref, watch, shallowReactive, onMounted, computed} from 'vue'
|
||||
import {ref, watch, shallowReactive, onMounted, computed, inject, type Ref} from 'vue'
|
||||
import {useI18n} from 'vue-i18n'
|
||||
|
||||
import TaskModel, {getHexColor} from '@/models/task'
|
||||
|
|
@ -246,6 +264,24 @@ const props = withDefaults(defineProps<{
|
|||
allTasks: () => [],
|
||||
})
|
||||
|
||||
// Collapse state
|
||||
const isCollapsed = ref(false)
|
||||
const collapseAll = inject<Ref<boolean>>('collapseAll', ref(false))
|
||||
|
||||
// Watch for global collapse/expand all
|
||||
watch(collapseAll, (newVal) => {
|
||||
isCollapsed.value = newVal
|
||||
})
|
||||
|
||||
const hasSubtasks = computed(() => {
|
||||
return typeof task.value.relatedTasks?.subtask !== 'undefined' &&
|
||||
task.value.relatedTasks.subtask.length > 0
|
||||
})
|
||||
|
||||
function toggleCollapse() {
|
||||
isCollapsed.value = !isCollapsed.value
|
||||
}
|
||||
|
||||
const emit = defineEmits<{
|
||||
'taskUpdated': [task: ITask],
|
||||
}>()
|
||||
|
|
@ -605,6 +641,41 @@ defineExpose({
|
|||
margin-inline-start: 1.75rem;
|
||||
}
|
||||
|
||||
.collapse-toggle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
inline-size: 20px;
|
||||
block-size: 20px;
|
||||
border: none;
|
||||
background: transparent;
|
||||
color: var(--grey-400);
|
||||
cursor: pointer;
|
||||
border-radius: $radius;
|
||||
transition: transform 0.2s ease, color 0.2s ease;
|
||||
margin-inline-start: 0.5rem;
|
||||
|
||||
&:hover {
|
||||
color: var(--grey-600);
|
||||
background: var(--grey-100);
|
||||
}
|
||||
|
||||
&.is-collapsed {
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
}
|
||||
|
||||
.collapse-toggle-left {
|
||||
margin-inline-start: 0;
|
||||
margin-inline-end: 0.5rem;
|
||||
order: -1;
|
||||
|
||||
// 窄屏隐藏左侧按钮,只保留右侧
|
||||
@media (max-width: 768px) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.popup) {
|
||||
border-radius: $radius;
|
||||
background-color: var(--white);
|
||||
|
|
|
|||
Loading…
Reference in New Issue