<template>
<div id="container1">
<div ref="contais" id="containerEMS"></div>
</div>
</template>
<script>
// 导入chart组件
import Highcharts from 'highcharts'
import gantt from 'highcharts/modules/gantt'
import moment from 'moment'
// import { showGanttData, projectShowAll } from '../../serviceAPIs/service'
import { deepClone } from '@src/utils'
gantt(Highcharts)
export default {
props: {
showGanttData: {
type: Array,
require: true
},
projectShowAllData: {
type: Array,
require: true
}
},
watch: {
allData(val) {},
projectShowAllData(newVal) {
if (newVal) {
this.getGantterData(this.showGanttData, this.projectShowAllData)
}
},
immediate: true,
deep: true
},
data() {
return {
// 存放二级进度数组
secondProgress: [],
// 存放一级进度
firstProgress: [],
resultArr: [],
trueTimeDataThree: [],
// 处理第一层数据
oneSeriesData: [],
// 处理第二层数据
twoSeriesData: [],
// 处理第三层数据
threeSeriesData: [],
// 存放甘特图数据
seriesData: [],
allData: []
}
},
methods: {
async getGantterData(res, productData) {
// console.log('甘特图刷新', res, productData)
this.allData = productData
// 再一级加入进度
this.calculateProgress(res, productData)
// 在一级钟加入三级最大实际结束时间
this.computingTime(res, productData)
// 渲染甘特图
this.HighchartsData()
},
// 计算二级进度
calculateProgress(res, productData) {
// 计算二级进度
productData.forEach((item) => {
item.children.forEach((item2) => {
let secondProgressTotal = 0
let secondProgressTotal2 = 0
let projectCompletionDegree = 0
let plancompletion = 0
let a = 0
let b = 0
// 计算工作计划的进度
if (item2.planName == '工作计划') {
item2.children.forEach((item3) => {
// 工作计划所有进度加起来的总和secondProgressTotal
secondProgressTotal += item3.completionDegree
})
// 工作计划进度,总和除以工作计划下的数组长度
projectCompletionDegree = (secondProgressTotal / item2.children.length).toFixed(1)
this.secondProgress.push({
projectName: item2.projectName,
id: item2.id,
mainProjectName: item.projectName,
secondProgressrate: projectCompletionDegree
})
}
// 计算物料计划的进度
if (item2.projectName == '物料计划') {
item2.children.forEach((item4) => {
// 入库量大于计划量
if (item4.scheduledReceipt > item4.planQuantity) {
item4.scheduledReceipt = item4.planQuantity
}
a += item4.scheduledReceipt
b += item4.planQuantity
// 给物料计划加进度
this.$set(item4, 'completionDegree', Number(((item4.scheduledReceipt / item4.planQuantity) * 100).toFixed(1)))
})
this.planCompletionDegree = ((a / b) * 100).toFixed(1)
this.secondProgress.push({
projectName: item2.projectName,
id: item2.id,
mainProjectName: item.projectName,
secondProgressrate: this.planCompletionDegree
})
}
})
})
this.calculatingProgressOperations(res, productData)
},
// 计算一级完成了率
calculatingProgressOperations(res, productData) {
// 往三级数据塞二级进度
productData.forEach((item) => {
item.children.forEach((item2) => {
this.secondProgress.forEach((second) => {
if (second.id == item2.id) {
this.$set(item2, 'twoAmount', Number(second.secondProgressrate))
}
})
})
})
let oneProgressTotal = 0
let firstProgressrate = 0
// 计算一级完成率
productData.forEach((item) => {
oneProgressTotal = 0
item.children.forEach((item2) => {
if (item.id == item2.parentId) {
// 二级进度不为NaN,相加
if (Object.is(item2.twoAmount, NaN)) {
} else {
oneProgressTotal += item2.twoAmount
}
// 一级进度,工作计划,和物理计划相加/2得出
firstProgressrate = (oneProgressTotal / 2).toFixed(1)
this.firstProgress.push({
projectName: item.projectName,
firstProgressrate: firstProgressrate
})
}
item2.children.forEach((item3) => {
this.$set(item2, 'name', item3.planName)
})
})
})
// 塞入计算后的一级进度
productData.forEach((item) => {
this.firstProgress.forEach((first) => {
if (first.projectName == item.projectName) {
this.$set(item, 'oneAmount', Number(first.firstProgressrate))
}
})
})
// console.log('productData', productData)
},
// 计算完成时间
computingTime(res, productData) {
let EndTime = []
let time1 = []
let time2 = 0
// 找出三级的最大实际完成时间
productData.forEach((item) => {
item.children.forEach((item2) => {
time1 = []
time2 = 0
let threeId = ''
let name = ''
item2.children.forEach((item3) => {
// 实际结束实际转为数字
if (item3.actualEndTime == null) {
item3.actualEndTime = 0
} else {
item3.actualEndTime = moment(item3.actualEndTime).valueOf()
}
time1.push(item3.actualEndTime)
time2 = Math.max(...time1)
threeId = item3.projectId
})
this.resultArr.push({
projectName: item.projectName,
planName: item2.projectName,
actualEndTime: time2,
planId: threeId
})
})
})
// 往二级塞三级最大实际结束时间
productData.forEach((item) => {
item.children.forEach((item2) => {
this.resultArr.forEach((item3) => {
if (item2.parentId == item3.planId) {
this.$set(item2, 'threeEndTime', item3.actualEndTime)
}
})
})
})
this.computingTimeOptions(res, productData)
},
// 往一级塞入三级最大实际结束时间
computingTimeOptions(res, productData) {
let oneData = []
let oneData2 = 0
let oneDataArr = []
productData.forEach((item) => {
item.children.forEach((item2) => {
oneData = []
oneData2 = 0
let parent = ''
item2.children.forEach((item3) => {
if (item3.actualEndTime == null) {
item3.actualEndTime = 0
} else {
item3.actualEndTime = moment(item3.actualEndTime).valueOf()
}
oneData.push(item3.actualEndTime)
oneData2 = Math.max(...oneData)
parent = item3.projectId
})
oneDataArr.push({
endtime: oneData2,
planName: item2.projectName,
projectName: item.projectName,
planId: parent
})
})
})
// 往一级塞入三级最大实际结束时间
productData.forEach((item) => {
item.children.forEach((item2) => {
oneDataArr.forEach((item3) => {
if (item2.parentId == item3.planId) {
this.$set(item, 'trueactualEndTime', item3.endtime)
}
})
})
})
this.processingData(res, productData)
this.insertGanttData()
},
// 处理甘特图所需数据,存放在数组中
processingData(res, productData) {
this.oneSeriesData = []
this.twoSeriesData = []
this.threeSeriesData = []
// 往甘特图的series塞需要的数据
productData.forEach((item) => {
this.oneSeriesData.push({
trueactualEndTime: item.trueactualEndTime,
oneAmount: Object.is(item.oneAmount, NaN) ? 0 : item.oneAmount,
projectName: item.projectName,
plannedStartTime: item.plannedStartTime,
plannedEndTime: item.plannedEndTime,
personResponsible: item.personResponsible,
id: item.id
})
item.children.forEach((item2, index, array1) => {
this.twoSeriesData.push({
threeEndTime: item2.threeEndTime,
twoAmount: item2.twoAmount,
oneid: item.id,
projectName: item2.projectName ? item2.projectName : item2.planName,
plannedStartTime: item2.plannedStartTime,
plannedEndTime: item2.plannedEndTime,
// actualStartTime: item2.actualStartTime,
// actualEndTime: item2.actualEndTime,
personResponsible: item2.personResponsible,
id: item2.id,
dependency: array1.length - 1 > index ? array1[index + 1].id : ''
})
item2.children.forEach((item3, index2, array2) => {
this.threeSeriesData.push({
twoprojectName: item2.projectName,
twoid: item2.id,
planName: item3.planName,
plannedStartTime: item3.plannedStartTime,
plannedEndTime: item3.plannedEndTime,
actualStartTime: item3.actualStartTime,
actualEndTime: item3.actualEndTime,
personResponsible: item3.personResponsible,
state: item3.state,
completionDegree: item3.completionDegree,
id: item3.id,
dependency: array2.length - 1 > index2 ? array2[index2 + 1].id : ''
})
})
// 2end
})
// 3end
})
},
// 往series塞数据
insertGanttData() {
this.seriesData = []
// 第一次
this.oneSeriesData.forEach((item) => {
this.seriesData.push({
name: item.projectName + '&' + item.id,
id: item.id,
start:
moment(item.plannedStartTime)
.startOf('days')
.valueOf() + 30000000,
end: moment(item.plannedEndTime)
.endOf('day')
.valueOf(),
owner: item.personResponsible,
color: 'rgba(128, 128, 128,0.3)',
dataLabels: {
align: 'center',
style: {
textOutline: 'none'
// 去除描边效果
},
color: 'rgb(196, 245, 229)',
formatter: function(e, options) {
if (item.oneAmount > 0 && item.oneAmount <= 100) {
return '项目总进度:' + item.oneAmount + '%'
} else {
return '未开始'
}
}
},
completed: {
amount: item.oneAmount / 100,
// fill: 'red'
fill: this.getclolrOne2(moment(item.plannedEndTime).valueOf(), item.trueactualEndTime, item.oneAmount)
}
})
})
// 第二次
this.twoSeriesData.forEach((item) => {
// console.log(item
this.seriesData.unshift({
name: (item.projectName ? item.projectName : item.planName) + '&' + item.id,
// name: item.id,
id: item.id,
dependency: item.oneid,
parent: item.oneid,
start:
moment(item.plannedStartTime)
.startOf('days')
.valueOf() + 30000000,
end: moment(item.plannedEndTime)
.endOf('day')
.valueOf(),
owner: item.personResponsible,
collapsed: true,
color: 'rgba(128, 128, 128,0.3)',
dataLabels: {
align: 'center',
style: {
textOutline: 'none' // 去除描边效果
},
color: 'rgb(247, 242, 199)',
formatter: function(e, options) {
if (item.twoAmount > 0 && item.twoAmount <= 100) {
return '分组进度:' + item.twoAmount + '%'
} else if (item.twoAmount > 100) {
return '分组进度:' + item.twoAmount + '% (超量)'
} else {
return '未开始'
}
}
},
completed: {
amount: item.twoAmount / 100,
// fill:'green'
fill: this.getclolrTwo2(moment(item.plannedEndTime).valueOf(), item.threeEndTime, item.twoAmount)
}
})
})
// 第三次
this.threeSeriesData.forEach((item) => {
this.seriesData.unshift({
name: (item.twoprojectName == '物料计划' ? item.planName : item.planName + '-' + item.personResponsible) + '&' + item.id,
id: item.id,
dependency: item.twoid,
parent: item.twoid,
start: moment(item.plannedStartTime).valueOf(),
end: moment(item.plannedEndTime)
.endOf('day')
.valueOf(),
owner: item.personResponsible,
color: 'rgba(128, 128, 128,0.3)',
dataLabels: {
align: 'center',
style: {
textOutline: 'none' // 去除描边效果
},
formatter: function(e, options) {
if (item.state === 0) {
return '未开始'
} else {
return '进度:' + item.completionDegree + '%'
}
}
},
completed: {
amount: item.completionDegree / 100,
// fill:'yellow'
fill: this.getclolrThree2(moment(item.plannedEndTime).valueOf(), item.actualEndTime ? moment(item.actualEndTime).valueOf() : moment(item.plannedEndTime).valueOf(), item.completionDegree)
}
})
})
},
HighchartsData() {
var today = new Date(),
day = 1000 * 60 * 60 * 24,
// Utility functions
dateFormat = Highcharts.dateFormat,
defined = Highcharts.defined,
isObject = Highcharts.isObject,
reduce = Highcharts.reduce
// Set to 00:00:00:000 today
today.setUTCHours(0)
today.setUTCMinutes(0)
today.setUTCSeconds(0)
today.setUTCMilliseconds(0)
today = today.getTime()
// console.log('************************:', this.seriesData)
// 获取图表容器
var container = document.getElementById('containerEMS')
var chart = Highcharts.ganttChart(container, {
series: [
{
name: '项目',
borderColor: 'none',
data: this.seriesData,
dataLabels: {
color: '#fff',
borderColor: 'red'
// borderWidth:10
},
events: {
legendItemClick: function(event) {}
}
}
],
mapNavigation: {
enabled: true,
enableButtons: false
},
tooltip: {
style: {
zIndex: '99999'
},
followPointer: true,
pointFormatter: function() {
var point = this,
format = '%e. %b',
options = point.options,
completed = options.completed,
amount = isObject(completed) ? completed.amount : completed,
status = (amount || 0) * 100 + '%',
lines
lines = [
{
value: point.name.split('&')[0],
style: 'font-weight: bold;'
},
{
title: '开始日期',
value: moment(point.options.start).format('YYYY-MM-DD')
},
{
visible: !options.milestone,
title: '结束日期',
value: moment(point.options.end).format('YYYY-MM-DD')
},
{
title: '进度',
value: status
}
// {
// title: '负责人',
// value: options.owner || 'unassigned'
// }
]
return reduce(
lines,
function(str, line) {
var s = '',
style = defined(line.style) ? line.style : 'font-size: 0.8em;'
if (line.visible !== false) {
s = '<span style="' + style + '">' + (defined(line.title) ? line.title + ': ' : '') + (defined(line.value) ? line.value : '') + '</span><br/>'
}
return str + s
},
''
)
}
},
credits: {
enabled: false
},
accessibility: {
enabled: false
},
chart: {
events: {
selection: function(event) {
// 阻止默认选中行为 选中下方拖动然后右边滚动条也跟着动
event.preventDefault()
}
},
scrollablePlotArea: {
minHeight: this.heightFnc(),
// opacity: 1,
opacity: 1
// scrollPositionY: 0
},
// height: this.heightFnc(), // 16:9 ratio
// height: 70 + '%', // 16:9 ratio
alignThresholds: true,
backgroundColor: {
linearGradient: [0, 0, 1, 280],
stops: [[0, 'rgba(33, 65, 166,1)'], [1, 'rgba(33, 65, 166,0)']]
},
// backgroundColor: ' linear-gradient(to top, red, green)',
// plotBackgroundColor: 'rgba(4, 181, 178,0.1)',
panning: true,
panKey: 'shift'
},
resetZoomButton: {
position: {},
relativeTo: 'plot',
theme: {
states: {
// 选择时的框子色
hover: {
stroke: '#1e3a97',
'stroke-width': 1
}
}
}
},
yAxis: [
{
labels: {
formatter: function(e) {
return '<span>' + this.value.split('&')[0] + "<p style='color:transparent;width:0px;display:none'>" + this.value.split('&')[1] + '</p>' + '</span>' // 设置字体颜色
},
// this.value.split('&')[0]
style: {
color: '#04b5b2'
}
},
gridLineWidth: 0,
tickColor: 'rgba(4, 181, 178, 0.3)',
lineColor: 'rgba(4, 181, 178, 0.3)',
min: 0,
max: null,
uniqueNames: true,
events: {
click: function(e) {
// 判断点击的位置是否在y轴上
if (e.axis.userOptions.className === 'highcharts-yaxis') {
// 获取点击的坐标值
var chart = this.chart,
y = Math.round(chart.yAxis[0].toValue(e.chartY))
// 根据点击的坐标值进行相应的处理
// 例如展开或收起子任务
// ...
}
}
}
}
],
xAxis: [
{
minTickInterval: 1000 * 60 * 60 * 24,
min: today - 90 * day,
max: today + 30 * day,
tickColor: 'rgba(4, 181, 178, 0.3)',
lineColor: 'rgba(4, 181, 178, 0.3)',
tickWidth: 3,
lineWidth: 1,
labels: {
format: `{value:%d}`,
indentation: 20,
padding: 1,
style: {
userSelect: 'none',
color: '#04b5b2',
fontSize: '13px',
fontFamily: '微软雅黑'
}
}
},
{
tickInterval: 31 * (24 * 3600 * 1000),
tickWidth: 3,
tickColor: 'rgba(4, 181, 178, 0.3)',
lineColor: 'rgba(4, 181, 178, 0.3)',
lineWidth: 1,
labels: {
// format: '{value: %Y年1 %W周}'
format: '{value: %Y-%m}',
style: {
userSelect: 'none',
color: '#04b5b2',
fontWeight: 'bold',
fontSize: '18px',
fontFamily: '微软雅黑'
}
}
}
]
})
// 监听鼠标滚轮事件
if (container.addEventListener) {
container.addEventListener('wheel', function(e) {
// e.preventDefault() // 阻止默认滚动行为
// 返出属性
if (Object.keys(chart).length === 0) return
if (e.ctrlKey) {
// Y放大125 Y缩小-125
var delta = e.deltaY || e.detail || e.wheelDelta // 获取滚动方向
// 放大125,缩小-125
// 向下放大0.9,向上缩小1.1
var scale = delta < 0 ? 1.1 : 0.9 // 向上滚动放大,向下滚动缩小
var xAxis = chart.xAxis[0]
var min = xAxis.min
var max = xAxis.max
var newMin = min + ((max - min) * (1 - scale)) / 2
var newMax = max - ((max - min) * (1 - scale)) / 2
if (min < moment('2023-05-01').valueOf()) {
if (e.ctrlKey) {
var delta = e.deltaY
var scale = delta < 0 ? 1.1 : 0.9
var xAxis = chart.xAxis[0]
var min = xAxis.min
var max = xAxis.max
var newMin = min + ((max - min) * (1 - scale)) / 2
var newMax = max - ((max - min) * (1 - scale)) / 2
if (scale == 0.9) {
xAxis.setExtremes(newMin, newMax)
}
}
} else {
xAxis.setExtremes(newMin, newMax)
}
} else {
}
})
}
},
heightFnc() {
let alldataInfo = []
let oneData = []
let twoData = []
let threeData = []
this.allData.forEach((item) => {
oneData.push(item)
item.children.forEach((item2) => {
twoData.push(item)
item2.children.forEach((item3) => {
threeData.push(item3)
})
})
})
alldataInfo = oneData.concat(twoData, threeData)
// return alldataInfo.length * 65
let leng = alldataInfo.length * 65
if (leng > 600) {
return alldataInfo.length * 65
} else {
return 1200
}
},
getclolrOne2(plannedEndTime, actualEndTime, state) {
if (state == 100) {
// 执行完成
if (plannedEndTime >= actualEndTime) {
// 没超时绿色
return 'rgba(1, 178, 121,1)'
} else if (plannedEndTime < actualEndTime) {
// 实际结束实际和预计结束实际对必,超时就是
// 红色
return 'red'
}
} else {
// 执行中
// 橙色
// return '#f35e03'
// #9ccdc4'
return '#1b9ff1'
}
},
getclolrTwo2(plannedEndTime, actualEndTime, state) {
if (state == 100) {
// 执行完成
if (plannedEndTime >= actualEndTime) {
// 没超时绿色
return 'rgba(1, 178, 121,1)'
} else if (plannedEndTime < actualEndTime) {
// 实际结束实际和预计结束实际对必,超时就是
// 红色
return 'red'
}
} else {
// 执行中
// 橙色
// return '#f35e03'
return '#1b9ff1'
}
},
getclolrThree2(plannedEndTime, actualEndTime, state) {
if (state == 100) {
// 执行完成
if (plannedEndTime >= actualEndTime) {
// 没超时绿色
return '#01b279'
} else if (Number(plannedEndTime) < Number(actualEndTime)) {
// 实际结束实际和预计结束实际对必,超时就是
// 红色
return 'red'
}
} else {
// 执行中
// 橙色
// return '#f35e03'
return '#1b9ff1'
}
}
}
}
</script>
<style scoped>
#container1 {
max-width: 100%;
margin: 1em auto;
}
#containerEMS {
max-width: 100%;
height: 96%;
margin: 0 auto;
}
.highcharts-axis-labels text:hover tspan {
text-decoration: none !important;
}
</style>
TS使用highcharts甘特图,滚动放大
最新推荐文章于 2024-02-06 10:44:34 发布