同步规程同步代码和录入监测代码
This commit is contained in:
571
klp-ui/src/views/wms/processSpec/coilSpecSync.vue
Normal file
571
klp-ui/src/views/wms/processSpec/coilSpecSync.vue
Normal file
@@ -0,0 +1,571 @@
|
||||
<template>
|
||||
<div class="page-wrap">
|
||||
|
||||
<!-- 搜索栏 -->
|
||||
<div class="search-bar">
|
||||
<el-form :model="query" inline size="small">
|
||||
<el-form-item label="入场卷号">
|
||||
<el-input v-model="query.enterCoilNo" placeholder="模糊查询" clearable style="width:150px"
|
||||
@keyup.enter.native="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="当前卷号">
|
||||
<el-input v-model="query.currentCoilNo" placeholder="模糊查询" clearable style="width:150px"
|
||||
@keyup.enter.native="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="材料">
|
||||
<el-input v-model="query.material" placeholder="模糊查询" clearable style="width:120px"
|
||||
@keyup.enter.native="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="规程">
|
||||
<el-input v-model="query.specCode" placeholder="编码或名称" clearable style="width:130px"
|
||||
@keyup.enter.native="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="钢种">
|
||||
<el-input v-model="query.grade" placeholder="当前页筛选" clearable style="width:110px"
|
||||
@keyup.enter.native="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="质量状态">
|
||||
<el-select v-model="query.qualityStatus" style="width:110px" clearable>
|
||||
<el-option label="合格" value="合格" />
|
||||
<el-option label="待判" value="待判" />
|
||||
<el-option label="不合格" value="不合格" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" @click="handleQuery">查询</el-button>
|
||||
<el-button icon="el-icon-refresh" @click="handleReset">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<!-- 整体统计条 -->
|
||||
<div class="stat-strip" v-if="overallStats.total > 0 || list.length">
|
||||
<div class="stat-tile">
|
||||
<span class="st-num">{{ overallStats.synced }}</span>
|
||||
<span class="st-label">已同步</span>
|
||||
</div>
|
||||
<div class="stat-div" />
|
||||
<div class="stat-tile">
|
||||
<span class="st-num warn">{{ overallStats.unsynced }}</span>
|
||||
<span class="st-label">未同步</span>
|
||||
</div>
|
||||
<div class="stat-div" />
|
||||
<div class="stat-tile">
|
||||
<span class="st-num muted">{{ overallStats.movedOn }}</span>
|
||||
<span class="st-label">已流转</span>
|
||||
</div>
|
||||
<div class="stat-div" />
|
||||
<div class="stat-tile">
|
||||
<span class="st-num info">{{ overallStats.total }}</span>
|
||||
<span class="st-label">总计</span>
|
||||
</div>
|
||||
<div class="stat-tip">当前页 {{ list.length }} 条 / 共 {{ total }} 条</div>
|
||||
</div>
|
||||
|
||||
<!-- 表格 -->
|
||||
<div class="table-area">
|
||||
<!-- Tab 切换 + 批量同步按钮 -->
|
||||
<div class="toolbar">
|
||||
<div class="sync-tabs">
|
||||
<span
|
||||
v-for="tab in syncTabs" :key="tab.value"
|
||||
class="sync-tab"
|
||||
:class="{ active: query.syncStatus === tab.value }"
|
||||
@click="switchTab(tab.value)">
|
||||
{{ tab.label }}
|
||||
</span>
|
||||
</div>
|
||||
<el-button type="primary" size="small" :disabled="!batchable.length"
|
||||
:loading="batchLoading" @click="handleBatchSync" style="margin-left:auto">
|
||||
<i class="el-icon-s-promotion" /> 批量同步
|
||||
<span v-if="batchable.length" class="btn-badge">{{ batchable.length }}</span>
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<el-table v-loading="loading" :data="filteredList" size="small" border
|
||||
:header-cell-style="{ background: '#fafafa', color: '#606266', fontWeight: '500' }"
|
||||
style="width:100%;margin-top:10px"
|
||||
@selection-change="onSelect">
|
||||
|
||||
<el-table-column type="selection" width="40" align="center" :selectable="canSelect" />
|
||||
|
||||
<!-- ── L3 WMS 字段 ── -->
|
||||
<el-table-column label="入场卷号" prop="enterCoilNo" min-width="148" fixed show-overflow-tooltip>
|
||||
<template slot-scope="{ row }">
|
||||
<span class="coil-no">{{ row.enterCoilNo || '—' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="当前钢卷号" prop="currentCoilNo" min-width="135" show-overflow-tooltip>
|
||||
<template slot-scope="{ row }">{{ row.currentCoilNo || '—' }}</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="供应商卷号" prop="supplierCoilNo" min-width="130" show-overflow-tooltip>
|
||||
<template slot-scope="{ row }">
|
||||
<span v-if="row.supplierCoilNo">{{ row.supplierCoilNo }}</span>
|
||||
<span v-else class="dim">—</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="净重(kg)" prop="netWeight" width="88" align="right">
|
||||
<template slot-scope="{ row }">
|
||||
<span v-if="row.netWeight != null">{{ row.netWeight }}</span>
|
||||
<span v-else class="dim">—</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="实测厚(mm)" prop="actualThickness" width="95" align="right">
|
||||
<template slot-scope="{ row }">
|
||||
<span v-if="row.actualThickness != null">{{ row.actualThickness }}</span>
|
||||
<span v-else class="dim">—</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="实测宽(mm)" prop="actualWidth" width="95" align="right">
|
||||
<template slot-scope="{ row }">
|
||||
<span v-if="row.actualWidth != null">{{ row.actualWidth }}</span>
|
||||
<span v-else class="dim">—</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="质量状态" prop="qualityStatus" width="88" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<el-tag v-if="row.qualityStatus" size="mini" :type="qualityTagType(row.qualityStatus)" effect="plain">
|
||||
{{ row.qualityStatus }}
|
||||
</el-tag>
|
||||
<span v-else class="dim">—</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="材质" prop="material" width="90" show-overflow-tooltip>
|
||||
<template slot-scope="{ row }">
|
||||
<span v-if="row.material">{{ row.material }}</span>
|
||||
<span v-else class="dim">—</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="规格" prop="specification" width="110" show-overflow-tooltip>
|
||||
<template slot-scope="{ row }">
|
||||
<span v-if="row.specification">{{ row.specification }}</span>
|
||||
<span v-else class="dim">—</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="上线时间" prop="onlineTime" width="148" show-overflow-tooltip>
|
||||
<template slot-scope="{ row }">
|
||||
<span v-if="row.onlineTime" class="time-val">{{ fmtTime(row.onlineTime) }}</span>
|
||||
<span v-else class="dim">—</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="下线时间" prop="offlineTime" width="148" show-overflow-tooltip>
|
||||
<template slot-scope="{ row }">
|
||||
<span v-if="row.offlineTime" class="time-val">{{ fmtTime(row.offlineTime) }}</span>
|
||||
<span v-else class="dim">—</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- ── L2 Oracle 字段 ── -->
|
||||
<el-table-column label="工艺代码" prop="processCode" width="108" show-overflow-tooltip>
|
||||
<template slot-scope="{ row }">
|
||||
<span v-if="row.processCode" class="process-code">{{ row.processCode }}</span>
|
||||
<span v-else-if="!row.l2Found" class="dim">无L2</span>
|
||||
<span v-else class="dim">—</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="钢种" prop="grade" width="100" show-overflow-tooltip>
|
||||
<template slot-scope="{ row }">
|
||||
<span v-if="row.grade" class="grade-tag">{{ row.grade }}</span>
|
||||
<span v-else class="dim">—</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="来料厚×宽(mm)" width="135" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<template v-if="row.entryThick != null || row.entryWidth != null">
|
||||
<span :class="dimClass(row.entryThick, row.matchEntryThickMin, row.matchEntryThickMax)">{{ fmt(row.entryThick) }}</span>
|
||||
<span class="spec-x">×</span>
|
||||
<span :class="dimClass(row.entryWidth, row.matchEntryWidthMin, row.matchEntryWidthMax)">{{ fmt(row.entryWidth) }}</span>
|
||||
</template>
|
||||
<span v-else-if="!row.l2Found" class="dim">无L2</span>
|
||||
<span v-else class="dim">—</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="出口厚×宽(mm)" width="135" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<template v-if="row.exitThick != null || row.exitWidth != null">
|
||||
<span :class="dimClass(row.exitThick, row.matchExitThickMin, row.matchExitThickMax)">{{ fmt(row.exitThick) }}</span>
|
||||
<span class="spec-x">×</span>
|
||||
<span :class="dimClass(row.exitWidth, row.matchExitWidthMin, row.matchExitWidthMax)">{{ fmt(row.exitWidth) }}</span>
|
||||
</template>
|
||||
<span v-else class="dim">—</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- ── 已绑规程 ── -->
|
||||
<el-table-column label="已绑规程" min-width="180" show-overflow-tooltip>
|
||||
<template slot-scope="{ row }">
|
||||
<template v-if="row.syncStatus === 'synced'">
|
||||
<i v-if="isDeviated(row)" class="el-icon-warning deviation-icon" title="实际值超出规程设定范围" />
|
||||
<span class="spec-name bound">{{ row.specName || row.specCode || '—' }}</span>
|
||||
<span v-if="row.versionCode" class="ver-tag">{{ row.versionCode }}</span>
|
||||
</template>
|
||||
<span v-else class="dim">—</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- ── 推荐规程 ── -->
|
||||
<el-table-column label="推荐规程" min-width="200" show-overflow-tooltip>
|
||||
<template slot-scope="{ row }">
|
||||
<template v-if="row.syncStatus !== 'synced' && row.candidateSpecCode">
|
||||
<span class="rec-badge">推荐</span>
|
||||
<span class="spec-name candidate">{{ row.candidateSpecName || row.candidateSpecCode }}</span>
|
||||
<span v-if="row.candidateVersionCode" class="ver-tag candidate-ver">{{ row.candidateVersionCode }}</span>
|
||||
</template>
|
||||
<span v-else class="dim">—</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="规程状态" width="100" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<div style="display:flex;flex-direction:column;align-items:center;gap:3px">
|
||||
<el-tag v-if="row.syncStatus === 'synced'" type="success" size="mini" effect="plain">已同步</el-tag>
|
||||
<el-tag v-else-if="row.candidateVersionId" type="warning" size="mini" effect="plain">可同步</el-tag>
|
||||
<el-tag v-else type="info" size="mini" effect="plain">无规程</el-tag>
|
||||
<el-tag v-if="row.movedOn" type="info" size="mini" effect="dark"
|
||||
style="font-size:10px;padding:0 4px;height:14px;line-height:14px">已流转</el-tag>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="操作" width="64" align="center" fixed="right">
|
||||
<template slot-scope="{ row }">
|
||||
<el-button v-if="row.syncStatus === 'unsynced' && row.candidateVersionId"
|
||||
type="text" size="mini" style="color:#e6a23c"
|
||||
:loading="row._syncing" @click="handleSyncOne(row)">同步</el-button>
|
||||
<span v-else class="dim">—</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination v-show="total > 0" :total="total"
|
||||
:page.sync="query.pageNum" :limit.sync="query.pageSize"
|
||||
:page-sizes="[20, 40, 100]"
|
||||
@pagination="loadData" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getCoilSyncPageList, syncCoilSpec } from '@/api/wms/processSpecVersion'
|
||||
|
||||
export default {
|
||||
name: 'CoilSpecSync',
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
batchLoading: false,
|
||||
list: [],
|
||||
total: 0,
|
||||
selected: [],
|
||||
overallStats: { total: 0, synced: 0, unsynced: 0, movedOn: 0 },
|
||||
syncTabs: [
|
||||
{ label: '未同步', value: 'unsynced' },
|
||||
{ label: '全部', value: '' },
|
||||
{ label: '已同步', value: 'synced' }
|
||||
],
|
||||
query: {
|
||||
pageNum: 1,
|
||||
pageSize: 40,
|
||||
enterCoilNo: '',
|
||||
currentCoilNo: '',
|
||||
material: '',
|
||||
specCode: '',
|
||||
grade: '',
|
||||
qualityStatus: '',
|
||||
syncStatus: 'unsynced'
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
filteredList() {
|
||||
const grade = (this.query.grade || '').trim().toLowerCase()
|
||||
if (!grade) return this.list
|
||||
return this.list.filter(r => r.grade && r.grade.toLowerCase().includes(grade))
|
||||
},
|
||||
batchable() {
|
||||
return this.selected.filter(r => r.syncStatus === 'unsynced' && r.candidateVersionId)
|
||||
}
|
||||
},
|
||||
created() { this.loadData() },
|
||||
methods: {
|
||||
loadData() {
|
||||
this.loading = true
|
||||
getCoilSyncPageList({
|
||||
pageNum: this.query.pageNum,
|
||||
pageSize: this.query.pageSize,
|
||||
enterCoilNo: this.query.enterCoilNo || undefined,
|
||||
currentCoilNo: this.query.currentCoilNo || undefined,
|
||||
material: this.query.material || undefined,
|
||||
specCode: this.query.specCode || undefined,
|
||||
qualityStatus: this.query.qualityStatus || undefined,
|
||||
syncStatus: this.query.syncStatus || undefined
|
||||
}).then(res => {
|
||||
const d = res.data || {}
|
||||
this.list = (d.rows || []).map(r => ({ ...r, _syncing: false }))
|
||||
this.total = d.total || 0
|
||||
const os = d.overallStats || {}
|
||||
this.overallStats = {
|
||||
total: os.total || 0,
|
||||
synced: os.synced || 0,
|
||||
unsynced: os.unsynced || 0,
|
||||
movedOn: os.movedOn || 0
|
||||
}
|
||||
}).finally(() => { this.loading = false })
|
||||
},
|
||||
handleQuery() { this.query.pageNum = 1; this.loadData() },
|
||||
switchTab(val) {
|
||||
if (this.query.syncStatus === val) return
|
||||
this.query.syncStatus = val
|
||||
this.query.pageNum = 1
|
||||
this.loadData()
|
||||
},
|
||||
handleReset() {
|
||||
this.query = { pageNum: 1, pageSize: 40, enterCoilNo: '', currentCoilNo: '', material: '', specCode: '', grade: '', qualityStatus: '', syncStatus: 'unsynced' }
|
||||
this.loadData()
|
||||
},
|
||||
onSelect(sel) { this.selected = sel },
|
||||
canSelect(row) { return row.syncStatus === 'unsynced' && !!row.candidateVersionId },
|
||||
isDeviated(row) {
|
||||
if (!row.l2Found) return false
|
||||
return [
|
||||
[row.entryThick, row.matchEntryThickMin, row.matchEntryThickMax],
|
||||
[row.exitThick, row.matchExitThickMin, row.matchExitThickMax],
|
||||
[row.entryWidth, row.matchEntryWidthMin, row.matchEntryWidthMax],
|
||||
[row.exitWidth, row.matchExitWidthMin, row.matchExitWidthMax]
|
||||
].some(([v, mn, mx]) => v != null && mn != null && mx != null && (+v < +mn || +v > +mx))
|
||||
},
|
||||
dimClass(val, min, max) {
|
||||
if (val == null || min == null || max == null) return 'dv'
|
||||
return +val < +min || +val > +max ? 'dv out' : 'dv ok'
|
||||
},
|
||||
qualityTagType(qs) {
|
||||
if (!qs) return 'info'
|
||||
if (qs.includes('合格') || qs === 'PASS') return 'success'
|
||||
if (qs.includes('待判') || qs.includes('HOLD')) return 'warning'
|
||||
return 'danger'
|
||||
},
|
||||
handleSyncOne(row) {
|
||||
if (!row.wmsCoilId) { this.$message.warning('该钢卷在WMS中无记录'); return }
|
||||
if (!row.candidateSpecId || !row.candidateVersionId) { this.$message.warning('无可同步规程'); return }
|
||||
this.$set(row, '_syncing', true)
|
||||
syncCoilSpec([{ coilId: row.wmsCoilId, specId: row.candidateSpecId, versionId: row.candidateVersionId }])
|
||||
.then(() => {
|
||||
this.$message.success('同步成功')
|
||||
// 原地更新行状态,不刷新整页(避免因 unsynced 过滤器导致该行消失)
|
||||
this.$set(row, 'syncStatus', 'synced')
|
||||
this.$set(row, 'specCode', row.candidateSpecCode)
|
||||
this.$set(row, 'specName', row.candidateSpecName)
|
||||
this.$set(row, 'versionCode', row.candidateVersionCode)
|
||||
this.$set(row, 'candidateSpecCode', null)
|
||||
this.$set(row, 'candidateSpecName', null)
|
||||
this.$set(row, 'candidateVersionCode', null)
|
||||
this.$set(row, 'candidateVersionId', null)
|
||||
this.$set(row, 'candidateSpecId', null)
|
||||
})
|
||||
.catch(() => this.$message.error('同步失败'))
|
||||
.finally(() => this.$set(row, '_syncing', false))
|
||||
},
|
||||
handleBatchSync() {
|
||||
const bindings = this.batchable
|
||||
.filter(r => r.wmsCoilId && r.candidateSpecId && r.candidateVersionId)
|
||||
.map(r => ({ coilId: r.wmsCoilId, specId: r.candidateSpecId, versionId: r.candidateVersionId }))
|
||||
if (!bindings.length) return
|
||||
this.batchLoading = true
|
||||
syncCoilSpec(bindings)
|
||||
.then(() => { this.$message.success(`批量同步完成,共 ${bindings.length} 条`); this.selected = []; this.loadData() })
|
||||
.catch(() => this.$message.error('批量同步失败'))
|
||||
.finally(() => { this.batchLoading = false })
|
||||
},
|
||||
fmt(val) { return val == null ? '—' : Number(val).toFixed(2) },
|
||||
fmtTime(val) {
|
||||
if (!val) return '—'
|
||||
const d = new Date(val)
|
||||
if (isNaN(d.getTime())) return String(val)
|
||||
const pad = n => String(n).padStart(2, '0')
|
||||
return `${d.getFullYear()}-${pad(d.getMonth()+1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page-wrap {
|
||||
padding: 16px;
|
||||
background: #f4f6f9;
|
||||
min-height: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* 搜索栏 */
|
||||
.search-bar {
|
||||
background: #fff;
|
||||
border-radius: 6px;
|
||||
padding: 14px 20px 4px;
|
||||
margin-bottom: 10px;
|
||||
box-shadow: 0 1px 4px rgba(0,0,0,.06);
|
||||
}
|
||||
|
||||
/* 当前页统计条 */
|
||||
.stat-strip {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: #fff;
|
||||
border-radius: 6px;
|
||||
padding: 8px 20px;
|
||||
margin-bottom: 10px;
|
||||
box-shadow: 0 1px 4px rgba(0,0,0,.06);
|
||||
font-size: 13px;
|
||||
gap: 4px;
|
||||
}
|
||||
.stat-tile {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 0 12px;
|
||||
}
|
||||
.st-num {
|
||||
font-size: 20px;
|
||||
font-weight: 700;
|
||||
color: #67c23a;
|
||||
line-height: 1;
|
||||
}
|
||||
.st-num.warn { color: #e6a23c; }
|
||||
.st-num.muted { color: #909399; }
|
||||
.st-num.danger { color: #f56c6c; }
|
||||
.st-num.info { color: #409eff; }
|
||||
.st-label { font-size: 12px; color: #606266; }
|
||||
.stat-div { width: 1px; background: #ebeef5; height: 24px; margin: 0 4px; }
|
||||
.stat-tip { margin-left: auto; font-size: 12px; color: #c0c4cc; }
|
||||
|
||||
/* 时间字段 */
|
||||
.time-val { font-size: 12px; color: #606266; font-variant-numeric: tabular-nums; }
|
||||
|
||||
/* 表格区 */
|
||||
.table-area {
|
||||
background: #fff;
|
||||
border-radius: 6px;
|
||||
padding: 16px 20px;
|
||||
box-shadow: 0 1px 4px rgba(0,0,0,.06);
|
||||
}
|
||||
.toolbar { display: flex; align-items: center; gap: 0; }
|
||||
|
||||
/* Tab 切换 */
|
||||
.sync-tabs {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: #f0f2f5;
|
||||
border-radius: 6px;
|
||||
padding: 3px;
|
||||
gap: 2px;
|
||||
}
|
||||
.sync-tab {
|
||||
padding: 4px 18px;
|
||||
font-size: 13px;
|
||||
color: #606266;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
transition: all .18s;
|
||||
user-select: none;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.sync-tab:hover { color: #303133; background: rgba(255,255,255,.6); }
|
||||
.sync-tab.active {
|
||||
background: #fff;
|
||||
color: #409eff;
|
||||
font-weight: 600;
|
||||
box-shadow: 0 1px 4px rgba(0,0,0,.1);
|
||||
}
|
||||
.btn-badge {
|
||||
display: inline-block;
|
||||
background: rgba(255,255,255,.3);
|
||||
border-radius: 10px;
|
||||
padding: 0 6px;
|
||||
font-size: 11px;
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
/* 卷号 */
|
||||
.coil-no {
|
||||
font-family: 'Courier New', monospace;
|
||||
font-size: 12.5px;
|
||||
letter-spacing: .3px;
|
||||
}
|
||||
|
||||
/* 规格维度 */
|
||||
.dv { font-variant-numeric: tabular-nums; font-size: 12.5px; color: #303133; }
|
||||
.dv.ok { color: #67c23a; }
|
||||
.dv.out { color: #f56c6c; font-weight: 600; }
|
||||
.spec-x { color: #c0c4cc; margin: 0 2px; font-size: 11px; }
|
||||
|
||||
/* 工艺代码 */
|
||||
.process-code {
|
||||
font-family: 'Courier New', monospace;
|
||||
font-size: 11.5px;
|
||||
color: #606266;
|
||||
background: #f5f7fa;
|
||||
padding: 1px 4px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
/* 钢种 */
|
||||
.grade-tag {
|
||||
display: inline-block;
|
||||
padding: 1px 6px;
|
||||
border-radius: 3px;
|
||||
background: #ecf5ff;
|
||||
color: #409eff;
|
||||
font-size: 11px;
|
||||
border: 1px solid #d9ecff;
|
||||
}
|
||||
|
||||
/* 规程 / 版本 */
|
||||
.spec-name { font-weight: 500; font-size: 12.5px; }
|
||||
.spec-name.bound { color: #67c23a; }
|
||||
.spec-name.candidate { color: #e6a23c; }
|
||||
.ver-tag {
|
||||
display: inline-block;
|
||||
margin-left: 5px;
|
||||
padding: 0 5px;
|
||||
height: 18px;
|
||||
line-height: 18px;
|
||||
border-radius: 2px;
|
||||
background: #f0f9eb;
|
||||
color: #67c23a;
|
||||
font-size: 11px;
|
||||
border: 1px solid #c2e7b0;
|
||||
}
|
||||
.ver-tag.candidate-ver {
|
||||
background: #fdf6ec;
|
||||
color: #e6a23c;
|
||||
border-color: #f5dab1;
|
||||
}
|
||||
|
||||
.deviation-icon { color: #f56c6c; margin-right: 4px; font-size: 13px; }
|
||||
.rec-badge {
|
||||
display: inline-block;
|
||||
margin-right: 5px;
|
||||
padding: 0 5px;
|
||||
height: 16px;
|
||||
line-height: 16px;
|
||||
border-radius: 2px;
|
||||
background: #fdf6ec;
|
||||
color: #e6a23c;
|
||||
font-size: 10px;
|
||||
border: 1px solid #f5dab1;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.dim { color: #c0c4cc; font-size: 12px; }
|
||||
</style>
|
||||
327
klp-ui/src/views/wms/processSpec/coilTypingCheck.vue
Normal file
327
klp-ui/src/views/wms/processSpec/coilTypingCheck.vue
Normal file
@@ -0,0 +1,327 @@
|
||||
<template>
|
||||
<div class="page-wrap">
|
||||
|
||||
<!-- 搜索栏 -->
|
||||
<div class="search-bar">
|
||||
<el-form :model="query" inline size="small">
|
||||
<el-form-item label="入场卷号">
|
||||
<el-input v-model="query.enterCoilNo" placeholder="模糊查询" clearable style="width:150px"
|
||||
@keyup.enter.native="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="当前卷号">
|
||||
<el-input v-model="query.currentCoilNo" placeholder="模糊查询" clearable style="width:150px"
|
||||
@keyup.enter.native="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="操作员">
|
||||
<el-input v-model="query.operatorName" placeholder="模糊查询" clearable style="width:110px"
|
||||
@keyup.enter.native="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="二级实绩">
|
||||
<el-select v-model="query.l2Filter" style="width:100px" clearable>
|
||||
<el-option label="全部" value="" />
|
||||
<el-option label="已有实绩" value="hasL2" />
|
||||
<el-option label="暂无实绩" value="noL2" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" @click="handleQuery">查询</el-button>
|
||||
<el-button icon="el-icon-refresh" @click="handleReset">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
<!-- 统计条 -->
|
||||
<div class="stat-strip" v-if="list.length">
|
||||
<div class="stat-tile">
|
||||
<span class="st-num danger">{{ pageStats.hasL2 }}</span>
|
||||
<span class="st-label">二级已实绩</span>
|
||||
</div>
|
||||
<div class="stat-div" />
|
||||
<div class="stat-tile">
|
||||
<span class="st-num muted">{{ pageStats.noL2 }}</span>
|
||||
<span class="st-label">暂无实绩</span>
|
||||
</div>
|
||||
<div class="stat-tip">当前页 {{ list.length }} 条(共 {{ total }} 条待录入)</div>
|
||||
</div>
|
||||
|
||||
<!-- 表格 -->
|
||||
<div class="table-area">
|
||||
<el-table v-loading="loading" :data="filteredList" size="small" border
|
||||
:header-cell-style="{ background: '#fafafa', color: '#606266', fontWeight: '500' }"
|
||||
style="width:100%;margin-top:0">
|
||||
|
||||
<!-- 入场卷号 -->
|
||||
<el-table-column label="入场卷号" prop="enterCoilNo" min-width="148" fixed show-overflow-tooltip>
|
||||
<template slot-scope="{ row }">
|
||||
<span class="coil-no">{{ row.enterCoilNo || '—' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 当前卷号 -->
|
||||
<el-table-column label="当前钢卷号" prop="currentCoilNo" min-width="135" show-overflow-tooltip>
|
||||
<template slot-scope="{ row }">{{ row.currentCoilNo || '—' }}</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 供应商卷号 -->
|
||||
<el-table-column label="供应商卷号" prop="supplierCoilNo" min-width="130" show-overflow-tooltip>
|
||||
<template slot-scope="{ row }">
|
||||
<span v-if="row.supplierCoilNo">{{ row.supplierCoilNo }}</span>
|
||||
<span v-else class="dim">—</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 物料名称 -->
|
||||
<el-table-column label="物料名称" prop="itemName" min-width="140" show-overflow-tooltip>
|
||||
<template slot-scope="{ row }">
|
||||
<span v-if="row.itemName">{{ row.itemName }}</span>
|
||||
<span v-else class="dim">—</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 材质 -->
|
||||
<el-table-column label="材质" prop="material" width="90" show-overflow-tooltip>
|
||||
<template slot-scope="{ row }">
|
||||
<span v-if="row.material">{{ row.material }}</span>
|
||||
<span v-else class="dim">—</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 规格 -->
|
||||
<el-table-column label="规格" prop="specification" width="110" show-overflow-tooltip>
|
||||
<template slot-scope="{ row }">
|
||||
<span v-if="row.specification">{{ row.specification }}</span>
|
||||
<span v-else class="dim">—</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 仓库 -->
|
||||
<el-table-column label="仓库" prop="warehouseName" width="110" show-overflow-tooltip>
|
||||
<template slot-scope="{ row }">
|
||||
<span v-if="row.warehouseName">{{ row.warehouseName }}</span>
|
||||
<span v-else class="dim">—</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 扫描时间 -->
|
||||
<el-table-column label="扫描时间" prop="scanTime" width="148" show-overflow-tooltip>
|
||||
<template slot-scope="{ row }">
|
||||
<span v-if="row.scanTime" class="time-val">{{ fmtTime(row.scanTime) }}</span>
|
||||
<span v-else class="dim">—</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 创建时间 -->
|
||||
<el-table-column label="创建时间" prop="createTime" width="148" show-overflow-tooltip>
|
||||
<template slot-scope="{ row }">
|
||||
<span v-if="row.createTime" class="time-val">{{ fmtTime(row.createTime) }}</span>
|
||||
<span v-else class="dim">—</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 操作员 -->
|
||||
<el-table-column label="操作员" prop="operatorName" width="90" show-overflow-tooltip>
|
||||
<template slot-scope="{ row }">
|
||||
<span v-if="row.operatorName">{{ row.operatorName }}</span>
|
||||
<span v-else class="dim">—</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 待操作状态 -->
|
||||
<el-table-column label="待操作状态" width="95" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<el-tag :type="actionStatusType(row.actionStatus)" size="mini" effect="plain">
|
||||
{{ actionStatusLabel(row.actionStatus) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 二级实绩 -->
|
||||
<el-table-column label="二级实绩" width="90" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<el-tag v-if="row.l2Found" type="danger" size="mini" effect="dark">已有实绩</el-tag>
|
||||
<span v-else class="dim">暂无</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 工艺代码 -->
|
||||
<el-table-column label="工艺代码" prop="processCode" width="108" show-overflow-tooltip>
|
||||
<template slot-scope="{ row }">
|
||||
<span v-if="row.processCode" class="process-code">{{ row.processCode }}</span>
|
||||
<span v-else class="dim">—</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 钢种 -->
|
||||
<el-table-column label="钢种" prop="grade" width="100" show-overflow-tooltip>
|
||||
<template slot-scope="{ row }">
|
||||
<span v-if="row.grade" class="grade-tag">{{ row.grade }}</span>
|
||||
<span v-else class="dim">—</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 来料厚×宽 -->
|
||||
<el-table-column label="来料厚×宽(mm)" width="135" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<template v-if="row.entryThick != null || row.entryWidth != null">
|
||||
<span class="dv">{{ fmt(row.entryThick) }}</span>
|
||||
<span class="spec-x">×</span>
|
||||
<span class="dv">{{ fmt(row.entryWidth) }}</span>
|
||||
</template>
|
||||
<span v-else class="dim">—</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 出口厚×宽 -->
|
||||
<el-table-column label="出口厚×宽(mm)" width="135" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<template v-if="row.exitThick != null || row.exitWidth != null">
|
||||
<span class="dv">{{ fmt(row.exitThick) }}</span>
|
||||
<span class="spec-x">×</span>
|
||||
<span class="dv">{{ fmt(row.exitWidth) }}</span>
|
||||
</template>
|
||||
<span v-else class="dim">—</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
</el-table>
|
||||
|
||||
<pagination v-show="total > 0" :total="total"
|
||||
:page.sync="query.pageNum" :limit.sync="query.pageSize"
|
||||
:page-sizes="[20, 40, 100]"
|
||||
@pagination="loadData" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getUntypedPageList } from '@/api/wms/processSpecVersion'
|
||||
|
||||
export default {
|
||||
name: 'CoilTypingCheck',
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
list: [],
|
||||
total: 0,
|
||||
query: {
|
||||
pageNum: 1,
|
||||
pageSize: 40,
|
||||
enterCoilNo: '',
|
||||
currentCoilNo: '',
|
||||
operatorName: '',
|
||||
l2Filter: ''
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
filteredList() {
|
||||
if (!this.query.l2Filter) return this.list
|
||||
if (this.query.l2Filter === 'hasL2') return this.list.filter(r => r.l2Found)
|
||||
if (this.query.l2Filter === 'noL2') return this.list.filter(r => !r.l2Found)
|
||||
return this.list
|
||||
},
|
||||
pageStats() {
|
||||
let hasL2 = 0, noL2 = 0
|
||||
this.list.forEach(r => { r.l2Found ? hasL2++ : noL2++ })
|
||||
return { hasL2, noL2 }
|
||||
}
|
||||
},
|
||||
created() { this.loadData() },
|
||||
methods: {
|
||||
loadData() {
|
||||
this.loading = true
|
||||
getUntypedPageList({
|
||||
pageNum: this.query.pageNum,
|
||||
pageSize: this.query.pageSize,
|
||||
enterCoilNo: this.query.enterCoilNo || undefined,
|
||||
currentCoilNo: this.query.currentCoilNo || undefined,
|
||||
operatorName: this.query.operatorName || undefined
|
||||
}).then(res => {
|
||||
const d = res.data || {}
|
||||
this.list = d.rows || []
|
||||
this.total = d.total || 0
|
||||
}).finally(() => { this.loading = false })
|
||||
},
|
||||
handleQuery() { this.query.pageNum = 1; this.loadData() },
|
||||
handleReset() {
|
||||
this.query = { pageNum: 1, pageSize: 40, enterCoilNo: '', currentCoilNo: '', operatorName: '', l2Filter: '' }
|
||||
this.loadData()
|
||||
},
|
||||
actionStatusType(s) {
|
||||
if (s === 0) return 'info'
|
||||
if (s === 1) return 'warning'
|
||||
return ''
|
||||
},
|
||||
actionStatusLabel(s) {
|
||||
if (s === 0) return '待处理'
|
||||
if (s === 1) return '处理中'
|
||||
return String(s ?? '—')
|
||||
},
|
||||
fmt(val) { return val == null ? '—' : Number(val).toFixed(2) },
|
||||
fmtTime(val) {
|
||||
if (!val) return '—'
|
||||
const d = new Date(val)
|
||||
if (isNaN(d.getTime())) return String(val)
|
||||
const pad = n => String(n).padStart(2, '0')
|
||||
return `${d.getFullYear()}-${pad(d.getMonth()+1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page-wrap {
|
||||
padding: 16px;
|
||||
background: #f4f6f9;
|
||||
min-height: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.search-bar {
|
||||
background: #fff;
|
||||
border-radius: 6px;
|
||||
padding: 14px 20px 4px;
|
||||
margin-bottom: 10px;
|
||||
box-shadow: 0 1px 4px rgba(0,0,0,.06);
|
||||
}
|
||||
|
||||
.stat-strip {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: #fff;
|
||||
border-radius: 6px;
|
||||
padding: 8px 20px;
|
||||
margin-bottom: 10px;
|
||||
box-shadow: 0 1px 4px rgba(0,0,0,.06);
|
||||
font-size: 13px;
|
||||
gap: 4px;
|
||||
}
|
||||
.stat-tile { display: flex; align-items: center; gap: 6px; padding: 0 12px; }
|
||||
.st-num { font-size: 20px; font-weight: 700; color: #67c23a; line-height: 1; }
|
||||
.st-num.danger { color: #f56c6c; }
|
||||
.st-num.muted { color: #909399; }
|
||||
.st-label { font-size: 12px; color: #606266; }
|
||||
.stat-div { width: 1px; background: #ebeef5; height: 24px; margin: 0 4px; }
|
||||
.stat-tip { margin-left: auto; font-size: 12px; color: #c0c4cc; }
|
||||
|
||||
.table-area {
|
||||
background: #fff;
|
||||
border-radius: 6px;
|
||||
padding: 16px 20px;
|
||||
box-shadow: 0 1px 4px rgba(0,0,0,.06);
|
||||
}
|
||||
|
||||
.coil-no { font-family: 'Courier New', monospace; font-size: 12.5px; letter-spacing: .3px; }
|
||||
.time-val { font-size: 12px; color: #606266; font-variant-numeric: tabular-nums; }
|
||||
.process-code {
|
||||
font-family: 'Courier New', monospace; font-size: 11.5px; color: #606266;
|
||||
background: #f5f7fa; padding: 1px 4px; border-radius: 3px;
|
||||
}
|
||||
.grade-tag {
|
||||
display: inline-block; padding: 1px 6px; border-radius: 3px;
|
||||
background: #ecf5ff; color: #409eff; font-size: 11px; border: 1px solid #d9ecff;
|
||||
}
|
||||
.dv { font-variant-numeric: tabular-nums; font-size: 12.5px; color: #303133; }
|
||||
.spec-x { color: #c0c4cc; margin: 0 2px; font-size: 11px; }
|
||||
.dim { color: #c0c4cc; font-size: 12px; }
|
||||
</style>
|
||||
@@ -85,6 +85,88 @@
|
||||
>模板导入</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 匹配条件面板 -->
|
||||
<div class="match-cond-panel" v-if="versionId">
|
||||
<div class="match-cond-header">
|
||||
<span class="match-cond-title"><i class="el-icon-aim" />匹配条件</span>
|
||||
<div class="match-cond-actions">
|
||||
<template v-if="matchCondEditing">
|
||||
<el-button size="mini" @click="cancelMatchCond">取消</el-button>
|
||||
<el-button size="mini" type="primary" :loading="matchCondSaving" @click="saveMatchCond">保存</el-button>
|
||||
</template>
|
||||
<el-button v-else size="mini" icon="el-icon-edit" @click="matchCondEditing = true">编辑</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="match-cond-body">
|
||||
<!-- 只读模式 -->
|
||||
<template v-if="!matchCondEditing">
|
||||
<div class="match-cond-item">
|
||||
<span class="mci-label">来料厚度</span>
|
||||
<span class="mci-val">{{ fmtRange(matchCondForm.matchEntryThickMin, matchCondForm.matchEntryThickMax, 'mm') }}</span>
|
||||
</div>
|
||||
<div class="match-cond-divider" />
|
||||
<div class="match-cond-item">
|
||||
<span class="mci-label">出口厚度</span>
|
||||
<span class="mci-val">{{ fmtRange(matchCondForm.matchExitThickMin, matchCondForm.matchExitThickMax, 'mm') }}</span>
|
||||
</div>
|
||||
<div class="match-cond-divider" />
|
||||
<div class="match-cond-item">
|
||||
<span class="mci-label">来料宽度</span>
|
||||
<span class="mci-val">{{ fmtRange(matchCondForm.matchEntryWidthMin, matchCondForm.matchEntryWidthMax, 'mm') }}</span>
|
||||
</div>
|
||||
<div class="match-cond-divider" />
|
||||
<div class="match-cond-item">
|
||||
<span class="mci-label">出口宽度</span>
|
||||
<span class="mci-val">{{ fmtRange(matchCondForm.matchExitWidthMin, matchCondForm.matchExitWidthMax, 'mm') }}</span>
|
||||
</div>
|
||||
<div class="match-cond-divider" />
|
||||
<div class="match-cond-item">
|
||||
<span class="mci-label">钢种关键字</span>
|
||||
<span class="mci-val">{{ matchCondForm.matchSteelGrade || '—' }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<!-- 编辑模式 -->
|
||||
<template v-else>
|
||||
<div class="match-cond-item">
|
||||
<span class="mci-label">来料厚度</span>
|
||||
<el-input v-model="matchCondForm.matchEntryThickMin" size="small" class="mci-input" placeholder="下限" />
|
||||
<span class="mci-sep">–</span>
|
||||
<el-input v-model="matchCondForm.matchEntryThickMax" size="small" class="mci-input" placeholder="上限" />
|
||||
<span class="mci-unit">mm</span>
|
||||
</div>
|
||||
<div class="match-cond-divider" />
|
||||
<div class="match-cond-item">
|
||||
<span class="mci-label">出口厚度</span>
|
||||
<el-input v-model="matchCondForm.matchExitThickMin" size="small" class="mci-input" placeholder="下限" />
|
||||
<span class="mci-sep">–</span>
|
||||
<el-input v-model="matchCondForm.matchExitThickMax" size="small" class="mci-input" placeholder="上限" />
|
||||
<span class="mci-unit">mm</span>
|
||||
</div>
|
||||
<div class="match-cond-divider" />
|
||||
<div class="match-cond-item">
|
||||
<span class="mci-label">来料宽度</span>
|
||||
<el-input v-model="matchCondForm.matchEntryWidthMin" size="small" class="mci-input" placeholder="下限" />
|
||||
<span class="mci-sep">–</span>
|
||||
<el-input v-model="matchCondForm.matchEntryWidthMax" size="small" class="mci-input" placeholder="上限" />
|
||||
<span class="mci-unit">mm</span>
|
||||
</div>
|
||||
<div class="match-cond-divider" />
|
||||
<div class="match-cond-item">
|
||||
<span class="mci-label">出口宽度</span>
|
||||
<el-input v-model="matchCondForm.matchExitWidthMin" size="small" class="mci-input" placeholder="下限" />
|
||||
<span class="mci-sep">–</span>
|
||||
<el-input v-model="matchCondForm.matchExitWidthMax" size="small" class="mci-input" placeholder="上限" />
|
||||
<span class="mci-unit">mm</span>
|
||||
</div>
|
||||
<div class="match-cond-divider" />
|
||||
<div class="match-cond-item">
|
||||
<span class="mci-label">钢种关键字</span>
|
||||
<el-input v-model="matchCondForm.matchSteelGrade" size="small" style="width:160px" placeholder="如:SPCC、Q345" />
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- DR 道次参数同步提示 -->
|
||||
<el-alert
|
||||
v-if="drSyncLoading"
|
||||
@@ -292,6 +374,7 @@ import * as XLSX from 'xlsx'
|
||||
import { listProcessPlan, addProcessPlan, updateProcessPlan, delProcessPlan } from '@/api/wms/processPlan'
|
||||
import { listProcessPlanParam, addProcessPlanParam, updateProcessPlanParam, delProcessPlanParam } from '@/api/wms/processPlanParam'
|
||||
import { listDrRecipe, listDrRecipeVersions, getDrRecipeVersionDetail } from '@/api/wms/drMill'
|
||||
import { getProcessSpecVersion, updateProcessSpecVersion } from '@/api/wms/processSpecVersion'
|
||||
|
||||
/** 表单内可选段类型(新建/编辑仍支持全部枚举) */
|
||||
const SEGMENT_FORM_OPTIONS = [
|
||||
@@ -367,7 +450,11 @@ export default {
|
||||
importStatus: 'idle', // idle, processing, finished, error
|
||||
importErrorMsg: '',
|
||||
validateLoading: false,
|
||||
importLoading: false
|
||||
importLoading: false,
|
||||
matchCondForm: {},
|
||||
matchCondSaving: false,
|
||||
matchCondEditing: false,
|
||||
_matchCondSnapshot: {}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -514,6 +601,7 @@ export default {
|
||||
this._drSyncAttempted = false // 路由切换时重置,避免重复同步
|
||||
if (this.versionId) {
|
||||
this.loadPlans()
|
||||
this.openMatchCond()
|
||||
}
|
||||
},
|
||||
goBack() { this.$router.go(-1) },
|
||||
@@ -1155,6 +1243,45 @@ export default {
|
||||
this.importErrorMsg = message
|
||||
this.validateLoading = false
|
||||
this.importLoading = false
|
||||
},
|
||||
openMatchCond() {
|
||||
getProcessSpecVersion(this.versionId).then(res => {
|
||||
const v = res.data || {}
|
||||
this.matchCondForm = {
|
||||
versionId: this.versionId,
|
||||
versionCode: v.versionCode || '',
|
||||
specId: v.specId || undefined,
|
||||
matchEntryThickMin: v.matchEntryThickMin ?? null,
|
||||
matchEntryThickMax: v.matchEntryThickMax ?? null,
|
||||
matchExitThickMin: v.matchExitThickMin ?? null,
|
||||
matchExitThickMax: v.matchExitThickMax ?? null,
|
||||
matchEntryWidthMin: v.matchEntryWidthMin ?? null,
|
||||
matchEntryWidthMax: v.matchEntryWidthMax ?? null,
|
||||
matchExitWidthMin: v.matchExitWidthMin ?? null,
|
||||
matchExitWidthMax: v.matchExitWidthMax ?? null,
|
||||
matchSteelGrade: v.matchSteelGrade || ''
|
||||
}
|
||||
this._matchCondSnapshot = { ...this.matchCondForm }
|
||||
this.matchCondEditing = false
|
||||
})
|
||||
},
|
||||
cancelMatchCond() {
|
||||
this.matchCondForm = { ...this._matchCondSnapshot }
|
||||
this.matchCondEditing = false
|
||||
},
|
||||
saveMatchCond() {
|
||||
this.matchCondSaving = true
|
||||
updateProcessSpecVersion(this.matchCondForm).then(() => {
|
||||
this._matchCondSnapshot = { ...this.matchCondForm }
|
||||
this.matchCondEditing = false
|
||||
this.$modal.msgSuccess('匹配条件保存成功')
|
||||
}).catch(e => console.error(e)).finally(() => { this.matchCondSaving = false })
|
||||
},
|
||||
fmtRange(min, max, unit) {
|
||||
if (min == null && max == null) return '—'
|
||||
const a = min != null ? min : '∞'
|
||||
const b = max != null ? max : '∞'
|
||||
return `${a} – ${b} ${unit}`
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1347,6 +1474,78 @@ export default {
|
||||
.seg-process { background: #f0f9eb; color: #3a7a2a; border: 1px solid #b3e19d; }
|
||||
.seg-outlet { background: #fdf6ec; color: #a86a00; border: 1px solid #f5dab1; }
|
||||
|
||||
/* ── 匹配条件面板 ── */
|
||||
.match-cond-panel {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0;
|
||||
border: 1px solid #e4e9f0;
|
||||
border-radius: 6px;
|
||||
background: #f8fafd;
|
||||
margin-bottom: 12px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.match-cond-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 7px 12px;
|
||||
background: #edf2f8;
|
||||
border-bottom: 1px solid #e4e9f0;
|
||||
}
|
||||
.match-cond-title {
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: #4a6585;
|
||||
letter-spacing: .3px;
|
||||
}
|
||||
.match-cond-title i { margin-right: 5px; }
|
||||
.match-cond-actions { display: flex; gap: 6px; }
|
||||
.mci-val {
|
||||
font-size: 12px;
|
||||
color: #303133;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
.match-cond-body {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
padding: 8px 12px;
|
||||
gap: 0;
|
||||
}
|
||||
.match-cond-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
padding: 2px 0;
|
||||
}
|
||||
.mci-label {
|
||||
font-size: 12px;
|
||||
color: #606266;
|
||||
white-space: nowrap;
|
||||
min-width: 60px;
|
||||
}
|
||||
.mci-input {
|
||||
width: 82px !important;
|
||||
}
|
||||
.mci-sep {
|
||||
color: #c0c4cc;
|
||||
font-size: 13px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.mci-unit {
|
||||
font-size: 11px;
|
||||
color: #909399;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.match-cond-divider {
|
||||
width: 1px;
|
||||
height: 20px;
|
||||
background: #e4e9f0;
|
||||
margin: 0 12px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
|
||||
/* 导入对话框样式 */
|
||||
.import-container {
|
||||
|
||||
Reference in New Issue
Block a user