v1.4.5 - add Task drag and drop ender TaskList

This commit is contained in:
LINING-PC\lining
2025-12-06 20:34:33 +08:00
parent 04b9e5fb75
commit 7d81f44778
16 changed files with 1471 additions and 86 deletions
+110 -6
View File
@@ -12,6 +12,7 @@ import VersionHistoryDrawer from './VersionHistoryDrawer.vue'
import HtmlContent from './HtmlContent.vue'
import { useMessage } from '../src/composables/useMessage'
import { useI18n } from '../src/composables/useI18n'
import { useDemoLocale } from './useDemoLocale'
import { getPredecessorIds, predecessorIdsToString } from '../src/utils/predecessorUtils'
import type { Task } from '../src/models/Task'
import type { TaskListConfig, TaskListColumnConfig } from '../src/models/configs/TaskListConfig'
@@ -19,6 +20,7 @@ import type { TaskBarConfig } from '../src/models/configs/TaskBarConfig'
const { showMessage } = useMessage()
const { t, formatTranslation } = useI18n()
const { locale: demoLocale, messages: demoMessages, setLocale: setDemoLocale, formatMessage, getTaskTypeName, getParentName } = useDemoLocale()
const tasks = ref<Task[]>([])
const milestones = ref<Task[]>([])
@@ -182,6 +184,9 @@ const taskListConfig = computed<TaskListConfig>(() => ({
// 控制是否允许拖拽和拉伸
const allowDragAndResize = ref(true)
// 控制是否启用TaskRow拖拽移动
const enableTaskRowMove = ref(true)
// TaskBar配置
const taskBarOptions = ref({
showAvatar: true,
@@ -236,6 +241,17 @@ const toggleTaskBarConfig = () => {
const showTaskClickDialog = ref(false)
const clickedTask = ref<Task | null>(null)
// TaskRow Move 相关(已移除确认对话框,直接显示提示消息)
// 同步语言切换
const handleLanguageChange = (lang: 'zh-CN' | 'en-US') => {
setDemoLocale(lang)
const languageText = lang === 'zh-CN' ? '中文' : 'English'
showMessage(formatTranslation('languageSwitchedTo', { language: languageText }), 'info', {
closable: true,
})
}
// 处理任务点击事件
const handleTaskClick = (task: Task) => {
clickedTask.value = task
@@ -306,12 +322,7 @@ const handleAddMilestone = () => {
showMilestoneDialog.value = true
}
const handleLanguageChange = (lang: 'zh' | 'en') => {
const languageText = lang === 'zh' ? '中文' : 'English'
showMessage(formatTranslation('languageSwitchedTo', { language: languageText }), 'info', {
closable: true,
})
}
const handleThemeChange = (isDark: boolean) => {
const themeText = isDark ? t.value.darkModeText : t.value.lightModeText
@@ -544,6 +555,86 @@ function onTimerStopped(task: Task) {
function taskDebug(item: any) {
// Placeholder for debugging
}
// TaskRow拖拽移动事件处理器
const handleTaskRowMoved = async (payload: {
draggedTask: Task
targetTask: Task
position: 'after' | 'child' // 'after': 放在目标任务之后(同级), 'child': 作为目标任务的子任务
oldParent: Task | null
newParent: Task | null
}) => {
const { draggedTask, targetTask, position, oldParent, newParent } = payload
// 【注意】组件内部已自动完成数据移动,通过对象引用修改实现 TaskList 和 Timeline 的自动同步
// 因此监听此事件是完全可选的,仅用于:
// 1. 显示自定义提示消息
// 2. 调用后端API保存任务层级变更
// 3. 记录操作日志
// 4. 触发其他业务逻辑(如更新关联数据)
// 构建提示消息
const oldParentName = getParentName(oldParent)
const newParentName = position === 'after'
? getParentName(newParent)
: getParentName({ type: targetTask.type, name: targetTask.name })
let message = ''
const msgs = demoMessages.value.taskMoveConfirm.messages
if (position === 'after') {
// 算法#1: 放置在目标任务之后
message = formatMessage(msgs.moveAfter, {
draggedTaskType: getTaskTypeName(draggedTask.type),
draggedTaskName: draggedTask.name,
targetTaskType: getTaskTypeName(targetTask.type),
targetTaskName: targetTask.name,
})
} else {
// 算法#2: 作为子任务放置
if (oldParent && oldParent.id !== targetTask.id) {
message = formatMessage(msgs.moveAsChild, {
draggedTaskName: draggedTask.name,
oldParentName,
newParentName,
})
} else if (!oldParent) {
message = formatMessage(msgs.moveAsChildNoOldParent, {
draggedTaskName: draggedTask.name,
newParentName,
})
} else {
message = formatMessage(msgs.moveAsChildSameParent, {
draggedTaskName: draggedTask.name,
newParentName,
})
}
}
// 显示移动成功提示
const successMsg = demoMessages.value.taskMoveConfirm.messages.moveSuccess
showMessage(`${successMsg}: ${message}`, 'success', { closable: true })
// ⚠️ 重要:必须更新 tasks.value 以同步 TaskList 和 Timeline
// TaskList 已更新内部视图,但 Timeline 依赖 props.tasks
// 此赋值会触发 GanttChart 的 watch,进而触发 Timeline 重新渲染
tasks.value = updatedTasks
// 调用后端API保存任务层级变更
// try {
// await api.updateTaskHierarchy({
// taskId: draggedTask.id,
// targetTaskId: targetTask.id,
// position: position, // 'after' 或 'child'
// oldParentId: oldParent?.id,
// newParentId: newParent?.id,
// })
// console.log('任务层级已保存到后端')
// } catch (error) {
// console.error('保存任务层级失败:', error)
// showMessage('保存失败,请刷新页面', 'error', { closable: true })
// }
}
</script>
<template>
@@ -907,6 +998,17 @@ function taskDebug(item: any) {
{{ t.taskBarConfig.mistouch.allowDragOnClickHint }}
</span>
</div>
<div class="control-row">
<label class="taskbar-control">
<input v-model="enableTaskRowMove" type="checkbox" />
<span class="taskbar-label">
启用TaskRow拖拽移动
</span>
</label>
<span class="control-hint">
允许通过拖拽TaskRow来调整任务的层级和顺序
</span>
</div>
<div class="control-row">
<label class="control-label">
{{ t.taskBarConfig.mistouch.dragThreshold }}:
@@ -985,6 +1087,7 @@ function taskDebug(item: any) {
:working-hours="workingHoursConfig"
:use-default-milestone-dialog="true"
:allow-drag-and-resize="allowDragAndResize"
:enable-task-row-move="enableTaskRowMove"
:on-export-csv="handleCustomCsvExport"
:on-language-change="handleLanguageChange"
:on-theme-change="handleThemeChange"
@@ -1011,6 +1114,7 @@ function taskDebug(item: any) {
@task-deleted="handleTaskDeleteEvent"
@task-added="handleTaskAddEvent"
@task-updated="handleTaskUpdateEvent"
@task-row-moved="handleTaskRowMoved"
>
<template #custom-task-content="item">
<HtmlContent