右键删除Task链接功能
This commit is contained in:
@@ -64,6 +64,7 @@ const emit = defineEmits([
|
|||||||
'task-added',
|
'task-added',
|
||||||
'task-updated',
|
'task-updated',
|
||||||
'task-collapse-change', // 任务折叠状态变化事件
|
'task-collapse-change', // 任务折叠状态变化事件
|
||||||
|
'link-deleted', // 链接删除事件
|
||||||
// 工具栏事件
|
// 工具栏事件
|
||||||
'add-task',
|
'add-task',
|
||||||
'add-milestone',
|
'add-milestone',
|
||||||
@@ -2156,6 +2157,39 @@ function handleTaskDelete(task: Task, deleteChildren?: boolean) {
|
|||||||
emit('task-deleted', { task })
|
emit('task-deleted', { task })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 处理链接删除事件
|
||||||
|
function handleLinkDeleted(event: {
|
||||||
|
sourceTaskId: number
|
||||||
|
targetTaskId: number
|
||||||
|
updatedTask: Task
|
||||||
|
}) {
|
||||||
|
if (props.tasks) {
|
||||||
|
// 在 tasks 树中找到目标任务并更新
|
||||||
|
const updateTaskInTree = (taskList: Task[]): boolean => {
|
||||||
|
for (let i = 0; i < taskList.length; i++) {
|
||||||
|
if (taskList[i].id === event.targetTaskId) {
|
||||||
|
// 使用新对象替换,确保响应式更新
|
||||||
|
taskList[i] = { ...taskList[i], predecessor: event.updatedTask.predecessor }
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if (taskList[i].children && taskList[i].children!.length > 0) {
|
||||||
|
if (updateTaskInTree(taskList[i].children!)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
updateTaskInTree(props.tasks)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 触发任务更新事件
|
||||||
|
emit('task-updated', { task: event.updatedTask })
|
||||||
|
|
||||||
|
// 向外部发送链接删除事件
|
||||||
|
emit('link-deleted', event)
|
||||||
|
}
|
||||||
|
|
||||||
// 处理里程碑双击事件
|
// 处理里程碑双击事件
|
||||||
function handleMilestoneDoubleClick(milestone: Milestone) {
|
function handleMilestoneDoubleClick(milestone: Milestone) {
|
||||||
// 先触发外部事件,让外部可以自定义处理
|
// 先触发外部事件,让外部可以自定义处理
|
||||||
@@ -2291,6 +2325,7 @@ function handleMilestoneDialogDelete(milestoneId: number) {
|
|||||||
@predecessor-added="handlePredecessorAdded"
|
@predecessor-added="handlePredecessorAdded"
|
||||||
@successor-added="handleSuccessorAdded"
|
@successor-added="handleSuccessorAdded"
|
||||||
@delete="handleTaskDelete"
|
@delete="handleTaskDelete"
|
||||||
|
@link-deleted="handleLinkDeleted"
|
||||||
>
|
>
|
||||||
<template v-if="$slots['custom-task-content']" #custom-task-content="barScope">
|
<template v-if="$slots['custom-task-content']" #custom-task-content="barScope">
|
||||||
<slot name="custom-task-content" v-bind="barScope" />
|
<slot name="custom-task-content" v-bind="barScope" />
|
||||||
|
|||||||
@@ -44,6 +44,8 @@ interface Props {
|
|||||||
isValidLinkTarget?: boolean
|
isValidLinkTarget?: boolean
|
||||||
// 是否是无效的连接目标
|
// 是否是无效的连接目标
|
||||||
isInvalidLinkTarget?: boolean
|
isInvalidLinkTarget?: boolean
|
||||||
|
// 所有任务列表(用于右键菜单删除链接功能)
|
||||||
|
allTasks?: Task[]
|
||||||
}
|
}
|
||||||
|
|
||||||
interface TaskStatus {
|
interface TaskStatus {
|
||||||
@@ -80,6 +82,7 @@ const emit = defineEmits([
|
|||||||
'add-predecessor',
|
'add-predecessor',
|
||||||
'add-successor',
|
'add-successor',
|
||||||
'delete',
|
'delete',
|
||||||
|
'delete-link',
|
||||||
'context-menu',
|
'context-menu',
|
||||||
'long-press',
|
'long-press',
|
||||||
'link-drag-start',
|
'link-drag-start',
|
||||||
@@ -2242,6 +2245,12 @@ const handleTaskDelete = (task: Task, deleteChildren?: boolean) => {
|
|||||||
closeContextMenu()
|
closeContextMenu()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 处理删除链接事件
|
||||||
|
const handleDeleteLink = (event: { sourceTaskId: number; targetTaskId: number }) => {
|
||||||
|
emit('delete-link', event)
|
||||||
|
closeContextMenu()
|
||||||
|
}
|
||||||
|
|
||||||
// 连接线触点事件处理
|
// 连接线触点事件处理
|
||||||
const handleLinkDragStart = (event: { task: Task; type: 'predecessor' | 'successor'; mouseEvent: MouseEvent }) => {
|
const handleLinkDragStart = (event: { task: Task; type: 'predecessor' | 'successor'; mouseEvent: MouseEvent }) => {
|
||||||
emit('link-drag-start', event)
|
emit('link-drag-start', event)
|
||||||
@@ -2494,12 +2503,14 @@ onUnmounted(() => {
|
|||||||
:visible="contextMenuVisible"
|
:visible="contextMenuVisible"
|
||||||
:task="contextMenuTask"
|
:task="contextMenuTask"
|
||||||
:position="contextMenuPosition"
|
:position="contextMenuPosition"
|
||||||
|
:all-tasks="allTasks"
|
||||||
@close="closeContextMenu"
|
@close="closeContextMenu"
|
||||||
@start-timer="$emit('start-timer', props.task)"
|
@start-timer="$emit('start-timer', props.task)"
|
||||||
@stop-timer="$emit('stop-timer', props.task)"
|
@stop-timer="$emit('stop-timer', props.task)"
|
||||||
@add-predecessor="$emit('add-predecessor', props.task)"
|
@add-predecessor="$emit('add-predecessor', props.task)"
|
||||||
@add-successor="$emit('add-successor', props.task)"
|
@add-successor="$emit('add-successor', props.task)"
|
||||||
@delete="handleTaskDelete"
|
@delete="handleTaskDelete"
|
||||||
|
@delete-link="handleDeleteLink"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { useI18n } from '../composables/useI18n'
|
|||||||
import type { Task } from '../models/classes/Task'
|
import type { Task } from '../models/classes/Task'
|
||||||
import ConfirmTimerDialog from './ConfirmTimerDialog.vue'
|
import ConfirmTimerDialog from './ConfirmTimerDialog.vue'
|
||||||
import GanttConfirmDialog from './GanttConfirmDialog.vue'
|
import GanttConfirmDialog from './GanttConfirmDialog.vue'
|
||||||
|
import { getPredecessorIds } from '../utils/predecessorUtils'
|
||||||
|
|
||||||
// 定义Props接口
|
// 定义Props接口
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -13,6 +14,7 @@ interface Props {
|
|||||||
y: number
|
y: number
|
||||||
}
|
}
|
||||||
task: Task | null
|
task: Task | null
|
||||||
|
allTasks?: Task[] // 所有任务列表,用于查找链接的任务名称
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = defineProps<Props>()
|
const props = defineProps<Props>()
|
||||||
@@ -23,6 +25,7 @@ const emit = defineEmits([
|
|||||||
'add-predecessor',
|
'add-predecessor',
|
||||||
'add-successor',
|
'add-successor',
|
||||||
'delete', // 新增delete事件
|
'delete', // 新增delete事件
|
||||||
|
'delete-link', // 删除链接事件
|
||||||
'close',
|
'close',
|
||||||
])
|
])
|
||||||
|
|
||||||
@@ -134,6 +137,51 @@ const handleDeleteNo = () => {
|
|||||||
// 新增:是否显示计时菜单项(非story类型才显示)
|
// 新增:是否显示计时菜单项(非story类型才显示)
|
||||||
const showTimerMenu = computed(() => props.task?.type !== 'story')
|
const showTimerMenu = computed(() => props.task?.type !== 'story')
|
||||||
|
|
||||||
|
// 子菜单状态管理
|
||||||
|
const showDeleteLinksSubmenu = ref(false)
|
||||||
|
let submenuHideTimer: number | null = null
|
||||||
|
|
||||||
|
// 计算当前任务的所有链接(前置和后置)
|
||||||
|
const taskLinks = computed(() => {
|
||||||
|
const links: Array<{ type: 'predecessor' | 'successor'; taskId: number; taskName: string }> = []
|
||||||
|
|
||||||
|
if (!props.task || !props.allTasks) return links
|
||||||
|
|
||||||
|
// 获取前置任务链接
|
||||||
|
if (props.task.predecessor) {
|
||||||
|
const predecessorIds = getPredecessorIds(props.task.predecessor)
|
||||||
|
for (const id of predecessorIds) {
|
||||||
|
const task = props.allTasks.find(t => t.id === id)
|
||||||
|
if (task) {
|
||||||
|
links.push({
|
||||||
|
type: 'predecessor',
|
||||||
|
taskId: id,
|
||||||
|
taskName: task.name || `任务 ${id}`,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取后置任务链接(当前任务作为其他任务的前置)
|
||||||
|
for (const task of props.allTasks) {
|
||||||
|
if (task.predecessor && task.id !== props.task.id) {
|
||||||
|
const predecessorIds = getPredecessorIds(task.predecessor)
|
||||||
|
if (predecessorIds.includes(props.task.id)) {
|
||||||
|
links.push({
|
||||||
|
type: 'successor',
|
||||||
|
taskId: task.id,
|
||||||
|
taskName: task.name || `任务 ${task.id}`,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return links
|
||||||
|
})
|
||||||
|
|
||||||
|
// 是否有链接可删除
|
||||||
|
const hasLinks = computed(() => taskLinks.value.length > 0)
|
||||||
|
|
||||||
// 监听菜单可见状态和位置变化
|
// 监听菜单可见状态和位置变化
|
||||||
watch(
|
watch(
|
||||||
[() => props.visible, () => props.position],
|
[() => props.visible, () => props.position],
|
||||||
@@ -243,6 +291,42 @@ const handleAddSuccessor = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 处理删除链接点击
|
||||||
|
const handleDeleteLink = (link: { type: 'predecessor' | 'successor'; taskId: number }) => {
|
||||||
|
// 清理定时器
|
||||||
|
if (submenuHideTimer) {
|
||||||
|
clearTimeout(submenuHideTimer)
|
||||||
|
submenuHideTimer = null
|
||||||
|
}
|
||||||
|
|
||||||
|
// 立即隐藏子菜单
|
||||||
|
showDeleteLinksSubmenu.value = false
|
||||||
|
|
||||||
|
// 发送删除事件
|
||||||
|
emit('delete-link', {
|
||||||
|
sourceTaskId: link.type === 'predecessor' ? link.taskId : props.task!.id,
|
||||||
|
targetTaskId: link.type === 'predecessor' ? props.task!.id : link.taskId,
|
||||||
|
})
|
||||||
|
|
||||||
|
// 关闭整个菜单
|
||||||
|
emit('close')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理子菜单鼠标进入/离开
|
||||||
|
const handleSubmenuMouseEnter = () => {
|
||||||
|
if (submenuHideTimer) {
|
||||||
|
clearTimeout(submenuHideTimer)
|
||||||
|
submenuHideTimer = null
|
||||||
|
}
|
||||||
|
showDeleteLinksSubmenu.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSubmenuMouseLeave = () => {
|
||||||
|
submenuHideTimer = window.setTimeout(() => {
|
||||||
|
showDeleteLinksSubmenu.value = false
|
||||||
|
}, 200)
|
||||||
|
}
|
||||||
|
|
||||||
// 处理点击其他地方关闭菜单
|
// 处理点击其他地方关闭菜单
|
||||||
const handleClickOutside = (event: MouseEvent) => {
|
const handleClickOutside = (event: MouseEvent) => {
|
||||||
if (menuRef.value && !menuRef.value.contains(event.target as Node)) {
|
if (menuRef.value && !menuRef.value.contains(event.target as Node)) {
|
||||||
@@ -267,6 +351,10 @@ onUnmounted(() => {
|
|||||||
// 移除事件监听
|
// 移除事件监听
|
||||||
document.removeEventListener('mousedown', handleClickOutside)
|
document.removeEventListener('mousedown', handleClickOutside)
|
||||||
document.removeEventListener('keydown', handleKeyDown)
|
document.removeEventListener('keydown', handleKeyDown)
|
||||||
|
// 清理子菜单定时器
|
||||||
|
if (submenuHideTimer) {
|
||||||
|
clearTimeout(submenuHideTimer)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -311,6 +399,43 @@ onUnmounted(() => {
|
|||||||
</div>
|
</div>
|
||||||
{{ t.addSuccessor }}
|
{{ t.addSuccessor }}
|
||||||
</div>
|
</div>
|
||||||
|
<!-- 删除链接菜单(带子菜单) -->
|
||||||
|
<div
|
||||||
|
v-if="hasLinks"
|
||||||
|
class="menu-item menu-item-with-submenu"
|
||||||
|
@mouseenter="handleSubmenuMouseEnter"
|
||||||
|
@mouseleave="handleSubmenuMouseLeave"
|
||||||
|
>
|
||||||
|
<div class="icon-wrapper">
|
||||||
|
<i class="menu-icon link-delete-icon"></i>
|
||||||
|
</div>
|
||||||
|
{{ t.deleteLinks }}
|
||||||
|
<i class="submenu-arrow">›</i>
|
||||||
|
<!-- 子菜单 -->
|
||||||
|
<div
|
||||||
|
v-if="showDeleteLinksSubmenu"
|
||||||
|
class="submenu"
|
||||||
|
@mouseenter="handleSubmenuMouseEnter"
|
||||||
|
@mouseleave="handleSubmenuMouseLeave"
|
||||||
|
>
|
||||||
|
<!-- eslint-disable vue/no-v-html -->
|
||||||
|
<div
|
||||||
|
v-for="link in taskLinks"
|
||||||
|
:key="`${link.type}-${link.taskId}`"
|
||||||
|
class="menu-item submenu-item"
|
||||||
|
@click.stop="handleDeleteLink(link)"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
v-html="
|
||||||
|
link.type === 'predecessor'
|
||||||
|
? t.predecessorLink.replace('{name}', link.taskName)
|
||||||
|
: t.successorLink.replace('{name}', link.taskName)
|
||||||
|
"
|
||||||
|
></span>
|
||||||
|
</div>
|
||||||
|
<!-- eslint-enable vue/no-v-html -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="menu-divider"></div>
|
<div class="menu-divider"></div>
|
||||||
<div class="menu-item menu-item-danger" @click="handleDeleteClick">
|
<div class="menu-item menu-item-danger" @click="handleDeleteClick">
|
||||||
<div class="icon-wrapper">
|
<div class="icon-wrapper">
|
||||||
@@ -588,4 +713,85 @@ onUnmounted(() => {
|
|||||||
width: 92%;
|
width: 92%;
|
||||||
margin-left: 4%;
|
margin-left: 4%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 带子菜单的菜单项 */
|
||||||
|
.menu-item-with-submenu {
|
||||||
|
position: relative;
|
||||||
|
padding-right: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.submenu-arrow {
|
||||||
|
position: absolute;
|
||||||
|
right: 12px;
|
||||||
|
font-style: normal;
|
||||||
|
font-size: 16px;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.submenu {
|
||||||
|
position: absolute;
|
||||||
|
left: 100%;
|
||||||
|
top: 0;
|
||||||
|
margin-left: 4px;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.15);
|
||||||
|
padding: 4px 0;
|
||||||
|
min-width: 200px;
|
||||||
|
z-index: 10001;
|
||||||
|
border: 1px solid #e4e7ed;
|
||||||
|
animation: fadeIn 0.15s ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.submenu-item {
|
||||||
|
padding: 8px 16px;
|
||||||
|
font-size: 13px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.submenu-item:hover {
|
||||||
|
background-color: #fef0f0;
|
||||||
|
color: #f56c6c;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 链接删除图标 */
|
||||||
|
.link-delete-icon {
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.link-delete-icon::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
width: 14px;
|
||||||
|
height: 2px;
|
||||||
|
background-color: currentColor;
|
||||||
|
top: 50%;
|
||||||
|
left: 3px;
|
||||||
|
transform: translateY(-50%) rotate(45deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.link-delete-icon::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
width: 14px;
|
||||||
|
height: 2px;
|
||||||
|
background-color: currentColor;
|
||||||
|
top: 50%;
|
||||||
|
left: 3px;
|
||||||
|
transform: translateY(-50%) rotate(-45deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 暗色主题下的子菜单 */
|
||||||
|
:global(html[data-theme='dark']) .submenu {
|
||||||
|
background-color: #2c2c2c;
|
||||||
|
border-color: #444444;
|
||||||
|
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.35);
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(html[data-theme='dark']) .submenu-item:hover {
|
||||||
|
background-color: #3a1f1f;
|
||||||
|
color: #f56c6c;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ const emit = defineEmits<{
|
|||||||
'predecessor-added': [{ targetTask: Task; newTask: Task }] // 前置任务已添加
|
'predecessor-added': [{ targetTask: Task; newTask: Task }] // 前置任务已添加
|
||||||
'successor-added': [{ targetTask: Task; newTask: Task }] // 后置任务已添加
|
'successor-added': [{ targetTask: Task; newTask: Task }] // 后置任务已添加
|
||||||
delete: [task: Task, deleteChildren?: boolean]
|
delete: [task: Task, deleteChildren?: boolean]
|
||||||
|
'link-deleted': [{ sourceTaskId: number; targetTaskId: number; updatedTask: Task }] // 链接已删除
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
// 多语言
|
// 多语言
|
||||||
@@ -3228,6 +3229,34 @@ const handleTaskDelete = (task: Task, deleteChildren?: boolean) => {
|
|||||||
emit('delete', task, deleteChildren)
|
emit('delete', task, deleteChildren)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 处理删除链接事件
|
||||||
|
const handleDeleteLink = (event: { sourceTaskId: number; targetTaskId: number }) => {
|
||||||
|
const targetTask = tasks.value.find(t => t.id === event.targetTaskId)
|
||||||
|
if (!targetTask || !targetTask.predecessor) return
|
||||||
|
|
||||||
|
const predecessorIds = getPredecessorIds(targetTask.predecessor)
|
||||||
|
const newIds = predecessorIds.filter(id => id !== event.sourceTaskId)
|
||||||
|
|
||||||
|
// 创建一个新的任务对象以触发响应式更新
|
||||||
|
const updatedTask = {
|
||||||
|
...targetTask,
|
||||||
|
predecessor: newIds.length > 0 ? (newIds as any) : undefined,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 触发链接删除事件,让 GanttChart 更新 tasks 数组
|
||||||
|
emit('link-deleted', {
|
||||||
|
sourceTaskId: event.sourceTaskId,
|
||||||
|
targetTaskId: event.targetTaskId,
|
||||||
|
updatedTask,
|
||||||
|
})
|
||||||
|
|
||||||
|
// 同时触发任务更新事件(兼容现有逻辑)
|
||||||
|
updateTask(updatedTask)
|
||||||
|
|
||||||
|
// 强制清除缓存,确保时间轴数据重新计算
|
||||||
|
clearTimelineCache()
|
||||||
|
}
|
||||||
|
|
||||||
// 月度视图中按年份分组的计算属性
|
// 月度视图中按年份分组的计算属性
|
||||||
const groupMonthsByYear = computed(() => {
|
const groupMonthsByYear = computed(() => {
|
||||||
if (currentTimeScale.value !== TimelineScale.MONTH) {
|
if (currentTimeScale.value !== TimelineScale.MONTH) {
|
||||||
@@ -4307,6 +4336,7 @@ const handleAddSuccessor = (task: Task) => {
|
|||||||
:is-invalid-link-target="
|
:is-invalid-link-target="
|
||||||
linkDragTargetTask?.id === task.id && isValidLinkTarget === false
|
linkDragTargetTask?.id === task.id && isValidLinkTarget === false
|
||||||
"
|
"
|
||||||
|
:all-tasks="tasks"
|
||||||
@update:task="updateTask"
|
@update:task="updateTask"
|
||||||
@bar-mounted="handleBarMounted"
|
@bar-mounted="handleBarMounted"
|
||||||
@click="handleTaskBarClick(task, $event)"
|
@click="handleTaskBarClick(task, $event)"
|
||||||
@@ -4320,6 +4350,7 @@ const handleAddSuccessor = (task: Task) => {
|
|||||||
@add-predecessor="handleAddPredecessor"
|
@add-predecessor="handleAddPredecessor"
|
||||||
@add-successor="handleAddSuccessor"
|
@add-successor="handleAddSuccessor"
|
||||||
@delete="handleTaskDelete"
|
@delete="handleTaskDelete"
|
||||||
|
@delete-link="handleDeleteLink"
|
||||||
@long-press="setHighlightTask"
|
@long-press="setHighlightTask"
|
||||||
@link-drag-start="handleLinkDragStart"
|
@link-drag-start="handleLinkDragStart"
|
||||||
@link-drag-move="handleLinkDragMove"
|
@link-drag-move="handleLinkDragMove"
|
||||||
|
|||||||
@@ -163,6 +163,10 @@ const messages = {
|
|||||||
predecessorPlaceholder: '请选择前置任务',
|
predecessorPlaceholder: '请选择前置任务',
|
||||||
selectPredecessor: '选择前置任务',
|
selectPredecessor: '选择前置任务',
|
||||||
removePredecessor: '移除前置任务',
|
removePredecessor: '移除前置任务',
|
||||||
|
deleteLinks: '删除链接',
|
||||||
|
noLinks: '无链接',
|
||||||
|
predecessorLink: '前置: {name}',
|
||||||
|
successorLink: '后置: {name}',
|
||||||
operationFailed: '操作失败,请重试',
|
operationFailed: '操作失败,请重试',
|
||||||
taskUpdateSuccess: '任务更新成功',
|
taskUpdateSuccess: '任务更新成功',
|
||||||
taskCreateSuccess: '任务创建成功',
|
taskCreateSuccess: '任务创建成功',
|
||||||
@@ -421,6 +425,10 @@ const messages = {
|
|||||||
predecessorPlaceholder: 'Select predecessor',
|
predecessorPlaceholder: 'Select predecessor',
|
||||||
selectPredecessor: 'Select Predecessor',
|
selectPredecessor: 'Select Predecessor',
|
||||||
removePredecessor: 'Remove Predecessor',
|
removePredecessor: 'Remove Predecessor',
|
||||||
|
deleteLinks: 'Delete Links',
|
||||||
|
noLinks: 'No Links',
|
||||||
|
predecessorLink: 'Predecessor: {name}',
|
||||||
|
successorLink: 'Successor: {name}',
|
||||||
operationFailed: 'Operation failed, please try again',
|
operationFailed: 'Operation failed, please try again',
|
||||||
taskUpdateSuccess: 'Task updated successfully',
|
taskUpdateSuccess: 'Task updated successfully',
|
||||||
taskCreateSuccess: 'Task created successfully',
|
taskCreateSuccess: 'Task created successfully',
|
||||||
|
|||||||
Reference in New Issue
Block a user