Files
klp-oa/klp-ui/src/views/micro/pages/dr/components/Actual.vue
wangyu 53a180787b 1完成酸轧轧辊调整
2完成双机架工艺规格串联
3完成双机架计划串联
4完成双机架wip快捷录入检索
5完成双机架实绩串联
2026-05-19 17:13:37 +08:00

469 lines
15 KiB
Vue

<template>
<div class="actual-page">
<div class="body-wrap">
<!-- 实绩表格 -->
<div class="table-card">
<div class="card-header">
<span class="card-title">双机架实绩</span>
<el-radio-group v-model="query.planStatus" size="mini" @change="onStatusChange">
<el-radio-button label="">全部</el-radio-button>
<el-radio-button label="0">准备</el-radio-button>
<el-radio-button label="1">上线</el-radio-button>
<el-radio-button label="2">生产中</el-radio-button>
<el-radio-button label="3">生产完成</el-radio-button>
</el-radio-group>
<el-button size="mini" icon="el-icon-refresh" style="margin-left:8px" @click="loadList">刷新</el-button>
</div>
<el-table
v-loading="loading"
:data="list"
size="mini"
border
highlight-current-row
:height="tableHeight"
style="width:100%"
@row-click="handleRowClick"
>
<el-table-column type="index" width="40" align="center" />
<el-table-column label="计划号" prop="planNo" width="150" show-overflow-tooltip />
<el-table-column label="入场钢卷号" prop="enterCoilNo" min-width="120" show-overflow-tooltip>
<template slot-scope="{ row }">{{ row.enterCoilNo || row.inMatNo || '—' }}</template>
</el-table-column>
<el-table-column label="出口钢卷号" prop="currentCoilNo" min-width="120" show-overflow-tooltip>
<template slot-scope="{ row }">{{ row.currentCoilNo || '—' }}</template>
</el-table-column>
<el-table-column label="合金牌号" prop="alloyNo" width="100" show-overflow-tooltip>
<template slot-scope="{ row }">{{ row.alloyNo || '—' }}</template>
</el-table-column>
<el-table-column label="计划状态" width="80" align="center">
<template slot-scope="{ row }">
<el-tag :type="planStatusType(row.planStatus)" size="mini">
{{ planStatusLabel(row.planStatus) }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="生产状态" width="80" align="center">
<template slot-scope="{ row }">
<el-tag :type="prodStatusType(row.prodStatus)" size="mini" effect="plain">
{{ row.prodStatus || '—' }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="来料厚(mm)" width="82" align="right">
<template slot-scope="{ row }">{{ row.inMatThick || '—' }}</template>
</el-table-column>
<el-table-column label="来料宽(mm)" width="82" align="right">
<template slot-scope="{ row }">{{ row.inMatWidth || '—' }}</template>
</el-table-column>
<el-table-column label="来料重(t)" width="76" align="right">
<template slot-scope="{ row }">{{ row.inMatWeight || '—' }}</template>
</el-table-column>
<el-table-column label="成品厚(mm)" width="82" align="right">
<template slot-scope="{ row }">
<span class="accent-val">{{ row.outThick || '—' }}</span>
</template>
</el-table-column>
<el-table-column label="道次数" prop="passCount" width="60" align="center">
<template slot-scope="{ row }">{{ row.passCount || '—' }}</template>
</el-table-column>
<el-table-column label="工艺方案" prop="recipeNo" width="110" show-overflow-tooltip>
<template slot-scope="{ row }">{{ row.recipeNo || '—' }}</template>
</el-table-column>
<el-table-column label="创建时间" width="148">
<template slot-scope="{ row }">{{ formatDate(row.createTime) }}</template>
</el-table-column>
<el-table-column label="创建人" prop="createBy" width="80" align="center">
<template slot-scope="{ row }">{{ row.createBy || '—' }}</template>
</el-table-column>
<el-table-column label="备注" prop="remark" min-width="100" show-overflow-tooltip>
<template slot-scope="{ row }">{{ row.remark || '—' }}</template>
</el-table-column>
</el-table>
<div class="table-footer">
<el-pagination
small
layout="total, sizes, prev, pager, next"
:page-sizes="[20, 50, 100]"
:total="total"
:page-size="query.pageSize"
:current-page="query.pageNum"
@size-change="handleSizeChange"
@current-change="handlePageChange"
/>
</div>
</div>
<!-- 右侧面板 -->
<div class="side-panel">
<!-- 查找 -->
<div class="panel-block">
<div class="panel-title">查找</div>
<div class="filter-item">
<span class="filter-label">钢卷号</span>
<el-input
v-model="query.inMatNo"
size="mini" clearable
placeholder="入场/出口钢卷号"
style="width:100%"
/>
</div>
<div class="filter-item">
<span class="filter-label">开始时间</span>
<el-date-picker
v-model="query.createStartTime"
type="datetime"
size="mini"
style="width:100%"
value-format="yyyy-MM-dd HH:mm:ss"
placeholder="创建开始时间"
/>
</div>
<div class="filter-item">
<span class="filter-label">结束时间</span>
<el-date-picker
v-model="query.createEndTime"
type="datetime"
size="mini"
style="width:100%"
value-format="yyyy-MM-dd HH:mm:ss"
placeholder="创建结束时间"
/>
</div>
<div class="filter-actions">
<el-button type="primary" size="mini" :loading="loading" @click="handleSearch">查找</el-button>
<el-button size="mini" @click="handleReset">重置</el-button>
</div>
</div>
<!-- 选中行详情 -->
<div v-if="selectedRow" class="panel-block detail-block">
<div class="panel-title">计划详情</div>
<div class="detail-grid">
<div class="detail-row">
<span class="detail-key">计划号</span>
<span class="detail-val">{{ selectedRow.planNo }}</span>
</div>
<div class="detail-row">
<span class="detail-key">入场卷号</span>
<span class="detail-val">{{ selectedRow.enterCoilNo || selectedRow.inMatNo || '—' }}</span>
</div>
<div class="detail-row">
<span class="detail-key">出口卷号</span>
<span class="detail-val">{{ selectedRow.currentCoilNo || '—' }}</span>
</div>
<div class="detail-row">
<span class="detail-key">合金牌号</span>
<span class="detail-val">{{ selectedRow.alloyNo || '—' }}</span>
</div>
<div class="detail-row">
<span class="detail-key">来料厚</span>
<span class="detail-val accent">{{ selectedRow.inMatThick ? selectedRow.inMatThick + ' mm' : '—' }}</span>
</div>
<div class="detail-row">
<span class="detail-key">来料宽</span>
<span class="detail-val accent">{{ selectedRow.inMatWidth ? selectedRow.inMatWidth + ' mm' : '—' }}</span>
</div>
<div class="detail-row">
<span class="detail-key">来料重</span>
<span class="detail-val accent">{{ selectedRow.inMatWeight ? selectedRow.inMatWeight + ' t' : '—' }}</span>
</div>
<div class="detail-row">
<span class="detail-key">来料长</span>
<span class="detail-val">{{ selectedRow.inMatLength ? selectedRow.inMatLength + ' m' : '—' }}</span>
</div>
<div class="detail-row">
<span class="detail-key">成品厚</span>
<span class="detail-val accent">{{ selectedRow.outThick ? selectedRow.outThick + ' mm' : '—' }}</span>
</div>
<div class="detail-row">
<span class="detail-key">道次数</span>
<span class="detail-val">{{ selectedRow.passCount || '—' }}</span>
</div>
<div class="detail-row">
<span class="detail-key">工艺方案</span>
<span class="detail-val">{{ selectedRow.recipeNo || '—' }}</span>
</div>
<div class="detail-row">
<span class="detail-key">计划状态</span>
<span class="detail-val">
<el-tag :type="planStatusType(selectedRow.planStatus)" size="mini">
{{ planStatusLabel(selectedRow.planStatus) }}
</el-tag>
</span>
</div>
<div class="detail-row">
<span class="detail-key">生产状态</span>
<span class="detail-val">
<el-tag :type="prodStatusType(selectedRow.prodStatus)" size="mini" effect="plain">
{{ selectedRow.prodStatus || '—' }}
</el-tag>
</span>
</div>
<div class="detail-row">
<span class="detail-key">创建人</span>
<span class="detail-val">{{ selectedRow.createBy || '—' }}</span>
</div>
<div class="detail-row">
<span class="detail-key">创建时间</span>
<span class="detail-val">{{ formatDate(selectedRow.createTime) }}</span>
</div>
<div v-if="selectedRow.remark" class="detail-row">
<span class="detail-key">备注</span>
<span class="detail-val">{{ selectedRow.remark }}</span>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { listDrActualPage } from '@/api/wms/drMill'
const PLAN_STATUS = {
'0': { label: '准备', type: 'info' },
'1': { label: '上线', type: 'primary' },
'2': { label: '生产中', type: 'warning' },
'3': { label: '生产完成', type: 'success' },
}
const PROD_STATUS_TYPE = {
Idle: 'info',
Rolling: 'warning',
NextCoil: 'primary',
Done: 'success',
Error: 'danger',
}
export default {
name: 'DrActual',
data() {
return {
loading: false,
list: [],
total: 0,
selectedRow: null,
query: {
pageNum: 1,
pageSize: 50,
planStatus: '',
inMatNo: '',
createStartTime: '',
createEndTime: '',
},
}
},
computed: {
tableHeight() { return 'calc(100vh - 210px)' }
},
created() { this.loadList() },
methods: {
loadList() {
this.loading = true
const params = {
...this.query,
planStatus: this.query.planStatus || undefined,
inMatNo: this.query.inMatNo || undefined,
createStartTime: this.query.createStartTime || undefined,
createEndTime: this.query.createEndTime || undefined,
}
listDrActualPage(params)
.then(res => {
this.list = res.rows || []
this.total = res.total || 0
})
.finally(() => { this.loading = false })
},
handlePageChange(page) {
this.query.pageNum = page
this.loadList()
},
handleSizeChange(size) {
this.query.pageSize = size
this.query.pageNum = 1
this.loadList()
},
onStatusChange() {
this.query.pageNum = 1
this.loadList()
},
handleRowClick(row) {
this.selectedRow = (this.selectedRow && this.selectedRow.planId === row.planId) ? null : row
},
handleSearch() {
this.query.pageNum = 1
this.loadList()
},
handleReset() {
this.query.planStatus = ''
this.query.inMatNo = ''
this.query.createStartTime = ''
this.query.createEndTime = ''
this.query.pageNum = 1
this.selectedRow = null
this.loadList()
},
planStatusLabel(s) { return (PLAN_STATUS[s] || { label: s || '—' }).label },
planStatusType(s) { return (PLAN_STATUS[s] || { type: '' }).type },
prodStatusType(s) { return PROD_STATUS_TYPE[s] || 'info' },
formatDate(v) {
if (!v) return '—'
return String(v).replace('T', ' ').substring(0, 19)
},
}
}
</script>
<style scoped lang="scss">
.actual-page {
display: flex;
flex-direction: column;
height: 100%;
background: #f5f7fa;
padding: 10px 12px;
box-sizing: border-box;
overflow: hidden;
}
.body-wrap {
flex: 1;
min-height: 0;
display: flex;
gap: 8px;
overflow: hidden;
}
/* ── 表格卡片 ── */
.table-card {
flex: 1;
min-width: 0;
background: #fff;
border: 1px solid #e4e7ed;
border-radius: 4px;
display: flex;
flex-direction: column;
overflow: hidden;
box-shadow: 0 1px 4px rgba(0,0,0,.04);
}
.card-header {
display: flex;
align-items: center;
padding: 10px 14px;
border-bottom: 1px solid #e4e7ed;
flex-shrink: 0;
gap: 8px;
}
.card-title {
font-size: 13px;
font-weight: 600;
color: #303133;
flex-shrink: 0;
}
.table-footer {
display: flex;
justify-content: flex-end;
padding: 6px 10px;
border-top: 1px solid #e4e7ed;
background: #fafafa;
flex-shrink: 0;
}
.accent-val {
font-family: 'Courier New', monospace;
font-weight: 600;
color: #409eff;
}
/* ── 侧边面板 ── */
.side-panel {
width: 220px;
flex-shrink: 0;
display: flex;
flex-direction: column;
gap: 8px;
overflow-y: auto;
&::-webkit-scrollbar { width: 4px; }
&::-webkit-scrollbar-thumb { background: #dcdfe6; border-radius: 2px; }
}
.panel-block {
background: #fff;
border: 1px solid #e4e7ed;
border-radius: 4px;
padding: 12px;
box-shadow: 0 1px 4px rgba(0,0,0,.04);
}
.panel-title {
font-size: 13px;
font-weight: 600;
color: #303133;
padding-bottom: 8px;
border-bottom: 1px solid #ebeef5;
margin-bottom: 10px;
}
.filter-item { margin-bottom: 10px; }
.filter-label {
display: block;
font-size: 11px;
color: #909399;
margin-bottom: 4px;
}
.filter-actions {
display: flex;
gap: 8px;
margin-top: 4px;
}
/* ── 详情 ── */
.detail-grid {
display: flex;
flex-direction: column;
gap: 6px;
}
.detail-row {
display: flex;
justify-content: space-between;
align-items: flex-start;
gap: 4px;
}
.detail-key {
font-size: 11px;
color: #909399;
flex-shrink: 0;
padding-top: 2px;
}
.detail-val {
font-size: 12px;
color: #303133;
text-align: right;
word-break: break-all;
&.accent {
color: #409eff;
font-weight: 600;
font-family: 'Courier New', monospace;
}
}
</style>