Merge remote-tracking branch 'origin/master'

master
suixy 3 days ago
commit 5d7e8f1ef6

@ -226,7 +226,7 @@ export function repairHoursStatList(query) {
}) })
} }
// 设备 OEE 分析报表 (注塑车间计算版本) // 注塑车间 OEE 分析报表:页面入口沿用设备 OEE 分析,后端按 A/P/Q 计算完整 OEE。
export function deviceOeeAnalysisList(query) { export function deviceOeeAnalysisList(query) {
return request({ return request({
url: '/report/injectionOee/deviceOeeAnalysis', url: '/report/injectionOee/deviceOeeAnalysis',

@ -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>

Loading…
Cancel
Save