From 16557a260e5d34f4ce8509f5bc4d23d84b4e5686 Mon Sep 17 00:00:00 2001 From: qiuchengw Date: Wed, 24 Sep 2025 20:38:53 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=AF=E6=8C=81=E5=88=97=E8=A1=A8=E5=85=A8?= =?UTF-8?q?=E9=83=A8=E5=B1=95=E5=BC=80/=E6=8A=98=E5=8F=A0=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- demo/App.vue | 1 + src/components/GanttChart.vue | 54 +++++++++++++++++++++++++ src/components/GanttToolbar.vue | 62 +++++++++++++++++++++++++++++ src/composables/useI18n.ts | 4 ++ src/models/configs/ToolbarConfig.ts | 1 + 5 files changed, 122 insertions(+) diff --git a/demo/App.vue b/demo/App.vue index c749cb9..5f257a1 100644 --- a/demo/App.vue +++ b/demo/App.vue @@ -41,6 +41,7 @@ const toolbarConfig = { showTimeScale: true, // 控制日|周|月时间刻度按钮组的可见性 timeScaleDimensions: ['week', 'month', 'quarter', 'year'], // 设置时间刻度按钮的展示维度,包含所有时间维度 defaultTimeScale: 'week', + showExpandCollapse: true, // 显示全部展开/折叠按钮 } // TaskList列配置 diff --git a/src/components/GanttChart.vue b/src/components/GanttChart.vue index 72e725e..182da43 100644 --- a/src/components/GanttChart.vue +++ b/src/components/GanttChart.vue @@ -37,6 +37,8 @@ const props = withDefaults(defineProps(), { onLanguageChange: undefined, onThemeChange: undefined, onFullscreenChange: undefined, + onExpandAll: undefined, + onCollapseAll: undefined, localeMessages: undefined, workingHours: () => ({ morning: { start: 8, end: 11 }, @@ -96,6 +98,8 @@ interface Props { onLanguageChange?: (lang: 'zh-CN' | 'en-US') => void onThemeChange?: (isDark: boolean) => void onFullscreenChange?: (isFullscreen: boolean) => void + onExpandAll?: () => void + onCollapseAll?: () => void /** * 自定义多语言(国际化)配置,结构参考内置 messages['zh-CN'],只需传递需要覆盖的 key 即可。 * 例如: @@ -346,6 +350,52 @@ const handleTaskCollapseChange = (task: Task) => { updateTaskTrigger.value++ } +// 全部展开任务 +const handleExpandAll = () => { + if (props.onExpandAll && typeof props.onExpandAll === 'function') { + props.onExpandAll() + } else { + // 默认行为:递归展开所有任务 + const expandAllTasks = (tasks: Task[]): void => { + tasks.forEach(task => { + if (task.children && task.children.length > 0) { + task.collapsed = false + expandAllTasks(task.children) + } + }) + } + + if (props.tasks) { + expandAllTasks(props.tasks) + // 触发Timeline重新计算 + updateTaskTrigger.value++ + } + } +} + +// 全部折叠任务 +const handleCollapseAll = () => { + if (props.onCollapseAll && typeof props.onCollapseAll === 'function') { + props.onCollapseAll() + } else { + // 默认行为:递归折叠所有任务 + const collapseAllTasks = (tasks: Task[]): void => { + tasks.forEach(task => { + if (task.children && task.children.length > 0) { + task.collapsed = true + collapseAllTasks(task.children) + } + }) + } + + if (props.tasks) { + collapseAllTasks(props.tasks) + // 触发Timeline重新计算 + updateTaskTrigger.value++ + } + } +} + // 用于强制触发Timeline重新计算的响应式值 const updateTaskTrigger = ref(0) @@ -1528,7 +1578,11 @@ function handleTaskDelete(task: Task, deleteChildren?: boolean) { :on-theme-change="props.onThemeChange" :on-fullscreen-change="props.onFullscreenChange" :on-time-scale-change="handleTimeScaleChange" + :on-expand-all="handleExpandAll" + :on-collapse-all="handleCollapseAll" @add-task="handleToolbarAddTask" + @expand-all="handleExpandAll" + @collapse-all="handleCollapseAll" /> diff --git a/src/components/GanttToolbar.vue b/src/components/GanttToolbar.vue index ada324a..313f0aa 100644 --- a/src/components/GanttToolbar.vue +++ b/src/components/GanttToolbar.vue @@ -20,6 +20,8 @@ const props = withDefaults(defineProps(), { onFullscreenChange: undefined, onSettingsConfirm: undefined, onTimeScaleChange: undefined, + onExpandAll: undefined, + onCollapseAll: undefined, }) const emit = defineEmits<{ @@ -32,6 +34,8 @@ const emit = defineEmits<{ 'theme-change': [isDark: boolean] 'fullscreen-change': [isFullscreen: boolean] 'time-scale-change': [scale: TimelineScale] + 'expand-all': [] + 'collapse-all': [] }>() // LocalStorage keys @@ -56,6 +60,8 @@ interface Props { onThemeChange?: (isDark: boolean) => void onFullscreenChange?: (isFullscreen: boolean) => void onTimeScaleChange?: (scale: TimelineScale) => void + onExpandAll?: () => void + onCollapseAll?: () => void // 外部确认接口 onSettingsConfirm?: ( type: 'theme' | 'language', @@ -140,6 +146,23 @@ const handleExportPdf = () => { } } +// 展开/折叠处理函数 +const handleExpandAll = () => { + if (props.onExpandAll && typeof props.onExpandAll === 'function') { + props.onExpandAll() + } else { + emit('expand-all') + } +} + +const handleCollapseAll = () => { + if (props.onCollapseAll && typeof props.onCollapseAll === 'function') { + props.onCollapseAll() + } else { + emit('collapse-all') + } +} + // 语言下拉菜单控制 const toggleLanguageDropdown = () => { showLanguageDropdown.value = !showLanguageDropdown.value @@ -461,6 +484,45 @@ onUnmounted(() => { + +
+ + +
+