(function () {
|
"use strict";
|
|
function nowDate() {
|
return new Date();
|
}
|
|
function startOfToday() {
|
var date = new Date();
|
date.setHours(0, 0, 0, 0);
|
return date;
|
}
|
|
function createDefaultFilters() {
|
return {
|
mode: "TASK",
|
keyword: "",
|
ioType: "",
|
finalWrkSts: "",
|
sourceStaNo: "",
|
staNo: "",
|
deviceType: "",
|
timeField: "finish_time",
|
timeRange: [startOfToday(), nowDate()]
|
};
|
}
|
|
function createEmptyAnalysis() {
|
return {
|
summary: {
|
taskCount: 0,
|
avgTotalDurationMs: null,
|
avgStationDurationMs: null,
|
avgCraneDurationMs: null,
|
faultTaskCount: 0,
|
faultDurationMs: 0,
|
partialTaskCount: 0
|
},
|
durationCompare: [],
|
trend: [],
|
faultPie: [],
|
faultDuration: [],
|
detail: []
|
};
|
}
|
|
new Vue({
|
el: "#app",
|
data: function () {
|
return {
|
options: {
|
ioTypes: [],
|
statuses: [],
|
stations: [],
|
deviceTypes: [],
|
timeFields: []
|
},
|
filters: createDefaultFilters(),
|
tableData: [],
|
currentPage: 1,
|
pageSize: 20,
|
pageTotal: 0,
|
listLoading: false,
|
analyzeLoading: false,
|
selectedWrkNoMap: {},
|
analysis: createEmptyAnalysis(),
|
analysisReady: false,
|
charts: {
|
duration: null,
|
trend: null,
|
faultPie: null,
|
faultDuration: null
|
},
|
resizeHandler: null
|
};
|
},
|
computed: {
|
selectedWrkNos: function () {
|
return Object.keys(this.selectedWrkNoMap).map(function (key) {
|
return Number(key);
|
}).filter(function (value) {
|
return !!value;
|
});
|
}
|
},
|
mounted: function () {
|
var self = this;
|
this.loadOptions();
|
this.loadList();
|
this.resizeHandler = function () {
|
self.resizeCharts();
|
};
|
window.addEventListener("resize", this.resizeHandler);
|
},
|
beforeDestroy: function () {
|
if (this.resizeHandler) {
|
window.removeEventListener("resize", this.resizeHandler);
|
}
|
this.disposeCharts();
|
},
|
methods: {
|
loadOptions: function () {
|
var self = this;
|
$.ajax({
|
url: baseUrl + "/wrkAnalysis/options/auth",
|
headers: { token: localStorage.getItem("token") },
|
method: "GET",
|
success: function (res) {
|
if (res && res.code === 200) {
|
self.options = Object.assign(self.options, res.data || {});
|
return;
|
}
|
self.$message.error((res && res.msg) || "分析选项加载失败");
|
},
|
error: function () {
|
self.$message.error("分析选项加载失败");
|
}
|
});
|
},
|
buildListParams: function () {
|
var params = {
|
curr: this.currentPage,
|
limit: this.pageSize,
|
keyword: this.filters.keyword,
|
ioType: this.filters.ioType,
|
finalWrkSts: this.filters.finalWrkSts,
|
sourceStaNo: this.filters.sourceStaNo,
|
staNo: this.filters.staNo,
|
deviceType: this.filters.deviceType
|
};
|
if (this.filters.timeRange && this.filters.timeRange.length === 2) {
|
if (this.filters.timeField === "appe_time") {
|
params.appeTimeRange = this.formatRange(this.filters.timeRange);
|
} else {
|
params.finishTimeRange = this.formatRange(this.filters.timeRange);
|
}
|
}
|
return this.cleanParams(params);
|
},
|
loadList: function () {
|
var self = this;
|
this.listLoading = true;
|
$.ajax({
|
url: baseUrl + "/wrkAnalysis/list/auth",
|
headers: { token: localStorage.getItem("token") },
|
method: "GET",
|
data: self.buildListParams(),
|
success: function (res) {
|
if (res && res.code === 200) {
|
var data = res.data || {};
|
self.tableData = data.records || [];
|
self.pageTotal = data.total || 0;
|
self.$nextTick(function () {
|
self.restoreSelection();
|
});
|
return;
|
}
|
self.$message.error((res && res.msg) || "历史任务加载失败");
|
},
|
error: function () {
|
self.$message.error("历史任务加载失败");
|
},
|
complete: function () {
|
self.listLoading = false;
|
}
|
});
|
},
|
handleSearch: function () {
|
this.currentPage = 1;
|
this.loadList();
|
},
|
handleReset: function () {
|
this.filters = createDefaultFilters();
|
this.currentPage = 1;
|
this.pageSize = 20;
|
this.selectedWrkNoMap = {};
|
this.analysis = createEmptyAnalysis();
|
this.analysisReady = false;
|
this.disposeCharts();
|
this.loadList();
|
},
|
handleSizeChange: function (size) {
|
this.pageSize = size;
|
this.currentPage = 1;
|
this.loadList();
|
},
|
handleCurrentChange: function (page) {
|
this.currentPage = page;
|
this.loadList();
|
},
|
restoreSelection: function () {
|
var table = this.$refs.historyTable;
|
var self = this;
|
if (!table) {
|
return;
|
}
|
table.clearSelection();
|
(this.tableData || []).forEach(function (row) {
|
if (self.selectedWrkNoMap[row.wrkNo]) {
|
table.toggleRowSelection(row, true);
|
}
|
});
|
},
|
syncCurrentPageSelection: function (selection) {
|
var selectedMap = {};
|
(selection || []).forEach(function (row) {
|
selectedMap[row.wrkNo] = true;
|
});
|
(this.tableData || []).forEach(function (row) {
|
delete this.selectedWrkNoMap[row.wrkNo];
|
}, this);
|
Object.keys(selectedMap).forEach(function (key) {
|
this.selectedWrkNoMap[key] = true;
|
}, this);
|
},
|
runAnalysis: function () {
|
var self = this;
|
var request = {
|
mode: this.filters.mode,
|
ioType: this.filters.ioType,
|
finalWrkSts: this.filters.finalWrkSts,
|
sourceStaNo: this.filters.sourceStaNo,
|
staNo: this.filters.staNo,
|
deviceType: this.filters.deviceType
|
};
|
if (this.filters.mode === "TASK") {
|
if (!this.selectedWrkNos.length) {
|
this.$message.warning("请先勾选要分析的任务");
|
return;
|
}
|
request.wrkNos = this.selectedWrkNos;
|
request.timeField = this.filters.timeField;
|
} else {
|
if (!this.filters.timeRange || this.filters.timeRange.length !== 2) {
|
this.$message.warning("请先选择分析时间范围");
|
return;
|
}
|
request.timeField = this.filters.timeField;
|
request.startTime = this.filters.timeRange[0].getTime();
|
request.endTime = this.filters.timeRange[1].getTime();
|
}
|
this.analyzeLoading = true;
|
$.ajax({
|
url: baseUrl + "/wrkAnalysis/analyze/auth",
|
headers: {
|
token: localStorage.getItem("token"),
|
"Content-Type": "application/json"
|
},
|
method: "POST",
|
data: JSON.stringify(this.cleanParams(request)),
|
success: function (res) {
|
if (res && res.code === 200) {
|
self.analysis = Object.assign(createEmptyAnalysis(), res.data || {});
|
self.analysisReady = true;
|
self.$nextTick(function () {
|
self.updateCharts();
|
});
|
return;
|
}
|
self.$message.error((res && res.msg) || "分析失败");
|
},
|
error: function () {
|
self.$message.error("分析失败");
|
},
|
complete: function () {
|
self.analyzeLoading = false;
|
}
|
});
|
},
|
updateCharts: function () {
|
if (!this.analysisReady) {
|
this.disposeCharts();
|
return;
|
}
|
this.ensureCharts();
|
this.renderDurationChart();
|
this.renderTrendChart();
|
this.renderFaultPieChart();
|
this.renderFaultDurationChart();
|
},
|
ensureCharts: function () {
|
if (this.$refs.durationChart && !this.charts.duration) {
|
this.charts.duration = echarts.init(this.$refs.durationChart);
|
}
|
if (this.$refs.trendChart && !this.charts.trend) {
|
this.charts.trend = echarts.init(this.$refs.trendChart);
|
}
|
if (this.$refs.faultPieChart && !this.charts.faultPie) {
|
this.charts.faultPie = echarts.init(this.$refs.faultPieChart);
|
}
|
if (this.$refs.faultDurationChart && !this.charts.faultDuration) {
|
this.charts.faultDuration = echarts.init(this.$refs.faultDurationChart);
|
}
|
},
|
renderDurationChart: function () {
|
if (!this.charts.duration) {
|
return;
|
}
|
var rows = this.analysis.durationCompare || [];
|
this.charts.duration.setOption({
|
tooltip: { trigger: "axis" },
|
legend: { data: ["站点耗时", "堆垛机耗时", "总耗时"] },
|
grid: { left: 50, right: 20, top: 40, bottom: 70 },
|
xAxis: {
|
type: "category",
|
data: rows.map(function (item) { return String(item.wrkNo); }),
|
axisLabel: { rotate: rows.length > 8 ? 30 : 0 }
|
},
|
yAxis: {
|
type: "value",
|
axisLabel: {
|
formatter: function (value) {
|
return Math.round((value || 0) / 1000) + "s";
|
}
|
}
|
},
|
series: [
|
{ name: "站点耗时", type: "bar", barMaxWidth: 28, data: rows.map(function (item) { return item.stationDurationMs || 0; }) },
|
{ name: "堆垛机耗时", type: "bar", barMaxWidth: 28, data: rows.map(function (item) { return item.craneDurationMs || 0; }) },
|
{ name: "总耗时", type: "bar", barMaxWidth: 28, data: rows.map(function (item) { return item.totalDurationMs || 0; }) }
|
]
|
}, true);
|
},
|
renderTrendChart: function () {
|
if (!this.charts.trend) {
|
return;
|
}
|
var rows = this.analysis.trend || [];
|
this.charts.trend.setOption({
|
tooltip: { trigger: "axis" },
|
legend: { data: ["平均总耗时", "平均站点耗时", "平均堆垛机耗时"] },
|
grid: { left: 50, right: 20, top: 40, bottom: 70 },
|
xAxis: {
|
type: "category",
|
data: rows.map(function (item) { return item.bucketLabel; }),
|
axisLabel: { rotate: rows.length > 8 ? 25 : 0 }
|
},
|
yAxis: {
|
type: "value",
|
axisLabel: {
|
formatter: function (value) {
|
return Math.round((value || 0) / 1000) + "s";
|
}
|
}
|
},
|
series: [
|
{ name: "平均总耗时", type: "line", smooth: true, data: rows.map(function (item) { return item.avgTotalDurationMs || 0; }) },
|
{ name: "平均站点耗时", type: "line", smooth: true, data: rows.map(function (item) { return item.avgStationDurationMs || 0; }) },
|
{ name: "平均堆垛机耗时", type: "line", smooth: true, data: rows.map(function (item) { return item.avgCraneDurationMs || 0; }) }
|
]
|
}, true);
|
},
|
renderFaultPieChart: function () {
|
if (!this.charts.faultPie) {
|
return;
|
}
|
this.charts.faultPie.setOption({
|
tooltip: { trigger: "item" },
|
legend: { bottom: 0 },
|
series: [{
|
type: "pie",
|
radius: ["42%", "68%"],
|
center: ["50%", "46%"],
|
label: { formatter: "{b}\n{d}%" },
|
data: this.analysis.faultPie || []
|
}]
|
}, true);
|
},
|
renderFaultDurationChart: function () {
|
if (!this.charts.faultDuration) {
|
return;
|
}
|
var rows = this.analysis.faultDuration || [];
|
this.charts.faultDuration.setOption({
|
tooltip: { trigger: "axis" },
|
grid: { left: 50, right: 20, top: 20, bottom: 40 },
|
xAxis: {
|
type: "category",
|
data: rows.map(function (item) { return item.name; })
|
},
|
yAxis: {
|
type: "value",
|
axisLabel: {
|
formatter: function (value) {
|
return Math.round((value || 0) / 1000) + "s";
|
}
|
}
|
},
|
series: [{
|
name: "故障耗时",
|
type: "bar",
|
barMaxWidth: 36,
|
data: rows.map(function (item) { return item.value || 0; })
|
}]
|
}, true);
|
},
|
resizeCharts: function () {
|
Object.keys(this.charts).forEach(function (key) {
|
if (this.charts[key]) {
|
this.charts[key].resize();
|
}
|
}, this);
|
},
|
disposeCharts: function () {
|
Object.keys(this.charts).forEach(function (key) {
|
if (this.charts[key]) {
|
this.charts[key].dispose();
|
this.charts[key] = null;
|
}
|
}, this);
|
},
|
formatRange: function (range) {
|
return this.formatDateTime(range[0]) + " ~ " + this.formatDateTime(range[1]);
|
},
|
formatDateTime: function (date) {
|
if (!date) {
|
return "";
|
}
|
var year = date.getFullYear();
|
var month = this.pad(date.getMonth() + 1);
|
var day = this.pad(date.getDate());
|
var hour = this.pad(date.getHours());
|
var minute = this.pad(date.getMinutes());
|
var second = this.pad(date.getSeconds());
|
return year + "-" + month + "-" + day + " " + hour + ":" + minute + ":" + second;
|
},
|
pad: function (value) {
|
return value < 10 ? "0" + value : String(value);
|
},
|
cleanParams: function (params) {
|
var result = {};
|
Object.keys(params || {}).forEach(function (key) {
|
var value = params[key];
|
if (value === "" || value === null || value === undefined) {
|
return;
|
}
|
if (Array.isArray(value) && !value.length) {
|
return;
|
}
|
result[key] = value;
|
});
|
return result;
|
},
|
formatNumber: function (value) {
|
var num = Number(value || 0);
|
if (!isFinite(num)) {
|
return "0";
|
}
|
return num.toLocaleString("zh-CN");
|
},
|
formatDuration: function (value) {
|
if (value === null || value === undefined || value === "") {
|
return "--";
|
}
|
var ms = Number(value);
|
if (!isFinite(ms)) {
|
return "--";
|
}
|
if (ms < 1000) {
|
return Math.round(ms) + " ms";
|
}
|
var totalSeconds = Math.floor(ms / 1000);
|
var hours = Math.floor(totalSeconds / 3600);
|
var minutes = Math.floor((totalSeconds % 3600) / 60);
|
var seconds = totalSeconds % 60;
|
if (hours > 0) {
|
return hours + "h " + this.pad(minutes) + "m " + this.pad(seconds) + "s";
|
}
|
if (minutes > 0) {
|
return minutes + "m " + this.pad(seconds) + "s";
|
}
|
return seconds + "s";
|
}
|
}
|
});
|
|
})();
|