<template>
|
<div style="padding: 0 10px">
|
|
<div style="padding: 10px 0;display: flex;">
|
<!-- <el-button type="primary" size="mini" @click="ganttUndo">回退拖动操作</el-button>-->
|
<!-- <el-button type="primary" size="mini" @click="ganttRedo">前进拖动操作</el-button>-->
|
<el-button type="primary" size="mini" @click="ganttZoomIn">放大</el-button>
|
<el-button type="primary" size="mini" @click="ganttZoomOut">缩小</el-button>
|
<el-date-picker
|
v-model="ganttDateRange"
|
style="margin-left: 10px;"
|
size="mini"
|
value-format="yyyy-MM-dd"
|
type="daterange"
|
:clearable="false"
|
range-separator="至"
|
start-placeholder="开始日期"
|
end-placeholder="结束日期"
|
@change="ganttDateRangeChange"
|
/>
|
<el-button type="primary" style="margin-left: 10px;" size="mini" @click="handleGetSelected">
|
获取复选框选中任务
|
</el-button>
|
<el-button size="mini" @click="handleClearSelection">
|
清空复选框选择
|
</el-button>
|
</div>
|
|
<div id="gantt_here" style="width:100%; height:calc(90vh - 50px);" />
|
|
<!-- 分页组件 -->
|
<div class="pagination-container">
|
<el-pagination
|
:current-page="currentPage"
|
:page-sizes="[10, 20, 50, 100]"
|
:page-size="pageSize"
|
layout="total, sizes, prev, pager, next, jumper"
|
:total="totalTasks"
|
@size-change="handleSizeChange"
|
@current-change="handleCurrentChange"
|
/>
|
</div>
|
</div>
|
</template>
|
|
<script>
|
import { gantt } from '@/components/dhtmlxGantt'
|
import '@/components/dhtmlxGantt/codebase/dhtmlxgantt.css'
|
import { handleDateReduceOneDay, handleDatetime, handleDatetime2 } from '@/utils/global'
|
|
export default {
|
data() {
|
return {
|
value: 'default',
|
ganttDateRange: ['2025-04-01', '2025-05-10'],
|
selectedIds: [],
|
// 分页相关数据
|
currentPage: 1,
|
pageSize: 10,
|
totalTasks: 0,
|
allTasks: [], // 存储所有任务数据
|
paginatedTasks: [] // 当前页的任务数据
|
}
|
},
|
mounted() {
|
// 先改变日期范围配置
|
this.ganttDateRangeChange(this.ganttDateRange)
|
|
// 初始化甘特图配置
|
this.initGantt()
|
|
// 然后加载任务数据(会自动渲染当前页)
|
this.loadTasks()
|
},
|
methods: {
|
|
initGantt() {
|
gantt.plugins({
|
|
critical_path: true,
|
drag_timeline: true,
|
grouping: true,
|
keyboard_navigation: true,
|
marker: true,
|
multiselect: true,
|
tooltip: true,
|
undo: true
|
})
|
gantt.i18n.setLocale('cn')
|
gantt.config.multiselect = true // 开启多任务选择
|
gantt.config.show_links = false // 不显示连接线
|
|
// 不再对齐时间轴刻度(比如天格子),而是按“小时”对齐
|
gantt.config.round_dnd_dates = false
|
// 最小步长还是 1 小时,但你已经从“天格子”变成“小时格子”了
|
gantt.config.time_step = 60 // 60 分钟 = 1 小时
|
|
gantt.config.row_height = 32 // 行高
|
gantt.config.bar_height = 20 // bar高
|
|
gantt.config.xml_date = '%Y-%m-%d %H:%i' // gantt的日期格式
|
|
gantt.config.drag_progress = false // 禁止通过拖动进度条改变任务进度
|
|
gantt.config.readonly = true // 只读模式
|
|
/* ↓↓↓ Group configuration ↓↓↓ */
|
gantt.serverList('task_priority', [
|
{ key: 1, label: '高' },
|
{ key: 2, label: '中等' },
|
{ key: 3, label: '低' }
|
])
|
|
gantt.serverList('task_status', [
|
{ key: 1, label: 'Planning' },
|
{ key: 2, label: 'Not started' },
|
{ key: 3, label: 'In Progress' },
|
{ key: 4, label: 'Complete' }
|
])
|
|
function byId(list, id) {
|
for (let i = 0; i < list.length; i++) {
|
if (list[i].key == id) {
|
return list[i].label || ''
|
}
|
}
|
return ''
|
}
|
|
/* ↑↑↑ Group configuration ↑↑↑ */
|
|
// 放大缩小属性
|
/* ↓↓↓ Zoom configuration ↓↓↓ */
|
const zoomConfig = {
|
levels: [
|
{
|
name: 'hour',
|
scale_height: 27,
|
min_column_width: 50,
|
scales: [
|
{ unit: 'day', format: '%Y年%M%d号' },
|
{ unit: 'hour', format: '%H时' }
|
]
|
},
|
{
|
name: 'day',
|
scale_height: 27,
|
min_column_width: 80,
|
scales: [
|
// { unit: 'day', step: 1, format: '%d %M' }
|
{ unit: 'day', step: 1, format: '%M%d号' }
|
]
|
},
|
{
|
name: 'week',
|
scale_height: 50,
|
min_column_width: 70,
|
scales: [
|
// {
|
// unit: 'week', step: 1, format: function(date) {
|
// const dateToStr = gantt.date.date_to_str('%d %M')
|
// const endDate = gantt.date.add(date, -6, 'day')
|
// const weekNum = gantt.date.date_to_str('%W')(date)
|
// return '第' + weekNum + '周, ' + dateToStr(date) + ' - ' + dateToStr(endDate)
|
// }
|
// },
|
// %M
|
{ unit: 'week', format: '%Y年第%W周' },
|
{ unit: 'day', step: 1, format: '%M%d号' }
|
// { unit: 'minute', step: 60, format: '%H:%i' }
|
// { unit: 'day', step: 1, format: '%j %D' }
|
// { unit: 'day', step: 1, format: '星期%D' }
|
]
|
},
|
{
|
name: 'month',
|
scale_height: 50,
|
min_column_width: 120,
|
scales: [
|
// { unit: 'month', format: '%Y年%F' },
|
{ unit: 'month', format: '%Y年%M' },
|
{ unit: 'week', format: '第%W周' }
|
]
|
},
|
{
|
name: 'quarter',
|
height: 50,
|
min_column_width: 90,
|
scales: [
|
// {
|
// unit: 'quarter', step: 1, format: function(date) {
|
// const dateToStr = gantt.date.date_to_str('%M')
|
// const endDate = gantt.date.add(gantt.date.add(date, 3, 'month'), -1, 'day')
|
// return dateToStr(date) + ' - ' + dateToStr(endDate)
|
// }
|
// },
|
{ unit: 'month', step: 1, format: '%Y年%M' }
|
]
|
},
|
{
|
name: 'year',
|
scale_height: 50,
|
min_column_width: 30,
|
scales: [
|
{ unit: 'year', step: 1, format: '%Y年' }
|
|
]
|
}
|
],
|
useKey: 'ctrlKey',
|
trigger: 'wheel',
|
element: function() {
|
return gantt.$root.querySelector('.gantt_task')
|
}
|
}
|
gantt.ext.zoom.init(zoomConfig)
|
gantt.ext.zoom.setLevel('week')
|
/* ↑↑↑ Zoom configuration ↑↑↑ */
|
|
// 是否是工作时间
|
/* ↓↓↓ Working Time configuration ↓↓↓ */
|
// gantt.templates.scale_cell_class = function(date) {
|
// if (!gantt.isWorkTime(date)) {
|
// return 'weekend'
|
// }
|
// }
|
//
|
// gantt.templates.timeline_cell_class = function(item, date) {
|
// if (!gantt.isWorkTime({ date: date, task: item })) {
|
// return 'weekend'
|
// }
|
// }
|
|
// gantt.config.work_time = true
|
|
// gantt.addCalendar({
|
// id: 'custom1',
|
// worktime: {
|
// hours: ['8:00-12:30', '13:00-17:30'], // global work hours for weekdays
|
// days: [0, 1, 1, 1, 1, 1, 1]
|
// }
|
// })
|
|
// gantt.addCalendar({
|
// id: 'custom2',
|
// hours: ['12:00-21:00'],
|
// days: [1, 0, 1, 0, 1, 0, 1]
|
// })
|
/* ↑↑↑ Working Time configuration ↑↑↑ */
|
|
// 甘特图列参数设置
|
/* ↓↓↓ Grid Columns configuration ↓↓↓ */
|
gantt.config.reorder_grid_columns = true
|
const textEditor = { type: 'text', map_to: 'text' }
|
const startDateEditor = { type: 'date', map_to: 'start_date' }
|
const durationEditor = { type: 'number', map_to: 'duration', min: 1, max: 100 }
|
gantt.config.columns = [
|
{
|
name: 'checked',
|
label: '选择',
|
align: 'center',
|
width: 35,
|
resize: false,
|
// 关键:用 template 返回一个复选框
|
template: (task) => {
|
const checked = task.checked ? 'checked' : ''
|
// data-action 用于在事件委托时识别是复选框
|
return `<input type="checkbox" class="taskCheckBox" data-action="check-row" ${checked} />`
|
}
|
},
|
// { name: 'wbs', label: '节点', width: 80, template: gantt.getWBSCode },
|
{ name: 'text', tree: true, align: 'center', label: '任务名称', width: 240, resize: true, editor: textEditor },
|
{ name: 'saleOrder', align: 'center', label: '销售订单', width: 100, resize: true },
|
{ name: 'partName', align: 'center', label: '产品名称', width: 80, resize: true },
|
{ name: 'partCode', align: 'center', label: '产品编码', width: 80, resize: true },
|
{
|
name: 'progress', align: 'center', label: '进度', width: 120, resize: true, template: function(task) {
|
return `<input type="range" onmousedown="event.preventDefault()" onmouseup="event.preventDefault()" id="taskRange" value="${task.progress * 100}"/> ${task.progress * 100}%`
|
// return `<el-progress :percentage='${task.progress * 100}'></el-progress> ${task.progress * 100}%`
|
}
|
},
|
{ name: 'start_date', align: 'center', label: '开始日期', width: 80, resize: true, editor: startDateEditor },
|
{
|
name: 'duration',
|
width: 60,
|
align: 'center',
|
label: '工期(天)',
|
resize: true,
|
editor: durationEditor,
|
template: function(task) {
|
// 如果duration是null或undefined,返回0
|
// return (task.duration || 0) + 1 // 在当前duration的基础上加1
|
return task.duration
|
}
|
}
|
// {
|
// name: 'owner', align: 'center', width: 75, label: '负责人', template: function(task) {
|
// return '张三'
|
// },
|
// resize: true
|
// },
|
// {
|
// name: 'priority', width: 60, label: '优先级', align: 'center', resize: true, template: function(task) {
|
// return byId(gantt.serverList('task_priority'), task.priority)
|
// }
|
// },
|
// { name: 'add', width: 44 }
|
]
|
/* ↑↑↑ Grid Columns configuration ↑↑↑ */
|
|
// 汉化窗口
|
gantt.locale.labels = {
|
dhx_cal_today_button: '今天',
|
day_tab: '日',
|
week_tab: '周',
|
month_tab: '月',
|
new_event: '新建日程',
|
icon_save: '保存',
|
icon_cancel: '关闭',
|
icon_details: '详细',
|
icon_edit: '编辑',
|
icon_delete: '删除',
|
confirm_closing: '请确认是否撤销修改!', // Your changes will be lost, are your sure?
|
confirm_deleting: '是否删除计划?',
|
section_description: '描述:',
|
section_resources: '自定义选择:',
|
section_calendar: '自定义选择2:',
|
section_time: '时间范围:',
|
section_type: '类型:',
|
section_text: '计划名称:',
|
section_test: '测试:',
|
section_projectClass: '项目类型:',
|
taskProjectType_0: '项目任务',
|
taskProjectType_1: '普通任务',
|
section_head: '负责人:',
|
section_priority: '优先级:',
|
taskProgress: '任务状态',
|
taskProgress_0: '未开始',
|
taskProgress_1: '进行中',
|
taskProgress_2: '已完成',
|
taskProgress_3: '已延期',
|
taskProgress_4: '搁置中',
|
section_template: 'Details',
|
/* grid columns */
|
column_text: '计划名称',
|
column_start_date: '开始时间',
|
column_duration: '持续时间',
|
column_add: '',
|
column_priority: '难度',
|
/* link confirmation */
|
link: '关联',
|
confirm_link_deleting: '将被删除',
|
message_ok: '确定',
|
message_cancel: '取消',
|
link_start: ' (开始)',
|
link_end: ' (结束)',
|
|
type_task: '任务',
|
type_project: '项目',
|
type_milestone: '里程碑',
|
minutes: '分钟',
|
hours: '小时',
|
days: '天',
|
weeks: '周',
|
months: '月',
|
years: '年'
|
}
|
|
gantt.config.lightbox.sections = [
|
{ name: 'description', height: 38, map_to: 'text', type: 'textarea', focus: true },
|
{
|
name: 'resources', type: 'resources', map_to: 'owner', options: gantt.serverList('people'), default_value: 8
|
},
|
{
|
name: 'calendar', height: 25, map_to: 'calendar_id', type: 'select', options: [
|
{ key: '', label: '默认' },
|
{ key: 'custom1', label: '选项一' },
|
{ key: 'custom2', label: '选项二' }
|
]
|
},
|
|
{ name: 'time', type: 'duration', map_to: 'auto' }
|
]
|
|
gantt.config.resource_store = 'resource'
|
gantt.config.resource_property = 'owner'
|
gantt.config.order_branch = true
|
gantt.config.open_tree_initially = true
|
|
gantt.config.show_errors = false // 发生异常时,不允许弹出警告到 UI 界面
|
|
const resourcesStore = gantt.createDatastore({
|
name: gantt.config.resource_store,
|
type: 'treeDatastore',
|
initItem: function(item) {
|
item.parent = item.parent || gantt.config.root_id
|
item[gantt.config.resource_property] = item.parent
|
item.open = true
|
return item
|
}
|
})
|
|
resourcesStore.attachEvent('onParse', function() {
|
const people = []
|
resourcesStore.eachItem(function(res) {
|
if (!resourcesStore.hasChild(res.id)) {
|
const copy = gantt.copy(res)
|
copy.key = res.id
|
copy.label = res.text
|
people.push(copy)
|
}
|
})
|
gantt.updateCollection('people', people)
|
})
|
|
resourcesStore.parse([
|
{ id: 1, text: 'QA', parent: null },
|
{ id: 2, text: 'Development', parent: null },
|
{ id: 3, text: 'Sales', parent: null },
|
{ id: 4, text: 'Other', parent: null },
|
{ id: 5, text: 'Unassigned', parent: 4 },
|
{ id: 6, text: 'John', parent: 1, unit: 'hours/day' },
|
{ id: 7, text: 'Mike', parent: 2, unit: 'hours/day' },
|
{ id: 8, text: 'Anna', parent: 2, unit: 'hours/day' },
|
{ id: 9, text: 'Bill', parent: 3, unit: 'hours/day' },
|
{ id: 10, text: 'Floe', parent: 3, unit: 'hours/day' }
|
])
|
/* ↑↑↑ Resource configuration ↑↑↑ */
|
|
gantt.config.grid_elastic_columns = true
|
|
// 自定义浮动框的显示内容 tooltip浮动框显示的End Date被追加1的问题修复(应该显示数据库的原始值)
|
gantt.templates.tooltip_text = function(start, end, task) {
|
// console.log(JSON.parse(JSON.stringify(task)))
|
// return '<b>任务:</b> ' + task.text + '<br/><b>开始时间:</b> ' + `${gantt.date.date_to_str('%Y-%m-%d')(start)}` + '<br/><b>结束时间:</b> ' + handleDateReduceOneDay(end)
|
// return '<b>任务:</b> ' + task.text + '<br/><b>开始时间:</b> ' + handleDatetime2(start) + '<br/><b>结束时间:</b> ' + handleDateReduceOneDay(end) + '<br/><b>进度:</b> ' + task.progress * 100 + '%'
|
return '<b>任务:</b> ' + task.text + '<br/><b>开始时间:</b> ' + handleDatetime2(start) + '<br/><b>结束时间:</b> ' + handleDatetime2(end) + '<br/><b>进度:</b> ' + task.progress * 100 + '%'
|
}
|
|
gantt.templates.task_text = function(start, end, task) {
|
// return '<span style="color: white; font-weight: bold; text-shadow: 1px 1px 1px #000;">' +
|
// task.description + ' - ' +
|
// '</span>'
|
return task.description
|
}
|
|
gantt.init('gantt_here')
|
// 注意:这里不立即加载数据,而是等待loadTasks被调用
|
|
// 绑定甘特图点击事件(官方推荐的事件委托用法)
|
gantt.attachEvent('onTaskClick', (id, e) => {
|
// 找到点击的是否是复选框
|
const checkbox = e.target.closest('[data-action="check-row"]')
|
if (!checkbox) {
|
// 不是点复选框,就保持默认行为
|
return true
|
}
|
|
// 是复选框:切换选中状态
|
const task = gantt.getTask(id)
|
if (task) {
|
task.checked = !task.checked
|
// 同时更新全局数据
|
const globalTask = this.allTasks.find(t => t.id === id)
|
if (globalTask) {
|
globalTask.checked = task.checked
|
}
|
gantt.updateTask(id) // 只刷新这一行,性能更好
|
this.syncSelected() // 同步到 Vue 的 selectedIds
|
}
|
|
// 阻止默认点击行行为(避免误触发其他逻辑)
|
return false
|
})
|
|
// 初始化完成后同步一次选中状态
|
this.syncSelected()
|
},
|
|
// 加载任务数据
|
loadTasks() {
|
// 使用原有的示例数据作为基础
|
this.allTasks = [
|
{
|
'id': 1,
|
'text': '工单:MO-2025-05-001',
|
saleOrder: 'SO-2025-05001',
|
partName: '跑步机',
|
partCode: 'Run01',
|
description: '排产数量:500 报工数量:100 进度:20%',
|
'type': 'project',
|
'start_date': '2025-04-02 00:00',
|
// 'duration': 5,
|
'progress': 0.2,
|
'owner': [{ 'resource_id': '5', 'value': 3 }],
|
'parent': 0,
|
'checked': false
|
// render: 'split'
|
},
|
{
|
'id': 2,
|
'text': '工序:切割',
|
saleOrder: 'SO-2025-05001',
|
partName: '跑步机',
|
partCode: 'Run01',
|
description: '排产数量:500 报工数量:100 进度:20%',
|
'type': 'project',
|
'start_date': '2025-04-02 00:00',
|
'duration': 2,
|
'progress': 0.2,
|
'owner': [{ 'resource_id': '5', 'value': 4 }],
|
'parent': '1',
|
checked: false
|
},
|
{
|
'id': 3,
|
'text': '设备:金工车间1号设备',
|
saleOrder: 'SO-2025-05001',
|
partName: '跑步机',
|
partCode: 'Run01',
|
description: '排产数量:500 报工数量:100 进度:20%',
|
'type': 'task',
|
'start_date': '2025-04-07 00:00',
|
'parent': '2',
|
'duration': 4,
|
'progress': 0.2,
|
'owner': [{ 'resource_id': '5', 'value': 2 }],
|
checked: false
|
},
|
{
|
'id': 4,
|
'text': '设备:金工车间2号设备',
|
saleOrder: 'SO-2025-05001',
|
partName: '跑步机',
|
partCode: 'Run01',
|
description: '排产数量:500 报工数量:100 进度:20%',
|
'type': 'task',
|
'start_date': '2025-04-15 00:00',
|
'parent': '2',
|
'duration': 3,
|
'progress': 0.2,
|
'owner': [{ 'resource_id': '5', 'value': 2 }],
|
checked: false
|
}, {
|
'id': 5,
|
'text': '工单:MO-2025-05-002',
|
saleOrder: 'SO-2025-05002',
|
partName: '走步机',
|
partCode: 'W01',
|
description: '排产数量:1000 报工数量:500 进度:50%',
|
'type': 'project',
|
'start_date': '2025-04-02 00:00',
|
// 'duration': 5,
|
'progress': 0.5,
|
'owner': [{ 'resource_id': '5', 'value': 3 }],
|
'parent': 0,
|
'checked': false
|
// render: 'split'
|
},
|
{
|
'id': 6,
|
'text': '工序:切割',
|
saleOrder: 'SO-2025-05002',
|
partName: '走步机',
|
partCode: 'W01',
|
description: '排产数量:1000 报工数量:500 进度:50%',
|
'type': 'project',
|
'start_date': '2025-04-02 00:00',
|
'duration': 5,
|
'progress': 0.5,
|
'owner': [{ 'resource_id': '5', 'value': 4 }],
|
'parent': '5',
|
checked: false
|
},
|
{
|
'id': 7,
|
'text': '设备:金工车间3号设备',
|
saleOrder: 'SO-2025-05002',
|
partName: '走步机',
|
partCode: 'W01',
|
description: '排产数量:1000 报工数量:500 进度:50%',
|
'type': 'task',
|
'start_date': '2025-04-07 00:00',
|
'parent': '6',
|
'duration': 3,
|
'progress': 0.5,
|
'owner': [{ 'resource_id': '5', 'value': 2 }],
|
checked: false
|
},
|
{
|
'id': 8,
|
'text': '设备:金工车间4号设备',
|
saleOrder: 'SO-2025-05002',
|
partName: '走步机',
|
partCode: 'W01',
|
description: '排产数量:1000 报工数量:600 进度:60%',
|
'type': 'task',
|
'start_date': '2025-04-12 00:00',
|
'parent': '6',
|
'duration': 4,
|
'progress': 0.6,
|
'owner': [{ 'resource_id': '5', 'value': 2 }],
|
checked: false
|
},
|
{
|
'id': 9,
|
'text': '设备:金工车间5号设备',
|
saleOrder: 'SO-2025-05002',
|
partName: '走步机',
|
partCode: 'W01',
|
description: '排产数量:1000 报工数量:400 进度:40%',
|
'type': 'task',
|
'start_date': '2025-04-10 00:00',
|
'parent': '6',
|
'duration': 3,
|
'progress': 0.4,
|
'owner': [{ 'resource_id': '5', 'value': 2 }],
|
checked: false
|
}
|
|
]
|
|
// 添加更多示例数据,使分页效果更明显
|
// for (let i = 25; i <= 100; i++) {
|
// this.allTasks.push({
|
// 'id': i,
|
// 'text': '任务' + i,
|
// 'type': 'task',
|
// // 'start_date': handleDatetime(`0${Math.floor(Math.random() * 9 + 1)}-04-2025 00:00`),
|
// 'start_date': `0${Math.floor(Math.random() * 9 + 1)}-04-2025 00:00`,
|
// 'duration': Math.floor(Math.random() * 5) + 1,
|
// 'parent': Math.floor(Math.random() * 10) + 1,
|
// 'progress': Math.random(),
|
// 'owner': [{ 'resource_id': '5', 'value': 3 }],
|
// 'priority': Math.floor(Math.random() * 3) + 1,
|
// 'checked': false
|
// })
|
// }
|
this.totalTasks = this.allTasks.length
|
this.updatePaginatedTasks()
|
this.renderGanttChart()
|
},
|
|
// 更新分页后的任务数据
|
updatePaginatedTasks() {
|
const startIndex = (this.currentPage - 1) * this.pageSize
|
const endIndex = Math.min(startIndex + this.pageSize, this.allTasks.length)
|
this.paginatedTasks = this.allTasks.slice(startIndex, endIndex)
|
},
|
|
// 渲染甘特图
|
renderGanttChart() {
|
gantt.clearAll()
|
console.log(JSON.parse(JSON.stringify(this.paginatedTasks)))
|
gantt.parse({
|
'data': this.paginatedTasks
|
})
|
// 确保甘特图重新渲染
|
// gantt.render()
|
},
|
|
// 页大小改变
|
handleSizeChange(newSize) {
|
this.pageSize = newSize
|
this.currentPage = 1 // 重置到第一页
|
this.updatePaginatedTasks()
|
this.renderGanttChart()
|
this.syncSelected()
|
},
|
|
// 当前页改变
|
handleCurrentChange(newPage) {
|
// 计算最大页数,防止超出范围
|
const maxPage = Math.ceil(this.totalTasks / this.pageSize)
|
if (newPage > maxPage) {
|
this.currentPage = maxPage
|
} else if (newPage < 1) {
|
this.currentPage = 1
|
} else {
|
this.currentPage = newPage
|
}
|
|
this.updatePaginatedTasks()
|
this.renderGanttChart()
|
this.syncSelected()
|
},
|
// 甘特图日期改变
|
ganttDateRangeChange(val) {
|
gantt.config.start_date = val[0]
|
gantt.config.end_date = val[1]
|
gantt.render()
|
},
|
// 回退拖动操作
|
ganttUndo() {
|
gantt.undo()
|
},
|
// 前进拖动操作
|
ganttRedo() {
|
gantt.redo()
|
},
|
// 放大
|
ganttZoomIn() {
|
gantt.ext.zoom.zoomIn()
|
},
|
// 缩小
|
ganttZoomOut() {
|
gantt.ext.zoom.zoomOut()
|
},
|
|
// 从甘特图中同步选中的 id 到 Vue data
|
syncSelected() {
|
// 同步当前页面任务到全局数据
|
gantt.eachTask((task) => {
|
const globalTask = this.allTasks.find(t => t.id === task.id)
|
if (globalTask) {
|
globalTask.checked = task.checked
|
}
|
})
|
|
// 获取所有选中的任务ID
|
this.selectedIds = this.allTasks.filter(t => t.checked).map(t => t.id)
|
console.log(this.selectedIds)
|
},
|
|
// 获取选中任务(示例)
|
handleGetSelected() {
|
const selected = this.allTasks.filter(t => t.checked)
|
this.$notify.success(`当前已选中${selected.length} 条任务`)
|
},
|
|
// 清空所有选择
|
handleClearSelection() {
|
// 遍历所有任务,将 checked 属性设置为 false
|
this.allTasks.forEach(task => {
|
task.checked = false
|
})
|
|
// 更新当前页面显示的任务
|
gantt.eachTask((task) => {
|
task.checked = false
|
gantt.updateTask(task.id)
|
})
|
|
// 同步到 Vue 组件数据
|
this.syncSelected()
|
|
// 显示提示信息
|
this.$notify.success('已清空所有选择')
|
}
|
|
}
|
}
|
|
</script>
|
|
<style>
|
body,
|
html {
|
width: 100%;
|
height: 100%;
|
margin: unset;
|
}
|
|
/*.gantt_task_cell {*/
|
/* background: rgba(5, 185, 100, .1);*/
|
/*}*/
|
|
/*!*非工作日*!*/
|
/*.weekend {*/
|
/* background: rgba(255, 255, 255, 0.5);*/
|
/*}*/
|
|
/* 为任务条内部的进度条添加圆角,保持视觉统一 */
|
.gantt_task_progress {
|
border-radius: 10px !important; /* 建议与任务条半径一致 */
|
}
|
|
.gantt_bar_task {
|
border-radius: 10px !important;
|
}
|
|
.gantt_bar_project {
|
border-radius: 10px !important;
|
}
|
|
.taskCheckBox {
|
cursor: pointer;
|
}
|
|
/* 分页容器样式 */
|
.pagination-container {
|
margin-top: 10px;
|
display: flex;
|
justify-content: end;
|
padding: 10px 0;
|
background-color: #fff;
|
border-top: 1px solid #ebeef5;
|
}
|
|
#taskRange {
|
width: 80px;
|
height: 6px;
|
border-radius: 2px;
|
|
}
|
|
/* 隐藏滑块 */
|
#taskRange::-webkit-slider-thumb {
|
opacity: 0;
|
-webkit-appearance: none !important;
|
width: 1px!important;
|
height: 1px!important;
|
}
|
|
#taskRange::-moz-range-thumb {
|
opacity: 0;
|
width: 1px!important;
|
height: 1px!important;
|
}
|
|
#taskRange::-ms-thumb {
|
opacity: 0;
|
width: 1px!important;
|
height: 1px!important;
|
}
|
|
</style>
|