@squallfire/vuegantt
v0.0.5
Published
A powerful Gantt chart component built with Vue 3 and Canvas
Readme
VueGantt
一个功能强大的 Vue 3 甘特图组件库,基于 Canvas 高性能渲染,支持任务管理、依赖关系、主题切换和国际化。
📷 预览

✨ 功能特性
核心功能
- 📊 任务管理 - 支持创建、编辑、删除任务
- 🎯 拖拽调整 - 拖拽任务条调整日期和进度
- 🔗 依赖关系 - 支持 FS/SS/FF/SF 四种依赖类型
- 🏁 里程碑 - 支持里程碑节点显示
- 📁 任务分组 - 支持父子任务层级关系
视图与显示
- 📅 多种视图 - 支持日/周/月/季度四种视图模式
- 🎨 主题切换 - 支持亮色和暗色主题
- 🌍 国际化 - 支持中文和英文
- 📱 响应式 - 灵活适应不同屏幕尺寸
交互功能
- ⌨️ 键盘快捷键 - Delete 删除、Ctrl+C/V 复制粘贴、←→ 移动任务
- 🖱️ 快捷操作面板 - 内置快捷键帮助和滚动操作提示
- 🎡 鼠标滚轮滚动 - 时间轴区域垂直滚动可触发水平滚动
- 🔄 滚动同步 - 时间轴滚动时同步更新 Canvas 渲染
运行示例
pnpm dev
| 示例目录 | 说明 |
| -------------------- | ---------------------------------------- |
| `examples/basic` | 基础甘特图,包含任务创建、拖拽、依赖关系 |
| `examples/theme` | 亮色/暗色主题切换 |
| `examples/view-mode` | 日/周/月/季度视图切换 |
| `examples/i18n` | 中英文国际化 |
## 🛠️ 开发命令
```bash
# 安装依赖
pnpm install
# 开发模式(启动后访问 http://localhost:5173)
pnpm dev
# 构建
pnpm build
# 运行测试
pnpm test
# 代码格式检查
pnpm lint
```
## 🚀 快速开始
### 在线演示
直接打开 `public/demo.html` 即可查看演示页面:
```bash
# 使用任意 HTTP 服务器
npx serve public/demo.html
# 或者使用 VS Code 的 Live Server 插件
# 或者直接用浏览器打开文件
```
### 安装
```bash
# 使用 npm
npm install @squallfire/vuegantt
# 使用 pnpm
pnpm add @squallfire/vuegantt
```
### 基础用法
```vue
<script setup lang="ts">
import { GanttChart } from '@squallfire/vuegantt'
import type { GanttTask } from '@squallfire/vuegantt'
const tasks: GanttTask[] = [
{
id: '1',
name: '项目启动',
startDate: new Date('2024-01-01'),
endDate: new Date('2024-01-05'),
progress: 100,
},
{
id: '2',
name: '需求分析',
startDate: new Date('2024-01-06'),
endDate: new Date('2024-01-10'),
progress: 60,
dependencies: ['1'],
},
]
</script>
<template>
<GanttChart :tasks="tasks" />
</template>
```
## 📖 使用文档
### 任务数据类型
```typescript
interface GanttTask {
id: string // 唯一标识
name: string // 任务名称
startDate: Date // 开始日期
endDate: Date // 结束日期
progress: number // 进度 (0-100)
type?: 'task' | 'milestone' | 'group' // 任务类型
isMilestone?: boolean // 是否为里程碑
dependencies?: string[] // 依赖任务ID数组
dependencyDetails?: TaskDependency[] // 依赖详情
assignee?: string // 负责人(对应用户 user_id)
description?: string // 描述
color?: string // 自定义颜色
isExpanded?: boolean // 是否展开(分组任务)
children?: GanttTask[] // 子任务
parentId?: string // 父任务ID
}
```
### 默认用户列表
组件内置了默认用户列表,可在任务分配时使用:
| 字段 | 类型 | 说明 |
| --------- | ------ | ------------ |
| user_id | string | 用户唯一标识 |
| user_name | string | 用户名称 |
**用户列表数据:**
```javascript
const users = [
{ user_id: '1', user_name: '张三' },
{ user_id: '2', user_name: '李四' },
{ user_id: '3', user_name: '王五' },
{ user_id: '4', user_name: '赵六' },
{ user_id: '5', user_name: '钱七' },
]
```
在任务编辑弹窗中选择负责人时,会显示上述用户列表供选择。
### 视图模式
```typescript
type ViewMode = 'day' | 'week' | 'month' | 'quarter'
```
| 模式 | 说明 | 适用场景 |
| --------- | -------- | ---------------------- |
| `day` | 日视图 | 短期任务、详细进度跟踪 |
| `week` | 周视图 | 中期项目规划(默认) |
| `month` | 月视图 | 月度计划、里程碑追踪 |
| `quarter` | 季度视图 | 长期战略规划 |
### Props 配置
| 属性 | 类型 | 默认值 | 说明 |
| ----------------- | ------------------- | --------- | -------------------- |
| `tasks` | `GanttTask[]` | `[]` | 任务列表 |
| `columns` | `Column[]` | 默认列 | 任务列表列配置 |
| `viewMode` | `ViewMode` | `'week'` | 视图模式 |
| `startDate` | `Date \| undefined` | 自动计算 | 甘特图开始日期 |
| `endDate` | `Date \| undefined` | 自动计算 | 甘特图结束日期 |
| `theme` | `'light' \| 'dark'` | `'light'` | 主题 |
| `locale` | `'en' \| 'zh-CN'` | `'zh-CN'` | 语言 |
| `rowHeight` | `number` | `36` | 行高(像素) |
| `showWeekends` | `boolean` | `true` | 是否显示周末背景 |
| `showToday` | `boolean` | `true` | 是否高亮今天 |
| `enableDrag` | `boolean` | `true` | 是否启用任务拖拽 |
| `enableResize` | `boolean` | `true` | 是否启用任务调整大小 |
| `enableCreate` | `boolean` | `true` | 是否允许创建任务 |
| `enableEdit` | `boolean` | `true` | 是否允许编辑任务 |
| `enableShortcuts` | `boolean` | `true` | 是否启用键盘快捷键 |
### 事件处理
```vue
<script setup lang="ts">
import { GanttChart } from '@squallfire/vuegantt'
import type { GanttTask } from '@squallfire/vuegantt'
function handleTaskClick(task: GanttTask, event: MouseEvent) {
console.log('点击任务:', task.name)
}
function handleDateChange(task: GanttTask, start: Date, end: Date) {
console.log('日期变更:', task.name, start, end)
}
function handleProgressChange(task: GanttTask, progress: number) {
console.log('进度变更:', task.name, progress)
}
function handleTaskAdd(task: Partial<GanttTask>) {
console.log('新增任务:', task)
}
function handleTaskDelete(taskId: string) {
console.log('删除任务:', taskId)
}
</script>
<template>
<GanttChart
:tasks="tasks"
@task-click="handleTaskClick"
@task-date-change="handleDateChange"
@task-progress-change="handleProgressChange"
@task-add="handleTaskAdd"
@task-delete="handleTaskDelete"
/>
</template>
```
| 事件名 | 参数 | 说明 |
| ---------------------- | -------------------- | ---------------- |
| `task-click` | `(task, event)` | 点击任务 |
| `task-dblclick` | `(task, event)` | 双击任务(编辑) |
| `task-change` | `(task)` | 任务内容变化 |
| `task-date-change` | `(task, start, end)` | 任务日期变化 |
| `task-progress-change` | `(task, progress)` | 任务进度变化 |
| `task-add` | `(task)` | 新增任务 |
| `task-delete` | `(taskId)` | 删除任务 |
| `view-mode-change` | `(mode)` | 视图模式变化 |
| `theme-change` | `(theme)` | 主题变化 |
| `locale-change` | `(locale)` | 语言变化 |
## 💻 示例代码
### 示例 1:基础甘特图
```vue
<script setup lang="ts">
import { GanttChart } from '@squallfire/vuegantt'
import type { GanttTask } from '@squallfire/vuegantt'
import { ref } from 'vue'
const tasks: GanttTask[] = [
{
id: '1',
name: '项目规划',
startDate: new Date('2024-01-01'),
endDate: new Date('2024-01-07'),
progress: 100,
},
{
id: '2',
name: '需求分析',
startDate: new Date('2024-01-08'),
endDate: new Date('2024-01-14'),
progress: 80,
dependencies: ['1'],
},
{
id: '3',
name: 'UI 设计',
startDate: new Date('2024-01-15'),
endDate: new Date('2024-01-21'),
progress: 50,
dependencies: ['2'],
},
{
id: '4',
name: '开发实现',
startDate: new Date('2024-01-22'),
endDate: new Date('2024-02-05'),
progress: 30,
dependencies: ['3'],
},
{
id: '5',
name: '测试验收',
startDate: new Date('2024-02-06'),
endDate: new Date('2024-02-15'),
progress: 0,
dependencies: ['4'],
},
]
const viewMode = ref<ViewMode>('week')
</script>
<template>
<div style="height: 500px;">
<GanttChart :tasks="tasks" v-model:viewMode="viewMode" />
</div>
</template>
```
### 示例 2:带依赖关系的任务
```vue
<script setup lang="ts">
import { GanttChart } from '@squallfire/vuegantt'
import type { GanttTask, TaskDependency } from '@squallfire/vuegantt'
const tasks: GanttTask[] = [
{
id: 'task-1',
name: '需求收集',
startDate: new Date('2024-01-01'),
endDate: new Date('2024-01-05'),
progress: 100,
},
{
id: 'task-2',
name: '系统设计',
startDate: new Date('2024-01-06'),
endDate: new Date('2024-01-12'),
progress: 60,
// 简化版依赖
dependencies: ['task-1'],
},
{
id: 'task-3',
name: '编码开发',
startDate: new Date('2024-01-13'),
endDate: new Date('2024-01-25'),
progress: 30,
// 详细依赖配置
dependencyDetails: [
{
taskId: 'task-3',
dependsOn: 'task-2',
type: 'FS', // Finish to Start
style: 'solid',
},
],
},
]
</script>
<template>
<div style="height: 400px;">
<GanttChart :tasks="tasks" />
</div>
</template>
```
### 示例 3:里程碑和自定义颜色
```vue
<script setup lang="ts">
import { GanttChart } from '@squallfire/vuegantt'
import type { GanttTask } from '@squallfire/vuegantt'
const tasks: GanttTask[] = [
{
id: 'milestone-1',
name: '项目启动会',
startDate: new Date('2024-01-01'),
endDate: new Date('2024-01-01'),
progress: 100,
isMilestone: true,
color: '#f59e0b', // 橙色里程碑
},
{
id: 'task-1',
name: '第一阶段开发',
startDate: new Date('2024-01-02'),
endDate: new Date('2024-01-20'),
progress: 50,
color: '#3b82f6', // 蓝色
},
{
id: 'milestone-2',
name: '阶段验收',
startDate: new Date('2024-01-21'),
endDate: new Date('2024-01-21'),
progress: 100,
isMilestone: true,
color: '#10b981', // 绿色里程碑
dependencies: ['task-1'],
},
{
id: 'task-2',
name: '第二阶段开发',
startDate: new Date('2024-01-22'),
endDate: new Date('2024-02-10'),
progress: 0,
color: '#8b5cf6', // 紫色
dependencies: ['task-1'],
},
]
</script>
<template>
<div style="height: 400px;">
<GanttChart :tasks="tasks" />
</div>
</template>
```
### 示例 4:主题切换
```vue
<script setup lang="ts">
import { GanttChart } from '@squallfire/vuegantt'
import type { GanttTask } from '@squallfire/vuegantt'
import { ref } from 'vue'
const tasks: GanttTask[] = [...]
const theme = ref<'light' | 'dark'>('light')
function toggleTheme() {
theme.value = theme.value === 'light' ? 'dark' : 'light'
}
function handleThemeChange(newTheme: 'light' | 'dark') {
console.log('主题已切换:', newTheme)
}
</script>
<template>
<div>
<button @click="toggleTheme">
{{ theme === 'light' ? '🌙 切换暗色' : '☀️ 切换亮色' }}
</button>
<GanttChart
:tasks="tasks"
:theme="theme"
@theme-change="handleThemeChange"
style="height: 500px;"
/>
</div>
</template>
```
### 示例 5:国际化
```vue
<script setup lang="ts">
import { GanttChart } from '@squallfire/vuegantt'
import type { GanttTask, ViewMode } from '@squallfire/vuegantt'
import { ref } from 'vue'
const tasks: GanttTask[] = [...]
const locale = ref<'en' | 'zh-CN'>('zh-CN')
const viewMode = ref<ViewMode>('week')
</script>
<template>
<div>
<div class="controls">
<select v-model="locale">
<option value="zh-CN">中文</option>
<option value="en">English</option>
</select>
<select v-model="viewMode">
<option value="day">日视图</option>
<option value="week">周视图</option>
<option value="month">月视图</option>
<option value="quarter">季度视图</option>
</select>
</div>
<GanttChart
:tasks="tasks"
:locale="locale"
v-model:viewMode="viewMode"
style="height: 500px;"
/>
</div>
</template>
```
> 📁 更多示例请参考 `examples/` 文件夹
## ⌨️ 键盘快捷键
| 快捷键 | 功能 |
| ---------- | -------------------- |
| `Delete` | 删除选中任务 |
| `Ctrl + C` | 复制任务 |
| `Ctrl + V` | 粘贴任务 |
| `←` | 向左移动任务(一天) |
| `→` | 向右移动任务(一天) |
| `Esc` | 取消选中 / 关闭弹窗 |
## 🖱️ 鼠标操作
| 操作 | 功能 |
| ------------ | ------------------ |
| 双击空白区域 | 新建任务 |
| 双击任务 | 编辑任务 |
| 拖拽任务条 | 调整任务日期和进度 |
| 拖拽依赖点 | 创建任务依赖关系 |
| 右键依赖线 | 删除依赖关系 |
## 📁 项目结构
```
@squallfire/vuegantt/
├── src/
│ ├── main.ts # 入口文件
│ ├── App.vue # 根组件
│ ├── index.ts # 库导出入口
│ ├── data/
│ │ └── sampleData.ts # 示例数据
│ ├── types/
│ │ ├── gantt.ts # 类型定义
│ │ └── gantt.spec.ts # 类型测试
│ ├── stores/
│ │ ├── gantt.ts # Pinia 状态管理
│ │ └── gantt.spec.ts # Store 测试
│ ├── composables/
│ │ ├── useTheme.ts # 主题管理
│ │ ├── useTheme.spec.ts # 主题测试
│ │ ├── useToast.ts # 提示消息
│ │ └── useKeyboardShortcuts.ts # 键盘快捷键
│ ├── i18n/
│ │ ├── index.ts # 国际化入口
│ │ ├── zh-CN.ts # 中文翻译
│ │ └── en.ts # 英文翻译
│ ├── renderer/
│ │ ├── canvas-architecture.ts # Canvas 架构文档
│ │ └── canvas/
│ │ ├── CanvasRenderer.ts # Canvas 渲染器
│ │ ├── CanvasRenderer.spec.ts # 渲染器测试
│ │ ├── index.ts
│ │ └── utils/
│ │ ├── dateUtils.ts # 日期工具
│ │ └── dateUtils.spec.ts # 日期工具测试
│ ├── components/
│ │ ├── HelloWorld.vue # 示例组件
│ │ └── gantt/
│ │ ├── index.ts # 组件导出
│ │ ├── GanttChart.vue # 主组件
│ │ ├── TaskList/ # 任务列表
│ │ │ ├── TaskList.vue
│ │ │ └── index.ts
│ │ ├── TimeAxis/ # 时间轴
│ │ │ ├── TimeAxis.vue
│ │ │ └── index.ts
│ │ ├── interaction/ # 交互组件
│ │ │ ├── DragHandler.ts
│ │ │ ├── DragHandler.spec.ts
│ │ │ └── ViewSwitcher.vue
│ │ ├── dialogs/ # 对话框
│ │ │ └── TaskEditDialog.vue
│ │ ├── ToastContainer.vue # 提示容器
│ │ ├── ColumnConfigDemo.vue # 列配置示例
│ │ └── DependencyDemo.vue # 依赖关系示例
├── examples/ # 示例代码
│ ├── basic/ # 基础示例
│ ├── theme/ # 主题切换示例
│ ├── view-mode/ # 视图模式示例
│ └── i18n/ # 国际化示例
├── docs/ # 文档
├── public/ # 静态资源
├── package.json
├── vite.config.js # Vite 配置
└── tsconfig.json # TypeScript 配置
```
## 🧪 在线示例
项目提供了完整的在线示例,可以直接运行:
```bash
# 进入示例目录
cd examples/basic # 基础示例
cd examples/theme # 主题切换示例
cd examples/view-mode # 视图模式示例
cd examples/i18n # 国际化示例
## 📄 许可证
MIT License - 请随意使用和修改。
## 🤝 贡献
欢迎提交 Issue 和 Pull Request!
## 🐛 已知问题
```