This commit is contained in:
2026-05-07 11:35:48 +08:00
32 changed files with 3088 additions and 4 deletions

View File

@@ -0,0 +1,62 @@
import request from '@/utils/request'
// 查询换辊记录分页列表(支持按机架、类型、时间筛选)
export function listRollChange(query) {
return request({
url: '/mes/rollChange/list',
method: 'get',
params: query
})
}
// 查询指定机架当前在机轧辊(最近一次换辊记录)
export function getCurrentRolls(standNo) {
return request({
url: '/mes/rollChange/current',
method: 'get',
params: { standNo }
})
}
// 查询指定机架当前轧辊实时工作长度m
export function getWorkLength(standNo) {
return request({
url: '/mes/rollChange/workLength',
method: 'get',
params: { standNo }
})
}
// 查询换辊记录详细
export function getRollChange(changeId) {
return request({
url: '/mes/rollChange/' + changeId,
method: 'get'
})
}
// 新增换辊记录(自动同步辊状态为 Online
export function addRollChange(data) {
return request({
url: '/mes/rollChange',
method: 'post',
data: data
})
}
// 修改换辊记录
export function updateRollChange(data) {
return request({
url: '/mes/rollChange',
method: 'put',
data: data
})
}
// 删除换辊记录
export function delRollChange(changeIds) {
return request({
url: '/mes/rollChange/' + changeIds,
method: 'delete'
})
}

View File

@@ -0,0 +1,87 @@
import request from '@/utils/request'
// 查询轧辊库分页列表
export function listRollInfo(query) {
return request({
url: '/mes/rollInfo/list',
method: 'get',
params: query
})
}
// 查询状态统计卡片
export function getRollStats() {
return request({
url: '/mes/rollInfo/stats',
method: 'get'
})
}
// 查询轧辊编号下拉rollType/status 均可为空,不传则不过滤)
export function listRollOptions(rollType, status) {
return request({
url: '/mes/rollInfo/options',
method: 'get',
params: { rollType, status }
})
}
// 查询轧辊详细
export function getRollInfo(rollId) {
return request({
url: '/mes/rollInfo/' + rollId,
method: 'get'
})
}
// 新增轧辊
export function addRollInfo(data) {
return request({
url: '/mes/rollInfo',
method: 'post',
data: data
})
}
// 修改轧辊
export function updateRollInfo(data) {
return request({
url: '/mes/rollInfo',
method: 'put',
data: data
})
}
// 删除轧辊(仅报废状态可删)
export function delRollInfo(rollIds) {
return request({
url: '/mes/rollInfo/' + rollIds,
method: 'delete'
})
}
// 封闭轧辊(→报废)
export function scrapRollInfo(rollId) {
return request({
url: '/mes/rollInfo/' + rollId + '/scrap',
method: 'put'
})
}
// 从换辊记录同步在线状态
export function syncRollStatus() {
return request({
url: '/mes/rollInfo/syncStatus',
method: 'post'
})
}
// 导出轧辊
export function exportRollInfo(query) {
return request({
url: '/mes/rollInfo/export',
method: 'post',
params: query,
responseType: 'blob'
})
}

View File

@@ -0,0 +1,53 @@
import request from '@/utils/request'
// 查询指定机架下批轧辊列表
export function listRollStandby(standNo) {
return request({
url: '/mes/rollStandby/list',
method: 'get',
params: { standNo }
})
}
// 查询下批轧辊详细
export function getRollStandby(standbyId) {
return request({
url: '/mes/rollStandby/' + standbyId,
method: 'get'
})
}
// 新增下批轧辊(自动同步辊状态为 Standby
export function addRollStandby(data) {
return request({
url: '/mes/rollStandby',
method: 'post',
data: data
})
}
// 修改下批轧辊
export function updateRollStandby(data) {
return request({
url: '/mes/rollStandby',
method: 'put',
data: data
})
}
// 删除单条下批轧辊(自动恢复辊状态为 Offline
export function delRollStandby(standbyId) {
return request({
url: '/mes/rollStandby/' + standbyId,
method: 'delete'
})
}
// 清空指定机架全部下批轧辊
export function clearRollStandby(standNo) {
return request({
url: '/mes/rollStandby/clear',
method: 'delete',
params: { standNo }
})
}

