528 lines
11 KiB
Vue
528 lines
11 KiB
Vue
<!--
|
|
filename: index.vue
|
|
author: liubin
|
|
date: 2023-09-04 09:34:52
|
|
description: 设备产量时序图
|
|
-->
|
|
|
|
<template>
|
|
<div
|
|
class="production-timegraph-container"
|
|
style="background: #f2f4f9; flex: 1; display: flex; flex-direction: column">
|
|
<el-row
|
|
class=""
|
|
style="
|
|
margin-bottom: 12px;
|
|
background: #fff;
|
|
padding: 16px 16px 0;
|
|
border-radius: 8px;
|
|
">
|
|
<div class="blue-title">生产节拍时序图</div>
|
|
<!-- <h1>设备状态时序图</h1> -->
|
|
<!-- 搜索工作栏 -->
|
|
<SearchBar
|
|
:formConfigs="searchBarFormConfig"
|
|
ref="search-bar"
|
|
:remove-blue="true"
|
|
@select-changed="handleSearchBarChanged"
|
|
@headBtnClick="handleSearchBarBtnClick" />
|
|
</el-row>
|
|
|
|
<el-row
|
|
class=""
|
|
style="
|
|
flex: 1;
|
|
display: flex;
|
|
flex-direction: column;
|
|
margin-bottom: 12px;
|
|
background: #fff;
|
|
padding: 16px 16px 24px;
|
|
border-radius: 8px;
|
|
">
|
|
<div class="blue-title">设备产量时序图</div>
|
|
|
|
<div class="main-area" style="flex: 1">
|
|
<div class="graphs" v-if="graphList.length">
|
|
<LineChart :config="templateConfig" />
|
|
</div>
|
|
<div class="no-data-bg" v-else></div>
|
|
</div>
|
|
</el-row>
|
|
|
|
<!-- 对话框(添加 / 修改) -->
|
|
<base-dialog
|
|
dialogTitle="添加设备"
|
|
:dialogVisible="open"
|
|
width="500px"
|
|
@close="open = false"
|
|
@cancel="open = false"
|
|
@confirm="submitForm">
|
|
<el-select
|
|
v-if="open"
|
|
style="width: 100%"
|
|
v-model="queryParams.equipmentId"
|
|
placeholder="请选择一个设备">
|
|
<el-option
|
|
v-for="eq in eqList"
|
|
:key="eq.id"
|
|
:value="eq.id"
|
|
:label="eq.name"></el-option>
|
|
</el-select>
|
|
</base-dialog>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import LineChart from './components/lineChart.vue';
|
|
// import response from './response.json';
|
|
|
|
export default {
|
|
name: 'SGProduction',
|
|
components: { LineChart },
|
|
props: {},
|
|
data() {
|
|
return {
|
|
startTime: null, // new Date(2023, 8, 26, 0, 0, 0, 0).getTime(),
|
|
accumulators: new Map(),
|
|
searchBarFormConfig: [
|
|
{
|
|
type: 'select',
|
|
label: '产线',
|
|
placeholder: '请选择产线',
|
|
selectOptions: [],
|
|
param: 'lineId',
|
|
onchange: true,
|
|
},
|
|
{
|
|
type: 'select',
|
|
label: '工段',
|
|
placeholder: '请选择工段',
|
|
selectOptions: [],
|
|
param: 'sectionId',
|
|
},
|
|
// 时间段
|
|
{
|
|
type: 'datePicker',
|
|
label: '时间段',
|
|
dateType: 'date', // datetimerange
|
|
// format: 'yyyy-MM-dd HH:mm:ss',
|
|
format: 'yyyy-MM-dd',
|
|
valueFormat: 'yyyy-MM-dd HH:mm:ss',
|
|
// valueFormat: 'timestamp',
|
|
// rangeSeparator: '-',
|
|
// startPlaceholder: '开始日期',
|
|
// endPlaceholder: '结束日期',
|
|
// defaultTime: ['00:00:00', '23:59:59'],
|
|
placeholder: '选择日期',
|
|
param: 'recordTime',
|
|
required: true,
|
|
},
|
|
{
|
|
type: 'button',
|
|
btnName: '查询',
|
|
name: 'search',
|
|
color: 'primary',
|
|
},
|
|
{
|
|
type: 'separate',
|
|
},
|
|
{
|
|
type: 'button',
|
|
btnName: '添加对比',
|
|
name: 'compare',
|
|
color: 'primary',
|
|
plain: true,
|
|
},
|
|
],
|
|
queryParams: {
|
|
lineId: null,
|
|
sectionId: null,
|
|
equipmentId: null,
|
|
recordTime: [],
|
|
},
|
|
open: false,
|
|
eqList: [],
|
|
graphList: [],
|
|
templateConfig: {
|
|
color: [
|
|
'#283D68',
|
|
'#FFB61F',
|
|
'#4481FF',
|
|
'#5AD8A6',
|
|
'#E97466',
|
|
'#ccc', //<=== 需按情况更新
|
|
'#ccc',
|
|
'#ccc',
|
|
'#ccc',
|
|
'#ccc',
|
|
],
|
|
grid: {
|
|
top: 48,
|
|
left: 48,
|
|
right: 24,
|
|
bottom: 24,
|
|
},
|
|
legend: {
|
|
top: 0,
|
|
right: 12,
|
|
padding: 6,
|
|
itemWidth: 16,
|
|
itemHeight: 8,
|
|
itemGap: 20,
|
|
textStyle: {
|
|
fontSize: 12,
|
|
lineHeight: 12,
|
|
color: '#0007',
|
|
},
|
|
},
|
|
tooltip: {
|
|
show: true,
|
|
trigger: 'axis',
|
|
formatter: function (params) {
|
|
return `
|
|
<div style="margin-bottom: 8px;">${new Date(
|
|
+params[0].name
|
|
).toLocaleTimeString()}</div>
|
|
${params
|
|
.map(({ seriesName, color, data }) =>
|
|
data != null
|
|
? `
|
|
<div style="min-width: 160px; display: flex; justify-content: space-between; align-items: center;">
|
|
<span style="display: flex; align-items: center;">
|
|
<span style="display: inline-block; margin-right: 8px; width: 12px; height: 12px; background: ${color}"></span>
|
|
<span style="">${seriesName}</span>
|
|
</span>
|
|
<span style="color: #c7c7c7; text-align: right;">${data}</span>
|
|
</div>
|
|
`
|
|
: ''
|
|
)
|
|
.join('')}
|
|
`;
|
|
},
|
|
},
|
|
xAxis: null,
|
|
yAxis: {
|
|
type: 'value',
|
|
name: '产量',
|
|
nameLocation: 'end',
|
|
nameTextStyle: {
|
|
fontSize: 14,
|
|
align: 'center',
|
|
},
|
|
axisLine: {
|
|
show: true,
|
|
},
|
|
max: function (value) {
|
|
return value.max + Math.ceil(value.max / 4);
|
|
// return value.max + 50
|
|
},
|
|
},
|
|
series: [
|
|
// {
|
|
// name: '产线1',
|
|
// data: Array(24)
|
|
// .fill(1)
|
|
// .map(() => Math.random() * 100),
|
|
// type: 'line',
|
|
// symbol: 'circle',
|
|
// // smooth: true,
|
|
// },
|
|
// {
|
|
// name: '产线2',
|
|
// data: Array(24)
|
|
// .fill(1)
|
|
// .map(() => Math.random() * 100),
|
|
// type: 'line',
|
|
// symbol: 'circle',
|
|
// // smooth: true,
|
|
// },
|
|
// {
|
|
// name: '产线3',
|
|
// data: Array(24)
|
|
// .fill(1)
|
|
// .map(() => Math.random() * 100),
|
|
// type: 'line',
|
|
// symbol: 'circle',
|
|
// // smooth: true,
|
|
// },
|
|
],
|
|
},
|
|
};
|
|
},
|
|
computed: {
|
|
timeArr() {
|
|
return Array(24)
|
|
.fill(this.startTime)
|
|
.map((time, index) => time + index * 3600000);
|
|
},
|
|
},
|
|
created() {
|
|
this.initProductline();
|
|
this.initWorksection();
|
|
this.initEquipment();
|
|
// this.getList();
|
|
},
|
|
methods: {
|
|
handleSearchBarBtnClick({ btnName, ...payload }) {
|
|
switch (btnName) {
|
|
case 'search':
|
|
if (!payload.recordTime || payload.recordTime.length <= 0) {
|
|
this.$message.error('请选择时间段');
|
|
return;
|
|
}
|
|
this.startTime = new Date(payload.recordTime).getTime();
|
|
|
|
this.queryParams.lineId = payload.lineId || null;
|
|
this.queryParams.sectionId = payload.sectionId || null;
|
|
this.queryParams.equipmentId = payload.equipmentId || null;
|
|
this.queryParams.recordTime = payload.recordTime
|
|
? [
|
|
payload.recordTime,
|
|
payload.recordTime.replace('00:00:00', '23:59:59'),
|
|
]
|
|
: null;
|
|
this.getList();
|
|
break;
|
|
case 'compare':
|
|
this.open = true;
|
|
break;
|
|
}
|
|
},
|
|
|
|
handleSearchBarChanged({ param, value }) {
|
|
if (!value) {
|
|
this.searchBarFormConfig[1].selectOptions = [];
|
|
return;
|
|
}
|
|
switch (param) {
|
|
case 'lineId':
|
|
this.getWorksectionById(value);
|
|
break;
|
|
}
|
|
},
|
|
|
|
/** 重置查询条件 */
|
|
initQuery() {
|
|
this.queryParams.lineId = null;
|
|
this.queryParams.sectionId = null;
|
|
this.queryParams.equipmentId = null;
|
|
this.queryParams.recordTime = [];
|
|
},
|
|
|
|
/** 对象到数组的转换 */
|
|
objectToArray(obj) {
|
|
return Object.keys(obj).map((key) => {
|
|
obj[key].sort((a, b) => a.startTime - b.startTime);
|
|
obj[key].key = key;
|
|
return obj[key];
|
|
});
|
|
},
|
|
|
|
initState() {
|
|
this.accumulators = new Map();
|
|
this.templateConfig.series = [];
|
|
},
|
|
|
|
async getList() {
|
|
this.initState();
|
|
|
|
const { code, data } = await this.$axios({
|
|
url: '/analysis/equipment-analysis/quantity',
|
|
method: 'get',
|
|
params: this.queryParams,
|
|
});
|
|
|
|
// const { code, data } = response;
|
|
if (code == 0) {
|
|
this.graphList = this.objectToArray(data);
|
|
this.setXaxis();
|
|
this.graphList.forEach(this.setSeries);
|
|
} else {
|
|
this.graphList = [];
|
|
}
|
|
},
|
|
|
|
setXaxis() {
|
|
const xaxis = {
|
|
type: 'category',
|
|
// interval: 12,
|
|
axisTick: {
|
|
alignWithLabel: true,
|
|
lineStyle: {
|
|
color: '#0003',
|
|
},
|
|
},
|
|
axisLabel: {
|
|
formatter: function (value, index) {
|
|
return new Date(+value)
|
|
.toLocaleTimeString()
|
|
.split(':')
|
|
.slice(0, 2)
|
|
.join(':');
|
|
},
|
|
},
|
|
data: this.timeArr,
|
|
};
|
|
this.templateConfig.xAxis = xaxis;
|
|
},
|
|
|
|
setYaxis() {},
|
|
|
|
setSeries(list) {
|
|
const data = Array(24).fill(null);
|
|
list.map((item, index) => {
|
|
const idx = this.timeArr.indexOf(item.startTime);
|
|
if (idx != -1) {
|
|
data[idx] = item.totalQuantity;
|
|
}
|
|
});
|
|
const seriesItem = {
|
|
name: list.key,
|
|
type: 'line',
|
|
symbol: 'circle',
|
|
data,
|
|
};
|
|
this.templateConfig.series.push(seriesItem);
|
|
},
|
|
|
|
setSeriesOld(eqArr) {
|
|
if (eqArr.length == 0) {
|
|
this.templateConfig.series = [];
|
|
return;
|
|
}
|
|
|
|
let isInit = false;
|
|
if (this.accumulators.has(eqArr.key) == false) {
|
|
this.accumulators.set(eqArr.key, 0);
|
|
isInit = true;
|
|
}
|
|
|
|
let accumulator = this.accumulators.get(eqArr.key);
|
|
if ((accumulator && !isInit) || (accumulator == 0 && isInit == false)) {
|
|
accumulator++;
|
|
this.accumulators.set(eqArr.key, accumulator);
|
|
}
|
|
|
|
this.templateConfig.series.push({
|
|
name: eqArr.key + (accumulator == 0 ? '' : '-' + accumulator),
|
|
// name: Math.random(),
|
|
type: 'line',
|
|
symbol: 'circle',
|
|
data: this.getEquipmentQuantity(eqArr),
|
|
});
|
|
},
|
|
|
|
/** 准备设备数据 */
|
|
async initEquipment() {
|
|
const { code, data } = await this.$axios({
|
|
url: '/base/core-equipment/listAll',
|
|
method: 'get',
|
|
});
|
|
if (code == 0) {
|
|
this.eqList = data.map((item) => {
|
|
return {
|
|
name: item.name,
|
|
id: item.id,
|
|
};
|
|
});
|
|
}
|
|
},
|
|
|
|
/** 准备产线数据 */
|
|
async initProductline() {
|
|
const { code, data } = await this.$axios({
|
|
url: '/base/production-line/listAll',
|
|
method: 'get',
|
|
});
|
|
if (code == 0) {
|
|
this.searchBarFormConfig[0].selectOptions = data.map((item) => {
|
|
return {
|
|
name: item.name,
|
|
id: item.id,
|
|
};
|
|
});
|
|
}
|
|
},
|
|
|
|
/** 准备工段数据 */
|
|
async initWorksection() {
|
|
const { code, data } = await this.$axios({
|
|
url: '/base/workshop-section/listAll',
|
|
method: 'get',
|
|
});
|
|
if (code == 0) {
|
|
this.searchBarFormConfig[1].selectOptions = data.map((item) => {
|
|
return {
|
|
name: item.name,
|
|
id: item.id,
|
|
};
|
|
});
|
|
}
|
|
},
|
|
|
|
/** 根据产线获取工段 */
|
|
async getWorksectionById(lineId) {
|
|
const { code, data } = await this.$axios({
|
|
url: '/base/workshop-section/listByParentId',
|
|
method: 'get',
|
|
params: {
|
|
id: lineId,
|
|
},
|
|
});
|
|
if (code == 0) {
|
|
this.searchBarFormConfig[1].selectOptions = data.map((item) => {
|
|
return {
|
|
name: item.name,
|
|
id: item.id,
|
|
};
|
|
});
|
|
}
|
|
},
|
|
|
|
async submitForm() {
|
|
const { code, data } = await this.$axios({
|
|
url: '/analysis/equipment-analysis/quantity',
|
|
method: 'get',
|
|
params: this.queryParams,
|
|
});
|
|
|
|
this.queryParams.equipmentId = null; // 清空一下
|
|
if (code == 0) {
|
|
const newEqlist = this.objectToArray(data);
|
|
if (!newEqlist || newEqlist.length == 0) {
|
|
this.$message.error('该设备没有产量数据');
|
|
return;
|
|
}
|
|
this.graphList.push(...newEqlist);
|
|
newEqlist.forEach(this.setSeries);
|
|
}
|
|
this.open = false;
|
|
},
|
|
},
|
|
};
|
|
</script>
|
|
|
|
<style scoped lang="scss">
|
|
.blue-title {
|
|
position: relative;
|
|
padding: 4px 0;
|
|
padding-left: 12px;
|
|
font-size: 14px;
|
|
color: #606266;
|
|
font-weight: 700;
|
|
margin-bottom: 12px;
|
|
|
|
&::before {
|
|
content: '';
|
|
position: absolute;
|
|
left: 0;
|
|
top: 6px;
|
|
height: 16px;
|
|
width: 4px;
|
|
border-radius: 1px;
|
|
background: #0b58ff;
|
|
}
|
|
}
|
|
</style>
|