Files
klp-oa/klp-ui/src/views/mes/roll/working/index.vue

933 lines
40 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="app-container working-roll-page">
<!-- 顶部行作业辊一览2/3+ 可用轧辊1/3 -->
<div class="top-row">
<!-- 作业辊一览 -->
<el-card shadow="never" class="roll-table-card top-row__main">
<div slot="header" class="card-header">
<span class="card-title"><i class="el-icon-s-grid" /> 作业辊一览</span>
<span class="header-meta" v-if="current['1#'] && current['1#'].changeTime">
1# 末次换辊{{ current['1#'].changeTime }}
</span>
<span class="header-meta" v-if="current['2#'] && current['2#'].changeTime">
&nbsp;·&nbsp;2# 末次换辊{{ current['2#'].changeTime }}
</span>
<span style="margin-left:auto;display:flex;align-items:center;gap:6px;flex-wrap:wrap">
<el-button size="mini" icon="el-icon-refresh-right" @click="handleOpenChange('1#')">1# 换辊</el-button>
<el-button size="mini" icon="el-icon-refresh-right" @click="handleOpenChange('2#')">2# 换辊</el-button>
<el-divider direction="vertical" />
<el-button type="success" size="mini" icon="el-icon-plus" @click="handleAddStandby('1#')">1# 添加下批</el-button>
<el-button type="danger" size="mini" icon="el-icon-delete" @click="handleClearStandby('1#')"
:disabled="!(standbyList['1#'] && standbyList['1#'].length)">1# 清空</el-button>
<el-button type="success" size="mini" icon="el-icon-plus" @click="handleAddStandby('2#')">2# 添加下批</el-button>
<el-button type="danger" size="mini" icon="el-icon-delete" @click="handleClearStandby('2#')"
:disabled="!(standbyList['2#'] && standbyList['2#'].length)">2# 清空</el-button>
</span>
</div>
<el-table
ref="mainTable"
:data="mergedRows"
v-loading="loadingCurrent['1#'] || loadingCurrent['2#'] || loadingStandby['1#'] || loadingStandby['2#']"
:row-class-name="rowClass"
:span-method="mergeParamCol"
border
size="small"
style="width:100%"
>
<el-table-column label="参数" width="126" align="left">
<template slot-scope="scope">
<span :class="['param-label', scope.row.group]">{{ scope.row.label }}</span>
</template>
</el-table-column>
<el-table-column label="当前在机轧辊" align="center">
<el-table-column label="1#" align="center" min-width="88">
<template slot-scope="scope">
<param-cell :data="scope.row.cur1" />
</template>
</el-table-column>
<el-table-column label="2#" align="center" min-width="88">
<template slot-scope="scope">
<param-cell :data="scope.row.cur2" />
</template>
</el-table-column>
</el-table-column>
<el-table-column label="下批轧辊" align="center">
<el-table-column label="1#" align="center" min-width="88">
<template slot-scope="scope">
<div
:class="['sb-cell',
scope.row.sb1 && scope.row.sb1.standbyId ? 'sb-cell--del' :
scope.row.rollType ? 'sb-cell--add' : '']"
@click="handleSbCellClick(scope.row.sb1, '1#', scope.row.rollType, scope.row.position)"
>
<param-cell :data="scope.row.sb1" />
</div>
</template>
</el-table-column>
<el-table-column label="2#" align="center" min-width="88">
<template slot-scope="scope">
<div
:class="['sb-cell',
scope.row.sb2 && scope.row.sb2.standbyId ? 'sb-cell--del' :
scope.row.rollType ? 'sb-cell--add' : '']"
@click="handleSbCellClick(scope.row.sb2, '2#', scope.row.rollType, scope.row.position)"
>
<param-cell :data="scope.row.sb2" />
</div>
</template>
</el-table-column>
</el-table-column>
</el-table>
</el-card>
<!-- 右侧可用辊 + 工作绩效纵向叠放 -->
<div class="top-row__aside aside-col">
<!-- 可用轧辊离线 -->
<el-card shadow="never" class="roll-table-card aside-panel">
<div slot="header" class="card-header">
<span class="card-title"><i class="el-icon-files" /> 可用轧辊离线</span>
<el-button size="mini" icon="el-icon-refresh" style="margin-left:auto" @click="loadOfflineRolls">刷新</el-button>
</div>
<el-table v-loading="offlineLoading" :data="offlineRolls" size="small" :height="asideHalfH" style="width:100%">
<el-table-column label="辊型" align="center" prop="rollType" width="52">
<template slot-scope="scope">
<el-tag size="mini" :type="scope.row.rollType === 'WR' ? 'primary' : 'warning'">{{ scope.row.rollType }}</el-tag>
</template>
</el-table-column>
<el-table-column label="轧辊编号" align="center" prop="rollNo" min-width="90" show-overflow-tooltip />
<el-table-column label="辊径(mm)" align="center" width="76">
<template slot-scope="scope">{{ scope.row.currentDia != null ? scope.row.currentDia : scope.row.initialDia }}</template>
</el-table-column>
<el-table-column label="粗糙度" align="center" prop="roughness" width="64" />
</el-table>
</el-card>
<!-- 工作绩效 -->
<el-card shadow="never" class="roll-table-card aside-panel">
<div slot="header" class="card-header">
<span class="card-title"><i class="el-icon-data-analysis" /> 工作绩效实时</span>
<el-button size="mini" icon="el-icon-refresh" style="margin-left:auto" @click="loadRollPerformance">刷新</el-button>
</div>
<el-table v-loading="perfLoading" :data="perfRows" size="small" :height="asideHalfH" border style="width:100%">
<el-table-column label="辊位" align="center" prop="label" width="70" />
<el-table-column label="1# 机架" align="center" min-width="1">
<template slot-scope="scope">
<perf-cell :d="scope.row['1#']" />
</template>
</el-table-column>
<el-table-column label="2# 机架" align="center" min-width="1">
<template slot-scope="scope">
<perf-cell :d="scope.row['2#']" />
</template>
</el-table-column>
</el-table>
</el-card>
</div>
</div>
<!-- 换辊历史 -->
<el-card shadow="never" class="roll-table-card" style="margin-top:16px">
<div slot="header" class="card-header">
<span class="card-title"><i class="el-icon-document" /> 换辊历史</span>
<el-form :inline="true" size="small" style="margin-left:auto;margin-bottom:0">
<el-form-item label="机架" style="margin-bottom:0">
<el-select v-model="historyQuery.standNo" placeholder="全部" clearable style="width:100px" @change="loadHistory">
<el-option label="1# 机架" value="1#" />
<el-option label="2# 机架" value="2#" />
</el-select>
</el-form-item>
<el-form-item label="类型" style="margin-bottom:0">
<el-select v-model="historyQuery.changeType" placeholder="全部" clearable style="width:110px" @change="loadHistory">
<el-option label="计划换辊" value="计划换辊" />
<el-option label="紧急换辊" value="紧急换辊" />
</el-select>
</el-form-item>
<el-form-item label="时间起" style="margin-bottom:0">
<el-date-picker v-model="historyQuery.changeTime" type="datetime"
value-format="yyyy-MM-dd HH:mm:ss" placeholder="开始时间"
style="width:160px" @change="loadHistory" />
</el-form-item>
</el-form>
</div>
<KLPTable v-loading="historyLoading" :data="historyList">
<el-table-column label="换辊编号" align="center" prop="changeNo" width="130" />
<el-table-column label="机架" align="center" prop="standNo" width="80" />
<el-table-column label="换辊时间" align="center" prop="changeTime" width="160" />
<el-table-column label="类型" align="center" prop="changeType" width="100">
<template slot-scope="scope">
<el-tag size="small" :type="scope.row.changeType === '紧急换辊' ? 'danger' : ''">{{ scope.row.changeType }}</el-tag>
</template>
</el-table-column>
<el-table-column label="操作人" align="center" prop="operator" width="80" />
<el-table-column label="换辊辊组" align="left" min-width="160">
<template slot-scope="scope">
<div class="roll-group-cell">
<span v-if="scope.row.upperBrNo" class="rg-item"><b>上BR</b> {{ scope.row.upperBrNo }}<em v-if="scope.row.upperBrDia"> φ{{ scope.row.upperBrDia }}</em></span>
<span v-if="scope.row.upperWrNo" class="rg-item"><b>上WR</b> {{ scope.row.upperWrNo }}<em v-if="scope.row.upperWrDia"> φ{{ scope.row.upperWrDia }}</em></span>
<span v-if="scope.row.lowerWrNo" class="rg-item"><b>下WR</b> {{ scope.row.lowerWrNo }}<em v-if="scope.row.lowerWrDia"> φ{{ scope.row.lowerWrDia }}</em></span>
<span v-if="scope.row.lowerBrNo" class="rg-item"><b>下BR</b> {{ scope.row.lowerBrNo }}<em v-if="scope.row.lowerBrDia"> φ{{ scope.row.lowerBrDia }}</em></span>
<span v-if="!scope.row.upperBrNo && !scope.row.upperWrNo && !scope.row.lowerWrNo && !scope.row.lowerBrNo" style="color:#c0c4cc"></span>
</div>
</template>
</el-table-column>
<el-table-column label="工作长度(m)" align="center" prop="workLength" width="96">
<template slot-scope="scope">
<span v-if="scope.row.workLength != null">{{ scope.row.workLength }}</span>
<span v-else style="color:#c0c4cc"></span>
</template>
</el-table-column>
<el-table-column label="过卷数" align="center" prop="coilCount" width="72">
<template slot-scope="scope">
<span v-if="scope.row.coilCount != null">{{ scope.row.coilCount }}</span>
<span v-else style="color:#c0c4cc"></span>
</template>
</el-table-column>
<el-table-column label="过卷重量" align="center" prop="totalWeight" width="90">
<template slot-scope="scope">
<span v-if="scope.row.totalWeight != null">{{ scope.row.totalWeight }}</span>
<span v-else style="color:#c0c4cc"></span>
</template>
</el-table-column>
<el-table-column label="备注" align="left" prop="remark" min-width="100" show-overflow-tooltip />
<el-table-column label="操作" align="center" width="110" fixed="right">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleEditHistory(scope.row)">补录</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" style="color:#c5221f"
@click="handleDeleteHistory(scope.row)">删除</el-button>
</template>
</el-table-column>
</KLPTable>
<pagination
v-show="historyTotal > 0"
:total="historyTotal"
:page.sync="historyQuery.pageNum"
:limit.sync="historyQuery.pageSize"
@pagination="loadHistory"
/>
</el-card>
<!-- 换辊确认弹窗纯展示无需填写 -->
<el-dialog :title="changeForm.standNo + ' 机架 — 确认换辊'" :visible.sync="changeOpen" width="420px" append-to-body @close="resetChangeForm">
<div class="roll-preview">
<div class="roll-preview__title">以下轧辊将被换入</div>
<div class="roll-preview__item">
<span class="rp-label">上支撑辊</span>
<span class="rp-val">{{ changeForm.upperBrNo || '—' }}</span>
<span class="rp-dia" v-if="changeForm.upperBrDia">φ{{ changeForm.upperBrDia }} mm</span>
</div>
<div class="roll-preview__item">
<span class="rp-label">上工作辊</span>
<span class="rp-val">{{ changeForm.upperWrNo || '—' }}</span>
<span class="rp-dia" v-if="changeForm.upperWrDia">φ{{ changeForm.upperWrDia }} mm</span>
</div>
<div class="roll-preview__item">
<span class="rp-label">下工作辊</span>
<span class="rp-val">{{ changeForm.lowerWrNo || '—' }}</span>
<span class="rp-dia" v-if="changeForm.lowerWrDia">φ{{ changeForm.lowerWrDia }} mm</span>
</div>
<div class="roll-preview__item">
<span class="rp-label">下支撑辊</span>
<span class="rp-val">{{ changeForm.lowerBrNo || '—' }}</span>
<span class="rp-dia" v-if="changeForm.lowerBrDia">φ{{ changeForm.lowerBrDia }} mm</span>
</div>
</div>
<div class="roll-preview__tip">
换辊时间和操作人将由系统自动记录
</div>
<div slot="footer">
<el-button type="primary" :loading="changeSubmitting" @click="submitChange">确认换辊</el-button>
<el-button @click="changeOpen = false"> </el-button>
</div>
</el-dialog>
<!-- 换辊历史补录/编辑对话框 -->
<el-dialog title="换辊记录补录" :visible.sync="historyEditOpen" width="560px" append-to-body @close="historyEditForm = {}">
<el-form ref="historyEditForm" :model="historyEditForm" label-width="100px" size="small">
<el-row :gutter="16">
<el-col :span="12">
<el-form-item label="机架">
<el-input :value="historyEditForm.standNo" readonly />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="换辊类型">
<el-select v-model="historyEditForm.changeType" style="width:100%">
<el-option label="计划换辊" value="计划换辊" />
<el-option label="紧急换辊" value="紧急换辊" />
<el-option label="三级换辊" value="三级换辊" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="16">
<el-col :span="12">
<el-form-item label="换辊时间">
<el-date-picker v-model="historyEditForm.changeTime" type="datetime"
value-format="yyyy-MM-dd HH:mm:ss" style="width:100%" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="操作人">
<el-input v-model="historyEditForm.operator" />
</el-form-item>
</el-col>
</el-row>
<el-divider content-position="left">工作辊</el-divider>
<el-row :gutter="16">
<el-col :span="12"><el-form-item label="上工作辊"><el-input v-model="historyEditForm.upperWrNo" /></el-form-item></el-col>
<el-col :span="12"><el-form-item label="上工作辊径"><el-input-number v-model="historyEditForm.upperWrDia" :precision="2" :min="0" style="width:100%" /></el-form-item></el-col>
</el-row>
<el-row :gutter="16">
<el-col :span="12"><el-form-item label="下工作辊"><el-input v-model="historyEditForm.lowerWrNo" /></el-form-item></el-col>
<el-col :span="12"><el-form-item label="下工作辊径"><el-input-number v-model="historyEditForm.lowerWrDia" :precision="2" :min="0" style="width:100%" /></el-form-item></el-col>
</el-row>
<el-divider content-position="left">支撑辊</el-divider>
<el-row :gutter="16">
<el-col :span="12"><el-form-item label="上支撑辊"><el-input v-model="historyEditForm.upperBrNo" /></el-form-item></el-col>
<el-col :span="12"><el-form-item label="上支撑辊径"><el-input-number v-model="historyEditForm.upperBrDia" :precision="2" :min="0" style="width:100%" /></el-form-item></el-col>
</el-row>
<el-row :gutter="16">
<el-col :span="12"><el-form-item label="下支撑辊"><el-input v-model="historyEditForm.lowerBrNo" /></el-form-item></el-col>
<el-col :span="12"><el-form-item label="下支撑辊径"><el-input-number v-model="historyEditForm.lowerBrDia" :precision="2" :min="0" style="width:100%" /></el-form-item></el-col>
</el-row>
<el-form-item label="备注">
<el-input v-model="historyEditForm.remark" type="textarea" :rows="2" />
</el-form-item>
</el-form>
<div slot="footer">
<el-button type="primary" @click="submitHistoryEdit"> </el-button>
<el-button @click="historyEditOpen = false"> </el-button>
</div>
</el-dialog>
<!-- 添加下批轧辊对话框 -->
<el-dialog title="添加下批轧辊" :visible.sync="standbyOpen" width="460px" append-to-body @close="resetStandbyForm">
<el-form ref="standbyForm" :model="standbyForm" :rules="standbyRules" label-width="100px">
<el-row :gutter="16">
<el-col :span="12">
<el-form-item label="机架" prop="standNo">
<el-select v-model="standbyForm.standNo" style="width:100%" :disabled="standbyFromCell">
<el-option label="1# 机架" value="1#" />
<el-option label="2# 机架" value="2#" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="辊型" prop="rollType">
<el-input
v-if="standbyFromCell"
:value="standbyForm.rollType === 'WR' ? '工作辊 WR' : '支撑辊 BR'"
readonly style="width:100%"
/>
<el-select v-else v-model="standbyForm.rollType" placeholder="请选择" style="width:100%"
@change="handleStandbyRollTypeChange">
<el-option label="工作辊 WR" value="WR" />
<el-option label="支撑辊 BR" value="BR" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="16">
<el-col :span="12">
<el-form-item label="辊位" prop="position">
<el-input
v-if="standbyFromCell"
:value="standbyForm.position === 'UP' ? '上辊' : '下辊'"
readonly style="width:100%"
/>
<el-select v-else v-model="standbyForm.position" placeholder="请选择" style="width:100%">
<el-option label="上辊" value="UP" />
<el-option label="下辊" value="DOWN" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="轧辊编号" prop="rollNo">
<el-select v-model="standbyForm.rollNo" placeholder="请选择" filterable style="width:100%">
<el-option
v-for="no in standbyForm.rollType === 'WR' ? wrOptions : brOptions"
:key="no" :label="no" :value="no"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-form-item label="就绪时间">
<el-date-picker v-model="standbyForm.readyTime" type="datetime"
value-format="yyyy-MM-dd HH:mm:ss" placeholder="默认当前时间" style="width:100%" />
</el-form-item>
<el-form-item label="备注">
<el-input v-model="standbyForm.remark" type="textarea" :rows="2" />
</el-form-item>
</el-form>
<div slot="footer">
<el-button type="primary" @click="submitStandby"> </el-button>
<el-button @click="standbyOpen = false"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { getCurrentRolls, listRollChange, addRollChange, updateRollChange, delRollChange, getRollPerformance } from '@/api/mes/roll/rollChange'
import { listRollStandby, addRollStandby, delRollStandby, clearRollStandby } from '@/api/mes/roll/rollStandby'
import { listRollOptions, listRollInfo } from '@/api/mes/roll/rollInfo'
import rollLineMixin from '../rollLineMixin'
const ParamCell = {
name: 'ParamCell',
props: { data: { type: Object, default: null } },
render(h) {
const d = this.data
if (!d || d.val == null || d.val === '') return h('span', { class: 'cell-empty' }, '—')
return h('span', { class: 'cell-main' }, String(d.val))
}
}
/** 绩效单元格:显示辊号 + 三项统计 */
const PerfCell = {
name: 'PerfCell',
props: { d: { type: Object, default: null } },
render(h) {
const d = this.d
if (!d || !d.rollNo) return h('span', { class: 'cell-empty' }, '—')
return h('div', { class: 'perf-cell' }, [
h('div', { class: 'perf-roll' }, d.rollNo),
h('div', { class: 'perf-stat' }, `${d.workLength != null ? d.workLength + 'm' : '—'} · ${d.coilCount != null ? d.coilCount + '卷' : '—'} · ${d.totalWeight != null ? d.totalWeight : '—'}`)
])
}
}
export default {
name: 'WorkingRoll',
components: { ParamCell, PerfCell },
mixins: [rollLineMixin],
data() {
return {
current: { '1#': {}, '2#': {} },
loadingCurrent: { '1#': false, '2#': false },
standbyList: { '1#': [], '2#': [] },
loadingStandby: { '1#': false, '2#': false },
rollInfoMap: {},
historyLoading: false,
historyList: [],
historyTotal: 0,
historyQuery: { pageNum: 1, pageSize: 15, standNo: undefined, changeType: undefined, changeTime: undefined },
wrOptions: [],
brOptions: [],
historyEditOpen: false,
historyEditForm: {},
offlineRolls: [],
offlineLoading: false,
perfData: {},
perfLoading: false,
asideHalfH: 200,
changeOpen: false,
changeSubmitting: false,
changeForm: this.getDefaultChangeForm(),
standbyOpen: false,
standbyForm: this.getDefaultStandbyForm(),
standbyFromCell: false,
standbyRules: {
standNo: [{ required: true, message: '请选择机架', trigger: 'change' }],
rollType: [{ required: true, message: '请选择辊型', trigger: 'change' }],
position: [{ required: true, message: '请选择辊位', trigger: 'change' }],
rollNo: [{ required: true, message: '请选择轧辊编号', trigger: 'change' }]
}
}
},
computed: {
mergedRows() {
const c1 = this.current['1#'] || {}
const c2 = this.current['2#'] || {}
const ri = this.rollInfoMap
// 当前辊:值来自换辊记录,凸度/粗糙度/材质从 rollInfoMap 查
const cv = (val, rollNo) => ({
val: (val == null || val === '') ? null : val,
sub: rollNo || null
})
const rv = (rollNo, field) => {
const info = rollNo ? ri[rollNo] : null
const val = info ? info[field] : null
return { val: (val == null || val === '') ? null : val, sub: rollNo || null }
}
// 下批辊:优先取 standby 记录自身字段,为空则从 rollInfoMap 读diameter 对应 currentDia
const sv = (standNo, rollType, pos, field) => {
const item = (this.standbyList[standNo] || []).find(
i => i.rollType === rollType && i.position === pos
)
if (!item) return { val: null, sub: null }
let val = item[field]
if ((val == null || val === '') && item.rollNo) {
const info = ri[item.rollNo]
if (info) {
val = field === 'diameter'
? (info.currentDia != null ? info.currentDia : info.initialDia)
: info[field]
}
}
return { val: (val == null || val === '') ? null : val, sub: item.rollNo, standbyId: item.standbyId }
}
const sm = (standNo, rollType, pos) => {
const item = (this.standbyList[standNo] || []).find(
i => i.rollType === rollType && i.position === pos
)
if (!item || !item.rollNo) return { val: null, sub: null }
const info = ri[item.rollNo]
return {
val: info ? (info.material || null) : null,
sub: item.rollNo,
standbyId: item.standbyId
}
}
return [
{
label: '上支承辊直径(mm)', group: 'br', rollType: 'BR', position: 'UP',
cur1: cv(c1.upperBrDia, c1.upperBrNo), cur2: cv(c2.upperBrDia, c2.upperBrNo),
sb1: sv('1#', 'BR', 'UP', 'diameter'), sb2: sv('2#', 'BR', 'UP', 'diameter')
},
{
label: '上工作辊直径(mm)', group: 'wr', rollType: 'WR', position: 'UP',
cur1: cv(c1.upperWrDia, c1.upperWrNo), cur2: cv(c2.upperWrDia, c2.upperWrNo),
sb1: sv('1#', 'WR', 'UP', 'diameter'), sb2: sv('2#', 'WR', 'UP', 'diameter')
},
{
label: '上工作辊凸度', group: 'wr', rollType: 'WR', position: 'UP',
cur1: rv(c1.upperWrNo, 'crown'), cur2: rv(c2.upperWrNo, 'crown'),
sb1: sv('1#', 'WR', 'UP', 'crown'), sb2: sv('2#', 'WR', 'UP', 'crown')
},
{
label: '上工作辊粗糙度(μm)', group: 'wr', rollType: 'WR', position: 'UP',
cur1: rv(c1.upperWrNo, 'roughness'), cur2: rv(c2.upperWrNo, 'roughness'),
sb1: sv('1#', 'WR', 'UP', 'roughness'), sb2: sv('2#', 'WR', 'UP', 'roughness')
},
{
label: '工作辊类型', group: 'wr', rollType: 'WR', position: 'UP',
cur1: rv(c1.upperWrNo, 'material'), cur2: rv(c2.upperWrNo, 'material'),
sb1: sm('1#', 'WR', 'UP'), sb2: sm('2#', 'WR', 'UP')
},
{
label: '下工作辊直径(mm)', group: 'wr', rollType: 'WR', position: 'DOWN',
cur1: cv(c1.lowerWrDia, c1.lowerWrNo), cur2: cv(c2.lowerWrDia, c2.lowerWrNo),
sb1: sv('1#', 'WR', 'DOWN', 'diameter'), sb2: sv('2#', 'WR', 'DOWN', 'diameter')
},
{
label: '下工作辊凸度', group: 'wr', rollType: 'WR', position: 'DOWN',
cur1: rv(c1.lowerWrNo, 'crown'), cur2: rv(c2.lowerWrNo, 'crown'),
sb1: sv('1#', 'WR', 'DOWN', 'crown'), sb2: sv('2#', 'WR', 'DOWN', 'crown')
},
{
label: '下工作辊粗糙度(μm)', group: 'wr', rollType: 'WR', position: 'DOWN',
cur1: rv(c1.lowerWrNo, 'roughness'), cur2: rv(c2.lowerWrNo, 'roughness'),
sb1: sv('1#', 'WR', 'DOWN', 'roughness'), sb2: sv('2#', 'WR', 'DOWN', 'roughness')
},
{
label: '下支承辊直径(mm)', group: 'br', rollType: 'BR', position: 'DOWN',
cur1: cv(c1.lowerBrDia, c1.lowerBrNo), cur2: cv(c2.lowerBrDia, c2.lowerBrNo),
sb1: sv('1#', 'BR', 'DOWN', 'diameter'), sb2: sv('2#', 'BR', 'DOWN', 'diameter')
},
{
label: '轧线设定(mm)', group: 'pl', rollType: null, position: null,
cur1: { val: null, sub: null }, cur2: { val: null, sub: null },
sb1: { val: null, sub: null }, sb2: { val: null, sub: null }
},
{
label: '轧线位置(mm)', group: 'pl', rollType: null, position: null,
cur1: { val: null, sub: null }, cur2: { val: null, sub: null },
sb1: { val: null, sub: null }, sb2: { val: null, sub: null }
},
]
},
/** 工作绩效表数据行4 辊位 × {label, 1#, 2#} */
perfRows() {
const POS = [
{ key: 'upperBr', label: '上支撑辊' },
{ key: 'upperWr', label: '上工作辊' },
{ key: 'lowerWr', label: '下工作辊' },
{ key: 'lowerBr', label: '下支撑辊' }
]
return POS.map(p => ({
label: p.label,
'1#': (this.perfData[p.key] || {})['1#'] || {},
'2#': (this.perfData[p.key] || {})['2#'] || {}
}))
}
},
created() {},
mounted() {
this.$nextTick(this.syncAsideHeight)
window.addEventListener('resize', this.syncAsideHeight)
},
beforeDestroy() {
window.removeEventListener('resize', this.syncAsideHeight)
},
methods: {
onLineResolved() {
this.loadAll()
this.loadRollOptions()
this.loadRollInfoMap()
},
getDefaultChangeForm(standNo) {
return {
standNo: standNo || undefined,
changeType: undefined,
changeTime: undefined,
operator: undefined,
upperWrNo: undefined,
upperWrDia: undefined,
lowerWrNo: undefined,
lowerWrDia: undefined,
upperBrNo: undefined,
upperBrDia: undefined,
lowerBrNo: undefined,
lowerBrDia: undefined,
remark: undefined
}
},
getDefaultStandbyForm(standNo, rollType, position) {
return {
standNo: standNo || undefined,
rollType: rollType || undefined,
position: position || undefined,
rollNo: undefined,
readyTime: undefined,
remark: undefined
}
},
loadAll() {
;['1#', '2#'].forEach(s => {
this.loadCurrent(s)
this.loadStandby(s)
})
this.loadHistory()
this.loadOfflineRolls()
this.loadRollPerformance()
},
loadRollPerformance() {
this.perfLoading = true
getRollPerformance(this.lineId).then(res => {
this.perfData = res.data || {}
}).finally(() => { this.perfLoading = false })
},
loadCurrent(standNo) {
this.$set(this.loadingCurrent, standNo, true)
getCurrentRolls(this.lineId, standNo).then(res => {
this.$set(this.current, standNo, res.data || {})
this.$set(this.loadingCurrent, standNo, false)
this.$nextTick(this.syncAsideHeight)
}).catch(() => { this.$set(this.loadingCurrent, standNo, false) })
},
loadStandby(standNo) {
this.$set(this.loadingStandby, standNo, true)
listRollStandby(this.lineId, standNo).then(res => {
this.$set(this.standbyList, standNo, res.data || [])
this.$set(this.loadingStandby, standNo, false)
}).catch(() => { this.$set(this.loadingStandby, standNo, false) })
},
loadHistory() {
this.historyLoading = true
listRollChange({ ...this.historyQuery, lineId: this.lineId }).then(res => {
this.historyList = res.rows || []
this.historyTotal = res.total || 0
this.historyLoading = false
}).catch(() => { this.historyLoading = false })
},
loadRollOptions() {
// 下批辊选择只显示离线Offline状态的轧辊限定当前产线
listRollOptions(this.lineId, 'WR', 'Offline').then(res => { this.wrOptions = res.data || [] })
listRollOptions(this.lineId, 'BR', 'Offline').then(res => { this.brOptions = res.data || [] })
},
loadRollInfoMap() {
listRollInfo({ lineId: this.lineId, pageNum: 1, pageSize: 500 }).then(res => {
const map = {}
;(res.rows || []).forEach(r => { map[r.rollNo] = r })
this.rollInfoMap = map
})
},
rowClass({ row }) {
if (row.group === 'br') return 'row-br'
if (row.group === 'pl') return 'row-pl'
return ''
},
// el-table span-method参数列不需要 span其余无特殊合并
mergeParamCol({ columnIndex }) {
if (columnIndex === 0) return [1, 1]
},
// 换辊:自动从下批辊填入辊号和径值
handleOpenChange(standNo) {
const list = this.standbyList[standNo] || []
const ri = this.rollInfoMap
const pick = (rollType, pos) => {
const item = list.find(i => i.rollType === rollType && i.position === pos)
if (!item) return { no: undefined, dia: undefined }
const info = ri[item.rollNo]
const dia = item.diameter != null ? item.diameter
: (info ? (info.currentDia != null ? info.currentDia : info.initialDia) : undefined)
return { no: item.rollNo, dia }
}
const uwr = pick('WR', 'UP')
const lwr = pick('WR', 'DOWN')
const ubr = pick('BR', 'UP')
const lbr = pick('BR', 'DOWN')
this.changeForm = {
...this.getDefaultChangeForm(standNo),
lineId: this.lineId,
upperWrNo: uwr.no, upperWrDia: uwr.dia,
lowerWrNo: lwr.no, lowerWrDia: lwr.dia,
upperBrNo: ubr.no, upperBrDia: ubr.dia,
lowerBrNo: lbr.no, lowerBrDia: lbr.dia
}
this.changeOpen = true
},
submitChange() {
if (this.changeSubmitting) return
this.changeSubmitting = true
const standNo = this.changeForm.standNo
addRollChange(this.changeForm).then(() => {
this.$modal.msgSuccess('换辊成功')
this.changeOpen = false
clearRollStandby(this.lineId, standNo).finally(() => {
this.loadCurrent(standNo)
this.loadStandby(standNo)
this.loadHistory()
this.loadOfflineRolls()
this.loadRollPerformance()
})
}).finally(() => {
this.changeSubmitting = false
})
},
resetChangeForm() {
this.changeForm = this.getDefaultChangeForm()
this.changeSubmitting = false
},
// 下批轧辊 — 单元格点击(空→新增,有数据→删除)
handleSbCellClick(cell, standNo, rollType, position) {
if (cell && cell.standbyId) {
this.handleDelStandby(cell.standbyId, standNo)
} else if (rollType) {
this.standbyForm = this.getDefaultStandbyForm(standNo, rollType, position)
this.standbyFromCell = true
this.standbyOpen = true
}
},
// 下批轧辊 — 顶部"添加下批"按钮(不预设辊型辊位)
handleAddStandby(standNo) {
this.standbyForm = this.getDefaultStandbyForm(standNo)
this.standbyFromCell = false
this.standbyOpen = true
},
handleStandbyRollTypeChange() {
this.$set(this.standbyForm, 'rollNo', undefined)
},
submitStandby() {
this.$refs.standbyForm.validate(valid => {
if (!valid) return
addRollStandby({ ...this.standbyForm, lineId: this.lineId }).then(() => {
this.$modal.msgSuccess('已添加到下批轧辊')
this.standbyOpen = false
this.loadStandby(this.standbyForm.standNo)
this.loadRollOptions() // 刷新离线辊下拉(已变为 Standby 的辊不再显示)
this.loadOfflineRolls() // 刷新可用辊面板
})
})
},
resetStandbyForm() {
this.standbyForm = this.getDefaultStandbyForm()
this.standbyFromCell = false
this.$nextTick(() => { this.$refs.standbyForm && this.$refs.standbyForm.clearValidate() })
},
handleDelStandby(standbyId, standNo) {
this.$modal.confirm('确认移除该下批轧辊?移除后该辊状态将恢复为"离线"。').then(() => {
return delRollStandby(standbyId)
}).then(() => {
this.$modal.msgSuccess('已移除')
this.loadStandby(standNo)
this.loadRollOptions()
this.loadOfflineRolls()
})
},
handleClearStandby(standNo) {
this.$modal.confirm('确认清空 ' + standNo + ' 机架的全部下批轧辊?').then(() => {
return clearRollStandby(this.lineId, standNo)
}).then(() => {
this.$modal.msgSuccess('已清空')
this.loadStandby(standNo)
})
},
// ── 换辊历史 补录 / 删除 ──────────────────────────────────
handleEditHistory(row) {
this.historyEditForm = { ...row }
this.historyEditOpen = true
},
submitHistoryEdit() {
updateRollChange(this.historyEditForm).then(() => {
this.$modal.msgSuccess('保存成功')
this.historyEditOpen = false
this.loadHistory()
})
},
handleDeleteHistory(row) {
this.$modal.confirm('确认删除该换辊记录?此操作不可恢复。').then(() => {
return delRollChange(row.changeId)
}).then(() => {
this.$modal.msgSuccess('已删除')
this.loadHistory()
})
},
// ── 可用离线辊列表 ────────────────────────────────────────
loadOfflineRolls() {
this.offlineLoading = true
listRollInfo({ lineId: this.lineId, status: 'Offline', pageNum: 1, pageSize: 30 }).then(res => {
this.offlineRolls = res.rows || []
}).finally(() => {
this.offlineLoading = false
})
},
// 右侧两个面板各占左侧表格高度的一半(各自减去卡片头高度)
syncAsideHeight() {
const el = this.$refs.mainTable && this.$refs.mainTable.$el
if (!el) return
const totalH = el.offsetHeight // 左侧 el-table 实际高度
const gap = 12 // 两个面板之间的间距
const headerH = 48 // 单个卡片 header 高度估值
const half = Math.max(100, Math.floor((totalH - gap) / 2) - headerH)
this.asideHalfH = half
}
}
}
</script>
<style scoped>
.working-roll-page { background: #f4f5f7; }
.roll-table-card { border: 1px solid #dcdee0; border-radius: 4px; }
/* 顶部两栏布局 */
.top-row {
display: flex;
gap: 12px;
align-items: stretch;
}
.top-row__main { flex: 2; min-width: 0; }
.top-row__aside { flex: 1; min-width: 0; }
/* 右侧列:两个面板纵向叠放 */
.aside-col { display: flex; flex-direction: column; gap: 12px; }
.aside-panel { flex: 1; min-width: 0; }
/* 绩效单元格 */
.perf-cell { padding: 2px 0; line-height: 1.4; }
.perf-roll { font-family: 'Consolas', monospace; font-size: 12px; font-weight: 600; color: #1f2329; }
.perf-stat { font-size: 11px; color: #8f9099; }
/* 历史换辊辊组 */
.roll-group-cell { display: flex; flex-wrap: wrap; gap: 4px; line-height: 1.5; }
.rg-item { font-size: 12px; color: #3d4b5c; }
.rg-item b { color: #5f6368; font-weight: 600; margin-right: 2px; }
.rg-item em { font-style: normal; color: #9aa0a6; font-size: 11px; }
.card-header { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.card-title { font-size: 13px; font-weight: 600; color: #3d4b5c; white-space: nowrap; }
.header-meta { font-size: 11px; color: #8f9099; white-space: nowrap; }
/* 参数列文字 */
.param-label { font-size: 12px; color: #3d4b5c; }
/* 数值单元格 */
.cell-main { font-family: 'Consolas', 'Courier New', monospace; font-size: 13px; font-weight: 600; color: #1f2329; }
.cell-empty { color: #c0c4cc; font-size: 12px; }
/* 换辊预览卡片 */
.roll-preview { background: #f7f8fa; border: 1px solid #e4e6eb; border-radius: 4px; padding: 10px 12px; }
.roll-preview__title { font-size: 11px; color: #8f9099; margin-bottom: 8px; letter-spacing: .5px; }
.roll-preview__item { display: flex; align-items: center; gap: 6px; padding: 4px 0; }
.rp-label { font-size: 12px; color: #8f9099; width: 56px; flex-shrink: 0; }
.rp-val { font-size: 13px; font-weight: 600; color: #1f2329; font-family: 'Consolas', monospace; flex: 1; }
.rp-dia { font-size: 11px; color: #9aa0a6; }
.roll-preview__tip { font-size: 11px; color: #b0b3bb; margin-top: 10px; text-align: center; }
/* 下批辊单元格容器:填满整个 td有数据时点击删除 */
.sb-cell {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
min-height: 36px;
}
/* 有数据 → 点击删除hover 浅红 */
.sb-cell--del {
cursor: pointer;
}
.sb-cell--del:hover {
background: rgba(198, 40, 40, 0.07);
}
/* 空格子 → 点击新增hover 浅绿 */
.sb-cell--add {
cursor: pointer;
}
.sb-cell--add:hover {
background: rgba(35, 134, 54, 0.07);
}
</style>
<style>
/* 行分组色scoped 无法穿透 el-table 内部) */
.working-roll-page .el-table .row-br > td { background-color: #f7f7f6 !important; }
.working-roll-page .el-table .row-pl > td { background-color: #eef2f8 !important; }
/* 列分组标题加粗区分 */
.working-roll-page .el-table__header th.el-table__cell {
background: #f0f2f5;
color: #3d4b5c;
font-weight: 600;
font-size: 12px;
}
</style>