WIP: #258 Compare page
This commit is contained in:
@@ -437,7 +437,7 @@ export default {
|
||||
getBarChart(chartData, content, caller) {
|
||||
const maxX = chartData.x_axis.max;
|
||||
const minX = chartData.x_axis.min;
|
||||
const getMoment = (time)=> this.$moment(time).format('YYYY/M/D hh:mm:ss');
|
||||
const getMoment = (time)=> this.$moment(time).format('YYYY/MM/DD');
|
||||
const getDateLabel = getDateLabelByMinMaxDate;
|
||||
let datasetsPrimary = chartData.data[0].data;
|
||||
let xDataPrimary;
|
||||
@@ -910,6 +910,349 @@ export default {
|
||||
|
||||
return [primeVueSetData, primeVueSetOption];
|
||||
},
|
||||
/**
|
||||
* 建立Case By Task水平長條圖
|
||||
* 避免共用 PrimeVue 設定值,避免覆蓋設定
|
||||
* @param { object } chartData chart data
|
||||
* @param { object } content titels 標題的文字
|
||||
* @param { boolean } isSingle 單個或雙數 activity
|
||||
* @param { string } xUnit x 軸單位
|
||||
*/
|
||||
getCaseByTaskHorizontalBarChart(chartData, content, isSingle, xUnit = 'count') {
|
||||
const maxX = chartData.x_axis.max;
|
||||
const getSimpleTimeLabel = simpleTimeLabel;
|
||||
const getFollowTimeLabel = followTimeLabel;
|
||||
const labelPrimary = chartData.data[0].label;
|
||||
const labelSecondary = chartData.data[1].label;
|
||||
let primeVueSetData = {};
|
||||
let primeVueSetOption = {};
|
||||
|
||||
// 大到小排序: Primary 為主
|
||||
const datasetsPrimary = chartData.data[0].data;
|
||||
const datasetsSecondary = chartData.data[1].data;
|
||||
datasetsPrimary.sort((a, b) => b.y - a.y);
|
||||
datasetsSecondary.sort((a, b) => {
|
||||
// Find the index of a.x in data1
|
||||
let indexA = datasetsPrimary.findIndex(item => item.x === a.x);
|
||||
// Find the index of b.x in data1
|
||||
let indexB = datasetsPrimary.findIndex(item => item.x === b.x);
|
||||
|
||||
// Compare the indexes
|
||||
return indexA - indexB;
|
||||
});
|
||||
|
||||
// 找出排序後,分別拉出 x, y Data
|
||||
const xLabelData = datasetsPrimary.map(item => item.x);
|
||||
const yDataPrimary = datasetsPrimary.map(item => item.y);
|
||||
const yDataSecondary = datasetsSecondary.map(item => item.y);
|
||||
|
||||
primeVueSetData = {
|
||||
labels: xLabelData,
|
||||
datasets: [
|
||||
{
|
||||
label: labelPrimary,
|
||||
data: yDataPrimary,
|
||||
backgroundColor: this.colorPrimary,
|
||||
},
|
||||
{
|
||||
label: labelSecondary,
|
||||
data: yDataSecondary,
|
||||
backgroundColor: this.colorSecondary,
|
||||
},
|
||||
]
|
||||
};
|
||||
primeVueSetOption = {
|
||||
indexAxis: 'y',
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
layout: {
|
||||
padding: {
|
||||
top: 16,
|
||||
left: 8,
|
||||
right: 8,
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
legend: false, // 圖例
|
||||
tooltip: {
|
||||
// displayColors: false,
|
||||
mode: 'index', // 可顯示全部的 data label
|
||||
titleFont: {weight: 'normal'},
|
||||
callbacks: {}
|
||||
},
|
||||
title: {
|
||||
display: false,
|
||||
},
|
||||
},
|
||||
scales: {
|
||||
x: {
|
||||
title: {
|
||||
display: true,
|
||||
color: '#334155',
|
||||
font: {
|
||||
size: 12,
|
||||
lineHeight: 2
|
||||
},
|
||||
text: content.x,
|
||||
},
|
||||
ticks: {
|
||||
display: true,
|
||||
maxRotation: 0, // 不旋轉 lable 0~50
|
||||
color: '#64748b',
|
||||
callback: function(value, index, ticks) {
|
||||
return value; // 計算數量,沒有時間單位才對
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
color: '#64748b',
|
||||
tickLength: 0, // 網格是否超過邊線
|
||||
},
|
||||
border: {
|
||||
display:false,
|
||||
},
|
||||
},
|
||||
y: {
|
||||
beginAtZero: true, // scale 包含 0
|
||||
type: 'category',
|
||||
title: {
|
||||
display: true,
|
||||
color: '#334155',
|
||||
font: {
|
||||
size: 12,
|
||||
lineHeight: 2
|
||||
},
|
||||
text: content.y,
|
||||
},
|
||||
ticks:{
|
||||
color: '#64748b',
|
||||
padding: 8,
|
||||
},
|
||||
grid: {
|
||||
display:false,
|
||||
color: '#64748b',
|
||||
},
|
||||
border: {
|
||||
display: false, // 隱藏左側多出來的線
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
switch (xUnit) {
|
||||
case 'count':
|
||||
default:
|
||||
primeVueSetOption.scales.x.ticks.precision = 0; // x 軸顯示小數點後 0 位
|
||||
primeVueSetOption.plugins.tooltip.callbacks.label = function(context) {
|
||||
let value = context.parsed.y;
|
||||
|
||||
value = context.parsed.x === null ? "n/a" : context.parsed.x;
|
||||
switch (context.datasetIndex) {
|
||||
case 0: // Primary
|
||||
return `${labelPrimary}: ${value}`;
|
||||
case 1: // Secondary
|
||||
return `${labelSecondary}: ${value}`;
|
||||
}
|
||||
};
|
||||
break;
|
||||
}
|
||||
if(isSingle) { // 設定一個活動的 y label、提示框文字
|
||||
primeVueSetOption.plugins.tooltip.callbacks.title = function(context) {
|
||||
return `${content.y}: ${context[0].label}`;
|
||||
};
|
||||
primeVueSetOption.scales.y.ticks.callback = function (value, index, ticks) {
|
||||
let label = xLabelData[index];
|
||||
if(label) {
|
||||
return label.length > 21 ? `${label.substring(0, 18)}...` : label
|
||||
};
|
||||
}
|
||||
|
||||
}else { // 設定「活動」到「活動」的 y label、提示框文字
|
||||
primeVueSetOption.plugins.tooltip.callbacks.title = function(context) {
|
||||
return `${content.y}: ${context[0].label.replace(',', ' - ')}`
|
||||
};
|
||||
primeVueSetOption.scales.y.ticks.callback = function (value, index, ticks) {
|
||||
let label = xLabelData[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 [primeVueSetData, primeVueSetOption]
|
||||
},
|
||||
/**
|
||||
* 建立 Average Processing Time水平長條圖
|
||||
* 避免共用 PrimeVue 設定值,避免覆蓋設定
|
||||
* @param { object } chartData chart data
|
||||
* @param { object } content titels 標題的文字
|
||||
* @param { boolean } isSingle 單個或雙數 activity
|
||||
* @param { string } xUnit x 軸單位 'date' | 'count',可傳入以上任一。
|
||||
*/
|
||||
getAvgProcessTimeHorizontalBarChart(chartData, content, isSingle, xUnit="date") {
|
||||
const maxY = chartData.y_axis.max;
|
||||
const getSimpleTimeLabel = simpleTimeLabel;
|
||||
const getFollowTimeLabel = followTimeLabel;
|
||||
const labelPrimary = chartData.data[0].label;
|
||||
const labelSecondary = chartData.data[1].label;
|
||||
let primeVueSetData = {};
|
||||
let primeVueSetOption = {};
|
||||
|
||||
// 大到小排序: Primary 為主
|
||||
const datasetsPrimary = chartData.data[0].data;
|
||||
const datasetsSecondary = chartData.data[1].data;
|
||||
datasetsPrimary.sort((a, b) => b.y - a.y);
|
||||
datasetsSecondary.sort((a, b) => {
|
||||
// Find the index of a.x in data1
|
||||
let indexA = datasetsPrimary.findIndex(item => item.x === a.x);
|
||||
// Find the index of b.x in data1
|
||||
let indexB = datasetsPrimary.findIndex(item => item.x === b.x);
|
||||
|
||||
// Compare the indexes
|
||||
return indexA - indexB;
|
||||
});
|
||||
|
||||
// 找出排序後,分別拉出 x, y Data
|
||||
const xLabelData = datasetsPrimary.map(item => item.x);
|
||||
const yDataPrimary = datasetsPrimary.map(item => item.y);
|
||||
const yDataSecondary = datasetsSecondary.map(item => item.y);
|
||||
|
||||
primeVueSetData = {
|
||||
labels: xLabelData,
|
||||
datasets: [
|
||||
{
|
||||
label: labelPrimary,
|
||||
data: yDataPrimary,
|
||||
backgroundColor: this.colorPrimary,
|
||||
},
|
||||
{
|
||||
label: labelSecondary,
|
||||
data: yDataSecondary,
|
||||
backgroundColor: this.colorSecondary,
|
||||
},
|
||||
]
|
||||
};
|
||||
primeVueSetOption = {
|
||||
indexAxis: 'y',
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
layout: {
|
||||
padding: {
|
||||
top: 16,
|
||||
left: 8,
|
||||
right: 8,
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
legend: false, // 圖例
|
||||
tooltip: {
|
||||
// displayColors: false,
|
||||
mode: 'index', // 可顯示全部的 data label
|
||||
titleFont: {weight: 'normal'},
|
||||
callbacks: {}
|
||||
},
|
||||
title: {
|
||||
display: false,
|
||||
},
|
||||
},
|
||||
scales: {
|
||||
x: {
|
||||
title: {
|
||||
display: true,
|
||||
color: '#334155',
|
||||
font: {
|
||||
size: 12,
|
||||
lineHeight: 2
|
||||
},
|
||||
text: content.x,
|
||||
},
|
||||
ticks: {
|
||||
display: true,
|
||||
maxRotation: 0, // 不旋轉 lable 0~50
|
||||
color: '#64748b',
|
||||
},
|
||||
grid: {
|
||||
color: '#64748b',
|
||||
tickLength: 0, // 網格是否超過邊線
|
||||
},
|
||||
border: {
|
||||
display:false,
|
||||
},
|
||||
},
|
||||
y: {
|
||||
beginAtZero: true, // scale 包含 0
|
||||
type: 'category',
|
||||
title: {
|
||||
display: true,
|
||||
color: '#334155',
|
||||
font: {
|
||||
size: 12,
|
||||
lineHeight: 2
|
||||
},
|
||||
text: content.y
|
||||
},
|
||||
ticks:{
|
||||
color: '#64748b',
|
||||
padding: 8,
|
||||
},
|
||||
grid: {
|
||||
display:false,
|
||||
color: '#64748b',
|
||||
},
|
||||
border: {
|
||||
display: false, // 隱藏左側多出來的線
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
switch (xUnit) {
|
||||
case 'date':
|
||||
default:
|
||||
primeVueSetOption.plugins.tooltip.callbacks.label = function(context) {
|
||||
let value = context.parsed.y;
|
||||
|
||||
value = context.parsed.x === null ? "n/a" : getSimpleTimeLabel(context.parsed.x, 2);
|
||||
switch (context.datasetIndex) {
|
||||
case 0: // Primary
|
||||
return `${labelPrimary}: ${value}`;
|
||||
case 1: // Secondary
|
||||
return `${labelSecondary}: ${value}`;
|
||||
}
|
||||
};
|
||||
primeVueSetOption.scales.x.ticks.callback = function (value, index, ticks) {
|
||||
return getFollowTimeLabel(value, maxY, 1)
|
||||
};
|
||||
break;
|
||||
}
|
||||
if(isSingle) { // 設定一個活動的 y label、提示框文字
|
||||
primeVueSetOption.plugins.tooltip.callbacks.title = function(context) {
|
||||
return `${content.y}: ${context[0].label}`;
|
||||
};
|
||||
primeVueSetOption.scales.y.ticks.callback = function (value, index, ticks) {
|
||||
let label = xLabelData[index];
|
||||
if(label) {
|
||||
return label.length > 21 ? `${label.substring(0, 18)}...` : label
|
||||
};
|
||||
}
|
||||
|
||||
}else { // 設定「活動」到「活動」的 y label、提示框文字
|
||||
primeVueSetOption.plugins.tooltip.callbacks.title = function(context) {
|
||||
return `${content.y}: ${context[0].label.replace(',', ' - ')}`
|
||||
};
|
||||
primeVueSetOption.scales.y.ticks.callback = function (value, index, ticks) {
|
||||
let label = xLabelData[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 [primeVueSetData, primeVueSetOption]
|
||||
},
|
||||
},
|
||||
async created() {
|
||||
this.isLoading = true; // moubeted 才停止 loading
|
||||
@@ -944,7 +1287,7 @@ export default {
|
||||
this.compareDashboardData.time.avg_cycle_efficiency, this.contentData.avgCycleEfficiency, "Cycle Eff");
|
||||
[this.avgProcessTimeData, this.avgProcessTimeOptions] = this.getLineChart(
|
||||
this.compareDashboardData.time.avg_process_time, this.contentData.avgProcessTime, 'date');
|
||||
[this.avgProcessTimeByTaskData, this.avgProcessTimeByTaskOptions] = this.getHorizontalBarChart(
|
||||
[this.avgProcessTimeByTaskData, this.avgProcessTimeByTaskOptions] = this.getAvgProcessTimeHorizontalBarChart(
|
||||
this.compareDashboardData.time.avg_process_time_by_task,
|
||||
this.contentData.avgProcessTimeByTask, true, 'date');
|
||||
[this.avgWaitingTimeData, this.avgWaitingTimeOptions] = this.getLineChart(
|
||||
@@ -958,7 +1301,7 @@ export default {
|
||||
}
|
||||
[this.freqData, this.freqOptions] = this.getLineChart(
|
||||
this.compareDashboardData.freq.cases, this.contentData.freq, 'count');
|
||||
[this.casesByTaskData, this.casesByTaskOptions] = this.getHorizontalBarChart(
|
||||
[this.casesByTaskData, this.casesByTaskOptions] = this.getCaseByTaskHorizontalBarChart(
|
||||
this.compareDashboardData.freq.cases_by_task, this.contentData.casesByTask, true, 'count');
|
||||
},
|
||||
mounted() {
|
||||
|
||||
Reference in New Issue
Block a user