v1.6.0-preview2 - 增加ask-list-row-class-name和task-list-row-style属性
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, onUnmounted, onMounted, computed, watch, nextTick, useSlots, provide } from 'vue'
|
||||
import type { StyleValue } from 'vue'
|
||||
import TaskList from './TaskList.vue'
|
||||
import Timeline from './Timeline.vue'
|
||||
import GanttToolbar from './GanttToolbar.vue'
|
||||
@@ -50,6 +51,8 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
allowDragAndResize: true,
|
||||
enableTaskRowMove: false,
|
||||
assigneeOptions: () => [],
|
||||
taskListRowClassName: undefined,
|
||||
taskListRowStyle: undefined,
|
||||
})
|
||||
|
||||
const emit = defineEmits([
|
||||
@@ -145,6 +148,12 @@ interface Props {
|
||||
// 格式:{ key?: string | number, value: string | number, label: string }
|
||||
// key 为可选项,若不存在则使用 value 作为选项的唯一标识
|
||||
assigneeOptions?: Array<{ key?: string | number; value: string | number; label: string }>
|
||||
// 任务行自定义样式类名,支持字符串或函数
|
||||
// 函数形式:(row: Task, rowIndex: number) => string
|
||||
taskListRowClassName?: string | ((row: Task, rowIndex: number) => string)
|
||||
// 任务行自定义样式,支持对象或函数,优先级高于 taskListRowClassName
|
||||
// 函数形式:(row: Task, rowIndex: number) => StyleValue
|
||||
taskListRowStyle?: StyleValue | ((row: Task, rowIndex: number) => StyleValue)
|
||||
}
|
||||
|
||||
// TaskList的固定总长度(所有列的最小宽度之和 + 边框等额外空间)
|
||||
@@ -2307,6 +2316,8 @@ function handleMilestoneDialogDelete(milestoneId: number) {
|
||||
:task-list-config="props.taskListConfig"
|
||||
:task-list-column-render-mode="props.taskListColumnRenderMode"
|
||||
:enable-task-row-move="props.enableTaskRowMove"
|
||||
:task-list-row-class-name="props.taskListRowClassName"
|
||||
:task-list-row-style="props.taskListRowStyle"
|
||||
@task-collapse-change="handleTaskCollapseChange"
|
||||
@start-timer="handleStartTimer"
|
||||
@stop-timer="handleStopTimer"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, onUnmounted, useSlots, computed, nextTick, inject } from 'vue'
|
||||
import type { StyleValue, Slots } from 'vue'
|
||||
import TaskRow from './TaskRow.vue'
|
||||
import { useI18n } from '../composables/useI18n'
|
||||
import type { Task } from '../models/classes/Task'
|
||||
@@ -7,7 +8,6 @@ import type { TaskListConfig } from '../models/configs/TaskListConfig'
|
||||
import { DEFAULT_TASK_LIST_COLUMNS } from '../models/configs/TaskListConfig'
|
||||
import { useTaskRowDrag } from '../composables/useTaskRowDrag'
|
||||
import { moveTask } from '../utils/taskTreeUtils'
|
||||
import type { Slots } from 'vue'
|
||||
import { useTaskListColumns } from '../composables/useTaskListColumns'
|
||||
import type { DeclarativeColumnConfig } from '../composables/useTaskListColumns'
|
||||
|
||||
@@ -17,6 +17,8 @@ interface Props {
|
||||
taskListConfig?: TaskListConfig
|
||||
taskListColumnRenderMode?: 'default' | 'declarative'
|
||||
enableTaskRowMove?: boolean
|
||||
taskListRowClassName?: string | ((row: Task, rowIndex: number) => string)
|
||||
taskListRowStyle?: StyleValue | ((row: Task, rowIndex: number) => StyleValue)
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
@@ -330,7 +332,12 @@ const visibleTaskRange = computed(() => {
|
||||
// 虚拟列表中需要渲染的任务
|
||||
const visibleTasks = computed(() => {
|
||||
const { startIndex, endIndex } = visibleTaskRange.value
|
||||
return flattenedTasks.value.slice(startIndex, endIndex)
|
||||
const slicedTasks = flattenedTasks.value.slice(startIndex, endIndex)
|
||||
// 添加 rowIndex(基于在扁平化列表中的实际索引)
|
||||
return slicedTasks.map((item, index) => ({
|
||||
...item,
|
||||
rowIndex: startIndex + index,
|
||||
}))
|
||||
})
|
||||
|
||||
// Spacer 高度用于撑起滚动区域
|
||||
@@ -677,10 +684,11 @@ onUnmounted(() => {
|
||||
<div class="task-list-body-spacer" :style="{ height: `${startSpacerHeight}px` }"></div>
|
||||
|
||||
<TaskRow
|
||||
v-for="{ task, level } in visibleTasks"
|
||||
v-for="{ task, level, rowIndex } in visibleTasks"
|
||||
:key="task.id"
|
||||
:task="task"
|
||||
:level="level"
|
||||
:row-index="rowIndex"
|
||||
:is-hovered="hoveredTaskId === task.id"
|
||||
:hovered-task-id="hoveredTaskId"
|
||||
:on-hover="handleTaskRowHover"
|
||||
@@ -693,6 +701,8 @@ onUnmounted(() => {
|
||||
:enable-drag="props.enableTaskRowMove"
|
||||
:drag-start="startDrag"
|
||||
:drag-over="handleDragOver"
|
||||
:task-list-row-class-name="props.taskListRowClassName"
|
||||
:task-list-row-style="props.taskListRowStyle"
|
||||
@toggle="toggleCollapse"
|
||||
@dblclick="handleTaskRowDoubleClick"
|
||||
@contextmenu="handleTaskRowContextMenu"
|
||||
|
||||
@@ -33,6 +33,7 @@ interface TaskRowSlotProps {
|
||||
interface Props {
|
||||
task: Task
|
||||
level: number
|
||||
rowIndex?: number
|
||||
isHovered?: boolean
|
||||
hoveredTaskId?: number | null
|
||||
onHover?: (taskId: number | null) => void
|
||||
@@ -45,6 +46,8 @@ interface Props {
|
||||
enableDrag?: boolean
|
||||
dragStart?: (task: Task, element: HTMLElement, event: MouseEvent) => void
|
||||
dragOver?: (task: Task, element: HTMLElement, event: MouseEvent) => void
|
||||
taskListRowClassName?: string | ((row: Task, rowIndex: number) => string)
|
||||
taskListRowStyle?: StyleValue | ((row: Task, rowIndex: number) => StyleValue)
|
||||
}
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
renderMode: 'default',
|
||||
@@ -235,6 +238,29 @@ const isMilestoneTask = computed(() => props.task.type === 'milestone')
|
||||
const isParentTask = computed(
|
||||
() => isStoryTask.value || hasChildren.value || isMilestoneGroup.value,
|
||||
)
|
||||
|
||||
// 计算自定义行类名
|
||||
const customRowClass = computed(() => {
|
||||
if (!props.taskListRowClassName) return ''
|
||||
|
||||
if (typeof props.taskListRowClassName === 'function') {
|
||||
return props.taskListRowClassName(props.task, props.rowIndex ?? 0)
|
||||
}
|
||||
|
||||
return props.taskListRowClassName
|
||||
})
|
||||
|
||||
// 计算自定义行样式(优先级高于类名)
|
||||
const customRowStyle = computed(() => {
|
||||
if (!props.taskListRowStyle) return {}
|
||||
|
||||
if (typeof props.taskListRowStyle === 'function') {
|
||||
return props.taskListRowStyle(props.task, props.rowIndex ?? 0)
|
||||
}
|
||||
|
||||
return props.taskListRowStyle
|
||||
})
|
||||
|
||||
function handleToggle() {
|
||||
emit('toggle', props.task)
|
||||
}
|
||||
@@ -506,7 +532,9 @@ onUnmounted(() => {
|
||||
'task-type-story': isStoryTask,
|
||||
'task-type-task': props.task.type === 'task',
|
||||
'task-type-milestone': isMilestoneTask,
|
||||
[customRowClass]: customRowClass,
|
||||
}"
|
||||
:style="customRowStyle"
|
||||
@click="handleRowClick"
|
||||
@dblclick="handleTaskRowDoubleClick"
|
||||
@mousedown="handleMouseDown"
|
||||
|
||||
Reference in New Issue
Block a user