# 使用文档
# 介绍
# 安装
npm install gantt-elastic-h --save # yarn add gantt-elastic-h # pnpm add gantt-elastic-h
点击查看代码
<!--
/**
* @fileoverview GanttElastic standalone version component
* @license MIT
* @author Rafal Pospiech <neuronet.io@gmail.com>
* @package
*/
-->
<template>
<div>
<gantt-elastic ref="elastic" :tasks="tasks" :options="options" :dynamicStyle="dynamicStyle">
<div slot="header">
<el-form size="mini" inline>
<el-form-item label="显示模式:">
<el-radio-group v-model="modeRadio">
<el-radio :label="false">图表</el-radio>
<el-radio :label="true">列表 + 图表</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item>
<el-button @click="goNow">Go Now</el-button>
</el-form-item>
<el-form-item label="zoom-Y">
<el-slider v-model="height" :min="7" :max="100" style="width: 200px"></el-slider>
</el-form-item>
</el-form>
</div>
<component v-if="components.footer" :is="components.footer" slot="footer"></component>
<template slot="label" slot-scope="{ task }">
<div>{{ task.label }}</div>
</template>
<template slot="operation" slot-scope="row">
<el-button size="mini" @click="onUpdate(row)">修改</el-button>
</template>
</gantt-elastic>
<el-dialog title="修改" :visible.sync="dialogFormVisible">
<el-form ref="form" :model="form" :rules="rules" label-width="120px">
<el-form-item label="Description" prop="label">
<el-input v-model="form.label" placeholder="Description"></el-input>
</el-form-item>
<el-form-item label="Assigned to" prop="user">
<el-input v-model="form.user" placeholder="Assigned to"></el-input>
</el-form-item>
<el-form-item label="Start" prop="timeArr">
<el-date-picker
v-model="form.timeArr"
type="daterange"
placeholder="选择日期"
format="yyyy 年 MM 月 dd 日"
value-format="timestamp"
>
</el-date-picker>
</el-form-item>
<el-form-item label="progress" prop="progress">
<el-input-number
v-model="form.progress"
controls-position="right"
:min="0"
:max="100"
placeholder="progress"
></el-input-number>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">取 消</el-button>
<el-button type="primary" @click="onSubmit">确 定</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import dayjs from 'dayjs';
import GanttElastic from '../src/GanttElastic.vue';
function getDate(hours) {
const currentDate = new Date();
const currentYear = currentDate.getFullYear();
const currentMonth = currentDate.getMonth() + 1;
const currentDay = currentDate.getDate();
const timeStamp = new Date(`${currentYear}-${currentMonth}-${currentDay} 00:00:00`).getTime();
return new Date(timeStamp + hours * 60 * 60 * 1000).getTime();
}
export default {
name: 'GanttElasticStandalone',
components: {
'gantt-elastic': GanttElastic,
},
props: ['header', 'footer'],
data() {
return {
dialogFormVisible: false,
form: {
id: '',
label: '',
user: '',
progress: '',
timeArr: [],
},
rules: {
label: [{ required: true, message: '不能为空', trigger: ['blur', 'change'] }],
user: [{ required: true, message: '不能为空', trigger: ['blur', 'change'] }],
progress: [{ required: true, message: '不能为空', trigger: ['blur', 'change'] }],
timeArr: [{ required: true, message: '不能为空', trigger: ['blur', 'change'] }],
},
// modeRadio: '',
components: {},
tasks: [
{
id: 1,
label: 'Make some noise',
user: '<a href="https://www.google.com/search?q=John+Doe" target="_blank" style="color:#0077c0;">John Doe</a>',
start: getDate(-24 * 5),
duration: 15 * 24 * 60 * 60 * 1000,
percent: 85,
type: 'project',
// collapsed: false,
},
{
id: 2,
label: 'With great power comes great responsibility',
user: '<a href="https://www.google.com/search?q=Peter+Parker" target="_blank" style="color:#0077c0;">Peter Parker</a>',
parentId: 1,
start: getDate(-24 * 4),
duration: 4 * 24 * 60 * 60 * 1000,
percent: 50,
type: 'milestone',
collapsed: true,
style: {
base: {
fill: '#1EBC61',
stroke: '#0EAC51',
},
/*'tree-row-bar': {
fill: '#1EBC61',
stroke: '#0EAC51'
},
'tree-row-bar-polygon': {
stroke: '#0EAC51'
}*/
},
},
{
id: 3,
label: 'Courage is being scared to death, but saddling up anyway.',
user: '<a href="https://www.google.com/search?q=John+Wayne" target="_blank" style="color:#0077c0;">John Wayne</a>',
parentId: 2,
start: getDate(-24 * 3),
duration: 2 * 24 * 60 * 60 * 1000,
percent: 100,
type: 'task',
},
{
id: 4,
label: 'Put that toy AWAY!',
user: '<a href="https://www.google.com/search?q=Clark+Kent" target="_blank" style="color:#0077c0;">Clark Kent</a>',
start: getDate(-24 * 2),
duration: 2 * 24 * 60 * 60 * 1000,
percent: 50,
type: 'task',
},
{
id: 5,
label: 'One billion, gajillion, fafillion... shabadylu...mil...shabady......uh, Yen.',
user: '<a href="https://www.google.com/search?q=Austin+Powers" target="_blank" style="color:#0077c0;">Austin Powers</a>',
parentId: 4,
start: getDate(0),
duration: 2 * 24 * 60 * 60 * 1000,
percent: 10,
type: 'milestone',
style: {
base: {
fill: '#0287D0',
stroke: '#0077C0',
},
},
},
{
id: 6,
label: 'Butch Mario and the Luigi Kid',
user: '<a href="https://www.google.com/search?q=Mario+Bros" target="_blank" style="color:#0077c0;">Mario Bros</a>',
parentId: 5,
start: getDate(24),
duration: 1 * 24 * 60 * 60 * 1000,
percent: 50,
type: 'task',
collapsed: true,
style: {
base: {
fill: '#8E44AD',
stroke: '#7E349D',
},
},
},
{
id: 7,
label: 'Devon, the old man wanted me, it was his dying request',
user: '<a href="https://www.google.com/search?q=Knight+Rider" target="_blank" style="color:#0077c0;">Knight Rider</a>',
parentId: 2,
dependentOn: [6],
start: getDate(24 * 2),
duration: 4 * 60 * 60 * 1000,
percent: 20,
type: 'task',
collapsed: true,
},
{
id: 8,
label: 'Hey, Baby! Anybody ever tell you I have beautiful eyes?',
user: '<a href="https://www.google.com/search?q=Johhny+Bravo" target="_blank" style="color:#0077c0;">Johhny Bravo</a>',
parentId: 7,
dependentOn: [7],
start: dayjs().startOf('day').valueOf(),
end: dayjs().startOf('day').add(1, 'day').valueOf(),
percent: 0,
type: 'task',
},
{
id: 9,
label: 'This better be important, woman. You are interrupting my very delicate calculations.',
user: '<a href="https://www.google.com/search?q=Dexter\'s+Laboratory" target="_blank" style="color:#0077c0;">Dexter\'s Laboratory</a>',
parentId: 8,
dependentOn: [8, 7],
start: getDate(24 * 4),
duration: 4 * 60 * 60 * 1000,
percent: 20,
type: 'task',
style: {
base: {
fill: '#8E44AD',
stroke: '#7E349D',
},
/*'tree-row-bar-polygon': {
stroke: '#7E349D'
},
'tree-row-bar': {
fill: '#8E44AD',
stroke: '#7E349D'
}*/
},
},
{
id: 10,
label: 'current task',
user: '<a href="https://www.google.com/search?q=Johnattan+Owens" target="_blank" style="color:#0077c0;">Johnattan Owens</a>',
start: getDate(24 * 5),
duration: 24 * 60 * 60 * 1000,
percent: 0,
type: 'task',
},
{
id: 11,
label: 'test task',
user: '<a href="https://www.google.com/search?q=Johnattan+Owens" target="_blank" style="color:#0077c0;">Johnattan Owens</a>',
start: getDate(24 * 6),
duration: 24 * 60 * 60 * 1000,
percent: 0,
type: 'task',
},
{
id: 12,
label: 'test task',
user: '<a href="https://www.google.com/search?q=Johnattan+Owens" target="_blank" style="color:#0077c0;">Johnattan Owens</a>',
start: getDate(24 * 7),
duration: 24 * 60 * 60 * 1000,
percent: 0,
type: 'task',
parentId: 11,
},
{
id: 13,
label: 'test task',
user: '<a href="https://www.google.com/search?q=Johnattan+Owens" target="_blank" style="color:#0077c0;">Johnattan Owens</a>',
start: getDate(24 * 8),
duration: 24 * 60 * 60 * 1000,
percent: 0,
type: 'task',
},
{
id: 14,
label: 'test task',
user: '<a href="https://www.google.com/search?q=Johnattan+Owens" target="_blank" style="color:#0077c0;">Johnattan Owens</a>',
start: getDate(24 * 9),
end: getDate(24 * 12),
percent: 0,
type: 'task',
},
{
id: 15,
label: 'test task',
user: '<a href="https://www.google.com/search?q=Johnattan+Owens" target="_blank" style="color:#0077c0;">Johnattan Owens</a>',
start: getDate(24 * 16),
duration: 24 * 60 * 60 * 1000,
percent: 0,
type: 'task',
},
],
options: {
taskMapping: {
progress: 'percent',
},
// maxRows: 2,
// maxHeight: 500,
title: {
label: 'Your project title as html (link or whatever...)',
html: false,
},
row: {
height: 24,
},
calendar: {
// hour: {
// // display: true,
// format: {
// short(date) {
// return '1';
// },
// },
// },
},
chart: {
progress: {
bar: false,
},
expander: {
display: true,
},
},
taskList: {
display: true,
expander: {
straight: false,
},
columns: [
{
id: 1,
label: 'ID',
value: 'id',
width: 40,
},
{
id: 2,
label: 'Description',
value: 'label',
width: 200,
expander: true,
// html: true,
slot: 'label',
events: {
click({ data, column }) {
alert('description clicked!\n' + data.label);
},
},
},
{
id: 3,
label: 'Assigned to',
value: 'user',
width: 130,
html: true,
},
{
id: 3,
label: 'Start',
value: (task) => dayjs(task.start).format('YYYY-MM-DD'),
width: 78,
},
{
id: 4,
label: 'Type',
value: 'type',
width: 68,
},
{
id: 5,
label: '%',
value: 'progress',
width: 70,
html: true,
style: {
'task-list-header-label': {
'text-align': 'center',
width: '100%',
},
'task-list-item-value-container': {
'text-align': 'center',
width: '100%',
},
},
},
{
id: 6,
label: '操作',
value: 'operation',
slot: 'operation',
width: 80,
style: {
'task-list-header-label': {
'text-align': 'center',
width: '100%',
},
'task-list-item-value-container': {
'text-align': 'center',
width: '100%',
},
},
},
],
},
},
dynamicStyle: {},
};
},
computed: {
modeRadio: {
get() {
return this.options.taskList.display;
},
set(val) {
console.log(val);
this.options.taskList.display = val;
},
},
height: {
get() {
console.log(this.options.row.height);
return this.options.row.height;
},
set(value) {
const elastic = this.$refs.elastic;
elastic.$emit('row-height-change', Number(value));
},
},
},
methods: {
onUpdate(row) {
console.log(row);
Object.keys(this.form).forEach((item) => {
if (item === 'timeArr') {
this.form[item] = [row.task['startTime'], row.task['endTime']];
} else {
this.form[item] = row.task[item];
}
});
this.dialogFormVisible = true;
},
onSubmit() {
const elastic = this.$refs.elastic;
this.$refs['form'].validate((valid) => {
if (valid) {
const time = this.form.timeArr;
elastic.updateTask(this.form.id, this.form);
elastic.updateTaskTime(this.form.id, time[0], time[1]);
this.dialogFormVisible = false;
console.log(this.tasks);
} else {
console.log('error submit!!');
return false;
}
});
},
goNow(type) {
const elastic = this.$refs.elastic;
elastic.goCurrentTime();
},
},
};
</script>
# 配置
# props
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
tasks | 任务列表 | Object | -- | -- |
options | 配置项 | |||
dynamicStyle | 自定义样式设置,样式字典 (opens new window) | Object | -- | -- |
# tasks
任务列表
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
parentId | 父 ID -- 用于生成树 | Number / String | -- | -- |
type | 任务类型, 可根据 options.taskMapping 修改字段名 必填 | String | milestone,task,project | -- |
start | 开始时间, 可根据 options.taskMapping 修改字段名 必填 | date | -- | -- |
duration | 任务持续时间(时间戳),可根据 options.taskMapping 修改字段名 必填 | Number | -- | -- |
progress | 任务完成百分比 ,可根据 options.taskMapping 修改字段名 必填 | Number | -- | -- |
collapsed | 是否默认收起,可根据 options.taskMapping 修改字段名 必填 | Boolean | -- | false |
style | 当前任务,样式设置。参考 (opens new window),样式字典 (opens new window) | Object | -- | -- |
# options
配置项
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
taskList | 左侧列表相关配置 | Object | -- | -- |
taskMapping | 组件需要用到的字段枚举。具体看下表 | Object | -- | -- |
scroll | 内容滚动相关配置。具体看下表 | Object | -- | -- |
scope | 右侧图表前后日期范围。具体看下表 | Object | -- | -- |
times | 右侧图表时间相关配置。具体看下表 | Object | -- | -- |
row | 左侧列表,行配置。具体看下表 | Object | -- | -- |
maxRows | 最多显示行数 | Number | -- | 20 |
maxHeight | 最大高度 (maxHeight 权重大于 MaxRows, maxHeight = 0 则不考虑该参数) | Number | -- | 0 |
chart | 右侧图表内容相关配置。具体看下表 | Object | -- | -- |
calendar | 右侧图表日历(日期)相关配置。具体看下表 | Object | -- | -- |
locale | i18n(语言包)配置,和 dayjs 的语言包一样; | Object | -- | -- |
# options.taskList
左侧列表相关配置
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
display | 是否显示左侧任务列表 | Boolean | -- | true |
widthThreshold | -- | Number | -- | -- |
columns | 任务列表 -- 列配置, 详细配置见下表 | Arrary | -- | [{ id: 0, label: 'ID', value: 'id', width: 40, }] |
percent | -- | Number | -- | 100 |
minWidth | 列最小宽度 | Number | -- | 18 |
expander | 任务列表 -- 折叠按钮配置,详细配置见下表 | Object | -- | { type: 'task-list', size: 50, columnWidth: 24, padding: 16, margin: 10, straight: false, } |
# options.taskList.columns
左侧列表 ,列配置
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
id | ||||
label | 显示的标题 | String | -- | -- |
value | 对应列内容的字段名 | String | -- | -- |
width | 列宽度 | Number | -- | 40 |
html | 解析为 html | Boolean | -- | false |
slot | 自定义 Vue 插槽, slot 权重大于 html | String | -- | -- |
expander | 是否显示折叠按钮 | Boolean | -- | false |
events | 事件注册 | Object | -- | -- |
style | 列样式 -- 参考 (opens new window) -- 字典 (opens new window) | Object | -- | -- |
# options.taskList.expander
左侧列表,折叠按钮配置
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
size | 按钮大小 | Number | -- | 16 |
padding | 子节点与父节点之间的缩进距离 | Number | -- | 16 |
margin | 整体与左侧的间隔距离 | Number | -- | 10 |
# options.taskMapping
组件需要用到的字段枚举
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
id | 任务 id | String | -- | id |
start | 任务开始时间 | date | -- | start |
label | 任务名称 | String | -- | label |
duration | 任务持续时间 | date | -- | duration |
progress | 任务完成进度 | Number | -- | progress |
type | 任务类型 | String | -- | type |
style | 任务样式,具体看下表 | Object | -- | style |
collapsed | 是否默认展开 | Boolean | -- | collapsed |
# options.scroll
内容滚动相关配置
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
dragXMoveMultiplier | 推拽速度,X 轴 | Number | -- | 3 |
dragYMoveMultiplier | 推拽速度,Y 轴 | Number | -- | 2 |
# options.scope
右侧图表前后日期范围
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
before | 前置天数间隔 | Number | -- | 1 |
after | 后置天数间隔 | Number | -- | 1 |
# options.times
右侧图表时间相关配置
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
timeZoom | 时间默认缩放层级 | Number | 1~21 | 17 |
# options.row
左侧列表,行配置
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
height | 行高度 | Number | -- | 24 |
# options.chart
右侧图表内容相关配置
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
grid | 网格配置 | Object | -- | -- |
text | 任务条右侧文本配置。具体看下表 | Object | -- | -- |
expander | 图表左侧折叠按钮配置 | Object | -- | -- |
# options.chart.text
任务条右侧文本配置
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
offset | 文本左侧偏移量 | Number | -- | 4 |
xPadding | 文本内容内边距 | Number | -- | 10 |
display | 是否显示文本 | Boolean | -- | true |
# options.chart.expander
图表左侧折叠按钮配置
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
display | 是否显示折叠按钮 | Boolean | -- | false |
offset | 距离右侧偏移量 | Number | -- | 12 |
size | 按钮大小 | Number | -- | 18 |
# options.calendar
右侧图表日历(日期)相关配置
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
workingDays | 工作日配置 | Array | [1, 2, 3, 4, 5, 6, 7] | [1, 2, 3, 4, 5] |
gap | 表格与表头之间的间距 | Number | -- | 6 |
hour | 表头时间节点行配置 | Object | -- | -- |
day | 表头日期节点行配置 | Object | -- | -- |
month | 表头月份节点行配置 | Object | -- | -- |
# options.calendar.hour
表头时间节点行配置
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
height | 高度 | Number | -- | 20 |
display | 是否显示时间 | Boolean | -- | true |
format | 时间显示内容格式。具体看下表 |
# options.calendar.day
表头日期节点行配置
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
height | 高度 | Number | -- | 20 |
display | 是否显示时间 | Boolean | -- | true |
format | 时间显示内容格式。具体看下表 |
# options.calendar.month
表头月份节点行配置
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
height | 高度 | Number | -- | 20 |
display | 是否显示时间 | Boolean | -- | true |
format | 时间显示内容格式。具体看下表 |
# format
date 为 dayjs 实例
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
long | 缩放层级,小 | Function(date) | -- | -- |
medium | 缩放层级,中 | Function(date) | -- | -- |
short | 缩放层级,大 | Function(date) | -- | -- |
# Methods
方法名称 | 说明 | 参数 |
---|---|---|
updateTask | 更新任务, 该方法不能更新任务时间,如需更新时间使用 updateTaskTime ;taskid: 任务 ID; data: 修改后的数据; | Function(taskId, data, props = {}) |
updateTaskTime | 更新任务时间; taskid: 任务 ID; start: 开始时间; end:结束时间 | Function(taskId, start, end) |
getTask | 根据任务 id,获取任务数据; | Function(taskId) |
getChildren | 根据任务 id,获取当前任务的子任务; | Function(taskId) |
goCurrentTime | 跳转到当前时间线 | Function() |
# Events
事件名称 | 说明 | 回调参数 |
---|---|---|
calendar-recalculate | 当大小发生变化(resize)触发 | -- |
tasks-changed | 任务数据(tasks)发生变化触发 | tasks |
options-changed | 配置项(options)发生变化触发 | options |
dynamic-style-changed | 样式发生变化触发 | style |
created | created | 组件实例 |
before-mount | before-mount | 组件实例 |
ready | ready | 组件实例 |
mounted | mounted | 组件实例 |
before-update | before-update | |
updated | updated | |
before-destroy | before-destroy | |
destroyed | destroyed | |
main-view-mousemove | 鼠标移动 | event |
main-view-mouseup | 鼠标松开 | event |
chart-scroll-horizontal | 水平滚动事件 | event |
chart-scroll-vertical | 垂直滚动事件 | event |
chart-wheel | 鼠标滚轮在元素上下滚动时触发 | event |
chart-task-click | 任务条事件,对应 Html Dom 事件 | {...event, data: task} |
chart-task-dblclick | 同上 | 同上 |
chart-task-mouseenter | 同上 | 同上 |
chart-task-mouseleave | 同上 | 同上 |
chart-task-mouseover | 同上 | 同上 |
chart-task-mouseout | 同上 | 同上 |
chart-task-mousemove | 同上 | 同上 |
chart-task-mousedown | 同上 | 同上 |
chart-task-mouseup | 同上 | 同上 |
chart-task-mousewheel | 同上 | 同上 |
chart-task-touchstart | 同上 | 同上 |
chart-task-touchmove | 同上 | 同上 |
chart-task-touchend | 同上 | 同上 |
task-list-click | 表格行事件,对应 Html Dom 事件 | {...event, data: task, column: column} |
task-list-dblclick | 同上 | 同上 |
task-list-mouseenter | 同上 | 同上 |
task-list-mouseover | 同上 | 同上 |
task-list-mouseout | 同上 | 同上 |
task-list-mousemove | 同上 | 同上 |
task-list-mousedown | 同上 | 同上 |
task-list-mouseup | 同上 | 同上 |
task-list-mousewheel | 同上 | 同上 |
task-list-touchstart | 同上 | 同上 |
task-list-touchmove | 同上 | 同上 |
task-list-touchend | 同上 | 同上 |