chart test

This commit is contained in:
2026-01-13 15:15:45 +03:00
parent 6ed75ba834
commit ca9a687133

View File

@@ -1,612 +1,115 @@
<template>
<v-col style="min-width:550px; max-width:550px;" cols="1">
<!-- <LineChart :data="chartData" /> -->
<v-container fluid id="BofGazTrend">
<div class="grid">
<div v-for="(item, index) in items" :key="index" class="grid-item">
{{ item.name }}
<LineChart :id="item.name" :data="item.data" />
</div>
</div>
<v-card-text class="text-center headline black--text">Циклограмма производства {{ BofSelect }} в ККЦ за период
{{ computedDateFormatted }}</v-card-text>
<v-divider class="mx-0"></v-divider>
<v-row>
<v-col style="min-width:250px; max-width:250px;" cols="12">
<v-menu v-model="datePickerMenu" :close-on-content-click="false" :nudge-right="40" :nudge-top="-5"
transition="scale-transition" offset-y min-width="290px">
<template v-slot:activator="{ on }">
<v-text-field id="datePicker" class="datePicker" v-model="computedDateFormatted" prepend-icon="event"
readonly v-on="on" single-line :disabled="loading" />
</template>
<v-date-picker no-title scrollable popover-align="center" v-model="dates"
@input="input($event) && datePickerMenu" @change="refreshData()" range></v-date-picker>
</v-menu>
</v-col>
<!-- <v-divider class="d-none d-md-flex mx-2 my-7" inset vertical></v-divider>
<v-col class="text-center my-4" cols="1" sm="1">
<v-btn tile outlined color="success" :disabled="loading || !data.table.length" @click="loader = Excel()">
<v-icon left size="35">mdi-file-excel</v-icon>Excel
</v-btn>
</v-col> -->
<v-divider class="d-none d-md-flex mx-2 my-7" inset vertical></v-divider>
<v-col style="min-width:220px; max-width:220px;" cols="12">
<v-select v-model="BofSelect" :items="listBof" persistent-hint @change="changeBOFselect()" density="compact"
:disabled="loading">
<template v-slot:selection="{ index }">
<span v-if="index === 0">{{ "№ конвертера: " + BofSelect + "" }}</span>
</template>
</v-select>
</v-col>
<v-divider class="d-none d-md-flex mx-2 my-7" inset vertical></v-divider>
<v-col class="text-center my-4" cols="1" sm="1">
<v-btn tile outlined color="success" :disabled="loading || !data.table.length" @click="loader = toImage()">
<v-icon left size="35">mdi-file-image</v-icon>PNG
</v-btn>
</v-col>
<v-divider class="d-none d-md-flex mx-2 my-7" inset vertical></v-divider>
<v-col class="text-center my-4" cols="1" sm="1">
<v-btn tile outlined color="success" :disabled="loading || !data.table.length" @click="loader = toPrint()">
<v-icon left size="35">mdi-printer</v-icon>Печать
</v-btn>
</v-col>
<v-divider class="d-none d-md-flex mx-2 my-7" inset vertical></v-divider>
<v-col>
<v-checkbox v-model="checkbox" :disabled="loading" label="Автообновление (5 мин)"
@click="loader = autoRefresh(checkbox)">
</v-checkbox>
</v-col>
</v-row>
<v-divider class="mx-0"></v-divider>
<v-progress-linear v-if="loading" indeterminate></v-progress-linear>
<v-progress-linear v-if="checkbox && !loading" color="orange" rounded :value="progress"
reactive></v-progress-linear>
<v-container fluid :style="{ 'height': barHeight + 'px' }">
<Bar v-if="chartData.datasets.length" :options="chartOptions" :data="chartData" ref="bar" />
</v-container>
<v-container fluid>
<v-expansion-panels v-if="data.table.length" v-show="!loading" :disabled="loading" tile focusable>
<v-expansion-panel>
<v-expansion-panel-header>
<span>
<v-icon>info</v-icon>
Простои подробнее...
</span>
</v-expansion-panel-header>
<v-expansion-panel-content class="my-5">
<v-data-table v-model="selected" @input="prostoiSelect()" :headers="headers" :items="data.table"
disable-pagination hide-default-footer :item-class="row_classes" dense fixed-header show-select
item-key="id" group-by='Agregat'>
<template v-slot:top>
<v-progress-linear v-if="loading" indeterminate></v-progress-linear>
</template>
<template v-slot:item.data-table-select="{ item, isSelected, select }">
<v-simple-checkbox v-show="item.Descr == 'Простой'" :value="isSelected" :readonly="item.disabled"
@input="select($event)"> </v-simple-checkbox>
</template>
</v-data-table>
</v-expansion-panel-content>
</v-expansion-panel>
</v-expansion-panels>
</v-container>
</v-container>
</template>
<script>
const jsDate = new Date();
import { Chart, LineController, LineElement, CategoryScale, LinearScale, PointElement } from 'chart.js';
import { Line as LineChart } from 'vue-chartjs';
Chart.register(LineController, LineElement, CategoryScale, LinearScale, PointElement);
import { mapGetters, mapActions, mapMutations } from "vuex";
import {
Chart as ChartJS,
Title,
Tooltip,
Legend,
BarElement,
CategoryScale,
LinearScale,
TimeScale
} from 'chart.js'
import { Bar } from 'vue-chartjs'
import 'chartjs-adapter-moment';
import ChartDataLabels from 'chartjs-plugin-datalabels';
ChartJS.register(CategoryScale, LinearScale, BarElement, Title, Tooltip, Legend, ChartDataLabels, TimeScale);
export default {
name: 'BarChart',
components: {
Bar
},
data() {
return {
dates: [
new Date(jsDate.getFullYear(), jsDate.getMonth(), jsDate.getDate() + 1)
.toISOString()
.substr(0, 10),
new Date(jsDate.getFullYear(), jsDate.getMonth(), jsDate.getDate() + 1)
.toISOString()
.substr(0, 10),
],
// dates: [
// new Date(jsDate.getFullYear(), jsDate.getMonth(), jsDate.getDate() + 1)
// .toISOString()
// .substr(0, 10),
// new Date(jsDate.getFullYear(), jsDate.getMonth(), jsDate.getDate() + 1)
// .toISOString()
// .substr(0, 10),
// ],
BofSelect: 'K1+K2',
listBof: ['K1', 'K2', 'K1+K2'],
selected: [],
checkbox: false,
progress: 100,
timerDelay: 60,
datePickerMenu: false,
barHeight: 0,
chartData: {
// labels: [],
datasets: [],
},
chartOptions: {
plugins: {
legend: {
display: true,
//onClick: (e) => e.stopPropagation(),
onClick: false,
labels: {
// filter: function (item) {
// //if (item.text != '')
// return 'item'
// }
generateLabels() {
return [{
text: 'Простой, мин',
fillStyle: '#C2CBD1',
components: { LineChart },
data: () => ({
items: [
{
name: "A",
data: {
labels: ["Resource Usage", '456'],
datasets: [
{
labels: ["Resource Usage", '456'],
backgroundColor: "#41b883",
data: [90, 99, 99, 20, 10]
},
{
text: 'Конвертер, мин',
fillStyle: '#51C27F',
label: "Mem Usage",
backgroundColor: "#FFAA0C",
data: [400, 400, 200, 100, 200]
}
]
}
},
{
text: 'УПК, мин',
fillStyle: '#FF6F4D',
name: "B",
data: {
labels: ["Resource Usage"],
datasets: [
{
label: "CPU Usage",
backgroundColor: "#41b883",
data: [90, 99]
},
{
text: 'МНЛЗ - прибытие, мин',
fillStyle: '#00eeff',
},
{
text: 'МНЛЗ - разливка, мин',
fillStyle: '#01d5e4',
},
{
text: 'МНЛЗ - порезка, мин',
fillStyle: '#03a2ad',
}]
// const data = chart.data;
// if (data.labels.length && data.datasets.length) {
// const {labels: {pointStyle}} = chart.legend.options;
// return data.labels.map((label, i) => {
// const meta = chart.getDatasetMeta(0);
// const style = meta.controller.getStyle(i);
// return {
// text: `${label}: ${data['datasets'][0].data[i]}`,
// fillStyle: style.backgroundColor,
// strokeStyle: style.borderColor,
// lineWidth: style.borderWidth,
// pointStyle: pointStyle,
// hidden: !chart.getDataVisibility(i),
// // Extra data used for toggling the correct item
// index: i
// };
// });
// }
// return [];
label: "Mem Usage",
backgroundColor: "#FFAA0C",
data: [400, 400]
}
},
},
title: {
display: true,
text: '',
align: 'center'
},
tooltip: {
callbacks: {
label: function (context) {
let label = '';
if (context.parsed.y !== null) {
if (context.dataset.aggregate === 'bof') {
label += 'Конвертер: ' + context.dataset.date_start + ' - ' + context.dataset.date_end
} else if (context.dataset.aggregate === 'prostoy') {
label += 'Простой: ' + context.dataset.data[context.dataIndex].prostoi_name + ' (' + context.dataset.p_start + ' - ' + context.dataset.p_end + ')'
} else if (context.dataset.aggregate === 'lf') {
label += 'УПК: ' + context.dataset.lf_start + ' - ' + context.dataset.lf_end
} else if (context.dataset.aggregate === 'ccm_status2') {
label += 'МНЛЗ - прибытие: ' + context.dataset.ccm_status2_start + ' - ' + context.dataset.ccm_status2_end
} else if (context.dataset.aggregate === 'ccm_status3') {
label += 'МНЛЗ - разливка: ' + context.dataset.ccm_status3_start + ' - ' + context.dataset.ccm_status3_end
} else if (context.dataset.aggregate === 'ccm_status4') {
label += 'МНЛЗ - порезка: ' + context.dataset.ccm_status4_start + ' - ' + context.dataset.ccm_status4_end
]
}
}
return label
}
}
},
datalabels: {
labels: {
name: {
//anchor: 'end',
//align: 'top',
color: 'black',
display: true,
font: { size: 12 },
formatter: function (value,) {
return value.PHASE_DURATION
}
},
value: {
color: 'black',
display: false,
padding: 2,
}
},
},
},
responsive: true,
maintainAspectRatio: false,
//aspectRatio: 12,
indexAxis: 'y',
scales: {
x: {
type: 'time',
//stacked: true,
time: {
displayFormats: {
'millisecond': 'MMM DD',
'second': 'MMM DD',
'minute': 'MMM DD',
'hour': 'HH:mm',
'day': 'MMM DD',
'week': 'MMM DD',
'month': 'MMM DD',
'quarter': 'MMM DD',
'year': 'MMM DD',
},
unit: 'hour',
//stepSize: '00:30',
},
// min: this.data.minDate,
// max: this.data.maxDate,
},
y: {
stacked: true,
ticks: {
callback: function () { }
}
// ticks: {
// callback: function (value, index, ticks) {
// console.log(index)
// console.log(ticks)
// // console.log(a)
// // console.log(c)
// // if (this.getLabelForValue(value)==='25K10867')
// // return this.getLabelForValue(value);
// if (this.getLabelForValue(value)==='25K10867')
// return this.getLabelForValue(value)
// },
// callback:this.myFunction(),
// }
},
},
}
}
},
computed: {
...mapGetters("BOFHeatPhase", {
loading: "loading",
data: "data"
}),
computedDateFormatted() {
let formatDates = [];
formatDates.push(this.formatDate(this.dates[0]));
formatDates.push(this.formatDate(this.dates[1]));
return formatDates.join(" ~ ");
},
headers() {
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
ctx.font = "12px Roboto, sans-serif";
this.data.headers.forEach(element => {
var metrics = ctx.measureText(element.text);
var cellWidth = metrics.width;
element.width = cellWidth + 65;
element.divider = true;
element.align = "center";
if (element.value === "id") {
element.align = " d-none";
}
});
return this.data.headers;
},
},
methods: {
...mapMutations("BOFHeatPhase", {
getExcel: "getExcel",
}),
...mapActions("BOFHeatPhase", {
getData: "getData",
refreshChart: "refreshChart",
changeAggregate: "changeAggregate"
}),
toPrint() {
var canvasEle = this.$refs.bar.$el;
var win = window.open();
// win.document.write("<br><img width='99%' height='80%' src='" + canvasEle.toDataURL() + "' />");
win.document.write("<br><img width='99%' src='" + canvasEle.toDataURL() + "' />");
setTimeout(function () { //giving it 200 milliseconds time to load
// win.document.close();
// win.focus()
win.print();
// win.location.reload()
}, 0);
// let url = this.$refs.bar.$el.toDataURL();
// let win = window.open();
// win.document.write("<img class='a4-container' src='" + url + "'/>");
// win.setTimeout(() => win.print(), 0);
},
toImage() {
const context = this.$refs.bar.$el.getContext('2d');
context.save();
context.globalCompositeOperation = 'destination-over';
context.fillStyle = 'white';
context.fillRect(0, 0, this.$refs.bar.$el.width, this.$refs.bar.$el.height);
context.restore();
const link = document.createElement("a");
link.download = 'chart.png'
link.href = this.$refs.bar.$el.toDataURL('image/png')
link.click();
},
// Excel() {
// const context = this.$refs.bar.$el.getContext('2d');
// context.save();
// context.globalCompositeOperation = 'destination-over';
// context.fillStyle = 'white';
// context.fillRect(0, 0, this.$refs.bar.$el.width, this.$refs.bar.$el.height);
// context.restore();
// this.getExcel([
// this.formatDate(this.dates[0]),
// this.formatDate(this.dates[1]),
// this.$refs.bar.$el.toDataURL('image/png')
// ]);
// },
input(e) {
if (e.length == 2) {
this.datePickerMenu = false;
}
},
formatDate(date) {
if (!date) return null;
const [year, month, day] = date.split("-");
return `${day}.${month}.${year}`;
},
row_classes(item) {
if (item.Descr === 'Простой') {
return 'grey lighten-3';
}
},
setLabelText(val) {
let selected = val
this.chartOptions.scales.y.ticks.callback = function (value,) {
let labelText = this.getLabelForValue(value);
let descrText = '';
selected.forEach((element) => {
if (this.getLabelForValue(value) == element.heat_number) {
descrText = `${element.prostoi_descr}, `;
labelText = `${descrText.slice(0, -2)} (${element.phase_duration}) - ${this.getLabelForValue(value)}`;
}
]
})
return labelText
}
},
changeBOFselect() {
this.barHeight = 0;
this.chartData.labels = [];
this.chartData.datasets = [];
this.changeAggregate(this.BofSelect).then(() => {
this.refreshChart([this.selected, this.BofSelect]).then(() => {
this.chartData.datasets = this.data.chart.dataset;
this.setLabelText(this.data.prostoiSelected)
this.barHeight += 175 + (this.data.chart.label.length * 25);
this.chartOptions.plugins.title.text = `Циклограмма производства ${this.BofSelect} в ККЦ за ${this.formatDate(this.dates[0])}`;
});
});
// this.barHeight = 0;
// this.chartData.labels = [];
// this.chartData.datasets = [];
// this.refreshChart([this.selected, this.BofSelect]).then(() => {
// this.chartData.datasets = this.data.chart.dataset;
// this.setLabelText(this.data.prostoiSelected)
// this.barHeight += 175 + (this.data.chart.label.length * 25);
// });
},
prostoiSelect() {
this.chartData.datasets = [];
this.refreshChart([this.selected, this.BofSelect]).then(() => {
this.chartData.datasets = this.data.chart.dataset;
this.setLabelText(this.data.prostoiSelected)
});
},
refreshData() {
this.chartData.labels = [];
this.chartData.datasets = [];
this.barHeight = 0;
this.getData([
this.formatDate(this.dates[0]),
this.formatDate(this.dates[1]), this.dates[1]],
)
.then(() => {
let dStart = new Date(new Date(this.dates[0]).getFullYear(),
new Date(this.dates[0]).getMonth(),
new Date(this.dates[0]).getDate())
.toISOString()
.substr(0, 10) + ' 23:00:00';
let dEnd =
new Date(new Date(this.dates[1]).getFullYear(),
new Date(this.dates[1]).getMonth(),
new Date(this.dates[1]).getDate() + 1)
.toISOString()
.substr(0, 10) + ' 23:00:00';
//this.chartOptions.plugins.title.text = 'Циклограмма производства в ККЦ за ' + this.formatDate(this.dates[0]);
this.chartOptions.plugins.title.text = `Циклограмма производства ${this.BofSelect} в ККЦ за ${this.formatDate(this.dates[0])}`;
this.chartOptions.scales.x.min = dStart;
this.chartOptions.scales.x.max = dEnd;
this.selected = this.data.prostoiSelected
this.progress = 101;
}).then(() => {
// this.barHeight += 145 + (this.data.chart.label.length * 20);
this.refreshChart([this.selected]).then(() => {
this.barHeight += 175 + (this.data.chart.label.length * 25);
this.chartData.datasets = this.data.chart.dataset;
this.setLabelText(this.data.prostoiSelected);
});
})
},
autoRefresh(e) {
if (e) {
this.progress = 101;
this.progressValue();
} else {
clearInterval(this.timerID);
}
},
progressValue() {
this.timerID = setInterval(() => {
this.progress = (this.progress - 0.02).toFixed(2);
if (this.progress < 0) {
this.progress = 101;
this.refreshData();
}
}, this.timerDelay);
}
},
mounted() {
this.refreshData();
}
}
</script>
<style>
.datePicker input {
text-align: center;
cursor: pointer;
<!-- <template>
<v-col style="min-width:550px; max-width:550px;" cols="1">
<LineChart :data="chartData" />
</v-col>
</template>
<script>
import { Chart, LineController, LineElement, CategoryScale, LinearScale, PointElement } from 'chart.js';
import { Line as LineChart } from 'vue-chartjs';
Chart.register(LineController, LineElement, CategoryScale, LinearScale, PointElement);
export default {
components: { LineChart },
data() {
return {
chartData: {
labels: ['January', 'February', 'March'],
datasets: [
{
label: "CPU Usage",
backgroundColor: "#41b883",
data: [90, 99, 99, 20, 10]
},
{
label: "Mem Usage",
backgroundColor: "#FFAA0C",
data: [400, 400, 200, 100, 200]
}
]
}
}
}
}
/* .theme--light.v-data-table tbody tr.v-data-table__selected {
background: #ffd296d2 !important;
}
.theme--dark.v-data-table tbody tr.v-data-table__selected {
background: #ffd296d2 !important;
} */
.a4-container {
width: 10mm !important;
height: 297mm !important;
margin: auto;
/* для центровки страницы */
page-break-after: always;
/* для начала следующего элемента с новой страницы */
}
#BofGazTrend .v-expansion-panel {
border-left: thin solid rgba(0, 0, 0, 0.12) !important;
border-right: thin solid rgba(0, 0, 0, 0.12) !important;
border-top: thin solid rgba(0, 0, 0, 0.12) !important;
border-bottom: thin solid rgba(0, 0, 0, 0.12) !important;
}
#BofGazTrend .v-expansion-panel::before {
box-shadow: none !important;
}
#BofGazTrend .v-data-table-header {
background-color: #fafafa !important;
}
#BofGazTrend .spacer {
margin-top: 3em;
}
#BofGazTrend .divider {
border-right: rgba(0, 0, 0, 0.12) solid 1px;
}
#BofGazTrend .v-data-table {
border-left: thin solid rgba(0, 0, 0, 0.12);
border-top: thin solid rgba(0, 0, 0, 0.12);
border-bottom: thin solid rgba(0, 0, 0, 0.12);
border-radius: 0;
}
#BofGazTrend .v-data-table table>tbody>tr>td {
border-right: thin solid rgba(0, 0, 0, 0.12);
}
#BofGazTrend #datePicker {
text-align: center;
}
/* #BOFHeatPhase .v-item-group.theme--light.v-expansion-panels.v-expansion-panels--focusable.v-expansion-panels--tile>div>div>div>div>div>table>thead>tr>th.text-start>div {
display: none;
} */
.theme--light.v-data-table tbody tr.v-data-table__selected {
background: #f5c17d70 !important;
}
.theme--dark.v-data-table tbody tr.v-data-table__selected {
background: #a17b4970 !important;
}
.theme--dark.v-data-table tbody tr.v-data-table__selected:hover {
background: #a17b49c2 !important;
}
.theme--light.v-data-table tbody tr.v-data-table__selected:hover {
background: #ffd296d2 !important;
}
</style>
</script> -->