diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b07e74..232084b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,20 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.4.3] - 2025-11-28 + +### Added +- 大数据加载演示 +- Large data loading demonstration + +### Enhancement +- 性能优化:TaskList和Timeline增加虚拟滚动支持,大幅降低节点数和重绘开销 +- 性能优化:大数据量任务渲染性能优化 +- 性能优化:虚拟渲染优化 +- Performance Optimization: TaskList and Timeline add virtualized scrolling support, greatly reducing node count and redraw overhead +- Performance Optimization: Large data volume task rendering performance optimization +- Performance Optimization: Virtualized rendering optimization + ## [1.4.2-patch3] - 2025-11-13 ### Added diff --git a/demo/App.vue b/demo/App.vue index f9c5fe9..17b505f 100644 --- a/demo/App.vue +++ b/demo/App.vue @@ -3,7 +3,8 @@ import { ref, computed, onMounted, nextTick } from 'vue' import GanttChart from '../src/components/GanttChart.vue' // import TaskDrawer from '../src/components/TaskDrawer.vue' // 移除 import MilestoneDialog from '../src/components/MilestoneDialog.vue' -import demoData from './data.json' +import normalData from './data.json' +import largeData from './data-large-1m.json' import packageInfo from '../package.json' // 导入主题变量 import '../src/styles/theme-variables.css' @@ -22,6 +23,100 @@ const { t, formatTranslation } = useI18n() const tasks = ref([]) const milestones = ref([]) +const rawDataSources = [ + { + key: 'normal', + fileName: 'data.json', + payload: normalData, + }, + { + key: 'large', + fileName: 'data-large-1m.json', + payload: largeData, + }, +] as const + +type DataSourceKey = (typeof rawDataSources)[number]['key'] +type RawDataSource = (typeof rawDataSources)[number] + +const dataSourceOptions = computed(() => { + const dsTranslations = t.value.dataSourceSwitch?.sources ?? {} + return rawDataSources.map(source => { + const optionTexts = dsTranslations[source.key as keyof typeof dsTranslations] || {} + return { + ...source, + label: optionTexts.label || source.fileName, + description: optionTexts.description || '', + badge: optionTexts.badge || source.fileName, + } + }) +}) + +const currentDataSource = ref('large') +const dataLoading = ref(false) + +const cloneData = (data: T): T => { + const globalClone = (globalThis as unknown as { structuredClone?: (value: K) => K }).structuredClone + if (typeof globalClone === 'function') { + return globalClone(data) + } + return JSON.parse(JSON.stringify(data)) as T +} + +const findRawDataSource = (key: DataSourceKey) => rawDataSources.find(source => source.key === key) + +const applyDataSource = (source: RawDataSource) => { + const payload = source.payload as { tasks?: Task[]; milestones?: Task[] } + tasks.value = cloneData(payload.tasks ?? []) + milestones.value = cloneData(payload.milestones ?? []) +} + +const getSourceTexts = (key: DataSourceKey) => { + const dsTranslations = t.value.dataSourceSwitch?.sources ?? {} + return dsTranslations[key as keyof typeof dsTranslations] || { label: key } +} + +const switchDataSource = async ( + key: DataSourceKey, + options: { silent?: boolean; force?: boolean } = {}, +) => { + if (dataLoading.value) return + + const source = findRawDataSource(key) + if (!source) return + + const sourceTexts = getSourceTexts(key) + const displayName = sourceTexts.label || source.fileName + + if (!options.force && currentDataSource.value === key && tasks.value.length > 0) { + showMessage(formatTranslation('dataSourceAlreadyLoaded', { name: displayName }), 'info', { + closable: true, + }) + return + } + + currentDataSource.value = key + dataLoading.value = true + + try { + await nextTick() + applyDataSource(source) + if (!options.silent) { + showMessage(formatTranslation('dataSourceLoadSuccess', { name: displayName }), 'success', { + closable: false, + }) + } + } catch (error) { + // eslint-disable-next-line no-console + console.error('切换数据源失败', error) + showMessage(formatTranslation('dataSourceLoadFailed', { name: displayName }), 'error', { + closable: true, + }) + } finally { + dataLoading.value = false + } +} + // MilestoneDialog状态管理 const showMilestoneDialog = ref(false) const currentMilestone = ref(null) @@ -110,6 +205,7 @@ const taskBarConfig = computed(() => ({ // 配置面板折叠状态 const isConfigPanelCollapsed = ref(false) +const isDataSourcePanelCollapsed = ref(false) // TaskList 配置区域折叠状态(默认收起) const isTaskListConfigCollapsed = ref(true) @@ -122,6 +218,10 @@ const toggleConfigPanel = () => { isConfigPanelCollapsed.value = !isConfigPanelCollapsed.value } +const toggleDataSourcePanel = () => { + isDataSourcePanelCollapsed.value = !isDataSourcePanelCollapsed.value +} + // 切换 TaskList 配置区域 const toggleTaskListConfig = () => { isTaskListConfigCollapsed.value = !isTaskListConfigCollapsed.value @@ -377,8 +477,7 @@ function handleMilestoneDragEnd(newMilestone) { } onMounted(() => { - tasks.value = demoData.tasks as Task[] - milestones.value = demoData.milestones as Task[] + switchDataSource(currentDataSource.value, { silent: true, force: true }) }) // 清理被删除任务的predecessor依赖关系 @@ -480,6 +579,64 @@ function taskDebug(item: any) { +
+
+

+ + + + {{ t.dataSourceSwitch?.title }} - {{ t.dataSourceSwitch?.subtitle }} +

+ +
+ +
+
+ + + {{ t.dataSourceSwitch?.loading }} + +
+
+
+
+
@@ -505,7 +662,7 @@ function taskDebug(item: any) { xmlns="http://www.w3.org/2000/svg" > 特别感谢 @qiuchengw的专业贡献", "Special thanks to @qiuchengw for his professional contribution" ] + }, + { + "version": "1.4.3", + "date": "2025-11-28", + "notes": [ + "性能优化:TaskList和Timeline增加虚拟滚动支持,大幅降低节点数和重绘开销", + "性能优化:大数据量任务渲染性能优化", + "性能优化:虚拟渲染优化", + "新增:大数据加载演示", + "Performance Optimization: TaskList and Timeline add virtualized scrolling support, greatly reducing node count and redraw overhead", + "Performance Optimization: Large data volume task rendering performance optimization", + "Performance Optimization: Virtualized rendering optimization", + "Added: Large data loading demonstration" + ] } ] diff --git a/package.json b/package.json index 4e8b9ae..0965921 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "jordium-gantt-vue3", - "version": "1.4.2-patch.3", + "version": "1.4.3", "type": "module", "main": "dist/jordium-gantt-vue3.cjs.js", "module": "dist/jordium-gantt-vue3.es.js", diff --git a/src/components/TaskRow.vue b/src/components/TaskRow.vue index a7e8567..e5d2d6c 100644 --- a/src/components/TaskRow.vue +++ b/src/components/TaskRow.vue @@ -1,5 +1,6 @@