v 1.6.0.preview1 - TaskList Slots

This commit is contained in:
LINING-PC\lining
2025-12-13 21:25:35 +08:00
parent 0c3620c7f7
commit c8aa1ba9a3
10 changed files with 995 additions and 55 deletions
+73 -3
View File
@@ -1,6 +1,6 @@
<script setup lang="ts">
import { ref, computed, onMounted, nextTick } from 'vue'
import GanttChart from '../src/components/GanttChart.vue'
// GanttChart 和 TaskListColumn 已经通过 app.use(JordiumGantt) 全局注册,无需导入
// import TaskDrawer from '../src/components/TaskDrawer.vue' // 移除
import MilestoneDialog from '../src/components/MilestoneDialog.vue'
import normalData from './data.json'
@@ -1126,6 +1126,7 @@ const handleTaskRowMoved = async (payload: {
:on-export-csv="handleCustomCsvExport"
:on-language-change="handleLanguageChange"
:on-theme-change="handleThemeChange"
task-list-column-render-mode="declarative"
@milestone-saved="handleMilestoneSaved"
@milestone-deleted="handleMilestoneDeleted"
@milestone-icon-changed="handleMilestoneIconChanged"
@@ -1162,12 +1163,16 @@ const handleTaskRowMoved = async (payload: {
</template>
<!-- 列级 Slot 示例:'name'列的渲染 -->
<template #header-name>
<div style="display: flex; align-items: center; gap: 6px;">
<img src="https://foruda.gitee.com/avatar/1764902889653058860/565633_nelson820125_1764902889.png!avatar200" width="32" height="32" style="border-radius: 50%;" />
<strong style="font-size: 14px;">{{ t.taskName }}</strong>
</div>
</template>
<template #column-name="{ task, column, value }">
<div style="display: flex; align-items: center; gap: 6px;">
<img src="https://i.pravatar.cc/50?img=1" width="20" height="20" style="border-radius: 50%;" />
<!-- 如果 value 包含 HTML使用 v-html 渲染 -->
<span v-html="value"></span>
<!-- 示例标签 -->
<span
v-if="task.priority"
style="
@@ -1243,6 +1248,41 @@ const handleTaskRowMoved = async (payload: {
</div>
</template>
-->
<!-- 使用 TaskListColumn 组件自定义列 声明式模式 -->
<TaskListColumn prop="name" :label="t.taskName" width="300" align="center">
<template #header>
<img src="https://foruda.gitee.com/avatar/1764902889653058860/565633_nelson820125_1764902889.png!avatar200" width="32" height="32" style="border-radius: 50%;" />
<strong style="font-size: 14px;">{{ t.taskName }}</strong>
</template>
<template #default="scope">
<div style="display: flex; align-items: center; gap: 6px;">
<!-- 里程碑分组图标 - 使用菱形图标 -->
<svg
v-if="scope.row.type === 'milestone-group'"
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
class="milestone-group-icon"
>
<polygon points="12,2 22,12 12,22 2,12" />
</svg>
<img
v-if="scope.row.avatar && scope.row.type === 'task'"
:src="scope.row.avatar"
width="20"
height="20"
style="border-radius: 50%;"
/>
<span v-html="scope.row.name"></span>
</div>
</template>
</TaskListColumn>
<TaskListColumn prop="startDate" :label="t.startDate" width="200" align="center" />
<TaskListColumn prop="endDate" :label="t.endDate" width="200" align="center" />
</GanttChart>
</div>
<div class="license-info">
@@ -2221,6 +2261,22 @@ const handleTaskRowMoved = async (payload: {
brightness(0.7);
}
/* 里程碑分组图标样式 - 统一使用红色并添加发光效果 */
.milestone-group-icon {
color: var(--gantt-danger, #f56c6c);
fill: var(--gantt-danger, #f56c6c);
opacity: 0.9;
filter: drop-shadow(0 0 6px var(--gantt-danger, #f56c6c));
animation: milestone-icon-glow 2.5s ease-in-out infinite alternate;
}
/* 里程碑图标悬停效果 */
.task-row:hover .milestone-group-icon {
filter: drop-shadow(0 0 10px var(--gantt-danger, #f56c6c))
drop-shadow(0 0 16px rgba(245, 108, 108, 0.4));
animation: milestone-icon-glow-intense 1.8s ease-in-out infinite alternate;
}
/* 移除旧的基于 SVG color 的样式,现在使用 filter */
/* 暗黑模式下覆盖所有链接样式 */
@@ -2262,6 +2318,20 @@ const handleTaskRowMoved = async (payload: {
brightness(1.2);
}
/* 暗黑模式下的里程碑图标发光效果 */
:global(html[data-theme='dark']) .milestone-group-icon {
color: var(--gantt-danger, #f67c7c);
fill: var(--gantt-danger, #f67c7c);
filter: drop-shadow(0 0 6px var(--gantt-danger, #f67c7c));
animation: milestone-icon-glow-dark 2.5s ease-in-out infinite alternate;
}
:global(html[data-theme='dark']) .task-row:hover .milestone-group-icon {
filter: drop-shadow(0 0 10px var(--gantt-danger, #f67c7c))
drop-shadow(0 0 16px rgba(246, 124, 124, 0.4));
animation: milestone-icon-glow-intense-dark 1.8s ease-in-out infinite alternate;
}
/* Task Click Dialog 样式 */
.task-click-dialog-overlay {
position: fixed;
+347
View File
@@ -0,0 +1,347 @@
<script setup lang="ts">
import { ref } from 'vue'
import { GanttChart } from '../src/index'
import type { Task } from '../src/models/classes/Task'
// 示例任务数据
const tasks = ref<Task[]>([
{
id: 1,
name: '项目规划',
type: 'story',
startDate: '2024-01-01',
endDate: '2024-01-15',
progress: 100,
assignee: '张三',
collapsed: false,
children: [
{
id: 11,
name: '需求分析',
type: 'task',
startDate: '2024-01-01',
endDate: '2024-01-05',
progress: 100,
assignee: '李四',
},
{
id: 12,
name: '技术方案设计',
type: 'task',
startDate: '2024-01-06',
endDate: '2024-01-15',
progress: 100,
assignee: '王五',
},
],
},
{
id: 2,
name: '开发阶段',
type: 'story',
startDate: '2024-01-16',
endDate: '2024-02-28',
progress: 65,
assignee: '张三',
collapsed: false,
children: [
{
id: 21,
name: '前端开发',
type: 'task',
startDate: '2024-01-16',
endDate: '2024-02-15',
progress: 80,
assignee: '赵六',
},
{
id: 22,
name: '后端开发',
type: 'task',
startDate: '2024-01-16',
endDate: '2024-02-20',
progress: 70,
assignee: '孙七',
},
{
id: 23,
name: '数据库设计',
type: 'task',
startDate: '2024-01-20',
endDate: '2024-02-10',
progress: 50,
assignee: '周八',
},
],
},
{
id: 3,
name: '测试上线',
type: 'story',
startDate: '2024-03-01',
endDate: '2024-03-15',
progress: 30,
assignee: '张三',
collapsed: false,
children: [
{
id: 31,
name: '功能测试',
type: 'task',
startDate: '2024-03-01',
endDate: '2024-03-08',
progress: 40,
assignee: '吴九',
},
{
id: 32,
name: '性能优化',
type: 'task',
startDate: '2024-03-05',
endDate: '2024-03-12',
progress: 20,
assignee: '郑十',
},
{
id: 33,
name: '生产部署',
type: 'task',
startDate: '2024-03-13',
endDate: '2024-03-15',
progress: 0,
assignee: '钱十一',
},
],
},
])
const milestones = ref<Task[]>([])
// Helper function for progress bar background
const getProgressColor = (progress: number) => {
if (progress >= 100) return '#67c23a'
if (progress >= 50) return '#409eff'
return '#e6a23c'
}
</script>
<template>
<div class="declarative-demo">
<h1>声明式列定义演示 (Declarative Columns Demo)</h1>
<div class="demo-section">
<h2>示例 1: 基础声明式列</h2>
<GanttChart
:tasks="tasks"
:milestones="milestones"
task-list-column-render-mode="declarative"
:show-toolbar="false"
style="height: 400px"
>
<TaskListColumn prop="assignee" label="负责人" width="120" align="center" />
<TaskListColumn prop="name" label="任务名称" width="300" />
<TaskListColumn prop="startDate" label="开始日期" width="140" />
<TaskListColumn prop="endDate" label="结束日期" width="140" />
<TaskListColumn prop="progress" label="进度" width="100" align="center" />
</GanttChart>
</div>
<div class="demo-section">
<h2>示例 2: 使用默认 Slot 自定义列内容</h2>
<GanttChart
:tasks="tasks"
:milestones="milestones"
task-list-column-render-mode="declarative"
:show-toolbar="false"
style="height: 400px"
>
<TaskListColumn prop="name" label="任务名称" width="300" />
<!-- 自定义负责人列显示 -->
<TaskListColumn prop="assignee" label="负责人" width="150" align="center">
<template #default="scope">
<div class="assignee-cell">
<div class="avatar">
{{ scope.row.assignee ? scope.row.assignee.charAt(0).toUpperCase() : '?' }}
</div>
<span>{{ scope.row.assignee || '未分配' }}</span>
</div>
</template>
</TaskListColumn>
<!-- 自定义进度列显示 -->
<TaskListColumn prop="progress" label="进度" width="150" align="center">
<template #default="scope">
<div class="progress-cell">
<div class="progress-bar-container">
<div
class="progress-bar"
:style="{
width: `${scope.row.progress || 0}%`,
background: getProgressColor(scope.row.progress || 0),
}"
></div>
</div>
<span class="progress-text">{{ scope.row.progress || 0 }}%</span>
</div>
</template>
</TaskListColumn>
<TaskListColumn prop="startDate" label="开始" width="120" />
<TaskListColumn prop="endDate" label="结束" width="120" />
</GanttChart>
</div>
<div class="demo-section">
<h2>示例 3: 自定义表头</h2>
<GanttChart
:tasks="tasks"
:milestones="milestones"
task-list-column-render-mode="declarative"
:show-toolbar="false"
style="height: 400px"
>
<TaskListColumn prop="name" width="300">
<template #header>
<div class="header-with-icon">
<svg
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<path
d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-5l-2-2H5a2 2 0 00-2 2z"
/>
</svg>
<span class="header-title">任务信息</span>
</div>
</template>
</TaskListColumn>
<TaskListColumn prop="assignee" width="150">
<template #header>
<div class="header-success">👤 负责人</div>
</template>
</TaskListColumn>
<TaskListColumn prop="progress" width="150">
<template #header>
<div class="header-warning">📊 完成度</div>
</template>
<template #default="scope">
<span :class="scope.row.progress >= 100 ? 'text-success' : 'text-warning'">
{{ scope.row.progress || 0 }}%
</span>
</template>
</TaskListColumn>
<TaskListColumn prop="startDate" label="开始日期" width="140" />
<TaskListColumn prop="endDate" label="结束日期" width="140" />
</GanttChart>
</div>
</div>
</template>
<style scoped>
.declarative-demo {
padding: 20px;
background: #f5f5f5;
min-height: 100vh;
}
h1 {
color: #333;
margin-bottom: 30px;
}
.demo-section {
background: white;
border-radius: 8px;
padding: 20px;
margin-bottom: 30px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.demo-section h2 {
color: #409eff;
margin-bottom: 15px;
font-size: 18px;
}
.assignee-cell {
display: flex;
align-items: center;
gap: 8px;
justify-content: center;
}
.avatar {
width: 24px;
height: 24px;
border-radius: 50%;
background: #409eff;
color: white;
display: flex;
align-items: center;
justify-content: center;
font-size: 12px;
}
.progress-cell {
display: flex;
align-items: center;
gap: 8px;
}
.progress-bar-container {
flex: 1;
height: 8px;
background: #f0f0f0;
border-radius: 4px;
overflow: hidden;
}
.progress-bar {
height: 100%;
transition: width 0.3s;
}
.progress-text {
min-width: 40px;
text-align: right;
}
.header-with-icon {
display: flex;
align-items: center;
gap: 4px;
color: #409eff;
}
.header-title {
font-weight: bold;
}
.header-success {
color: #67c23a;
font-weight: bold;
}
.header-warning {
color: #e6a23c;
font-weight: bold;
}
.text-success {
color: #67c23a;
}
.text-warning {
color: #e6a23c;
}
</style>
+7 -1
View File
@@ -1,5 +1,11 @@
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import JordiumGantt from '../src/index'
// import DeclarativeColumnsDemo from './DeclarativeColumnsDemo.vue'
createApp(App).mount('#app')
// 使用 DeclarativeColumnsDemo 替代 App 来演示声明式列功能
// 如果要切换回原来的演示,取消注释 App 并注释掉 DeclarativeColumnsDemo
const app = createApp(App)
app.use(JordiumGantt) // 全局注册 GanttChart 和 TaskListColumn
app.mount('#app')