mt-yd-ui/src/views/modules/monitoring/equipmentTimesequence.vue

571 lines
15 KiB
Vue

<template>
<!-- 设备效率分析 -->
<div class="mod-config">
<el-form :inline="true" :model="dataForm" @keyup.enter.native="getDataList()" class="blueTip" size="small">
<!-- 产线 -->
<el-form-item>
{{ $t('pl.title') }}
</el-form-item>
<el-form-item>
<el-select v-model="dataForm.productlines" :placeholder="$t('pl.title')" @change="handleProductLineChange" clearable>
<el-option v-for="productLine in productLineList" :key="productLine.id" :value="productLine.id"
:label="productLine.name" />
</el-select>
</el-form-item>
<!-- 工序 -->
<el-form-item>
{{ $t('pl.process') }}
</el-form-item>
<el-form-item>
<!-- <el-select v-model="dataForm.factoryId" :placeholder="$t('eq.name') + ' / ' + $t('eq.code')" clearable></el-select> -->
<el-select v-model="dataForm.wsId" :placeholder="$t('pl.process')" clearable>
<el-option v-for="ws in wsList" :key="ws.id" :value="ws.id" :label="ws.name" />
</el-select>
</el-form-item>
<!-- 日期选择 -->
<el-form-item>
{{ $t('time') }}
</el-form-item>
<el-form-item>
<el-date-picker key="date-picker" v-model="rawTime" type="date" :placeholder="$t('time')" format="yyyy-MM-dd" />
</el-form-item>
<!-- 按钮 -->
<el-form-item>
<el-button class="buttonColor" @click="getDataList()">{{ $t('search') }}</el-button>
<!-- <el-button v-if="$hasPermission('monitoring:equipmentEffiency:save')" type="primary" @click="addOrUpdateHandle()">{{ $t('add') }}</el-button> -->
</el-form-item>
<el-form-item>
<el-button type="success" @click="addEq()">{{ $t('pl.add') }}</el-button>
</el-form-item>
</el-form>
<div class="time-chart" style="margin-top: 10px;">
<div v-show="equipmentCount > 0" id="time-chart__inner" ref="time-chart__inner" class="time-chart__inner"
style="min-height: 50vh;" :style="{ height: autoHeight + 'px', width: '100%' }" />
<div v-show="equipmentCount === 0">{{ $t('pl.queryFirst') }}</div>
<!-- <div v-show="equipmentCount === 0">{{ $t('module.basicData.visual.hints.searchFirst') }}</div> -->
</div>
<el-dialog :visible.sync="dialogVisible" :title="$t('pl.add')" width="30%">
<el-select v-model="eqId" style="width: 100%" :placeholder="$t('pl.choose')" clearable>
<el-option v-for="eq in dialogEqList" :key="eq.id" :label="eq.name" :value="eq.id" />
</el-select>
<div slot="footer">
<el-button @click="dialogVisible = false">{{ $t('pl.cancel') }}</el-button>
<el-button type="primary" @click="dialogConfirm">{{ $t('pl.confirm') }}</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import * as echarts from 'echarts'
import i18n from '@/i18n'
import BaseTable from '@/components/base-table'
import { calcMaxHeight } from '@/utils'
import moment from 'moment'
// import TableOperateComponent from '@/components/base-table/components/operationComponent'
// import TableTextComponent from '@/components/base-table/components/detailComponent'
// import { timeFilter } from '@/utils/filters'
function renderItem(params, api) {
var categoryIndex = api.value(0)
var start = api.coord([api.value(1), categoryIndex])
var end = api.coord([api.value(2), categoryIndex])
var height = 32
return {
type: 'rect',
shape: echarts.graphic.clipRectByRect(
{
x: start[0],
y: start[1] - height / 2,
width: end[0] - start[0],
height: height
},
{
x: params.coordSys.x,
y: params.coordSys.y,
width: params.coordSys.width,
height: params.coordSys.height
}
),
style: api.style()
}
}
class ChartOption {
constructor() {
this.color = ['#4caf50', '#ffb300', '#e53935']
this.legend = {
data: [
// i18n.t('module.basicData.visual.echartLegends.working'),
i18n.t('normal'),
i18n.t('shutdown'),
i18n.t('malfunction')
],
bottom: '0%',
selectedMode: false,
textStyle: {
color: '#000'
}
}
this.tooltip = {
formatter: function (params) {
return moment(params.value[1]).format('YYYY-MM-DD HH:mm:ss') + ' - ' + moment(params.value[2]).format('YYYY-MM-DD HH:mm:ss') + ' : ' + params.name
}
}
this.title = {
// text: i18n.t('module.basicData.visual.echartTitles.eqStatus'),
text: i18n.t('diagram'),
left: 'center'
}
this.xAxis = {
type: 'time',
// min: +new Date().setHours(0, 0, 0, 0),
splitNumber: 24,
interval: 3600 * 1000,
axisTick: {
show: true,
alignWithLabel: true
},
splitLine: {
show: true
},
axisLine: {
show: true
},
axisLabel: {
formatter: function (val) {
const time = new Date(val)
const hour = time.getHours()
const minute = time.getMinutes()
const hours = hour >= 10 ? hour + '' : '0' + hour
const minutes = minute >= 10 ? minute + '' : '0' + minute
return hours + ':' + minutes
}
}
}
this.yAxis = {
// data: Object.keys(eqData).map(item => eqData[item].name)
data: []
}
this.series = [
{ name: /** i18n.t('module.basicData.visual.echartLegends.working') */ i18n.t('normal'), type: 'bar', data: [] },
{ name: i18n.t('shutdown'), type: 'bar', data: [] },
{ name: i18n.t('malfunction'), type: 'bar', data: [] },
{
type: 'custom',
renderItem: renderItem,
itemStyle: {
opacity: 0.8
},
encode: {
x: [1, 2],
y: 0
},
data: []
}
]
}
setTitle(title) {
this.title.text = title
}
// date: 服务器返回来的日期时间数据
setXAxis(date) {
// this.xAxis.min = +new Date(date).setHours(0)
this.xAxis.min = +new Date(date).setHours(0, 0, 0, 0)
this.xAxis.max = this.xAxis.min + 3600 * 1000 * 24
}
setYAxis(data) {
this.yAxis.data = data
}
setData(data) {
this.series[3].data = data
}
}
export default {
data() {
return {
/** hfxny part */
wsList: [],
productLineList: [],
chart: null,
chartOption: new ChartOption(),
equipments: {},
state: [this.$t('normal'),this.$t('shutdown'),this.$t('malfunction')],
colors: ['#4caf50', '#ffb300', '#e53935'],
// queryBuffer: {},
// tableConfigs,
calcMaxHeight,
timeType: 'range',
currentLine: null,
rawTime: new Date(),
dataForm: {
wsId: null,
productlines: null,
startTime: null,
entTime: null
},
dataList: [],
pageIndex: 1,
pageSize: 10,
totalPage: 0,
dataListLoading: false,
/** dialog */
dialogVisible: false,
eqId: null,
dialogEqList: []
}
},
components: {
BaseTable
},
computed: {
autoHeight: function () {
return Object.keys(this.equipments).length * 100 || 500
},
equipmentCount: function () {
return Object.keys(this.equipments).length
}
},
created() {
this.getEqList()
},
mounted() {
this.$nextTick(() => {
this.initChart()
})
},
activated() {
this.getProductLineList().then(() => {
this.getWorksetionList()
})
},
updated() {
if (this.chart) this.chart.resize()
},
watch: {
timeType() {
// 防止切换日期类型时报错
this.rawTime = null
}
},
methods: {
initChart() {
if (!this.chart) {
this.chart = echarts.init(this.$refs['time-chart__inner'])
}
},
// 获取产线列表
getProductLineList() {
return this.$http({
url: this.$http.adornUrl('/monitoring/productionLine/list'),
method: 'get'
}).then(({ data: res }) => {
if (res && res.code === 0) {
this.productLineList = res.data
/** set default */
if (this.productLineList.length) {
this.dataForm.productlines = this.productLineList[0].id
}
} else {
this.productLineList = []
}
})
},
// 获取工序列表
getWorksetionList() {
// 分页列表才有根据产线过滤功能
this.$http({
// url: this.$http.adornUrl('/monitoring/workshopSection/list'),
url: this.$http.adornUrl('/monitoring/workshopSection/page'),
method: 'get',
params: this.$http.adornParams({
limit: 99999,
page: 1,
lineId: this.dataForm.productlines ?? ''
})
}).then(({ data: res }) => {
if (res && res.code === 0) {
this.wsList = res.data.list
/** select 默认选项set default */
// if (this.wsList.length) {
// this.dataForm.wsId = this.wsList[0].id
// } else {
// this.dataForm.wsId = null
// }
} else {
this.wsList.splice(0)
}
})
},
// 把服务器数据按照设备分组
transformDataToEquipments(dataList) {
console.log('transformDataToEquipments() datalist: ', dataList)
const equipments = {}
dataList.map(item => {
if (equipments[item.eqId]) {
// 如果设备已存在
// equipments[item.eqId].name = item.eqName
equipments[item.eqId].status.push({
startTime: +new Date(item.startTime),
endTime: +new Date(item.endTime),
status: this.state[item.status] // 0 正常、1 停机、2 故障
})
} else {
equipments[item.eqId] = {
name: item.eqName,
status: [
{
startTime: +new Date(item.startTime),
endTime: +new Date(item.endTime),
status: this.state[item.status] // 0 正常、1 停机、2 故障
}
]
}
}
})
console.log('created equipments --- ', equipments)
return equipments
},
// 把分组好的设备数据转换为echarts需要的series数据
transformEquipmentsToSeries(equipments) {
const seriesData = []
Object.entries(equipments).map(([key, item], index) => {
item.status.forEach(status => {
seriesData.push({
name: status.status,
value: [index, status.startTime, status.endTime],
itemStyle: {
normal: {
color: status.status === this.$t('normal') ? '#4caf50' : status.status === this.$t('shutdown') ? '#ffb300' : status.status === this.$t('malfunction') ? '#e53935' : null
}
}
})
})
})
return seriesData
},
// 获取数据列表
getDataList() {
let startTime = this.rawTime
? moment(this.rawTime)
.set({ hour: 0, minute: 0, second: 0, millisecond: 0 })
.format('YYYY-MM-DDTHH:mm:ss')
: ''
let endTime = startTime
? moment(startTime)
.add(1, 'd')
.format('YYYY-MM-DDTHH:mm:ss')
: ''
// this.dataListLoading = true
const condition = {
startTime,
endTime,
productlines: [this.dataForm.productlines],
wsId: this.dataForm.wsId
}
/** fetch data */
this.$http({
url: this.$http.adornUrl('/monitoring/eqAnalysis/timeAndStatus'),
method: 'post',
data: condition
}).then(({ data: res }) => {
if (res.code === 500) {
this.dataList.splice(0)
this.equipments = {} // 关闭 echarts 的显示
this.$message.error(res.msg)
} else {
/** handle actual data */
this.dataList = res.data
/** test data */
// this.dataList = [
// {
// eqId: 'eq-001',
// eqName: 'A1预热机',
// startTime: '2022-05-04T00:30:34',
// endTime: '2022-05-04T08:30:34',
// status: 0
// },
// {
// eqId: 'eq-001',
// eqName: 'A1预热机',
// startTime: '2022-05-04T08:30:34',
// endTime: '2022-05-04T09:30:34',
// status: 1
// },
// {
// eqId: 'eq-001',
// eqName: 'A1预热机',
// startTime: '2022-05-04T09:30:34',
// endTime: '2022-05-04T11:30:34',
// status: 2
// },
// {
// eqId: 'eq-001',
// eqName: 'A1预热机',
// startTime: '2022-05-04T11:30:34',
// endTime: '2022-05-04T13:30:34',
// status: 1
// }
// ]
this.equipments = this.transformDataToEquipments(this.dataList)
this.chartOption.setYAxis(Object.keys(this.equipments).map(eId => this.equipments[eId].name))
console.log('(((set x axis))): ', this.dataList[0].startTime)
this.chartOption.setXAxis(this.dataList[0].startTime)
this.chartOption.setData(this.transformEquipmentsToSeries(this.equipments))
this.$nextTick(() => {
this.renderChart()
})
}
})
},
handleProductLineChange(val) {
this.getWorksetionList()
},
// 渲染 echarts
renderChart() {
console.log('>>> chart configs: ', this.chartOption)
this.chart.setOption(this.chartOption)
},
// 获取对话框里的设备列表
getEqList() {
this.$http({
url: this.$http.adornUrl('/monitoring/equipment/page'),
method: 'get',
params: this.$http.adornParams({
page: 1,
limit: 99999
})
}).then(({ data }) => {
if (data && data.code === 0) {
this.dialogEqList = data.data.list
} else {
this.dialogEqList.splice(0)
}
})
},
// 添加设备
addEq() {
if (this.equipmentCount) {
this.dialogVisible = true
} else {
this.$message.warning(this.$t('pl.queryFirst'))
}
},
// 确认添加设备
dialogConfirm() {
let startTime = this.rawTime
? moment(this.rawTime)
.set({ hour: 0, minute: 0, second: 0, millisecond: 0 })
.format('YYYY-MM-DDTHH:mm:ss')
: ''
let endTime = startTime
? moment(startTime)
.add(1, 'd')
.format('YYYY-MM-DDTHH:mm:ss')
: ''
const condition = {
startTime,
endTime,
productlines: [this.dataForm.productlines],
wsId: this.dataForm.wsId,
eqId: this.eqId
}
/** fetch data */
this.$http({
url: this.$http.adornUrl('/monitoring/eqAnalysis/timeAndStatus'),
method: 'post',
data: condition
}).then(({ data: res }) => {
if (res.code === 500) {
this.$message.error(res.msg)
} else {
/** handle new equipment */
const newEqStatusList = res.data
// console.log('添加设备', res)
const newEq = this.transformDataToEquipments(newEqStatusList)
this.$set(this.equipments, Object.keys(newEq)[0], newEq[Object.keys(newEq)[0]])
this.chartOption.setYAxis(Object.keys(this.equipments).map(item => this.equipments[item].name))
this.chartOption.setData(this.transformEquipmentsToSeries(this.equipments))
this.$message.success(this.$t('pl.success'))
this.$nextTick(() => {
this.dialogVisible = false
this.renderChart()
})
}
})
},
// 每页数
sizeChangeHandle(val) {
this.pageSize = val
this.pageIndex = 1
this.getDataList()
},
// 当前页
currentChangeHandle(val) {
this.pageIndex = val
this.getDataList()
},
// 多选
selectionChangeHandle(val) {
this.dataListSelections = val
},
handleOperations({ type, data: id }) {
switch (type) {
case 'view-detail':
return this.addOrUpdateHandle(id, true)
case 'edit':
return this.addOrUpdateHandle(id)
case 'delete':
return this.deleteHandle(id)
}
}
}
}
</script>
<style scoped>
/* .time-chart__inner {
transition: all 300ms ease-out;
} */
.blueTip::before {
display: inline-block;
content: '';
width: 4px;
height: 24px;
background: #0b58ff;
border-radius: 1px;
margin-right: 8px;
margin-top: 4px;
}
.buttonColor {
color: #fff;
background: #0b58ff;
}
</style>