feat(wms/coil): 新增排产单展示功能,优化多页面布局与样式

1.  为分步加工弹窗添加全屏属性
2.  在typing、merge、stepSplit、split页面新增排产单列表与详情展示,支持多排产单切换
3.  重构split页面表单布局为双列样式,优化页面结构
This commit is contained in:
2026-05-28 17:43:04 +08:00
parent 8e6ae90690
commit 1f4dcea63a
5 changed files with 534 additions and 216 deletions

View File

@@ -89,6 +89,40 @@
</div>
</div>
</div>
<!-- 今日排产单 -->
<div v-if="planSheetList.length > 0" class="plan-sheet-section">
<el-descriptions :column="1" border :title="'最近排产单(' + planSheetLineName + ''" size="small" />
<el-tabs v-model="activePlanSheetId" type="card" size="mini">
<el-tab-pane v-for="sheet in planSheetList" :key="sheet.planSheetId"
:name="sheet.planSheetId"
:label="sheet.planCode || ('排产单' + sheet.planSheetId)" />
</el-tabs>
<el-table v-loading="planSheetLoading" :data="activePlanSheetDetails" border stripe size="mini" max-height="300">
<el-table-column type="index" label="#" width="40" />
<el-table-column prop="bizSeqNo" label="序号" width="55" />
<el-table-column label="订单信息">
<el-table-column prop="orderCode" label="订单号" width="130" show-overflow-tooltip />
<el-table-column prop="contractCode" label="合同号" width="130" show-overflow-tooltip />
<el-table-column prop="customerName" label="客户" width="100" show-overflow-tooltip />
<el-table-column prop="salesman" label="业务员" width="80" show-overflow-tooltip />
</el-table-column>
<el-table-column label="成品信息">
<el-table-column prop="productName" label="成品名称" width="130" show-overflow-tooltip />
<el-table-column prop="productMaterial" label="材质" width="80" />
<el-table-column prop="coatingG" label="镀层g" width="70" />
<el-table-column prop="productWidth" label="宽度" width="80" />
<el-table-column prop="rollingThick" label="轧厚" width="80" />
<el-table-column prop="planQty" label="数量" width="65" />
<el-table-column prop="planWeight" label="重量" width="80" />
</el-table-column>
<el-table-column prop="remark" label="备注" width="100" show-overflow-tooltip />
</el-table>
</div>
<div v-else-if="planSheetLineName && !planSheetLoading" class="plan-sheet-section">
<el-descriptions :column="1" border :title="'最近排产单(' + planSheetLineName + ''" size="small" />
<el-empty description="今天暂无排产单" :image-size="60" />
</div>
</div>
<!-- 右侧目标卷信息 -->
@@ -300,6 +334,8 @@
<script>
import { getMaterialCoil, mergeMaterialCoil } from '@/api/wms/coil';
import { listPendingAction, getPendingAction } from '@/api/wms/pendingAction';
import { listPlanSheet } from '@/api/aps/planSheet'
import { listPlanDetail } from '@/api/aps/planDetail'
import CoilSelector from '@/components/CoilSelector';
import ActualWarehouseSelect from "@/components/KLPService/ActualWarehouseSelect";
import RawMaterialSelector from "@/components/KLPService/RawMaterialSelect";
@@ -413,7 +449,12 @@ export default {
defectCode: null,
degree: null,
remark: null
}
},
// 排产单相关
planSheetList: [],
planSheetDetailMap: {},
planSheetLoading: false,
activePlanSheetId: null,
};
},
computed: {
@@ -441,7 +482,25 @@ export default {
return this.pendingMergeList.filter(pending => !this.sourceCoils.some(source => source.enterCoilNo === pending.enterCoilNo))
}
return [];
}
},
planSheetLineName() {
const mapping = {
11: '酸轧线', 200: '酸轧线', 520: '酸轧线',
501: '镀锌线', 521: '镀锌线',
203: '脱脂线', 502: '脱脂线', 522: '脱脂线',
204: '拉矫线', 503: '拉矫线', 523: '拉矫线',
205: '双机架', 504: '双机架', 524: '双机架',
505: '镀铬线', 525: '镀铬线',
}
return mapping[parseInt(this.actionTypeCode)] || ''
},
todayDateStr() {
const d = new Date()
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`
},
activePlanSheetDetails() {
return this.planSheetDetailMap[this.activePlanSheetId] || []
},
},
watch: {
// 不再需要watch直接用@change事件处理
@@ -471,6 +530,7 @@ export default {
// 保存当前页面的待操作类型
if (actionTypeCode) {
this.actionTypeCode = actionTypeCode;
this.fetchPlanSheets();
}
// 设置只读模式
@@ -867,6 +927,33 @@ export default {
this.$router.back();
},
async fetchPlanSheets() {
if (!this.planSheetLineName) return
this.planSheetLoading = true
try {
const res = await listPlanSheet({
lineName: this.planSheetLineName,
pageSize: 3, pageNum: 1,
})
this.planSheetList = res.rows || []
this.planSheetDetailMap = {}
if (this.planSheetList.length > 0) {
this.activePlanSheetId = this.planSheetList[0].planSheetId
for (const sheet of this.planSheetList) {
this.fetchPlanSheetDetail(sheet.planSheetId)
}
}
} catch (e) { console.error('查询排产单失败', e) }
finally { this.planSheetLoading = false }
},
async fetchPlanSheetDetail(planSheetId) {
try {
const res = await listPlanDetail({ planSheetId, pageSize: 100, pageNum: 1 })
const details = (res.rows || []).sort((a, b) => (parseInt(a.bizSeqNo) || 0) - (parseInt(b.bizSeqNo) || 0))
this.$set(this.planSheetDetailMap, planSheetId, details)
} catch (e) { console.error('查询排产单明细失败', e) }
},
// 新增异常
addAbnormal() {
this.currentAbnormalIndex = -1;
@@ -1439,4 +1526,8 @@ export default {
transform: translateY(-2px);
}
}
.plan-sheet-section {
margin-top: 16px;
}
</style>

View File

@@ -317,7 +317,7 @@
<label-render :content="labelRender.data" :labelType="labelRender.type" />
</el-dialog>
<el-dialog title="分步加工" :visible.sync="stepSpilt.visible" width="1400px" append-to-body>
<el-dialog title="分步加工" :visible.sync="stepSpilt.visible" width="1400px" append-to-body fullscreen>
<step-split @print="handlePrintLabel" @complete="handleComposeSplit" :actionId="stepSpilt.actionId"
:coilId="stepSpilt.coilId" :actionStatus="stepSpilt.actionStatus" :actionType="stepSpilt.actionType" />
</el-dialog>

View File

@@ -88,7 +88,7 @@
</el-table-column>
</el-table>
<el-descriptions :column="1" border title="镀锌二级数据"
<!-- <el-descriptions :column="1" border title="镀锌二级数据"
v-if="actionType == 501 && showSplitForm"></el-descriptions>
<el-table v-if="actionType == 501 && showSplitForm" v-loading="zincLoading" :data="zincList" border stripe
@row-click="handleZincItemClick" highlight-current-row>
@@ -97,7 +97,51 @@
<el-table-column prop="createTime" label="生产开始时间" />
<el-table-column prop="endTime" label="生产结束时间" />
<el-table-column prop="shiftNo" label="班组" />
</el-table>
</el-table> -->
<!-- 今日排产单 -->
<div v-if="planSheetList.length > 0" class="plan-sheet-section">
<el-descriptions :column="1" border :title="'最近排产单(' + planSheetLineName + ''">
</el-descriptions>
<el-tabs v-model="activePlanSheetId" type="card">
<el-tab-pane v-for="sheet in planSheetList" :key="sheet.planSheetId"
:name="sheet.planSheetId"
:label="sheet.planCode || ('排产单' + sheet.planSheetId)" />
</el-tabs>
<el-table v-loading="planSheetLoading" :data="activePlanSheetDetails" border stripe size="mini"
max-height="400">
<el-table-column type="index" label="序号" width="50" />
<el-table-column label="订单信息" header-align="center">
<el-table-column prop="contractCode" label="合同号" width="140" show-overflow-tooltip />
<el-table-column prop="customerName" label="客户" width="120" show-overflow-tooltip />
<el-table-column prop="salesman" label="业务员" width="100" show-overflow-tooltip />
</el-table-column>
<el-table-column label="成品信息" header-align="center">
<el-table-column prop="productName" label="成品名称" width="140" show-overflow-tooltip />
<el-table-column prop="productMaterial" label="材质" width="100" />
<el-table-column prop="coatingG" label="镀层g" width="80" />
<el-table-column prop="productWidth" label="成品宽度" width="100" />
<el-table-column prop="rollingThick" label="轧制厚度" width="100" />
<el-table-column prop="markCoatThick" label="标丝厚度" width="100" />
<el-table-column prop="tonSteelLengthRange" label="长度区间(m)" width="120" />
<el-table-column prop="planQty" label="数量" width="80" />
<el-table-column prop="planWeight" label="重量" width="100" />
<el-table-column prop="surfaceTreatment" label="表面处理" width="110" show-overflow-tooltip />
<el-table-column prop="widthReq" label="切边要求" width="110" show-overflow-tooltip />
<el-table-column prop="productPackaging" label="包装要求" width="100" show-overflow-tooltip />
<el-table-column prop="productEdgeReq" label="宽度要求" width="100" show-overflow-tooltip />
<el-table-column prop="usageReq" label="用途" width="100" show-overflow-tooltip />
</el-table-column>
<el-table-column prop="remark" label="备注" width="140" show-overflow-tooltip />
</el-table>
</div>
<!-- 今日排产单空状态 -->
<div v-if="planSheetList.length === 0 && planSheetLineName && !planSheetLoading" class="plan-sheet-section">
<el-descriptions :column="1" border :title="'最近排产单(' + planSheetLineName + ''">
</el-descriptions>
<el-empty description="今天暂无排产单" :image-size="80" />
</div>
</div>
</el-col>
@@ -318,6 +362,8 @@ import { getMaterialCoil, listMaterialCoil, createSpecialChild, completeSpecialS
import { completeAction, getPendingAction, updatePendingAction } from '@/api/wms/pendingAction'
import { saveCoilCache, getCoilCacheByCoilId, delCoilCache } from '@/api/wms/coilCache'
import { getGalvanize1TypingPrefill } from '@/api/pocket/acidTyping';
import { listPlanSheet } from '@/api/aps/planSheet'
import { listPlanDetail } from '@/api/aps/planDetail'
import ProductSelect from "@/components/KLPService/ProductSelect";
import RawMaterialSelect from "@/components/KLPService/RawMaterialSelect";
import WarehouseSelect from "@/components/KLPService/WarehouseSelect";
@@ -454,6 +500,11 @@ export default {
parsedCacheData: null,
// 最早的热轧卷板材质
firstHeatMaterial: '',
// 排产单相关
planSheetList: [],
planSheetDetailMap: {},
planSheetLoading: false,
activePlanSheetId: null,
}
},
computed: {
@@ -461,6 +512,39 @@ export default {
getItemLabel() {
return this.splitForm.itemType === 'product' ? '成品' : this.splitForm.itemType === 'raw_material' ? '原料' : '材料项'
},
// actionType → 产线名称映射
planSheetLineName() {
const mapping = {
11: '酸轧线',
200: '酸轧线',
520: '酸轧线',
206: '镀锌线',
501: '镀锌线',
521: '镀锌线',
203: '脱脂线',
502: '脱脂线',
522: '脱脂线',
204: '拉矫线',
503: '拉矫线',
523: '拉矫线',
205: '双机架',
504: '双机架',
524: '双机架',
505: '镀铬线',
525: '镀铬线',
}
return mapping[this.actionType] || ''
},
todayDateStr() {
const d = new Date()
const y = d.getFullYear()
const m = String(d.getMonth() + 1).padStart(2, '0')
const day = String(d.getDate()).padStart(2, '0')
return `${y}-${m}-${day}`
},
activePlanSheetDetails() {
return this.planSheetDetailMap[this.activePlanSheetId] || []
},
},
watch: {
coilId: {
@@ -490,10 +574,57 @@ export default {
// 获取镀锌线二级系统数据
this.getZincList()
}
if (this.planSheetLineName) {
this.fetchPlanSheets()
}
}
}
},
methods: {
// 查询最近排产单及明细
async fetchPlanSheets() {
if (!this.planSheetLineName) return
this.planSheetLoading = true
try {
const res = await listPlanSheet({
lineName: this.planSheetLineName,
pageSize: 3,
pageNum: 1,
})
this.planSheetList = res.rows || []
this.planSheetDetailMap = {}
if (this.planSheetList.length > 0) {
this.activePlanSheetId = this.planSheetList[0].planSheetId
for (const sheet of this.planSheetList) {
this.fetchPlanSheetDetail(sheet.planSheetId)
}
}
} catch (e) {
console.error('查询排产单失败', e)
} finally {
this.planSheetLoading = false
}
},
async fetchPlanSheetDetail(planSheetId) {
try {
const res = await listPlanDetail({
planSheetId,
pageSize: 100,
pageNum: 1,
})
const details = res.rows || []
details.sort((a, b) => {
const na = parseInt(a.bizSeqNo) || 0
const nb = parseInt(b.bizSeqNo) || 0
return na - nb
})
this.$set(this.planSheetDetailMap, planSheetId, details)
} catch (e) {
console.error('查询排产单明细失败', e)
}
},
// 查询待分条的钢卷信息
async getCoilInfo() {
try {
@@ -1102,4 +1233,8 @@ export default {
transform: translateY(-2px);
}
}
.plan-sheet-section {
margin-top: 16px;
}
</style>

View File

@@ -14,7 +14,7 @@
<!-- 流程图区域 -->
<div class="flow-container">
<!-- 左侧母卷信息 -->
<!-- 左侧母卷信息 + 排产信息 -->
<div class="flow-left">
<div class="flow-section-title">
<span>母卷信息</span>
@@ -24,7 +24,7 @@
<i class="el-icon-s-grid"></i>
<span class="coil-title">钢卷信息</span>
</div>
<div class="coil-body">
<div class="coil-body two-col">
<div class="coil-info-row">
<span class="label">入场钢卷号</span>
<span class="value">{{ motherCoil.enterCoilNo || '—' }}</span>
@@ -65,9 +65,9 @@
<span class="label">钢卷表面处理</span>
<span class="value">{{ motherCoil.coilSurfaceTreatment || '—' }}</span>
</div>
<div class="coil-info-row" v-if="motherCoil.materialName || motherCoil.productName">
<div class="coil-info-row" v-if="motherCoil.itemName || motherCoil.productName">
<span class="label">物料名称</span>
<span class="value">{{ motherCoil.materialName || motherCoil.productName || '—' }}</span>
<span class="value">{{ motherCoil.itemName || motherCoil.productName || '—' }}</span>
</div>
<div class="coil-info-row">
<span class="label">规格</span>
@@ -83,20 +83,39 @@
</div>
</div>
</div>
</div>
<!-- 中间流程箭头 -->
<div class="flow-middle">
<div class="flow-arrow-container">
<div class="arrow-line" v-for="(item, index) in splitList" :key="index">
<div class="arrow-start"></div>
<div class="arrow-body"></div>
<div class="arrow-end"></div>
</div>
<!-- 今日排产单 -->
<div v-if="planSheetList.length > 0" class="plan-sheet-section">
<el-descriptions :column="1" border title="最近排产单(酸轧线)" size="small" />
<el-tabs v-model="activePlanSheetId" type="card" size="mini">
<el-tab-pane v-for="sheet in planSheetList" :key="sheet.planSheetId"
:name="sheet.planSheetId"
:label="sheet.planCode || ('排产单' + sheet.planSheetId)" />
</el-tabs>
<el-table v-loading="planSheetLoading" :data="activePlanSheetDetails" border stripe size="mini" max-height="300">
<el-table-column type="index" label="#" width="40" />
<el-table-column prop="bizSeqNo" label="序号" width="55" />
<el-table-column label="订单信息">
<el-table-column prop="orderCode" label="订单号" width="130" show-overflow-tooltip />
<el-table-column prop="contractCode" label="合同号" width="130" show-overflow-tooltip />
<el-table-column prop="customerName" label="客户" width="100" show-overflow-tooltip />
<el-table-column prop="salesman" label="业务员" width="80" show-overflow-tooltip />
</el-table-column>
<el-table-column label="成品信息">
<el-table-column prop="productName" label="成品名称" width="130" show-overflow-tooltip />
<el-table-column prop="productMaterial" label="材质" width="80" />
<el-table-column prop="coatingG" label="镀层g" width="70" />
<el-table-column prop="productWidth" label="宽度" width="80" />
<el-table-column prop="rollingThick" label="轧厚" width="80" />
<el-table-column prop="planQty" label="数量" width="65" />
<el-table-column prop="planWeight" label="重量" width="80" />
</el-table-column>
<el-table-column prop="remark" label="备注" width="100" show-overflow-tooltip />
</el-table>
</div>
<div class="flow-label">
<i class="el-icon-d-arrow-right"></i>
<span>分割</span>
<div v-else-if="!planSheetLoading" class="plan-sheet-section">
<el-descriptions :column="1" border title="最近排产单(酸轧线)" size="small" />
<el-empty description="今天暂无排产单" :image-size="60" />
</div>
</div>
@@ -121,144 +140,162 @@
</div>
<div class="sub-coil-body">
<el-form size="small" label-width="90px">
<el-form-item label="卷号" required>
<el-input v-model="item.currentCoilNo" placeholder="输入子卷卷号" :disabled="readonly"></el-input>
<current-coil-no :current-coil-no="item.currentCoilNo" />
</el-form-item>
<el-form-item label="班组" required>
<el-select v-model="item.team" placeholder="请选择班组" style="width: 100%" :disabled="readonly">
<el-option key="甲" label="甲" value="甲" />
<el-option key="" label="" value="" />
</el-select>
</el-form-item>
<div class="form-row">
<el-form-item label="卷号" required class="form-item-half">
<el-input v-model="item.currentCoilNo" placeholder="输入子卷卷号" :disabled="readonly"></el-input>
<current-coil-no :current-coil-no="item.currentCoilNo" />
</el-form-item>
<el-form-item label="班组" required class="form-item-half">
<el-select v-model="item.team" placeholder="请选择班组" style="width: 100%" :disabled="readonly">
<el-option key="" label="" value="" />
<el-option key="乙" label="乙" value="乙" />
</el-select>
</el-form-item>
</div>
<el-form-item label="材料类型" required>
<el-select v-model="item.materialType" placeholder="请选择材料类型" style="width: 100%" :disabled="readonly"
@change="handleMaterialTypeChange(item, index)">
<el-option label="原料" value="原料" />
<el-option label="成品" value="成品" />
</el-select>
</el-form-item>
<div class="form-row">
<el-form-item label="材料类型" required class="form-item-half">
<el-select v-model="item.materialType" placeholder="请选择" style="width: 100%" :disabled="readonly"
@change="handleMaterialTypeChange(item, index)">
<el-option label="原料" value="原料" />
<el-option label="成品" value="成品" />
</el-select>
</el-form-item>
<el-form-item :label="getItemLabel(item.materialType)" class="form-item-half">
<raw-material-select v-if="item.materialType === '原料'" v-model="item.itemId" placeholder="请选择原料"
style="width: 100%" clearable :disabled="readonly || !item.materialType" />
<product-select v-else-if="item.materialType === '成品'" v-model="item.itemId" placeholder="请选择成品"
style="width: 100%" clearable :disabled="readonly || !item.materialType" />
<div v-else>请先选择物料类型</div>
</el-form-item>
</div>
<!-- 物品类型由材料类型自动决定不显示选择框 -->
<el-form-item :label="getItemLabel(item.materialType)">
<raw-material-select v-if="item.materialType === '原料'" v-model="item.itemId" placeholder="请选择原料"
style="width: 100%" clearable :disabled="readonly || !item.materialType" />
<product-select v-else-if="item.materialType === '成品'" v-model="item.itemId" placeholder="请选择成品"
style="width: 100%" clearable :disabled="readonly || !item.materialType" />
<div v-else>请先选择物料类型</div>
</el-form-item>
<div class="form-row">
<el-form-item label="质量状态" prop="qualityStatus" class="form-item-half">
<el-select v-model="item.qualityStatus" placeholder="请选择" style="width: 100%" :disabled="readonly">
<el-option v-for="opt in dict.type.coil_quality_status" :key="opt.value" :label="opt.label"
:value="opt.value" />
</el-select>
</el-form-item>
<el-form-item label="切边要求" prop="trimmingRequirement" class="form-item-half">
<el-select v-model="item.trimmingRequirement" placeholder="请选择" style="width: 100%" :disabled="readonly">
<el-option label="净边料" value="净边料" />
<el-option label="毛边料" value="毛边料" />
</el-select>
</el-form-item>
</div>
<el-form-item label="质量状态" prop="qualityStatus">
<el-select v-model="item.qualityStatus" placeholder="请选择质量状态" style="width: 100%"
:disabled="readonly">
<el-option v-for="item in dict.type.coil_quality_status" :key="item.value" :label="item.label"
:value="item.value" />
</el-select>
</el-form-item>
<div class="form-row">
<el-form-item label="原料材质" prop="packingStatus" class="form-item-half">
<el-input v-model="item.packingStatus" placeholder="请输入原料材质" :disabled="readonly" />
</el-form-item>
<el-form-item label="包装要求" prop="packagingRequirement" class="form-item-half">
<el-select v-model="item.packagingRequirement" placeholder="请选择" style="width: 100%" :disabled="readonly">
<el-option label="裸包" value="裸包" />
<el-option label="普包" value="普包" />
<el-option label="简包" value="简包" />
<el-option label="精包" value="精包" />
</el-select>
</el-form-item>
</div>
<el-form-item label="切边要求" prop="trimmingRequirement">
<el-select v-model="item.trimmingRequirement" placeholder="请选择切边要求" style="width: 100%"
:disabled="readonly">
<el-option label="净边料" value="净边料" />
<el-option label="毛边料" value="毛边料" />
</el-select>
</el-form-item>
<div class="form-row">
<el-form-item label="毛重(t)" required class="form-item-half">
<el-input-number precision="3" :controls="false" v-model="item.grossWeight" placeholder="请输入毛重"
:step="0.01" :disabled="readonly">
<template slot="append"></template>
</el-input-number>
</el-form-item>
<el-form-item label="净重(t)" required class="form-item-half">
<el-input-number precision="3" :controls="false" v-model="item.netWeight" placeholder="请输入净重"
:step="0.01" :disabled="readonly">
<template slot="append"></template>
</el-input-number>
</el-form-item>
</div>
<el-form-item label="原料材质" prop="packingStatus">
<el-input v-model="item.packingStatus" placeholder="请输入原料材质" :disabled="readonly">
</el-input>
</el-form-item>
<div class="form-row">
<el-form-item label="长度(m)" class="form-item-half">
<el-input-number :controls="false" v-model="item.length" placeholder="请输入长度"
:step="0.01" :disabled="readonly">
<template slot="append"></template>
</el-input-number>
</el-form-item>
<el-form-item label="实测长度(m)" prop="actualLength" class="form-item-half">
<el-input-number :controls="false" v-model="item.actualLength" placeholder="实测长度"
:step="0.01" :disabled="readonly">
<template slot="append">m</template>
</el-input-number>
</el-form-item>
</div>
<el-form-item label="包装要求" prop="packagingRequirement">
<el-select v-model="item.packagingRequirement" placeholder="请选择包装要求" style="width: 100%"
:disabled="readonly">
<el-option label="裸包" value="裸包" />
<el-option label="普包" value="普包" />
<el-option label="简包" value="简包" />
<el-option label="精包" value="精包" />
</el-select>
</el-form-item>
<div class="form-row">
<el-form-item label="实测厚度(mm)" prop="actualThickness" class="form-item-half">
<el-input-number :controls="false" v-model="item.actualThickness" placeholder="实测厚度"
:step="0.01" :disabled="readonly">
<template slot="append">mm</template>
</el-input-number>
</el-form-item>
<el-form-item label="实测宽度(mm)" prop="actualWidth" class="form-item-half">
<el-input-number :controls="false" v-model="item.actualWidth" placeholder="实测宽度"
:step="0.01" :disabled="readonly">
<template slot="append">mm</template>
</el-input-number>
</el-form-item>
</div>
<el-form-item label="毛重(t)" required>
<el-input-number precision="3" :controls="false" v-model="item.grossWeight" placeholder="请输入毛重"
type="number" :step="0.01" :disabled="readonly">
<template slot="append"></template>
</el-input-number>
</el-form-item>
<el-form-item label="净重(t)" required>
<el-input-number precision="3" :controls="false" v-model="item.netWeight" placeholder="请输入净重"
type="number" :step="0.01" :disabled="readonly">
<template slot="append"></template>
</el-input-number>
</el-form-item>
<el-form-item label="长度(m)">
<el-input-number :controls="false" v-model="item.length" placeholder="请输入长度" type="number"
:step="0.01" :disabled="readonly">
<template slot="append"></template>
</el-input-number>
</el-form-item>
<el-form-item label="实测长度(m)" prop="actualLength">
<el-input-number :controls="false" v-model="item.actualLength" placeholder="请输入实测长度" type="number"
:step="0.01" :disabled="readonly">
<template slot="append">m</template>
</el-input-number>
</el-form-item>
<el-form-item label="实测厚度(mm)" prop="actualThickness" class="form-item-half">
<el-input-number :controls="false" v-model="item.actualThickness" placeholder="请输入实测厚度" type="number"
:step="0.01" :disabled="readonly">
<template slot="append">mm</template>
</el-input-number>
</el-form-item>
<el-form-item label="实测宽度(mm)" prop="actualWidth">
<el-input-number :controls="false" v-model="item.actualWidth" placeholder="请输入实测宽度" type="number"
:step="0.01" :disabled="readonly">
<template slot="append">mm</template>
</el-input-number>
</el-form-item>
<el-form-item label="业务目的" prop="businessPurpose">
<el-select v-model="item.businessPurpose" placeholder="请选择业务目的" style="width: 100%">
<el-option v-for="item in dict.type.coil_business_purpose" :key="item.value" :value="item.value"
:label="item.label" />
</el-select>
</el-form-item>
<el-form-item label="调制度" prop="temperGrade">
<el-input v-model="item.temperGrade" placeholder="请输入调制度" />
</el-form-item>
<el-form-item label="镀层种类" prop="coatingType">
<MemoInput storageKey="coatingType" v-model="item.coatingType" placeholder="请输入镀层种类" />
</el-form-item>
<el-form-item label="钢卷表面处理" prop="coilSurfaceTreatment">
<MemoInput storageKey="surfaceTreatmentDesc" v-model="item.coilSurfaceTreatment"
placeholder="请输入钢卷表面处理" />
</el-form-item>
<el-form-item label="逻辑库区" required>
<WarehouseSelect v-model="item.warehouseId" placeholder="请选择逻辑库区" :disabled="readonly" />
</el-form-item>
<!-- <el-form-item label="真实库区">
<ActualWarehouseSelect v-model="item.actualWarehouseId" placeholder="请选择真实库区" block
:disabled="readonly" />
</el-form-item> -->
<el-form-item label="生产开始时间">
<TimeInput v-model="item.productionStartTime" @input="() => calculateProductionDuration(item)"
:disabled="readonly" />
</el-form-item>
<el-form-item label="生产结束时间">
<TimeInput v-model="item.productionEndTime" @input="() => calculateProductionDuration(item)"
:disabled="readonly" :show-now-button="true" />
</el-form-item>
<el-form-item label="生产耗时">
<el-input v-model="item.formattedDuration" placeholder="自动计算" disabled />
</el-form-item>
<el-form-item label="备注">
<el-input v-model="item.remark" placeholder="请输入备注" :disabled="readonly" />
</el-form-item>
<div class="form-row">
<el-form-item label="业务目的" prop="businessPurpose" class="form-item-half">
<el-select v-model="item.businessPurpose" placeholder="请选择" style="width: 100%">
<el-option v-for="opt in dict.type.coil_business_purpose" :key="opt.value" :value="opt.value"
:label="opt.label" />
</el-select>
</el-form-item>
<el-form-item label="调制度" prop="temperGrade" class="form-item-half">
<el-input v-model="item.temperGrade" placeholder="请输入调制度" />
</el-form-item>
</div>
<el-form-item label="关联合同" prop="contractId">
<ContractSelect v-model="item.contractId" placeholder="请选择合同" />
</el-form-item>
<div class="form-row">
<el-form-item label="镀层种类" prop="coatingType" class="form-item-half">
<MemoInput storageKey="coatingType" v-model="item.coatingType" placeholder="请输入镀层种类" />
</el-form-item>
<el-form-item label="钢卷表面处理" prop="coilSurfaceTreatment" class="form-item-half">
<MemoInput storageKey="surfaceTreatmentDesc" v-model="item.coilSurfaceTreatment"
placeholder="请输入" />
</el-form-item>
</div>
<el-form-item label="异常信息">
<div class="form-row">
<el-form-item label="逻辑库区" required class="form-item-half">
<WarehouseSelect v-model="item.warehouseId" placeholder="请选择逻辑库区" :disabled="readonly" />
</el-form-item>
<el-form-item label="关联合同" prop="contractId" class="form-item-half">
<ContractSelect v-model="item.contractId" placeholder="请选择合同" />
</el-form-item>
</div>
<div class="form-row">
<el-form-item label="生产开始时间" class="form-item-half">
<TimeInput v-model="item.productionStartTime" @input="() => calculateProductionDuration(item)"
:disabled="readonly" />
</el-form-item>
<el-form-item label="生产结束时间" class="form-item-half">
<TimeInput v-model="item.productionEndTime" @input="() => calculateProductionDuration(item)"
:disabled="readonly" :show-now-button="true" />
</el-form-item>
</div>
<div class="form-row">
<el-form-item label="生产耗时" class="form-item-half">
<el-input v-model="item.formattedDuration" placeholder="自动计算" disabled />
</el-form-item>
<el-form-item label="备注" class="form-item-half">
<el-input v-model="item.remark" placeholder="请输入备注" :disabled="readonly" />
</el-form-item>
</div>
<el-form-item label="异常信息" class="form-item-full">
<div class="abnormal-container">
<div v-for="(abnormal, abnormalIndex) in item.abnormals" :key="abnormalIndex" class="abnormal-item"
@click="editAbnormal(index, abnormalIndex)">
@@ -299,6 +336,8 @@
import { getMaterialCoil, splitMaterialCoil, getFirstHeatCoilMaterial } from '@/api/wms/coil';
import { listWarehouse } from '@/api/wms/warehouse';
import { completeAction, getPendingAction } from '@/api/wms/pendingAction';
import { listPlanSheet } from '@/api/aps/planSheet'
import { listPlanDetail } from '@/api/aps/planDetail'
import ActualWarehouseSelect from "@/components/KLPService/ActualWarehouseSelect";
import RawMaterialSelect from "@/components/KLPService/RawMaterialSelect";
import ProductSelect from "@/components/KLPService/ProductSelect";
@@ -401,9 +440,25 @@ export default {
},
// 最早热轧卷板材质
firstHeatMaterial: null,
// 排产单相关
actionTypeCode: '',
planSheetList: [],
planSheetDetailMap: {},
planSheetLoading: false,
activePlanSheetId: null,
};
},
computed: {
planSheetLineName() {
return '酸轧线'
},
todayDateStr() {
const d = new Date()
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`
},
activePlanSheetDetails() {
return this.planSheetDetailMap[this.activePlanSheetId] || []
},
},
async created() {
// 先加载库区列表
@@ -416,6 +471,12 @@ export default {
const coilId = this.$route.query.coilId;
const actionId = this.$route.query.actionId;
const readonly = this.$route.query.readonly;
const actionTypeCode = this.$route.query.actionTypeCode;
if (actionTypeCode) {
this.actionTypeCode = actionTypeCode;
}
this.fetchPlanSheets();
// 获取待操作详情
getPendingAction(actionId).then(res => {
@@ -866,7 +927,34 @@ export default {
if (!dict) return code;
const item = dict.find(item => item.value === code);
return item ? item.label : code;
}
},
// 查询最近排产单(酸轧线)
async fetchPlanSheets() {
this.planSheetLoading = true
try {
const res = await listPlanSheet({
lineName: '酸轧线',
pageSize: 3, pageNum: 1,
})
this.planSheetList = res.rows || []
this.planSheetDetailMap = {}
if (this.planSheetList.length > 0) {
this.activePlanSheetId = this.planSheetList[0].planSheetId
for (const sheet of this.planSheetList) {
this.fetchPlanSheetDetail(sheet.planSheetId)
}
}
} catch (e) { console.error('查询排产单失败', e) }
finally { this.planSheetLoading = false }
},
async fetchPlanSheetDetail(planSheetId) {
try {
const res = await listPlanDetail({ planSheetId, pageSize: 100, pageNum: 1 })
const details = (res.rows || []).sort((a, b) => (parseInt(a.bizSeqNo) || 0) - (parseInt(b.bizSeqNo) || 0))
this.$set(this.planSheetDetailMap, planSheetId, details)
} catch (e) { console.error('查询排产单明细失败', e) }
},
}
};
</script>
@@ -907,25 +995,17 @@ export default {
/* 流程图容器 */
.flow-container {
display: flex;
gap: 40px;
gap: 20px;
background: #fff;
padding: 30px;
padding: 20px;
border-radius: 4px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
min-height: 600px;
}
.flow-left {
flex: 0 0 300px;
}
.flow-middle {
flex: 0 0 120px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
position: relative;
flex: 0 0 340px;
overflow-y: auto;
}
.flow-right {
@@ -983,6 +1063,12 @@ export default {
.coil-body {
padding: 20px;
&.two-col {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 0 12px;
}
}
.coil-info-row {
@@ -1041,43 +1127,6 @@ export default {
}
/* 流程箭头 */
.flow-arrow-container {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 100%;
}
.arrow-line {
position: relative;
height: 3px;
margin: 20px 0;
display: flex;
align-items: center;
}
.arrow-start {
width: 8px;
height: 8px;
background: #0066cc;
border-radius: 50%;
}
.arrow-body {
flex: 1;
height: 3px;
background: #0066cc;
}
.arrow-end {
width: 0;
height: 0;
border-left: 12px solid #0066cc;
border-top: 8px solid transparent;
border-bottom: 8px solid transparent;
}
.flow-label {
position: absolute;
bottom: 20px;
@@ -1223,6 +1272,31 @@ export default {
}
}
/* 双列表单布局 */
.form-row {
display: flex;
gap: 16px;
margin-bottom: 0;
&:last-child {
margin-bottom: 0;
}
}
.form-item-half {
flex: 1;
min-width: 0;
}
.form-item-full {
width: 100%;
}
/* 排产单区域 */
.plan-sheet-section {
margin-top: 16px;
}
// 异常信息样式
.abnormal-container {
display: flex;

View File

@@ -11,12 +11,17 @@
</div>
<!-- 排产计划 -->
<el-card class="plan-card" v-if="planDetailList.length > 0" style="margin-bottom: 20px;">
<el-card class="plan-card" v-if="planSheetList.length > 0" style="margin-bottom: 20px;">
<div slot="header" class="card-header">
<span><i class="el-icon-s-order"></i> {{ currentLineName }}排产计划</span>
</div>
<el-tabs v-model="activePlanSheetId" type="card" size="mini">
<el-tab-pane v-for="sheet in planSheetList" :key="sheet.planSheetId"
:name="sheet.planSheetId"
:label="sheet.planCode || ('排产单' + sheet.planSheetId)" />
</el-tabs>
<div style="overflow-x: auto;">
<el-table :data="planDetailList" size="small" max-height="300" stripe border>
<el-table :data="activePlanSheetDetails" size="small" max-height="300" stripe border>
<el-table-column label="订单号" prop="orderCode" width="160" />
<el-table-column label="合同号" prop="contractCode" width="160" />
<el-table-column label="客户" prop="customerName" width="100" />
@@ -503,8 +508,9 @@ export default {
parsedCacheData: null,
itemSelectorQueryParams: {},
// 排产计划
planDetailList: [],
currentPlanSheet: null,
planSheetList: [],
planSheetDetailMap: {},
activePlanSheetId: null,
currentLineName: '',
};
},
@@ -512,6 +518,9 @@ export default {
l2HotCoilId() {
return (this.currentInfo && this.currentInfo.enterCoilNo) || ''
},
activePlanSheetDetails() {
return this.planSheetDetailMap[this.activePlanSheetId] || []
},
/** 是否双机架工序actionType 504=正常 / 524=修复) */
isDrAction() {
return this.actionType === 504 || this.actionType === 524
@@ -702,7 +711,7 @@ export default {
}
},
// 根据当前actionType加载对应产线的排产计划
// 根据当前actionType加载对应产线的最近3个排产计划
async loadPlanDetails() {
const lineName = actionTypeToLineName[this.actionType]
if (!lineName) return
@@ -711,24 +720,33 @@ export default {
const sheetRes = await listPlanSheet({
lineName,
pageNum: 1,
pageSize: 1,
pageSize: 3,
})
if (sheetRes.rows && sheetRes.rows.length > 0) {
const planSheet = sheetRes.rows[0]
this.currentPlanSheet = planSheet
const detailRes = await listPlanDetail({
planSheetId: planSheet.planSheetId,
pageNum: 1,
pageSize: 50,
})
if (detailRes.rows) {
this.planDetailList = detailRes.rows
this.planSheetList = sheetRes.rows || []
this.planSheetDetailMap = {}
if (this.planSheetList.length > 0) {
this.activePlanSheetId = this.planSheetList[0].planSheetId
for (const sheet of this.planSheetList) {
this.fetchPlanSheetDetail(sheet.planSheetId)
}
}
} catch (error) {
console.error('加载排产计划失败', error)
}
},
async fetchPlanSheetDetail(planSheetId) {
try {
const detailRes = await listPlanDetail({
planSheetId,
pageNum: 1,
pageSize: 50,
})
if (detailRes.rows) {
const details = detailRes.rows.sort((a, b) => (parseInt(a.bizSeqNo) || 0) - (parseInt(b.bizSeqNo) || 0))
this.$set(this.planSheetDetailMap, planSheetId, details)
}
} catch (e) { console.error('查询排产单明细失败', e) }
},
// 复制当前信息到更新表单
copyFromCurrent() {