feat: Performance all chart done.

This commit is contained in:
chiayin
2024-02-05 15:50:33 +08:00
parent 5063d49794
commit c811baefa6
2 changed files with 149 additions and 104 deletions

View File

@@ -79,11 +79,11 @@ const routes = [
component: Conformance, component: Conformance,
props: true, props: true,
}, },
// { {
// path: "/discover/performance/:type/:fileId", path: "/discover/performance/:type/:fileId",
// name: "Performance", name: "Performance",
// component: Performance, component: Performance,
// } }
] ]
}, },
] ]
@@ -93,11 +93,11 @@ const routes = [
name: "NotFound404", name: "NotFound404",
component: NotFound404, component: NotFound404,
}, },
{ // {
path: "/discover/performance", // path: "/discover/performance",
name: "Performance", // name: "Performance",
component: Performance, // component: Performance,
} // }
]; ];
const base_url = import.meta.env.BASE_URL; const base_url = import.meta.env.BASE_URL;

View File

@@ -1,7 +1,7 @@
<template> <template>
<main class="h-screen-main relative"> <main class="h-screen-main relative">
<div class="h-full relative bg-neutral-50"> <div class="h-full relative bg-neutral-50">
<div class="flex justify-start items-start p-4 h-full overflow-y-auto scroll-smooth"> <div class="flex justify-start items-start p-4 h-full">
<!-- tag --> <!-- tag -->
<aside class="border-r border-neutral-300 pr-4 mr-4 h-full sticky top-0 self-start"> <aside class="border-r border-neutral-300 pr-4 mr-4 h-full sticky top-0 self-start">
<section class="px-2 space-y-2 w-56 h-full"> <section class="px-2 space-y-2 w-56 h-full">
@@ -20,7 +20,7 @@
</section> </section>
</aside> </aside>
<!-- graph --> <!-- graph -->
<article class="w-full h-full"> <article class="w-full h-full overflow-x-hidden overflow-y-auto scrollbar scroll-smooth">
<section> <section>
<p class="h2 px-4 border-b border-neutral-900"><span class="material-symbols-outlined mr-2 align-middle">schedule</span>Time Usage</p> <p class="h2 px-4 border-b border-neutral-900"><span class="material-symbols-outlined mr-2 align-middle">schedule</span>Time Usage</p>
</section> </section>
@@ -28,35 +28,36 @@
<ul class="list-disc list-inside px-4 pl-7"> <ul class="list-disc list-inside px-4 pl-7">
<li id="cycleTime" class="scroll-smooth"> <li id="cycleTime" class="scroll-smooth">
<span class="inline-block py-4">Cycle Time & Efficiency</span> <span class="inline-block py-4">Cycle Time & Efficiency</span>
<div> <ul>
<div class="card bg-neutral-10 mb-4"> <li class="bg-neutral-10 mb-4">
<Chart type="line" :data="avgCycleTimeData" :options="avgCycleTimeOptions" class="h-96" /> <Chart type="line" :data="avgCycleTimeData" :options="avgCycleTimeOptions" class="h-96" />
</div> </li>
<div class="card bg-neutral-10"> <li class="bg-neutral-10">
<Chart type="bar" :data="avgCycleEfficiencyData" :options="avgCycleEfficiencyOptions" class="h-96" /> <Chart type="bar" :data="avgCycleEfficiencyData" :options="avgCycleEfficiencyOptions" class="h-96" />
</div> </li>
<!-- <div class="flex justify-start items-center"> </ul>
<div class="card">
<Chart type="line" :data="avgCycleTimeData" :options="avgCycleTimeOptions" class="h-96" />
</div>
<div class="card">
<Chart type="line" :data="avgCycleTimeData" :options="avgCycleTimeOptions" class="h-96" />
</div>
</div> -->
</div>
</li> </li>
<li id="processingTime"> <li id="processingTime">
<span class="inline-block py-4">Processing Time</span> <span class="inline-block py-4">Processing Time</span>
<div class=""> <ul>
<div class="card bg-neutral-10 "> <li class="bg-neutral-10 mb-4">
<Chart type="line" :data="avgProcessTimeData" :options="avgProcessTimeOptions" class="h-96" />
</li>
<li class="bg-neutral-10">
<Chart type="bar" :data="avgProcessTimeByTaskData" :options="avgProcessTimeByTaskOptions" :height="horizontalBar"/> <Chart type="bar" :data="avgProcessTimeByTaskData" :options="avgProcessTimeByTaskOptions" :height="horizontalBar"/>
</div> </li>
</div> </ul>
</li> </li>
<li id="waitingTime"> <li id="waitingTime">
<span class="inline-block py-4">Waiting Time</span> <span class="inline-block py-4">Waiting Time</span>
<div class=""> <ul>
</div> <li class="bg-neutral-10 mb-4">
<Chart type="line" :data="avgWaitingTimeData" :options="avgWaitingTimeOptions" class="h-96" />
</li>
<li class="bg-neutral-10">
<Chart type="bar" :data="avgWaitingTimeByEdgeData" :options="avgWaitingTimeByEdgeOptions" :height="horizontalBar"/>
</li>
</ul>
</li> </li>
</ul> </ul>
</section> </section>
@@ -65,8 +66,14 @@
<ul class="list-disc list-inside px-4 pl-7"> <ul class="list-disc list-inside px-4 pl-7">
<li id="cases"> <li id="cases">
<span class="inline-block py-4">Number of Cases</span> <span class="inline-block py-4">Number of Cases</span>
<div class=""> <ul>
</div> <li class="bg-neutral-10 mb-4">
<Chart type="line" :data="freqData" :options="freqOptions" class="h-96" />
</li>
<li class="bg-neutral-10">
<Chart type="bar" :data="casesByTaskData" :options="casesByTaskOptions" :height="horizontalBar"/>
</li>
</ul>
</li> </li>
</ul> </ul>
</section> </section>
@@ -108,13 +115,33 @@ export default {
// {tagId: '#trace', label: 'Number of Trace'}, // {tagId: '#trace', label: 'Number of Trace'},
// {tagId: '#resource', label: 'Resource'}, // {tagId: '#resource', label: 'Resource'},
], ],
contentData: {
avgCycleTime: {title: 'Average Cycle Time', x: 'Date', y: 'Cycle time'},
avgCycleEfficiency: {title: 'Cycle Efficiency', x: 'Date', y: 'Cycle efficiency (%)'},
avgProcessTime: {title: 'Average Processing Time', x: 'Date', y: 'Processing time'},
avgProcessTimeByTask: {title: 'Average Processing Time by Activity', x: 'Processing time', y: 'Activity'},
avgWaitingTime: {title: 'Average Waiting Time', x: 'Date', y: 'Waiting time'},
avgWaitingTimeByEdge: {title: 'Average Waiting Time by Activity', x: 'Waiting time', y: 'Activity'},
freq: {title: 'New Cases', x: 'Date', y: 'Count'},
casesByTask: {title: 'Number of Cases by Activity', x: 'Count', y: 'Activity'},
},
isActive: null, isActive: null,
avgCycleTimeData: null, avgCycleTimeData: null,
avgCycleTimeOptions: null, avgCycleTimeOptions: null,
avgCycleEfficiencyData: null, avgCycleEfficiencyData: null,
avgCycleEfficiencyOptions: null, avgCycleEfficiencyOptions: null,
avgProcessTimeData: null,
avgProcessTimeOptions: null,
avgProcessTimeByTaskData: null, avgProcessTimeByTaskData: null,
avgProcessTimeByTaskOptions: null, avgProcessTimeByTaskOptions: null,
avgWaitingTimeData: null,
avgWaitingTimeOptions: null,
avgWaitingTimeByEdgeData: null,
avgWaitingTimeByEdgeOptions: null,
freqData: null,
freqOptions: null,
casesByTaskData: null,
casesByTaskOptions: null,
horizontalBarHeight: 500, // horizontal Bar default height horizontalBarHeight: 500, // horizontal Bar default height
horizontalBar: 500, horizontalBar: 500,
data: { data: {
@@ -143,24 +170,25 @@ export default {
} }
return data; return data;
}, },
getAvgCycleTime() { getLineChart(chartData, content) {
let data = this.data.time.avg_cycle_time; let datasets = setLineChartData(chartData.data, chartData.x_axis.max, chartData.x_axis.min, false, chartData.y_axis.max, chartData.y_axis.min);
let datasets = setLineChartData(data.data, data.x_axis.max, data.x_axis.min, false, data.y_axis.max, data.y_axis.min); let minX = chartData.x_axis.min;
let minX = data.x_axis.min; let maxX = chartData.x_axis.max;
let maxX = data.x_axis.max; let maxY = chartData.y_axis.max;
let maxY = data.y_axis.max; let xData = this.xLabelsData(chartData.x_axis)
let xData = this.xLabelsData(data.x_axis) let setData = {};
let setOption = {};
const getMoment = (time)=> { const getMoment = (time)=> {
return this.$moment(time).format('YYYY/M/D hh:mm:ss') return this.$moment(time).format('YYYY/M/D hh:mm:ss')
}; };
const getSimpleTimeLabel = simpleTimeLabel; const getSimpleTimeLabel = simpleTimeLabel;
const getFollowTimeLabel = followTimeLabel; const getFollowTimeLabel = followTimeLabel;
this.avgCycleTimeData = { setData = {
labels: xData, labels: xData,
datasets: [ datasets: [
{ {
label: 'Average Cycle Time', label: content.title,
data: datasets, data: datasets,
fill: false, fill: false,
tension: 0, // 貝茲曲線張力 tension: 0, // 貝茲曲線張力
@@ -168,7 +196,7 @@ export default {
} }
] ]
}; };
this.avgCycleTimeOptions = { setOption = {
responsive: true, responsive: true,
maintainAspectRatio: false, maintainAspectRatio: false,
layout: { layout: {
@@ -185,16 +213,16 @@ export default {
titleFont: {weight: 'normal'}, titleFont: {weight: 'normal'},
callbacks: { callbacks: {
title: function(context) { title: function(context) {
return `Date: ${getMoment(context[0].parsed.x)}`; return `${content.x}: ${getMoment(context[0].parsed.x)}`;
}, },
label: function(context) { label: function(context) {
return `Cycle time: ${getSimpleTimeLabel(context.parsed.y, 2)}`; return `${content.y}: ${getSimpleTimeLabel(context.parsed.y, 2)}`;
} }
}, },
}, },
title: { title: {
display: true, display: true,
text: 'Average Cycle Time', text: content.title,
color: '#334155', color: '#334155',
padding: { padding: {
bottom: 16 bottom: 16
@@ -213,7 +241,7 @@ export default {
max: maxX, max: maxX,
title: { title: {
display: true, display: true,
text: 'Date', text: content.x,
color: '#334155', color: '#334155',
font: { font: {
size: 12, size: 12,
@@ -239,7 +267,7 @@ export default {
beginAtZero: true, // scale 包含 0 beginAtZero: true, // scale 包含 0
title: { title: {
display: true, display: true,
text: 'Cycle time', text: content.y,
color: '#334155', color: '#334155',
font: { font: {
size: 12, size: 12,
@@ -262,16 +290,19 @@ export default {
}, },
}, },
}; };
return [setData, setOption]
}, },
getAvgCycleEfficiency() { getBarChart(chartData, content) {
const data = this.data.time.avg_cycle_efficiency; const maxX = chartData.x_axis.max;
const maxX = data.x_axis.max; const minX = chartData.x_axis.min;
const minX = data.x_axis.min;
const getMoment = (time)=> this.$moment(time).format('YYYY/M/D hh:mm:ss'); const getMoment = (time)=> this.$moment(time).format('YYYY/M/D hh:mm:ss');
const getDateLabel = dateLabel; const getDateLabel = dateLabel;
let datasets = data.data; let datasets = chartData.data;
let xData; let xData;
let yData; let yData;
let setData = {};
let setOption = {};
datasets = datasets.map(value => { datasets = datasets.map(value => {
return { return {
@@ -282,17 +313,17 @@ export default {
xData = datasets.map(i => i.x); xData = datasets.map(i => i.x);
yData = datasets.map(i => i.y) yData = datasets.map(i => i.y)
this.avgCycleEfficiencyData = { setData = {
labels: xData, labels: xData,
datasets: [ datasets: [
{ {
label: 'Cycle Efficiency', label: content.title,
data: yData, data: yData,
backgroundColor: '#0099FF' backgroundColor: '#0099FF'
} }
] ]
}; };
this.avgCycleEfficiencyOptions = { setOption = {
responsive: true, responsive: true,
maintainAspectRatio: false, maintainAspectRatio: false,
layout: { layout: {
@@ -309,16 +340,16 @@ export default {
titleFont: {weight: 'normal'}, titleFont: {weight: 'normal'},
callbacks: { callbacks: {
title: function(context) { title: function(context) {
return `Date: ${context[0].label}`; return `${content.x}: ${context[0].label}`;
}, },
label: function(context) { label: function(context) {
return `Cycle efficiency(%): ${context.parsed.y.toFixed(2)}`; return `${content.y}: ${context.parsed.y.toFixed(2)}`;
} }
}, },
}, },
title: { title: {
display: true, display: true,
text: 'Cycle Efficiency', text: content.title,
color: '#334155', color: '#334155',
padding: { padding: {
bottom: 16 bottom: 16
@@ -334,7 +365,7 @@ export default {
x: { x: {
title: { title: {
display: true, display: true,
text: 'Date', text: content.x,
color: '#334155', color: '#334155',
font: { font: {
size: 12, size: 12,
@@ -358,7 +389,7 @@ export default {
beginAtZero: true, // scale 包含 0 beginAtZero: true, // scale 包含 0
title: { title: {
display: true, display: true,
text: 'Cycle efficiency(%)', text: content.y,
color: '#334155', color: '#334155',
font: { font: {
size: 12, size: 12,
@@ -378,35 +409,35 @@ export default {
}, },
}, },
}; };
return [setData, setOption]
}, },
getAvgProcessTimeByTask() { getHorizontalBarChart(chartData, content, isSingle) {
// const data = this.data.time.avg_process_time_by_task; // 一個 const maxY = chartData.y_axis.max;
const data = this.data.time.avg_waiting_time_by_edge;
const maxY = data.y_axis.max;
const getSimpleTimeLabel = simpleTimeLabel; const getSimpleTimeLabel = simpleTimeLabel;
const getFollowTimeLabel = followTimeLabel; const getFollowTimeLabel = followTimeLabel;
let setData = {};
let setOption = {};
// 大到小排序 // 大到小排序
data.data.sort((a, b) => b.y - a.y); chartData.data.sort((a, b) => b.y - a.y);
// const xData = data.data.map(item => item.x); // 一個 const xData = chartData.data.map(item => item.x);
// const xData = data.data.map(item => item.x.join(' - ')); const yData = chartData.data.map(item => item.y);
const xData = data.data.map(item => item.x); const totalBars = chartData.data.length;
const yData = data.data.map(item => item.y);
const totalBars = data.data.length;
if(totalBars > 10) this.horizontalBar = (totalBars - 10) * 20 + this.horizontalBarHeight; if(totalBars > 10) this.horizontalBar = (totalBars - 10) * 20 + this.horizontalBarHeight;
this.avgProcessTimeByTaskData = { setData = {
labels: xData, labels: xData,
datasets: [ datasets: [
{ {
label: 'Average Processing Time by Activity', label: content.title,
data: yData, data: yData,
backgroundColor: '#0099FF', backgroundColor: '#0099FF',
} }
] ]
}; };
this.avgProcessTimeByTaskOptions = { setOption = {
indexAxis: 'y', indexAxis: 'y',
responsive: true, responsive: true,
maintainAspectRatio: false, maintainAspectRatio: false,
@@ -423,19 +454,14 @@ export default {
displayColors: false, displayColors: false,
titleFont: {weight: 'normal'}, titleFont: {weight: 'normal'},
callbacks: { callbacks: {
title: function(context) {
// return `Activity: ${context[0].label}`;
console.log(context[0].label);
return `Activity: ${context[0].label.replace(',', ' - ')}`
},
label: function(context) { label: function(context) {
return `Processing time: ${getSimpleTimeLabel(context.parsed.x, 2)}`; return `${content.x}: ${getSimpleTimeLabel(context.parsed.x, 2)}`;
} }
}, },
}, },
title: { title: {
display: true, display: true,
text: 'Average Processing Time by Activity', text: content.title,
color: '#334155', color: '#334155',
padding: { padding: {
bottom: 16 bottom: 16
@@ -451,7 +477,7 @@ export default {
x: { x: {
title: { title: {
display: true, display: true,
text: 'Processing time', text: content.x,
color: '#334155', color: '#334155',
font: { font: {
size: 12, size: 12,
@@ -478,7 +504,7 @@ export default {
type: 'category', type: 'category',
title: { title: {
display: true, display: true,
text: 'Activity', text: content.y,
color: '#334155', color: '#334155',
font: { font: {
size: 12, size: 12,
@@ -488,18 +514,6 @@ export default {
ticks:{ ticks:{
color: '#64748b', color: '#64748b',
padding: 8, padding: 8,
callback: function (value, index, ticks) {
// let label = xData[index];
// return label.length > 21 ? `${label.substring(0, 18)}...` : label
let label = xData[index];
let labelStart = label[0];
let labelEnd = label[1];
labelStart = labelStart.length > 10 ? `${labelStart.substring(0,7)}...` : labelStart
labelEnd = labelEnd.length > 10 ? `${labelEnd.substring(0,7)}...` : labelEnd
return labelStart + " - " + labelEnd
}
}, },
grid: { grid: {
display:false, display:false,
@@ -511,19 +525,50 @@ export default {
}, },
}, },
}; };
if(isSingle) { // 設定一個活動的 y label、提示框文字
setOption.plugins.tooltip.callbacks.title = function(context) {
return `${content.y}: ${context[0].label}`;
};
setOption.scales.y.ticks.callback = function (value, index, ticks) {
let label = xData[index];
return label.length > 21 ? `${label.substring(0, 18)}...` : label
};
}else { // 設定「活動」到「活動」的 y label、提示框文字
setOption.plugins.tooltip.callbacks.title = function(context) {
return `${content.y}: ${context[0].label.replace(',', ' - ')}`
};
setOption.scales.y.ticks.callback = function (value, index, ticks) {
let label = xData[index];
let labelStart = label[0];
let labelEnd = label[1];
labelStart = labelStart.length > 10 ? `${labelStart.substring(0,7)}...` : labelStart;
labelEnd = labelEnd.length > 10 ? `${labelEnd.substring(0,7)}...` : labelEnd;
return labelStart + " - " + labelEnd
};
}
return [setData, setOption]
}, },
}, },
async created() { async created() {
this.isLoading = true; this.isLoading = true;
// const routeParams = this.$route.params; const routeParams = this.$route.params;
// let id = routeParams.fileId; let id = routeParams.fileId;
// let type = routeParams.type; let type = routeParams.type;
// // 取得 Performance Data // 取得 Performance Data
// await this.performanceStore.getPerformance(type, id); await this.performanceStore.getPerformance(type, id);
this.getAvgCycleTime(); console.log(this.performanceData);
this.getAvgCycleEfficiency();
this.getAvgProcessTimeByTask(); [this.avgCycleTimeData, this.avgCycleTimeOptions] = this.getLineChart(this.performanceData.time.avg_cycle_time, this.contentData.avgCycleTime);
[this.avgCycleEfficiencyData, this.avgCycleEfficiencyOptions] = this.getBarChart(this.performanceData.time.avg_cycle_efficiency, this.contentData.avgCycleEfficiency);
[this.avgProcessTimeData, this.avgProcessTimeOptions] = this.getLineChart(this.performanceData.time.avg_process_time, this.contentData.avgProcessTime);
[this.avgProcessTimeByTaskData, this.avgProcessTimeByTaskOptions] = this.getHorizontalBarChart(this.performanceData.time.avg_process_time_by_task, this.contentData.avgProcessTimeByTask, true);
[this.avgWaitingTimeData, this.avgWaitingTimeOptions] = this.getLineChart(this.performanceData.time.avg_waiting_time, this.contentData.avgWaitingTime);
[this.avgWaitingTimeByEdgeData, this.avgWaitingTimeByEdgeOptions] = this.getHorizontalBarChart(this.performanceData.time.avg_waiting_time_by_edge, this.contentData.avgWaitingTimeByEdge, true);
[this.freqData, this.freqOptions] = this.getLineChart(this.performanceData.freq.cases, this.contentData.freq);
[this.casesByTaskData, this.casesByTaskOptions] = this.getHorizontalBarChart(this.performanceData.freq.cases_by_task, this.contentData.casesByTask, true);
this.isLoading = false; this.isLoading = false;
} }