|
|
|
@ -35,55 +35,75 @@
|
|
|
|
|
|
|
|
|
|
|
|
<div class="charts-container">
|
|
|
|
<div class="charts-container">
|
|
|
|
<el-card class="chart-card">
|
|
|
|
<el-card class="chart-card">
|
|
|
|
<div slot="header" class="chart-title">设备 OEE 对比 (注塑车间班次计算版)</div>
|
|
|
|
<div slot="header" class="chart-title">每台设备 OEE 对比</div>
|
|
|
|
<div ref="barChart" class="chart-content" />
|
|
|
|
<div ref="barChart" class="chart-content" />
|
|
|
|
</el-card>
|
|
|
|
</el-card>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<el-table v-loading="loading" :data="reportList" style="margin-top: 10px; width: 100%" border>
|
|
|
|
<el-table v-loading="loading" :data="reportList" style="margin-top: 10px; width: 100%" border>
|
|
|
|
<el-table-column label="班次日期" align="center" prop="SHIFT_DATE" width="105" />
|
|
|
|
<el-table-column label="设备编码" align="center" prop="DEVICE_CODE" width="130" />
|
|
|
|
<el-table-column label="班次" align="center" prop="SHIFT_NAME" width="80" />
|
|
|
|
<el-table-column label="设备名称" align="center" prop="DEVICE_NAME" min-width="160" show-overflow-tooltip />
|
|
|
|
<el-table-column label="设备编码" align="center" prop="DEVICE_CODE" width="120" />
|
|
|
|
<el-table-column label="班次" align="center" prop="SHIFT_NAME" width="90" />
|
|
|
|
<el-table-column label="设备名称" align="center" prop="DEVICE_NAME" min-width="120" show-overflow-tooltip />
|
|
|
|
<el-table-column label="OEE" align="center" prop="OEE" width="100">
|
|
|
|
<el-table-column label="利用率(A)" align="center" prop="AVAILABILITY" width="90">
|
|
|
|
|
|
|
|
<template slot-scope="scope">
|
|
|
|
<template slot-scope="scope">
|
|
|
|
<span>{{ formatPercent(scope.row.AVAILABILITY) }}</span>
|
|
|
|
<span class="oee-value">{{ formatPercent(scope.row.OEE) }}</span>
|
|
|
|
</template>
|
|
|
|
</template>
|
|
|
|
</el-table-column>
|
|
|
|
</el-table-column>
|
|
|
|
<el-table-column label="性能(P)" align="center" prop="PERFORMANCE" width="90">
|
|
|
|
<el-table-column label="设备利用率(A)" align="center" prop="AVAILABILITY" width="130">
|
|
|
|
<template slot-scope="scope">
|
|
|
|
<template slot-scope="scope">
|
|
|
|
<span :title="'诊断值: ' + formatPercent(scope.row.DIAGNOSTIC_PERFORMANCE)">{{ formatPercent(scope.row.PERFORMANCE) }}</span>
|
|
|
|
<span class="util util-total">{{ formatPercent(scope.row.AVAILABILITY) }}</span>
|
|
|
|
</template>
|
|
|
|
</template>
|
|
|
|
</el-table-column>
|
|
|
|
</el-table-column>
|
|
|
|
<el-table-column label="良品率(Q)" align="center" prop="QUALITY" width="90">
|
|
|
|
<el-table-column label="性能稼动率(P)" align="center" prop="PERFORMANCE" width="130">
|
|
|
|
|
|
|
|
<template slot-scope="scope">
|
|
|
|
|
|
|
|
<span>{{ formatPercent(scope.row.PERFORMANCE) }}</span>
|
|
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
|
|
<el-table-column label="良品率(Q)" align="center" prop="QUALITY" width="110">
|
|
|
|
<template slot-scope="scope">
|
|
|
|
<template slot-scope="scope">
|
|
|
|
<span>{{ formatPercent(scope.row.QUALITY) }}</span>
|
|
|
|
<span>{{ formatPercent(scope.row.QUALITY) }}</span>
|
|
|
|
</template>
|
|
|
|
</template>
|
|
|
|
</el-table-column>
|
|
|
|
</el-table-column>
|
|
|
|
<el-table-column label="OEE" align="center" prop="OEE" width="90">
|
|
|
|
<el-table-column label="总利用率(A)" align="center" prop="TOTAL_AVAILABILITY" width="130">
|
|
|
|
<template slot-scope="scope">
|
|
|
|
<template slot-scope="scope">
|
|
|
|
<span style="font-weight: bold; color: #409EFF;">{{ formatPercent(scope.row.OEE) }}</span>
|
|
|
|
<span>{{ formatPercent(scope.row.TOTAL_AVAILABILITY) }}</span>
|
|
|
|
</template>
|
|
|
|
</template>
|
|
|
|
</el-table-column>
|
|
|
|
</el-table-column>
|
|
|
|
<el-table-column label="运行时间" align="center" width="100">
|
|
|
|
<el-table-column label="周利用率(A)" align="center" prop="WEEK_AVAILABILITY" width="130">
|
|
|
|
<template slot-scope="scope">
|
|
|
|
<template slot-scope="scope">
|
|
|
|
<span>{{ (scope.row.ACTUAL_RUN_SECONDS / 60).toFixed(1) }} 分钟</span>
|
|
|
|
<span class="util util-week">{{ formatPercent(scope.row.WEEK_AVAILABILITY) }}</span>
|
|
|
|
</template>
|
|
|
|
</template>
|
|
|
|
</el-table-column>
|
|
|
|
</el-table-column>
|
|
|
|
<el-table-column label="计划时间" align="center" width="90">
|
|
|
|
<el-table-column label="本日利用率(A)" align="center" prop="TODAY_AVAILABILITY" width="140">
|
|
|
|
<template slot-scope="scope">
|
|
|
|
<template slot-scope="scope">
|
|
|
|
<span>{{ scope.row.PLANNED_TIME_MINUTES }} 分钟</span>
|
|
|
|
<span class="util util-today">{{ formatPercent(scope.row.TODAY_AVAILABILITY) }}</span>
|
|
|
|
</template>
|
|
|
|
</template>
|
|
|
|
</el-table-column>
|
|
|
|
</el-table-column>
|
|
|
|
<el-table-column label="开模数" align="center" prop="SHOTS" width="80" />
|
|
|
|
<el-table-column label="运行时间(分钟)" align="center" prop="RUN_TIME_MINUTES" width="130">
|
|
|
|
<el-table-column label="模腔数" align="center" prop="CAVITIES" width="70" />
|
|
|
|
|
|
|
|
<el-table-column label="产出数" align="center" prop="OUTPUT_QTY" width="90" />
|
|
|
|
|
|
|
|
<el-table-column label="标准周期" align="center" width="100">
|
|
|
|
|
|
|
|
<template slot-scope="scope">
|
|
|
|
<template slot-scope="scope">
|
|
|
|
<span :title="scope.row.CYCLE_SOURCE">{{ scope.row.STANDARD_CYCLE.toFixed(2) }} 秒</span>
|
|
|
|
<span>{{ formatNumber(scope.row.RUN_TIME_MINUTES, 1) }}</span>
|
|
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
|
|
<el-table-column label="开模次数" align="center" prop="SHOTS" width="110" />
|
|
|
|
|
|
|
|
<el-table-column label="模腔数" align="center" prop="CAVITIES" width="90" />
|
|
|
|
|
|
|
|
<el-table-column label="产出件数" align="center" prop="OUTPUT_QTY" width="110">
|
|
|
|
|
|
|
|
<template slot-scope="scope">
|
|
|
|
|
|
|
|
<span>{{ formatNumber(scope.row.OUTPUT_QTY, 0) }}</span>
|
|
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
|
|
<el-table-column label="标准周期(s)" align="center" prop="STANDARD_CYCLE_SECONDS" width="130">
|
|
|
|
|
|
|
|
<template slot-scope="scope">
|
|
|
|
|
|
|
|
<span :title="scope.row.STANDARD_CYCLE_SOURCE">{{ formatNumber(scope.row.STANDARD_CYCLE_SECONDS, 2) }}</span>
|
|
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
|
|
<el-table-column label="数据说明" align="center" prop="DOWNGRADE_REASON" min-width="220" show-overflow-tooltip>
|
|
|
|
|
|
|
|
<template slot-scope="scope">
|
|
|
|
|
|
|
|
<el-tag v-if="scope.row.DOWNGRADE_REASON" class="notice-tag" type="warning" size="mini">
|
|
|
|
|
|
|
|
{{ scope.row.DOWNGRADE_REASON }}
|
|
|
|
|
|
|
|
</el-tag>
|
|
|
|
|
|
|
|
<span v-else>-</span>
|
|
|
|
</template>
|
|
|
|
</template>
|
|
|
|
</el-table-column>
|
|
|
|
</el-table-column>
|
|
|
|
<el-table-column label="降级说明" align="center" prop="DOWNGRADE_REASON" min-width="150" show-overflow-tooltip />
|
|
|
|
|
|
|
|
</el-table>
|
|
|
|
</el-table>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
</template>
|
|
|
|
@ -118,9 +138,23 @@ export default {
|
|
|
|
mounted() {
|
|
|
|
mounted() {
|
|
|
|
this.$nextTick(() => {
|
|
|
|
this.$nextTick(() => {
|
|
|
|
this.barChart = echarts.init(this.$refs.barChart)
|
|
|
|
this.barChart = echarts.init(this.$refs.barChart)
|
|
|
|
|
|
|
|
this.initBarChart()
|
|
|
|
|
|
|
|
window.addEventListener('resize', this.handleResize)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
|
|
|
beforeDestroy() {
|
|
|
|
|
|
|
|
window.removeEventListener('resize', this.handleResize)
|
|
|
|
|
|
|
|
if (this.barChart) {
|
|
|
|
|
|
|
|
this.barChart.dispose()
|
|
|
|
|
|
|
|
this.barChart = null
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
},
|
|
|
|
methods: {
|
|
|
|
methods: {
|
|
|
|
|
|
|
|
handleResize() {
|
|
|
|
|
|
|
|
if (this.barChart) {
|
|
|
|
|
|
|
|
this.barChart.resize()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
},
|
|
|
|
/** 查询报表数据 */
|
|
|
|
/** 查询报表数据 */
|
|
|
|
getList() {
|
|
|
|
getList() {
|
|
|
|
this.loading = true
|
|
|
|
this.loading = true
|
|
|
|
@ -154,31 +188,36 @@ export default {
|
|
|
|
/** 初始化柱状图 */
|
|
|
|
/** 初始化柱状图 */
|
|
|
|
initBarChart() {
|
|
|
|
initBarChart() {
|
|
|
|
if (!this.barChart) return
|
|
|
|
if (!this.barChart) return
|
|
|
|
// X轴标签包含设备名与班次
|
|
|
|
|
|
|
|
const xData = (this.reportList || []).map(item => {
|
|
|
|
const xData = (this.reportList || []).map(item => item.DEVICE_NAME || item.DEVICE_CODE)
|
|
|
|
const devName = item.DEVICE_NAME || item.DEVICE_CODE
|
|
|
|
const yDataOee = (this.reportList || []).map(item => item.OEE || 0)
|
|
|
|
return `${devName}\n(${item.SHIFT_NAME})`
|
|
|
|
const yDataA = (this.reportList || []).map(item => item.AVAILABILITY || 0)
|
|
|
|
})
|
|
|
|
const yDataP = (this.reportList || []).map(item => item.PERFORMANCE || 0)
|
|
|
|
const yData = (this.reportList || []).map(item => item.OEE || 0)
|
|
|
|
const yDataQ = (this.reportList || []).map(item => item.QUALITY || 0)
|
|
|
|
|
|
|
|
|
|
|
|
const option = {
|
|
|
|
const option = {
|
|
|
|
tooltip: {
|
|
|
|
tooltip: {
|
|
|
|
trigger: 'axis',
|
|
|
|
trigger: 'axis',
|
|
|
|
|
|
|
|
axisPointer: { type: 'shadow' },
|
|
|
|
formatter: params => {
|
|
|
|
formatter: params => {
|
|
|
|
if (!params || !params.length) return ''
|
|
|
|
if (!params || !params.length) return ''
|
|
|
|
const p = params[0]
|
|
|
|
const devName = params[0].name
|
|
|
|
const item = this.reportList[p.dataIndex]
|
|
|
|
let html = `<div style="font-weight: bold; margin-bottom: 5px;">${devName}</div>`
|
|
|
|
if (!item) return `${p.name}<br/>OEE:${this.formatPercent(p.data)}`
|
|
|
|
params.forEach(p => {
|
|
|
|
return `${item.DEVICE_NAME || item.DEVICE_CODE} (${item.SHIFT_DATE} ${item.SHIFT_NAME})<br/>` +
|
|
|
|
html += `${p.marker} ${p.seriesName}:${(p.value * 100).toFixed(2)}%<br/>`
|
|
|
|
`OEE:${this.formatPercent(item.OEE)}<br/>` +
|
|
|
|
})
|
|
|
|
`└ 利用率(A):${this.formatPercent(item.AVAILABILITY)}<br/>` +
|
|
|
|
return html
|
|
|
|
`└ 性能(P):${this.formatPercent(item.PERFORMANCE)} (诊断值: ${this.formatPercent(item.DIAGNOSTIC_PERFORMANCE)})<br/>` +
|
|
|
|
|
|
|
|
`└ 良品率(Q):${this.formatPercent(item.QUALITY)}`
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
|
|
|
legend: {
|
|
|
|
|
|
|
|
data: ['OEE', 'A 设备利用率', 'P 性能稼动率', 'Q 良品率'],
|
|
|
|
|
|
|
|
top: '0%'
|
|
|
|
|
|
|
|
},
|
|
|
|
grid: {
|
|
|
|
grid: {
|
|
|
|
left: '3%',
|
|
|
|
left: '3%',
|
|
|
|
right: '4%',
|
|
|
|
right: '4%',
|
|
|
|
bottom: '10%',
|
|
|
|
bottom: '10%',
|
|
|
|
|
|
|
|
top: '15%',
|
|
|
|
containLabel: true
|
|
|
|
containLabel: true
|
|
|
|
},
|
|
|
|
},
|
|
|
|
xAxis: {
|
|
|
|
xAxis: {
|
|
|
|
@ -191,6 +230,7 @@ export default {
|
|
|
|
},
|
|
|
|
},
|
|
|
|
yAxis: {
|
|
|
|
yAxis: {
|
|
|
|
type: 'value',
|
|
|
|
type: 'value',
|
|
|
|
|
|
|
|
max: 1,
|
|
|
|
axisLabel: {
|
|
|
|
axisLabel: {
|
|
|
|
formatter: value => `${(value * 100).toFixed(0)}%`
|
|
|
|
formatter: value => `${(value * 100).toFixed(0)}%`
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@ -199,11 +239,43 @@ export default {
|
|
|
|
{
|
|
|
|
{
|
|
|
|
name: 'OEE',
|
|
|
|
name: 'OEE',
|
|
|
|
type: 'bar',
|
|
|
|
type: 'bar',
|
|
|
|
data: yData
|
|
|
|
barGap: '15%',
|
|
|
|
|
|
|
|
itemStyle: {
|
|
|
|
|
|
|
|
color: '#2f7ed8',
|
|
|
|
|
|
|
|
borderRadius: [4, 4, 0, 0]
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
data: yDataOee
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
name: 'A 设备利用率',
|
|
|
|
|
|
|
|
type: 'bar',
|
|
|
|
|
|
|
|
itemStyle: {
|
|
|
|
|
|
|
|
color: '#00a889',
|
|
|
|
|
|
|
|
borderRadius: [4, 4, 0, 0]
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
data: yDataA
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
name: 'P 性能稼动率',
|
|
|
|
|
|
|
|
type: 'bar',
|
|
|
|
|
|
|
|
itemStyle: {
|
|
|
|
|
|
|
|
color: '#7b4ee6',
|
|
|
|
|
|
|
|
borderRadius: [4, 4, 0, 0]
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
data: yDataP
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
name: 'Q 良品率',
|
|
|
|
|
|
|
|
type: 'bar',
|
|
|
|
|
|
|
|
itemStyle: {
|
|
|
|
|
|
|
|
color: '#ff9f43',
|
|
|
|
|
|
|
|
borderRadius: [4, 4, 0, 0]
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
data: yDataQ
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
this.barChart.setOption(option)
|
|
|
|
this.barChart.setOption(option, true)
|
|
|
|
},
|
|
|
|
},
|
|
|
|
/** 百分比格式化 */
|
|
|
|
/** 百分比格式化 */
|
|
|
|
formatPercent(val) {
|
|
|
|
formatPercent(val) {
|
|
|
|
@ -211,6 +283,13 @@ export default {
|
|
|
|
const num = Number(val)
|
|
|
|
const num = Number(val)
|
|
|
|
if (isNaN(num)) return '-'
|
|
|
|
if (isNaN(num)) return '-'
|
|
|
|
return (num * 100).toFixed(2) + '%'
|
|
|
|
return (num * 100).toFixed(2) + '%'
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
/** 数值格式化,用于 OEE 业务量字段展示 */
|
|
|
|
|
|
|
|
formatNumber(val, digits) {
|
|
|
|
|
|
|
|
if (val == null || val === undefined) return '-'
|
|
|
|
|
|
|
|
const num = Number(val)
|
|
|
|
|
|
|
|
if (isNaN(num)) return '-'
|
|
|
|
|
|
|
|
return num.toFixed(digits)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@ -230,4 +309,23 @@ export default {
|
|
|
|
font-size: 16px;
|
|
|
|
font-size: 16px;
|
|
|
|
font-weight: bold;
|
|
|
|
font-weight: bold;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
.oee-value {
|
|
|
|
|
|
|
|
color: #2f7ed8;
|
|
|
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
.util {
|
|
|
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
.util-total {
|
|
|
|
|
|
|
|
color: #00a889;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
.util-week {
|
|
|
|
|
|
|
|
color: #7b4ee6;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
.util-today {
|
|
|
|
|
|
|
|
color: #409EFF;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
.notice-tag {
|
|
|
|
|
|
|
|
max-width: 100%;
|
|
|
|
|
|
|
|
}
|
|
|
|
</style>
|
|
|
|
</style>
|
|
|
|
|