View File

@@ -8,8 +8,8 @@
<div class="el-table-container" ref="elTableWrapper" @mouseleave="handleTableLeave">
<!-- 原生 Table 核心透传 props/事件/插槽 -->
<el-table :ref="tableRef" v-bind="$attrs" v-on="$listeners" :class="['my-table', customClass]"
@cell-mouse-enter="handleCellEnter" @row-mouseleave="handleRowLeave" :height="height">
<el-table :ref="tableRef" v-bind="tableAttrs" v-on="$listeners" :class="['my-table', customClass]"
@cell-mouse-enter="handleCellEnter" @row-mouseleave="handleRowLeave">
<!-- 2. 透传原生内置插槽 empty 空数据插槽append 底部插槽等 -->
<template v-slot:empty="scope">
<slot name="empty" v-bind="scope"></slot>
@@ -102,6 +102,13 @@ export default {
};
},
computed: {
tableAttrs() {
const attrs = { ...this.$attrs }
if (this.height !== '' && this.height !== null && this.height !== undefined) {
attrs.height = this.height
}
return attrs
},
floatLayerColumns() {
if (this.floatLayerConfig?.columns?.length > 1) {
return this.floatLayerConfig.columns

View File

@@ -1,5 +1,5 @@
<template>
<div :class="{'hidden':hidden}" class="pagination-container" :style="style">
<div :class="{'hidden':hidden}" class="pagination-container" :style="containerStyle">
<el-pagination
:background="background"
:current-page.sync="currentPage"
@@ -61,7 +61,7 @@ export default {
type: Boolean,
default: false
},
style: {
containerStyle: {
type: String,
default: ''
}

View File

@@ -0,0 +1,469 @@
<template>
<div class="app-container roll-overview">
<!-- 状态统计看板 -->
<div class="stat-panel mb16">
<div class="stat-item">
<div class="stat-icon-wrap total-icon"><i class="el-icon-data-line" /></div>
<div class="stat-body">
<div class="stat-num">{{ stats.total || 0 }}</div>
<div class="stat-label">轧辊总数</div>
</div>
<div class="stat-divider" />
</div>
<div class="stat-item">
<div class="stat-icon-wrap online-icon"><i class="el-icon-circle-check" /></div>
<div class="stat-body">
<div class="stat-num online-num">{{ stats.Online || 0 }}</div>
<div class="stat-label"> 线</div>
</div>
<div class="stat-divider" />
</div>
<div class="stat-item">
<div class="stat-icon-wrap standby-icon"><i class="el-icon-time" /></div>
<div class="stat-body">
<div class="stat-num standby-num">{{ stats.Standby || 0 }}</div>
<div class="stat-label"> </div>
</div>
<div class="stat-divider" />
</div>
<div class="stat-item">
<div class="stat-icon-wrap offline-icon"><i class="el-icon-remove-outline" /></div>
<div class="stat-body">
<div class="stat-num offline-num">{{ stats.Offline || 0 }}</div>
<div class="stat-label"> 线</div>
</div>
<div class="stat-divider" />
</div>
<div class="stat-item">
<div class="stat-icon-wrap scrapped-icon"><i class="el-icon-warning-outline" /></div>
<div class="stat-body">
<div class="stat-num scrapped-num">{{ stats.Scrapped || 0 }}</div>
<div class="stat-label"> </div>
</div>
</div>
</div>
<!-- 搜索栏 -->
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="轧辊编号" prop="rollNo">
<el-input v-model="queryParams.rollNo" placeholder="请输入轧辊编号" clearable @keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item label="辊型" prop="rollType">
<el-select v-model="queryParams.rollType" placeholder="全部" clearable style="width:120px">
<el-option label="工作辊 WR" value="WR" />
<el-option label="支撑辊 BR" value="BR" />
</el-select>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="全部" clearable style="width:130px">
<el-option label="在线" value="Online" />
<el-option label="备用" value="Standby" />
<el-option label="离线" value="Offline" />
<el-option label="报废" value="Scrapped" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<!-- 操作按钮 -->
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="el-icon-edit" size="mini" :disabled="single" @click="handleUpdate">修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport">导出</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="info" plain icon="el-icon-refresh" size="mini" @click="handleSyncStatus">同步在线状态</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList" />
</el-row>
<!-- 数据表格 -->
<KLPTable v-loading="loading" :data="rollList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="轧辊编号" align="center" prop="rollNo" min-width="130">
<template slot-scope="scope">
<span class="roll-no-text">{{ scope.row.rollNo }}</span>
</template>
</el-table-column>
<el-table-column label="辊型" align="center" prop="rollType" width="100">
<template slot-scope="scope">
<span :class="['roll-type-tag', scope.row.rollType === 'WR' ? 'wr-tag' : 'br-tag']">
{{ scope.row.rollType === 'WR' ? '工作辊 WR' : '支撑辊 BR' }}
</span>
</template>
</el-table-column>
<el-table-column label="状态" align="center" prop="status" width="90">
<template slot-scope="scope">
<span :class="['status-dot-wrap', 'status-' + scope.row.status]">
<span class="status-dot" />
{{ statusLabel(scope.row.status) }}
</span>
</template>
</el-table-column>
<el-table-column label="初始直径(mm)" align="right" prop="initialDia" width="120" />
<el-table-column label="当前直径(mm)" align="right" prop="currentDia" width="120">
<template slot-scope="scope">
<span :class="{ 'warn-text': isDiaLow(scope.row) }">{{ scope.row.currentDia }}</span>
</template>
</el-table-column>
<el-table-column label="最小直径(mm)" align="right" prop="minDia" width="120" />
<el-table-column label="粗糙度" align="right" prop="roughness" width="90" />
<el-table-column label="凸度" align="right" prop="crown" width="90" />
<el-table-column label="材质" align="center" prop="material" width="100" />
<el-table-column label="磨削次数" align="center" prop="grindCount" width="90" />
<el-table-column label="累计轧制量(t)" align="right" prop="totalRolledWeight" width="130" />
<el-table-column label="制造日期" align="center" prop="manufactureDate" width="110" />
<el-table-column label="备注" align="left" prop="remark" min-width="120" show-overflow-tooltip />
<el-table-column label="操作" align="center" width="160" fixed="right">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)">修改</el-button>
<el-button v-if="scope.row.status === 'Offline'" size="mini" type="text"
class="scrap-btn" icon="el-icon-lock" @click="handleScrap(scope.row)">封闭</el-button>
<el-button v-if="scope.row.status === 'Scrapped'" size="mini" type="text"
class="del-btn" icon="el-icon-delete" @click="handleDelete(scope.row)">删除</el-button>
</template>
</el-table-column>
</KLPTable>
<!-- 分页 -->
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList" />
<!-- 新增/修改对话框 -->
<el-dialog :title="title" :visible.sync="open" width="620px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="110px">
<el-row :gutter="16">
<el-col :span="12">
<el-form-item label="轧辊编号" prop="rollNo">
<el-input v-model="form.rollNo" placeholder="请输入轧辊编号" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="辊型" prop="rollType">
<el-select v-model="form.rollType" placeholder="请选择辊型" style="width:100%">
<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="初始直径(mm)" prop="initialDia">
<el-input-number v-model="form.initialDia" :precision="2" :min="0" style="width:100%" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="当前直径(mm)" prop="currentDia">
<el-input-number v-model="form.currentDia" :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="最小直径(mm)" prop="minDia">
<el-input-number v-model="form.minDia" :precision="2" :min="0" style="width:100%" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="材质" prop="material">
<el-input v-model="form.material" placeholder="请输入材质" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="16">
<el-col :span="12">
<el-form-item label="粗糙度" prop="roughness">
<el-input-number v-model="form.roughness" :precision="4" :min="0" style="width:100%" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="凸度" prop="crown">
<el-input-number v-model="form.crown" :precision="4" style="width:100%" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="16">
<el-col :span="12">
<el-form-item label="制造日期" prop="manufactureDate">
<el-date-picker v-model="form.manufactureDate" type="date" value-format="yyyy-MM-dd"
placeholder="请选择制造日期" style="width:100%" />
</el-form-item>
</el-col>
<el-col :span="12" v-if="!form.rollId">
<el-form-item label="状态">
<el-input value="离线" readonly style="width:100%" />
</el-form-item>
</el-col>
</el-row>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" :rows="2" placeholder="请输入备注" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { listRollInfo, getRollStats, getRollInfo, addRollInfo, updateRollInfo, delRollInfo, scrapRollInfo, syncRollStatus } from '@/api/mes/roll/rollInfo'
export default {
name: 'RollOverview',
data() {
return {
loading: false,
showSearch: true,
single: true,
multiple: true,
total: 0,
rollList: [],
stats: {},
title: '',
open: false,
queryParams: {
pageNum: 1,
pageSize: 20,
rollNo: undefined,
rollType: undefined,
status: undefined
},
form: {},
rules: {
rollNo: [{ required: true, message: '轧辊编号不能为空', trigger: 'blur' }],
rollType: [{ required: true, message: '请选择辊型', trigger: 'change' }]
},
ids: []
}
},
created() {
this.getStats()
this.getList()
},
methods: {
getList() {
this.loading = true
listRollInfo(this.queryParams).then(res => {
this.rollList = res.rows
this.total = res.total
this.loading = false
}).catch(() => { this.loading = false })
},
getStats() {
getRollStats().then(res => { this.stats = res.data || {} })
},
handleQuery() {
this.queryParams.pageNum = 1
this.getList()
},
resetQuery() {
this.resetForm('queryForm')
this.handleQuery()
},
handleSelectionChange(selection) {
this.ids = selection.map(item => item.rollId)
this.single = selection.length !== 1
this.multiple = !selection.length
},
handleAdd() {
this.reset()
this.title = '新增轧辊'
this.open = true
},
handleUpdate(row) {
this.reset()
const rollId = row ? row.rollId : this.ids[0]
getRollInfo(rollId).then(res => {
this.form = res.data
this.title = '修改轧辊'
this.open = true
})
},
handleDelete(row) {
const rollIds = row ? [row.rollId] : this.ids
this.$modal.confirm('确认删除该报废轧辊记录?此操作不可恢复。').then(() => {
return delRollInfo(rollIds.join(','))
}).then(() => {
this.getList()
this.getStats()
this.$modal.msgSuccess('删除成功')
})
},
handleScrap(row) {
this.$modal.confirm('确认封闭轧辊【' + row.rollNo + '】?封闭后状态将变为报废,不可恢复。').then(() => {
return scrapRollInfo(row.rollId)
}).then(() => {
this.getList()
this.getStats()
this.$modal.msgSuccess('封闭成功')
})
},
handleSyncStatus() {
this.$modal.confirm('将从换辊记录中重新推算各机架当前在机轧辊的状态,确认执行?').then(() => {
return syncRollStatus()
}).then(() => {
this.getList()
this.getStats()
this.$modal.msgSuccess('状态同步完成')
})
},
handleExport() {
this.download('/mes/rollInfo/export', this.queryParams, '轧辊数据.xlsx')
},
submitForm() {
this.$refs.form.validate(valid => {
if (!valid) return
const action = this.form.rollId ? updateRollInfo : addRollInfo
action(this.form).then(() => {
this.$modal.msgSuccess(this.form.rollId ? '修改成功' : '新增成功')
this.open = false
this.getList()
this.getStats()
})
})
},
cancel() {
this.open = false
this.reset()
},
reset() {
this.form = { status: 'Offline' }
this.resetForm('form')
},
statusLabel(status) {
const map = { Online: '在线', Standby: '备用', Offline: '离线', Scrapped: '报废' }
return map[status] || status
},
// 当前直径接近最小直径时高亮警告
isDiaLow(row) {
if (!row.currentDia || !row.minDia) return false
return Number(row.currentDia) - Number(row.minDia) < 5
}
}
}
</script>
<style scoped>
/* ─── 调色板(金属灰工业风) ─────────────────────────────────── */
/* 主背景 #f4f5f7 卡片底 #fff 边框 #dcdee0 文字主 #1f2329 文字副 #646a73 */
/* 在线=深绿 #0a7c42 备用=深琥珀 #8b5c00 离线=钢灰 #5f6368 报废=深红 #a61c00 */
.roll-overview { background: #f4f5f7; }
.mb16 { margin-bottom: 16px; }
/* ─── 统计看板 ──────────────────────────────────────────────── */
.stat-panel {
display: flex;
background: #fff;
border: 1px solid #dcdee0;
border-radius: 4px;
padding: 0;
overflow: hidden;
}
.stat-item {
flex: 1;
display: flex;
align-items: center;
padding: 18px 20px;
gap: 14px;
position: relative;
}
.stat-divider {
position: absolute;
right: 0; top: 16px; bottom: 16px;
width: 1px;
background: #e4e6ea;
}
.stat-icon-wrap {
width: 42px; height: 42px;
border-radius: 4px;
display: flex; align-items: center; justify-content: center;
font-size: 20px;
flex-shrink: 0;
}
.total-icon { background: #edf0f3; color: #3d4b5c; }
.online-icon { background: #e8f5ef; color: #0a7c42; }
.standby-icon { background: #fdf3e3; color: #8b5c00; }
.offline-icon { background: #f0f1f2; color: #5f6368; }
.scrapped-icon { background: #fdecea; color: #a61c00; }
.stat-body { display: flex; flex-direction: column; }
.stat-num {
font-size: 26px;
font-weight: 700;
line-height: 1;
color: #1f2329;
font-variant-numeric: tabular-nums;
letter-spacing: -0.5px;
}
.online-num { color: #0a7c42; }
.standby-num { color: #8b5c00; }
.offline-num { color: #5f6368; }
.scrapped-num { color: #a61c00; }
.stat-label {
font-size: 12px;
color: #8f9099;
margin-top: 4px;
letter-spacing: 1px;
}
/* ─── 表格内样式 ─────────────────────────────────────────────── */
.roll-no-text {
font-family: 'Consolas', 'Courier New', monospace;
font-weight: 600;
color: #1f2329;
letter-spacing: .3px;
}
/* 辊型标签 */
.roll-type-tag {
display: inline-block;
padding: 1px 8px;
border-radius: 2px;
font-size: 11px;
font-weight: 600;
letter-spacing: .3px;
}
.wr-tag { background: #e8edf5; color: #2b4c8c; border: 1px solid #c5d0e8; }
.br-tag { background: #f0eae0; color: #6b4c1e; border: 1px solid #dccfb8; }
/* 状态指示 */
.status-dot-wrap {
display: inline-flex; align-items: center; gap: 5px;
font-size: 12px; font-weight: 500;
}
.status-dot {
width: 7px; height: 7px;
border-radius: 50%;
display: inline-block;
flex-shrink: 0;
}
.status-Online { color: #0a7c42; }
.status-Online .status-dot { background: #0a7c42; box-shadow: 0 0 0 2px #c8ead8; }
.status-Standby { color: #8b5c00; }
.status-Standby .status-dot { background: #d4860a; box-shadow: 0 0 0 2px #f5e2b8; }
.status-Offline { color: #5f6368; }
.status-Offline .status-dot { background: #9aa0a6; box-shadow: 0 0 0 2px #e0e2e4; }
.status-Scrapped { color: #a61c00; }
.status-Scrapped .status-dot { background: #c5221f; box-shadow: 0 0 0 2px #f5c6c4; }
/* 直径接近下限警告 */
.warn-text { color: #a61c00; font-weight: 600; }
/* 封闭按钮 */
.scrap-btn { color: #8b5c00 !important; }
/* 删除按钮单独着色 */
.del-btn { color: #c5221f !important; }
</style>

View File

@@ -0,0 +1,852 @@
<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>
<!-- 可用轧辊离线 -->
<el-card shadow="never" class="roll-table-card top-row__aside">
<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="asideTableHeight" style="width:100%">
<el-table-column label="辊型" align="center" prop="rollType" width="58">
<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="110" show-overflow-tooltip />
<el-table-column label="辊径(mm)" align="center" width="82">
<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="70" />
<el-table-column label="磨削次数" align="center" prop="grindCount" width="70" />
</el-table>
</el-card>
</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="90" />
<el-table-column label="上工作辊" align="center" prop="upperWrNo" width="110" />
<el-table-column label="下工作辊" align="center" prop="lowerWrNo" width="110" />
<el-table-column label="上支撑辊" align="center" prop="upperBrNo" width="110" />
<el-table-column label="下支撑辊" align="center" prop="lowerBrNo" width="110" />
<el-table-column label="工作长度(m)" align="center" prop="workLength" width="110">
<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="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, getWorkLength } from '@/api/mes/roll/rollChange'
import { listRollStandby, addRollStandby, delRollStandby, clearRollStandby } from '@/api/mes/roll/rollStandby'
import { listRollOptions, listRollInfo } from '@/api/mes/roll/rollInfo'
/**
* 单元格组件:只显示数值,不展示辊号副文本和删除图标
* 删除逻辑由外层 div 的 click 事件处理,保证所有单元格高度一致
*/
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))
}
}
export default {
name: 'WorkingRoll',
components: { ParamCell },
data() {
return {
current: { '1#': {}, '2#': {} },
loadingCurrent: { '1#': false, '2#': false },
standbyList: { '1#': [], '2#': [] },
loadingStandby: { '1#': false, '2#': false },
/** 当前在机轧辊实时工作长度m */
workLength: { '1#': null, '2#': null },
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,
asideTableHeight: 400,
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 }
},
{
label: '工作长度(m)', group: 'pl', rollType: null, position: null,
cur1: { val: this.workLength['1#'] }, cur2: { val: this.workLength['2#'] },
sb1: { val: null }, sb2: { val: null }
}
]
}
},
created() {
this.loadAll()
this.loadRollOptions()
this.loadRollInfoMap()
},
mounted() {
this.$nextTick(this.syncAsideHeight)
window.addEventListener('resize', this.syncAsideHeight)
},
beforeDestroy() {
window.removeEventListener('resize', this.syncAsideHeight)
},
methods: {
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.loadWorkLength(s)
})
this.loadHistory()
this.loadOfflineRolls()
},
loadWorkLength(standNo) {
getWorkLength(standNo).then(res => {
this.$set(this.workLength, standNo, res.data != null ? res.data : null)
}).catch(() => {})
},
loadCurrent(standNo) {
this.$set(this.loadingCurrent, standNo, true)
getCurrentRolls(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(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).then(res => {
this.historyList = res.rows || []
this.historyTotal = res.total || 0
this.historyLoading = false
}).catch(() => { this.historyLoading = false })
},
loadRollOptions() {
// 下批辊选择只显示离线Offline状态的轧辊
listRollOptions('WR', 'Offline').then(res => { this.wrOptions = res.data || [] })
listRollOptions('BR', 'Offline').then(res => { this.brOptions = res.data || [] })
},
loadRollInfoMap() {
listRollInfo({ 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),
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(standNo).finally(() => {
this.loadCurrent(standNo)
this.loadStandby(standNo)
this.loadWorkLength(standNo)
this.loadHistory()
this.loadOfflineRolls()
})
}).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).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(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({ status: 'Offline', pageNum: 1, pageSize: 30 }).then(res => {
this.offlineRolls = res.rows || []
}).finally(() => {
this.offlineLoading = false
})
},
// 让右侧表格高度 = 左侧卡片 body 区域高度
syncAsideHeight() {
const el = this.$refs.mainTable && this.$refs.mainTable.$el
if (!el) return
// el-table 的 $el 就是 .el-table 根节点,取其实际渲染高度
const h = el.offsetHeight
if (h > 0) this.asideTableHeight = h
}
}
}
</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; }
.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>