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

@@ -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;