支持配置左侧table 列显示
This commit is contained in:
@@ -11,6 +11,7 @@ import html2canvas from 'html2canvas'
|
||||
import type { Task } from '../models/classes/Task'
|
||||
import type { Milestone } from '../models/classes/Milestone'
|
||||
import type { ToolbarConfig } from '../models/configs/ToolbarConfig'
|
||||
import type { TaskListConfig } from '../models/configs/TaskListConfig'
|
||||
import { TimelineScale } from '../models/types/TimelineScale'
|
||||
import { useMessage } from '../composables/useMessage'
|
||||
|
||||
@@ -41,6 +42,7 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
morning: { start: 8, end: 11 },
|
||||
afternoon: { start: 13, end: 17 },
|
||||
}),
|
||||
taskListConfig: undefined,
|
||||
})
|
||||
|
||||
const emit = defineEmits([
|
||||
@@ -107,6 +109,8 @@ interface Props {
|
||||
morning?: { start: number; end: number } // 上午工作时间,如 { start: 8, end: 11 }
|
||||
afternoon?: { start: number; end: number } // 下午工作时间,如 { start: 13, end: 17 }
|
||||
}
|
||||
// 任务列表配置
|
||||
taskListConfig?: TaskListConfig
|
||||
}
|
||||
|
||||
const leftPanelWidth = ref(320)
|
||||
@@ -1539,6 +1543,7 @@ function handleTaskDelete(task: Task, deleteChildren?: boolean) {
|
||||
:on-task-double-click="props.onTaskDoubleClick"
|
||||
:edit-component="props.editComponent"
|
||||
:use-default-drawer="props.useDefaultDrawer"
|
||||
:task-list-config="props.taskListConfig"
|
||||
@task-collapse-change="handleTaskCollapseChange"
|
||||
@start-timer="handleStartTimer"
|
||||
@stop-timer="handleStopTimer"
|
||||
|
||||
@@ -4,12 +4,15 @@ import type { Component } from 'vue'
|
||||
import TaskRow from './TaskRow.vue'
|
||||
import { useI18n } from '../composables/useI18n'
|
||||
import type { Task } from '../models/classes/Task'
|
||||
import type { TaskListConfig } from '../models/configs/TaskListConfig'
|
||||
import { DEFAULT_TASK_LIST_COLUMNS } from '../models/configs/TaskListConfig'
|
||||
|
||||
interface Props {
|
||||
tasks?: Task[]
|
||||
onTaskDoubleClick?: (task: Task) => void
|
||||
editComponent?: Component
|
||||
useDefaultDrawer?: boolean
|
||||
taskListConfig?: TaskListConfig
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
@@ -33,6 +36,18 @@ const hasRowSlot = computed(() => Boolean(slots['custom-task-content']))
|
||||
// 多语言支持
|
||||
const { t } = useI18n()
|
||||
|
||||
// 计算可见的列配置
|
||||
const visibleColumns = computed(() => {
|
||||
const columns = props.taskListConfig?.columns || DEFAULT_TASK_LIST_COLUMNS
|
||||
const showAllColumns = props.taskListConfig?.showAllColumns ?? true
|
||||
|
||||
if (!showAllColumns) {
|
||||
return columns.filter(col => col.visible !== false)
|
||||
}
|
||||
|
||||
return columns
|
||||
})
|
||||
|
||||
// 内部响应式任务列表
|
||||
const localTasks = ref<Task[]>([])
|
||||
|
||||
@@ -385,14 +400,15 @@ onUnmounted(() => {
|
||||
<template>
|
||||
<div class="task-list">
|
||||
<div class="task-list-header">
|
||||
<div class="col col-name">{{ t.taskName }}</div>
|
||||
<div class="col col-pre">{{ t.predecessor }}</div>
|
||||
<div class="col col-assignee">{{ t.assignee }}</div>
|
||||
<div class="col col-date">{{ t.startDate }}</div>
|
||||
<div class="col col-date">{{ t.endDate }}</div>
|
||||
<div class="col col-hours">{{ t.estimatedHours }}</div>
|
||||
<div class="col col-hours">{{ t.actualHours }}</div>
|
||||
<div class="col col-progress">{{ t.progress }}</div>
|
||||
<div
|
||||
v-for="column in visibleColumns"
|
||||
:key="column.type"
|
||||
class="col"
|
||||
:class="column.cssClass"
|
||||
:style="column.width ? { width: column.width + 'px' } : undefined"
|
||||
>
|
||||
{{ (t as any)[column.key] }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="task-list-body" @scroll="handleTaskListScroll">
|
||||
<TaskRow
|
||||
@@ -404,6 +420,7 @@ onUnmounted(() => {
|
||||
:hovered-task-id="hoveredTaskId"
|
||||
:on-double-click="props.onTaskDoubleClick"
|
||||
:on-hover="handleTaskRowHover"
|
||||
:columns="visibleColumns"
|
||||
@toggle="toggleCollapse"
|
||||
@dblclick="handleTaskRowDoubleClick"
|
||||
@contextmenu="handleTaskRowContextMenu"
|
||||
|
||||
+58
-31
@@ -3,6 +3,7 @@ import { ref, onMounted, onUnmounted, computed, watch, useSlots } from 'vue'
|
||||
import { useI18n } from '../composables/useI18n'
|
||||
import { formatPredecessorDisplay } from '../utils/predecessorUtils'
|
||||
import type { Task } from '../models/classes/Task'
|
||||
import type { TaskListColumnConfig } from '../models/configs/TaskListConfig'
|
||||
import TaskContextMenu from './TaskContextMenu.vue'
|
||||
|
||||
interface Props {
|
||||
@@ -12,6 +13,7 @@ interface Props {
|
||||
isHovered?: boolean
|
||||
hoveredTaskId?: number | null
|
||||
onHover?: (taskId: number | null) => void
|
||||
columns: TaskListColumnConfig[]
|
||||
}
|
||||
const props = defineProps<Props>()
|
||||
const emit = defineEmits([
|
||||
@@ -385,38 +387,62 @@ onUnmounted(() => {
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- 里程碑分组不显示详细信息 -->
|
||||
<template v-if="isMilestoneGroup">
|
||||
<div class="col col-pre milestone-empty-col"></div>
|
||||
<div class="col col-assignee milestone-empty-col"></div>
|
||||
<div class="col col-date milestone-empty-col"></div>
|
||||
<div class="col col-date milestone-empty-col"></div>
|
||||
<div class="col col-hours milestone-empty-col"></div>
|
||||
<div class="col col-hours milestone-empty-col"></div>
|
||||
<div class="col col-progress milestone-empty-col"></div>
|
||||
</template>
|
||||
<!-- 动态渲染列 -->
|
||||
<div
|
||||
v-for="column in columns"
|
||||
:key="column.key"
|
||||
class="col"
|
||||
:class="`col-${column.key}`"
|
||||
>
|
||||
<!-- 里程碑分组显示空列 -->
|
||||
<template v-if="isMilestoneGroup">
|
||||
<div class="milestone-empty-col"></div>
|
||||
</template>
|
||||
<!-- 普通任务显示具体内容 -->
|
||||
<template v-else>
|
||||
<!-- 前置任务列 -->
|
||||
<template v-if="column.key === 'predecessor'">
|
||||
{{ formatPredecessorDisplay(props.task.predecessor) }}
|
||||
</template>
|
||||
|
||||
<!-- 普通任务显示详细信息 -->
|
||||
<template v-else>
|
||||
<div class="col col-pre">{{ formatPredecessorDisplay(props.task.predecessor) }}</div>
|
||||
<div class="col col-assignee">
|
||||
<div class="assignee-info">
|
||||
<div class="avatar">
|
||||
{{ props.task.assignee ? props.task.assignee.charAt(0) : '-' }}
|
||||
<!-- 负责人列 -->
|
||||
<template v-else-if="column.key === 'assignee'">
|
||||
<div class="assignee-info">
|
||||
<div class="avatar">
|
||||
{{ props.task.assignee ? props.task.assignee.charAt(0) : '-' }}
|
||||
</div>
|
||||
<span class="assignee-name">{{ props.task.assignee || '-' }}</span>
|
||||
</div>
|
||||
<span class="assignee-name">{{ props.task.assignee || '-' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col col-date">{{ props.task.startDate || '-' }}</div>
|
||||
<div class="col col-date">{{ props.task.endDate || '-' }}</div>
|
||||
<div class="col col-hours">{{ props.task.estimatedHours || '-' }}</div>
|
||||
<div class="col col-hours">{{ props.task.actualHours || '-' }}</div>
|
||||
<div class="col col-progress">
|
||||
<span class="progress-value" :class="progressClass">
|
||||
{{ props.task.progress != null ? props.task.progress + '%' : '-' }}
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<!-- 开始日期列 -->
|
||||
<template v-else-if="column.key === 'startDate'">
|
||||
{{ props.task.startDate || '-' }}
|
||||
</template>
|
||||
|
||||
<!-- 结束日期列 -->
|
||||
<template v-else-if="column.key === 'endDate'">
|
||||
{{ props.task.endDate || '-' }}
|
||||
</template>
|
||||
|
||||
<!-- 预估工时列 -->
|
||||
<template v-else-if="column.key === 'estimatedHours'">
|
||||
{{ props.task.estimatedHours || '-' }}
|
||||
</template>
|
||||
|
||||
<!-- 实际工时列 -->
|
||||
<template v-else-if="column.key === 'actualHours'">
|
||||
{{ props.task.actualHours || '-' }}
|
||||
</template>
|
||||
|
||||
<!-- 进度列 -->
|
||||
<template v-else-if="column.key === 'progress'">
|
||||
<span class="progress-value" :class="progressClass">
|
||||
{{ props.task.progress != null ? props.task.progress + '%' : '-' }}
|
||||
</span>
|
||||
</template>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<template
|
||||
v-if="hasChildren && !props.task.collapsed && !isMilestoneGroup"
|
||||
@@ -430,6 +456,7 @@ onUnmounted(() => {
|
||||
:hovered-task-id="props.hoveredTaskId"
|
||||
:on-double-click="props.onDoubleClick"
|
||||
:on-hover="props.onHover"
|
||||
:columns="props.columns"
|
||||
@toggle="emit('toggle', $event)"
|
||||
@dblclick="emit('dblclick', $event)"
|
||||
@start-timer="emit('start-timer', $event)"
|
||||
@@ -438,7 +465,7 @@ onUnmounted(() => {
|
||||
@add-successor="emit('add-successor', $event)"
|
||||
@delete="handleTaskDelete"
|
||||
>
|
||||
<template v-if="hasContentSlot" #custom-task-content="childScope: any">
|
||||
<template v-if="hasContentSlot" #custom-task-content="childScope">
|
||||
<slot name="custom-task-content" v-bind="childScope" />
|
||||
</template>
|
||||
</TaskRow>
|
||||
|
||||
@@ -10,6 +10,10 @@ export { default as TaskRow } from './components/TaskRow.vue'
|
||||
export type { Task } from './models/classes/Task.ts' // 导出Task类型
|
||||
export { useMessage } from './composables/useMessage.ts' // 导出useMessage组合式函数
|
||||
|
||||
// 导出配置类型
|
||||
export type { TaskListConfig, TaskListColumnConfig, TaskListColumnType } from './models/configs/TaskListConfig'
|
||||
export type { ToolbarConfig } from './models/configs/ToolbarConfig'
|
||||
|
||||
// 导出样式文件
|
||||
import './styles/theme-variables.css'
|
||||
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
// TaskList 列配置类型定义
|
||||
|
||||
export type TaskListColumnType =
|
||||
| 'name'
|
||||
| 'predecessor'
|
||||
| 'assignee'
|
||||
| 'startDate'
|
||||
| 'endDate'
|
||||
| 'estimatedHours'
|
||||
| 'actualHours'
|
||||
| 'progress'
|
||||
|
||||
export interface TaskListColumnConfig {
|
||||
type?: TaskListColumnType
|
||||
key: string // 用于国际化的key,也可以作为识别符
|
||||
label?: string // 显示标签
|
||||
cssClass?: string // CSS类名
|
||||
width?: number // 可选的列宽度
|
||||
visible?: boolean // 是否显示,默认true
|
||||
}
|
||||
|
||||
export interface TaskListConfig {
|
||||
columns?: TaskListColumnConfig[]
|
||||
showAllColumns?: boolean // 是否显示所有列,默认true
|
||||
}
|
||||
|
||||
// 默认列配置
|
||||
export const DEFAULT_TASK_LIST_COLUMNS: TaskListColumnConfig[] = [
|
||||
{
|
||||
type: 'name',
|
||||
key: 'taskName',
|
||||
label: '任务名称',
|
||||
cssClass: 'col-name',
|
||||
visible: true,
|
||||
},
|
||||
{
|
||||
type: 'predecessor',
|
||||
key: 'predecessor',
|
||||
label: '前置任务',
|
||||
cssClass: 'col-pre',
|
||||
visible: true,
|
||||
},
|
||||
{
|
||||
type: 'assignee',
|
||||
key: 'assignee',
|
||||
label: '负责人',
|
||||
cssClass: 'col-assignee',
|
||||
visible: true,
|
||||
},
|
||||
{
|
||||
type: 'startDate',
|
||||
key: 'startDate',
|
||||
label: '开始日期',
|
||||
cssClass: 'col-date',
|
||||
visible: true,
|
||||
},
|
||||
{
|
||||
type: 'endDate',
|
||||
key: 'endDate',
|
||||
label: '结束日期',
|
||||
cssClass: 'col-date',
|
||||
visible: true,
|
||||
},
|
||||
{
|
||||
type: 'estimatedHours',
|
||||
key: 'estimatedHours',
|
||||
label: '预估工时',
|
||||
cssClass: 'col-hours',
|
||||
visible: true,
|
||||
},
|
||||
{
|
||||
type: 'actualHours',
|
||||
key: 'actualHours',
|
||||
label: '实际工时',
|
||||
cssClass: 'col-hours',
|
||||
visible: true,
|
||||
},
|
||||
{
|
||||
type: 'progress',
|
||||
key: 'progress',
|
||||
label: '进度',
|
||||
cssClass: 'col-progress',
|
||||
visible: true,
|
||||
},
|
||||
]
|
||||
Reference in New Issue
Block a user