Files
klp-oa/klp-ui/src/views/wms/coil/panels/stepSplit.vue
砂糖 5e80208d61 feat(wms): 在完成操作时传递新钢卷ID参数
修改completeAction接口以接收新钢卷ID参数,并在多个视图中调用时传递该参数
2026-04-15 15:28:28 +08:00

1008 lines
39 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="split-coil-container" v-loading="loading">
<!-- 左右分栏布局 -->
<el-row :gutter="20">
<!-- 左侧钢卷信息 + 新增按钮 + 已分条列表 -->
<el-col :span="12">
<div class="coil-info-card">
<el-row :gutter="20" flex justify="end">
<!-- 新增分条按钮 -->
<el-button type="primary" icon="el-icon-plus" @click="addSplitForm" :loading="buttonLoading"
v-if="actionStatus != 2">
新增分条
</el-button>
<!-- 完成分条按钮 -->
<el-button type="success" icon="el-icon-check" @click="completeSplit" :disabled="splitList.length === 0"
:loading="buttonLoading" v-if="actionStatus != 2">
完成整体分条
</el-button>
<el-button type="primary" icon="el-icon-refresh" @click="refresh" :loading="buttonLoading">
刷新
</el-button>
</el-row>
<el-descriptions :column="2" border title="待分条钢卷信息">
<el-descriptions-item label="入场钢卷号">{{ coilInfo.enterCoilNo || '-' }}</el-descriptions-item>
<el-descriptions-item label="当前钢卷号">{{ coilInfo.currentCoilNo || '-' }}</el-descriptions-item>
<el-descriptions-item label="厂家原料卷号">{{ coilInfo.supplierCoilNo || '-' }}</el-descriptions-item>
<el-descriptions-item label="所在库位">{{ coilInfo.warehouseName || '-' }}</el-descriptions-item>
<el-descriptions-item label="材料类型">{{ coilInfo.materialType || '-' }}</el-descriptions-item>
<el-descriptions-item label="净重">{{ coilInfo.netWeight || '-' }} T</el-descriptions-item>
<el-descriptions-item label="物料名称">{{ coilInfo.itemName || '-' }}</el-descriptions-item>
<el-descriptions-item label="规格">{{ coilInfo.specification || '-' }}</el-descriptions-item>
<el-descriptions-item label="材质">{{ coilInfo.material || '-' }}</el-descriptions-item>
<el-descriptions-item label="原料材质">{{ coilInfo.packingStatus || '-' }}</el-descriptions-item>
<el-descriptions-item label="实测长度(m)">{{ coilInfo.actualLength || '-' }}</el-descriptions-item>
<el-descriptions-item label="实测宽度(m)">{{ coilInfo.actualWidth || '-' }}</el-descriptions-item>
<el-descriptions-item label="实测厚度(m)">{{ coilInfo.actualThickness || '-' }}</el-descriptions-item>
<el-descriptions-item label="钢卷表面处理">{{ coilInfo.coilSurfaceTreatment || '-' }}</el-descriptions-item>
<el-descriptions-item label="净重">{{ coilInfo.netWeight || '-' }} T</el-descriptions-item>
</el-descriptions>
<!-- 已分条钢卷列表 -->
<el-descriptions :column="1" border title="已分出的钢卷列表"></el-descriptions>
<el-table v-loading="splitListLoading" :data="splitList" @row-click="handleSplitItemClick"
highlight-current-row border stripe>
<el-table-column prop="enterCoilNo" label="入场钢卷号" />
<el-table-column prop="currentCoilNo" label="当前钢卷号" />
<el-table-column label="物料类型">
<template #default="scope">
<ProductInfo v-if="scope.row.itemType == 'product'" :product="scope.row" />
<RawMaterialInfo v-else-if="scope.row.itemType === 'raw_material'" :material="scope.row" />
</template>
</el-table-column>
<el-table-column prop="netWeight" label="净重" width="70" />
<el-table-column prop="dataType" label="钢卷状态" width="80">
<template #default="scope">
<div v-if="scope.row.status == 1">
<el-tag type="info">已发货</el-tag>
</div>
<div v-else-if="scope.row.dataType == 1">
<el-tag type="success">当前在库</el-tag>
</div>
<div v-else-if="scope.row.dataType == 0 || scope.row.dataType == 2">
<el-tag type="warning">历史卷</el-tag>
</div>
<div v-else>
<el-tag type="danger">未知状态</el-tag>
</div>
</template>
</el-table-column>
<el-table-column label="操作" width="180">
<template #default="scope">
<div v-if="scope.row.dataType == 1 && scope.row.status == 0">
<el-button @click.stop="handlePrint(scope.row)">打印</el-button>
<el-button @click.stop="handleEditSplit(scope.row)">编辑</el-button>
<el-button @click.stop="handleDeleteSplit(scope.row)">删除</el-button>
</div>
</template>
</el-table-column>
</el-table>
<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">
<el-table-column prop="enterCoilNo" label="入场钢卷号" />
<el-table-column prop="createTime" label="生产开始时间" />
<el-table-column prop="endTime" label="生产结束时间" />
<el-table-column prop="shiftNo" label="班组" />
</el-table>
</div>
</el-col>
<!-- 右侧分条表单 / 分条详情 -->
<el-col :span="12">
<div class="split-form-card" v-if="showSplitForm">
<el-card title="分条钢卷信息录入" shadow="hover">
<el-form ref="splitFormRef" :model="splitForm" :rules="rules" label-width="100px" style="max-width: 800px;">
<el-form-item label="入场钢卷号" prop="enterCoilNo">
<el-input v-model="splitForm.enterCoilNo" placeholder="请输入入场钢卷号" disabled />
</el-form-item>
<el-form-item label="当前钢卷号" prop="currentCoilNo">
<el-input v-model="splitForm.currentCoilNo" placeholder="请输入当前钢卷号" />
<current-coil-no :current-coil-no="splitForm.currentCoilNo" />
</el-form-item>
<el-form-item label="所在库位" prop="warehouseId">
<warehouse-select v-model="splitForm.warehouseId" placeholder="请选择仓库/库区/库位" style="width: 100%;"
clearable />
</el-form-item>
<el-form-item label="班组" prop="team">
<el-select v-model="splitForm.team" placeholder="请选择班组" style="width: 100%">
<el-option key="甲" label="甲" value="甲" />
<el-option key="乙" label="乙" value="乙" />
</el-select>
</el-form-item>
<el-form-item label="材料类型" prop="materialType">
<el-select v-model="splitForm.materialType" placeholder="请选择材料类型" @change="handleMaterialTypeChange">
<el-option label="成品" value="成品" />
<el-option label="原料" value="原料" />
</el-select>
</el-form-item>
<el-form-item :label="getItemLabel" prop="itemId">
<product-select v-if="splitForm.itemType === 'product'" v-model="splitForm.itemId" placeholder="请选择成品"
style="width: 100%;" clearable />
<raw-material-select v-else-if="splitForm.itemType === 'raw_material'" v-model="splitForm.itemId"
placeholder="请选择原料" style="width: 100%;" clearable />
<div v-else>请先选择材料类型</div>
</el-form-item>
<el-form-item label="质量状态" prop="qualityStatus">
<el-select v-model="splitForm.qualityStatus" placeholder="请选择质量状态" style="width: 100%">
<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>
<el-form-item label="切边要求" prop="trimmingRequirement">
<el-select v-model="splitForm.trimmingRequirement" placeholder="请选择切边要求" style="width: 100%">
<el-option label="净边料" value="净边料" />
<el-option label="毛边料" value="毛边料" />
</el-select>
</el-form-item>
<el-form-item label="原料材质" prop="packingStatus">
<el-input v-model="splitForm.packingStatus" placeholder="请输入原料材质" />
</el-form-item>
<el-form-item label="包装要求" prop="packagingRequirement">
<el-select v-model="splitForm.packagingRequirement" placeholder="请选择包装要求" style="width: 100%">
<el-option label="裸包" value="裸包" />
<el-option label="普包" value="普包" />
<el-option label="简包" value="简包" />
</el-select>
</el-form-item>
<el-form-item label="毛重" prop="grossWeight">
<el-input v-model="splitForm.grossWeight" placeholder="请输入毛重" type="number" />
</el-form-item>
<el-form-item label="净重" prop="netWeight">
<el-input v-model="splitForm.netWeight" placeholder="请输入净重" type="number" />
</el-form-item>
<el-form-item label="长度" prop="length">
<el-input v-model="splitForm.length" placeholder="请输入长度" type="number" />
</el-form-item>
<el-form-item label="实测长度(m)" prop="actualLength">
<el-input-number :controls="false" v-model="splitForm.actualLength" placeholder="请输入实测长度" type="number"
:step="0.01" />
</el-form-item>
<el-form-item label="实测厚度(m)" prop="actualThickness">
<el-input-number :controls="false" v-model="splitForm.actualThickness" placeholder="请输入实测厚度"
type="number" :step="0.01" />
</el-form-item>
<el-form-item label="实测宽度(m)" prop="actualWidth">
<el-input-number :controls="false" v-model="splitForm.actualWidth" placeholder="请输入实测宽度" type="number"
:step="0.01" />
</el-form-item>
<el-form-item label="业务目的" prop="businessPurpose">
<el-select v-model="splitForm.businessPurpose" placeholder="业务目的" filterable>
<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="splitForm.temperGrade" placeholder="请输入调制度" />
</el-form-item>
<el-form-item label="镀层种类" prop="coatingType">
<MemoInput storageKey="coatingType" v-model="splitForm.coatingType" placeholder="请输入镀层种类" />
</el-form-item>
<el-form-item label="钢卷表面处理" prop="coilSurfaceTreatment">
<MemoInput storageKey="surfaceTreatmentDesc" v-model="splitForm.coilSurfaceTreatment" placeholder="请输入钢卷表面处理" />
</el-form-item>
<el-form-item label="生产开始时间" prop="productionStartTime">
<TimeInput v-model="splitForm.productionStartTime" @input="calculateProductionDuration" />
</el-form-item>
<el-form-item label="生产结束时间" prop="productionEndTime">
<TimeInput v-model="splitForm.productionEndTime" @input="calculateProductionDuration"
:show-now-button="true" />
</el-form-item>
<el-form-item label="生产耗时" prop="productionDuration">
<el-input v-model="splitForm.formattedDuration" placeholder="自动计算" disabled />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="splitForm.remark" placeholder="请输入备注" type="textarea" />
</el-form-item>
<el-form-item label="异常信息">
<div class="abnormal-container">
<div v-for="(abnormal, index) in abnormals" :key="index" class="abnormal-item"
@click="editAbnormal(index)">
<div class="abnormal-content">
<div class="abnormal-info">
<div class="abnormal-position">{{ getAbnormalPositionText(abnormal.position) }}</div>
<div class="abnormal-code">{{ getAbnormalCodeText(abnormal.defectCode) }}</div>
</div>
<el-button type="danger" size="mini" icon="el-icon-close" class="abnormal-delete"
@click.stop="deleteAbnormal(index)"></el-button>
</div>
</div>
<div class="abnormal-add" @click="addAbnormal">
<i class="el-icon-plus"></i>
</div>
</div>
</el-form-item>
<el-form-item>
<el-button type="info" @click="copyFromSourceCoil" icon="el-icon-document-copy">复制源卷信息</el-button>
<el-button :loading="buttonLoading" type="primary" @click="addSplit">提交分条</el-button>
<el-button :loading="buttonLoading" @click="resetSplitForm">重置</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
<!-- 分条钢卷详情选中列表项时显示 -->
<div class="split-detail-card" v-else-if="selectedSplitItem">
<el-card title="分条钢卷详情" shadow="hover">
<!-- <el-button type="primary" @click="handlePrint(selectedSplitItem)">打印</el-button> -->
<el-descriptions :column="2" border size="large">
<el-descriptions-item label="入场钢卷号">{{ selectedSplitItem.enterCoilNo || '-' }}</el-descriptions-item>
<el-descriptions-item label="当前钢卷号">{{ selectedSplitItem.currentCoilNo || '-' }}</el-descriptions-item>
<el-descriptions-item label="厂家原料卷号">{{ selectedSplitItem.supplierCoilNo || '-' }}</el-descriptions-item>
<el-descriptions-item label="逻辑库位">{{ selectedSplitItem.warehouseName || '-' }}</el-descriptions-item>
<el-descriptions-item label="实际库区">{{ selectedSplitItem.actualWarehouseName || '-'
}}</el-descriptions-item>
<el-descriptions-item label="班组">{{ selectedSplitItem.team || '-' }}</el-descriptions-item>
<el-descriptions-item label="材料类型">{{ selectedSplitItem.materialType || '-' }}</el-descriptions-item>
<el-descriptions-item label="产品/原料">{{ selectedSplitItem.itemName || '-' }}</el-descriptions-item>
<el-descriptions-item label="规格">{{ selectedSplitItem.specification || '-' }}</el-descriptions-item>
<el-descriptions-item label="材质">{{ selectedSplitItem.material || '-' }}</el-descriptions-item>
<el-descriptions-item label="厂家">{{ selectedSplitItem.manufacturer || '-' }}</el-descriptions-item>
<el-descriptions-item label="镀层质量">{{ selectedSplitItem.zincLayer || '-' }}</el-descriptions-item>
<el-descriptions-item label="表面处理">{{ selectedSplitItem.surfaceTreatmentDesc || '-'
}}</el-descriptions-item>
<el-descriptions-item label="质量状态">{{ selectedSplitItem.qualityStatus || '-' }}</el-descriptions-item>
<el-descriptions-item label="切边要求">{{ selectedSplitItem.trimmingRequirement || '-'
}}</el-descriptions-item>
<el-descriptions-item label="原料材质">{{ selectedSplitItem.packingStatus || '-' }}</el-descriptions-item>
<el-descriptions-item label="包装要求">{{ selectedSplitItem.packagingRequirement || '-'
}}</el-descriptions-item>
<el-descriptions-item label="实测厚度(m)">{{ selectedSplitItem.actualThickness || '-' }}
m</el-descriptions-item>
<el-descriptions-item label="实测宽度(m)">{{ selectedSplitItem.actualWidth || '-' }}
m</el-descriptions-item>
<el-descriptions-item label="长度">{{ selectedSplitItem.length || '-' }}
m</el-descriptions-item>
<el-descriptions-item label="毛重">{{ selectedSplitItem.grossWeight || '-' }} t</el-descriptions-item>
<el-descriptions-item label="净重">{{ selectedSplitItem.netWeight || '-' }} t</el-descriptions-item>
<el-descriptions-item label="调制度">{{ selectedSplitItem.temperGrade || '-' }}</el-descriptions-item>
<el-descriptions-item label="镀层种类">{{ selectedSplitItem.coatingType || '-' }}</el-descriptions-item>
<el-descriptions-item label="钢卷表面处理">{{ selectedSplitItem.coilSurfaceTreatment || '-' }}</el-descriptions-item>
<el-descriptions-item label="生产开始时间">{{ selectedSplitItem.productionStartTime || '-'
}}</el-descriptions-item>
<el-descriptions-item label="生产结束时间">{{ selectedSplitItem.productionEndTime || '-'
}}</el-descriptions-item>
<el-descriptions-item label="生产耗时">{{ selectedSplitItem.formattedDuration ||
(selectedSplitItem.productionDuration ? selectedSplitItem.productionDuration + ' 分钟' : '-')
}}</el-descriptions-item>
<el-descriptions-item label="备注" :span="2">{{ selectedSplitItem.remark || '-' }}</el-descriptions-item>
</el-descriptions>
</el-card>
</div>
<!-- 初始提示 -->
<div class="empty-tip" v-else>
<el-empty description="请选择左侧已分条钢卷查看详情,或点击「新增分条」创建新分条"></el-empty>
</div>
</el-col>
</el-row>
<!-- 异常表单弹窗 -->
<el-dialog :title="currentAbnormalIndex === -1 ? '新增异常' : '编辑异常'" :visible.sync="abnormalDialogVisible"
width="600px" append-to-body>
<abnormal-form ref="abnormalForm" v-model="abnormalForm" :show-coil-selector="false"></abnormal-form>
<div slot="footer" class="dialog-footer">
<el-button @click="abnormalDialogVisible = false"> </el-button>
<el-button type="primary" @click="saveAbnormal"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { getMaterialCoil, listMaterialCoil, createSpecialChild, completeSpecialSplit, updateMaterialCoilSimple, checkCoilNo, delMaterialCoil } from '@/api/wms/coil'
import { completeAction, getPendingAction, updatePendingAction } from '@/api/wms/pendingAction'
import { getGalvanize1TypingPrefill } from '@/api/pocket/acidTyping';
import ProductSelect from "@/components/KLPService/ProductSelect";
import RawMaterialSelect from "@/components/KLPService/RawMaterialSelect";
import WarehouseSelect from "@/components/KLPService/WarehouseSelect";
import ActualWarehouseSelect from "@/components/KLPService/ActualWarehouseSelect";
import TimeInput from "@/components/TimeInput";
import AbnormalForm from '../components/AbnormalForm';
import { generateCoilNoPrefix } from "@/utils/coil/coilNo";
import ProductInfo from "@/components/KLPService/Renderer/ProductInfo";
import RawMaterialInfo from "@/components/KLPService/Renderer/RawMaterialInfo";
export default {
name: 'StepSplit',
props: {
actionId: {
type: [String, Number],
required: true,
},
coilId: {
type: String,
required: true,
},
actionStatus: {
type: Number,
default: 0,
},
actionType: {
type: Number,
required: true,
},
},
components: {
ProductSelect,
RawMaterialSelect,
WarehouseSelect,
ActualWarehouseSelect,
TimeInput,
AbnormalForm,
ProductInfo,
RawMaterialInfo,
},
dicts: ['coil_quality_status', 'coil_abnormal_position', 'coil_abnormal_code', 'coil_abnormal_degree', 'coil_business_purpose'],
data() {
const currentCoilNoPrefix = generateCoilNoPrefix()
return {
currentCoilNoPrefix,
// 待分条钢卷基础信息
coilInfo: {},
loading: false,
// 分条表单数据
splitForm: {
coilId: '', // 分条钢卷ID编辑时赋值
enterCoilNo: '',
currentCoilNo: currentCoilNoPrefix,
supplierCoilNo: '',
warehouseId: '',
actualWarehouseId: '',
team: '',
materialType: '',
itemType: '', // product/raw_material
itemId: '',
qualityStatus: '',
trimmingRequirement: '',
packingStatus: '',
packagingRequirement: '',
grossWeight: '',
netWeight: '',
length: '',
actualLength: '',
actualWidth: '',
temperGrade: '',
coatingType: '',
remark: '',
productionStartTime: '',
productionEndTime: '',
productionDuration: '',
formattedDuration: '',
},
// 已分条钢卷列表
splitList: [],
// 列表加载状态
splitListLoading: false,
// 选中的分条项(用于显示详情)
selectedSplitItem: null,
// 是否显示分条表单
showSplitForm: false,
// 表单验证规则
rules: {
currentCoilNo: [
{ required: true, message: "当前钢卷号不能为空", trigger: "blur" },
{
// 当前钢卷号必须大于等于10位
validator: (rule, value, callback) => {
if (value.length < 11) {
callback(new Error('当前钢卷号必须大于等于11位'));
} else {
callback();
}
}, trigger: 'blur'
},
// 仅在新增的时候校验
// {
// validator: (rule, value, callback) => {
// // 没有coilId则为新增 触发校验
// checkCoilNo({ currentCoilNo: value, coilId: this.splitForm.coilId }).then(res => {
// const { duplicateType } = res.data;
// if (duplicateType === 'current' || duplicateType === 'both') {
// // alert('当前钢卷号重复,请重新输入');
// callback(new Error('当前钢卷号重复,请重新输入'));
// } else {
// callback();
// }
// })
// }, trigger: 'blur'
// }
],
materialType: [{ required: true, message: '请选择材料类型', trigger: 'change' }],
itemId: [{ required: true, message: '请选择成品/原料', trigger: 'change' }],
netWeight: [{ required: true, message: '请输入净重', trigger: 'blur' }],
warehouseId: [{ required: true, message: '请选择所在库位', trigger: 'change' }],
},
buttonLoading: false,
currentAction: {},
// 异常信息
abnormals: [],
// 异常表单弹窗
abnormalDialogVisible: false,
// 当前编辑的异常索引
currentAbnormalIndex: -1,
// 异常表单数据
abnormalForm: {
coilId: null,
position: null,
startPosition: 0,
endPosition: 0,
length: 0,
defectCode: null,
degree: null,
remark: null
},
zincList: [],
zincLoading: false,
}
},
computed: {
// 动态获取成品/原料标签
getItemLabel() {
return this.splitForm.itemType === 'product' ? '成品' : this.splitForm.itemType === 'raw_material' ? '原料' : '材料项'
},
},
watch: {
coilId: {
immediate: true, // 初始化时立即执行
async handler(val) {
if (val) {
this.loading = true
await this.getCoilInfo()
await this.getSplitList()
this.loading = false
// 更新父钢卷ID
this.splitForm.parentCoilId = val
}
},
},
actionId: {
immediate: true,
handler(val) {
// 若actionId变化需要重新加载数据可在此补充逻辑
},
},
actionType: {
immediate: true,
handler(val) {
console.log('actionType', val)
if (val == 501) {
// 获取镀锌线二级系统数据
this.getZincList()
}
}
}
},
methods: {
// 查询待分条的钢卷信息
async getCoilInfo() {
try {
const res = await getMaterialCoil(this.coilId)
if (res.code === 200) {
this.coilInfo = res.data || {}
} else {
this.$message.error('查询钢卷信息失败:' + res.msg)
}
} catch (error) {
this.$message.error('查询钢卷信息异常:' + error.message)
}
},
async getZincList() {
this.zincLoading = true
const res = await getGalvanize1TypingPrefill({
pageSize: 10,
pageNum: 1,
})
this.zincList = res.rows || []
this.zincLoading = false
},
async handlePrint(row) {
this.$emit('print', row)
},
async handleDeleteSplit(row) {
this.$modal.confirm('确认删除该分卷吗?').then(async () => {
try {
await delMaterialCoil(row.coilId)
this.$message.success('删除成功')
// 刷新钢卷信息
this.refresh()
} catch (error) {
this.$message.error('删除失败:' + error.message)
}
})
},
// 刷新分条列表
async refresh() {
this.loading = true
await this.getSplitList()
await this.getCoilInfo()
this.loading = false
},
// 查询钢卷的已分条列表
async getSplitList() {
this.splitListLoading = true
try {
if (!this.actionId) {
return
}
const action = await getPendingAction(this.actionId)
this.currentAction = action.data || {}
// this.$set(this.splitForm, 'productionStartTime', action.data.createTime)
const coilIds = action.data.remark;
console.log('coilIds', coilIds)
if (!coilIds) {
this.splitList = []
return
}
const res = await listMaterialCoil({
coilIds
})
this.splitList = res.rows || []
updatePendingAction({
actionId: action.data.actionId,
actionStatus: action.data.actionStatus,
actionType: action.data.actionType,
coilId: action.data.coilId,
currentCoilNo: action.data.currentCoilNo,
remark: res.rows.map(item => item.coilId).join(','),
})
} catch (error) {
this.$message.error('查询分条列表异常:' + error.message)
} finally {
this.splitListLoading = false
}
},
// 新增一个分条表单(重置表单并显示)
async addSplitForm() {
this.showSplitForm = true
this.selectedSplitItem = null
this.resetSplitForm()
this.splitForm.enterCoilNo = this.coilInfo.enterCoilNo || ''
},
// 重置分条表单
resetSplitForm() {
this.$refs.splitFormRef?.resetFields()
this.splitForm = {
coilId: undefined,
enterCoilNo: '',
currentCoilNo: this.currentCoilNoPrefix,
supplierCoilNo: '',
warehouseId: '',
actualWarehouseId: '',
team: '',
materialType: '',
itemType: '',
itemId: '',
qualityStatus: '',
trimmingRequirement: '',
packingStatus: '',
packagingRequirement: '',
grossWeight: '',
netWeight: '',
length: '',
temperGrade: '',
coatingType: '',
remark: '',
productionStartTime: this.currentAction.createTime,
productionEndTime: '',
productionDuration: '',
formattedDuration: '',
parentCoilId: this.coilId,
}
// 重置异常信息
this.abnormals = [];
},
// 材料类型变更处理
handleMaterialTypeChange(val) {
// 清空物品选择
this.splitForm.itemId = null;
// 根据材料类型设置物品类型
if (val === '成品') {
this.splitForm.itemType = 'product';
} else if (val === '原料') {
this.splitForm.itemType = 'raw_material';
}
},
// 选中分条列表项(显示详情)
handleSplitItemClick(row) {
this.selectedSplitItem = row
this.showSplitForm = false
},
handleZincItemClick(row) {
this.splitForm = {
...this.splitForm,
team: row.shiftNo,
// enterCoilNo: row.enterCoilNo,
productionStartTime: row.createTime,
productionEndTime: row.endTime,
itemType: 'product',
materialType: '成品',
length: row.exitLength,
netWeight: row.exitNetWeight,
}
},
// 编辑分条项
async handleEditSplit(row) {
this.showSplitForm = true
this.selectedSplitItem = null
// 赋值表单数据
this.splitForm = { ...row }
},
// 新增/编辑分条
async addSplit() {
// 表单验证
const valid = await this.$refs.splitFormRef.validate()
console.log('valid', valid)
if (!valid) {
return
}
try {
// 区分新增/编辑有coilId则为编辑否则为新增
let res
this.buttonLoading = true
// 添加异常信息到表单数据
const splitData = {
...this.splitForm,
abnormals: this.abnormals
};
if (this.splitForm.coilId) {
// 编辑分条:调用更新接口
res = await updateMaterialCoilSimple(splitData)
} else {
// 新增分条:调用创建接口
res = await createSpecialChild(this.coilId, this.actionId, splitData)
}
this.$message.success(this.splitForm.coilId ? '编辑分条成功' : '新增分条成功')
// 重置表单
this.resetSplitForm()
this.showSplitForm = false
// 刷新分条列表
this.getSplitList()
} catch (error) {
// 表单验证失败时的提示
console.log('error', error)
if (error.name !== 'ValidationError') {
this.$message.error((this.splitForm.coilId ? '编辑' : '新增') + '分条异常:' + error.message)
}
} finally {
this.buttonLoading = false
}
},
// 完成整体分条
async completeSplit() {
this.$confirm('确认完成整体分条操作?完成后将无法修改分条信息', '提示', {
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning',
}).then(async () => {
const loading = this.$loading({
lock: true,
text: '正在记录分条操作...',
background: 'rgba(0, 0, 0, 0.7)',
})
try {
this.buttonLoading = true
// 1. 完成分条主流程
const splitRes = await completeSpecialSplit(this.actionId)
if (splitRes.code !== 200) {
this.$message.error('完成分条失败:' + splitRes.msg)
return
}
// 2. 完成待办动作(根据业务逻辑调整)
const actionRes = await completeAction(this.actionId, splitRes.data.childCoilIds.join(','))
if (actionRes.code !== 200) {
this.$message.error('完成待办动作失败:' + actionRes.msg)
return
}
this.buttonLoading = false
this.$message.success('分条操作已完成')
// 通知父组件(如需要)
this.$emit('complete')
} catch (error) {
if (error.message !== 'cancel') { // 排除取消确认的情况
this.$message.error('完成分条异常:' + error.message)
}
} finally {
loading.close()
}
})
},
// 格式化毫秒值为xx天xx小时xx分钟
formatDuration(milliseconds) {
if (!milliseconds || milliseconds < 0) return '';
const seconds = Math.floor(milliseconds / 1000);
const minutes = Math.floor(seconds / 60);
const hours = Math.floor(minutes / 60);
const days = Math.floor(hours / 24);
const remainingHours = hours % 24;
const remainingMinutes = minutes % 60;
let result = '';
if (days > 0) result += `${days}`;
if (remainingHours > 0) result += `${remainingHours}小时`;
if (remainingMinutes > 0) result += `${remainingMinutes}分钟`;
return result || '0分钟';
},
// 计算生产耗时
calculateProductionDuration() {
const { productionStartTime, productionEndTime } = this.splitForm;
if (productionStartTime && productionEndTime) {
const start = new Date(productionStartTime).getTime();
const end = new Date(productionEndTime).getTime();
if (end < start) {
this.$message({
message: '结束时间不能早于开始时间',
type: 'error',
});
this.$set(this.splitForm, 'productionDuration', '');
this.$set(this.splitForm, 'formattedDuration', '');
} else {
const durationMs = end - start;
const durationMinutes = Math.round(durationMs / (1000 * 60));
this.$set(this.splitForm, 'productionDuration', durationMinutes);
this.$set(this.splitForm, 'formattedDuration', this.formatDuration(durationMinutes * 60 * 1000));
}
} else {
this.$set(this.splitForm, 'productionDuration', '');
this.$set(this.splitForm, 'formattedDuration', '');
}
},
// 新增异常
addAbnormal() {
this.currentAbnormalIndex = -1;
this.abnormalForm = {
coilId: this.splitForm.coilId || null,
position: null,
startPosition: 0,
endPosition: 0,
length: 0,
defectCode: null,
degree: null,
remark: null
};
this.abnormalDialogVisible = true;
},
// 编辑异常
editAbnormal(index) {
this.currentAbnormalIndex = index;
this.abnormalForm = { ...this.abnormals[index] };
this.abnormalDialogVisible = true;
},
// 保存异常
saveAbnormal() {
this.$refs.abnormalForm.validate(valid => {
if (valid) {
// 计算缺陷长度
this.abnormalForm.length = this.abnormalForm.endPosition - this.abnormalForm.startPosition;
if (this.currentAbnormalIndex === -1) {
// 新增异常
this.abnormals.push({ ...this.abnormalForm });
} else {
// 编辑异常
this.abnormals[this.currentAbnormalIndex] = { ...this.abnormalForm };
}
this.abnormalDialogVisible = false;
}
});
},
// 删除异常
deleteAbnormal(index) {
this.$confirm('确定要删除这个异常信息吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.abnormals.splice(index, 1);
});
},
// 获取异常位置文本
getAbnormalPositionText(position) {
if (!position) return '';
const dict = this.dict.type.coil_abnormal_position;
if (!dict) return position;
const item = dict.find(item => item.value === position);
return item ? item.label : position;
},
// 获取异常代码文本
getAbnormalCodeText(code) {
if (!code) return '';
const dict = this.dict.type.coil_abnormal_code;
if (!dict) return code;
const item = dict.find(item => item.value === code);
return item ? item.label : code;
},
// 复制源卷信息到分条表单
copyFromSourceCoil() {
// 复制除了指定字段之外的其他字段
const excludeFields = ['enterCoilNo', 'currentCoilNo', 'coilId', 'createTime', 'createBy'];
// 构建要复制的字段
const copiedFields = {
supplierCoilNo: this.coilInfo.supplierCoilNo,
warehouseId: this.coilInfo.warehouseId,
actualWarehouseId: this.coilInfo.actualWarehouseId,
team: this.coilInfo.team,
materialType: this.coilInfo.materialType,
itemType: this.coilInfo.itemType,
itemId: this.coilInfo.itemId,
qualityStatus: this.coilInfo.qualityStatus,
trimmingRequirement: this.coilInfo.trimmingRequirement,
packingStatus: this.coilInfo.packingStatus,
packagingRequirement: this.coilInfo.packagingRequirement,
grossWeight: parseFloat(this.coilInfo.grossWeight) || null,
netWeight: parseFloat(this.coilInfo.netWeight) || null,
length: parseFloat(this.coilInfo.length) || null,
actualLength: parseFloat(this.coilInfo.actualLength) || null,
actualWidth: parseFloat(this.coilInfo.actualWidth) || null,
temperGrade: this.coilInfo.temperGrade,
coatingType: this.coilInfo.coatingType,
remark: this.coilInfo.remark,
productionStartTime: this.coilInfo.productionStartTime,
productionEndTime: this.coilInfo.productionEndTime,
productionDuration: this.coilInfo.productionDuration,
formattedDuration: this.coilInfo.productionDuration ? this.formatDuration(this.coilInfo.productionDuration * 60 * 1000) : ''
};
// 合并到分条表单
this.splitForm = {
...this.splitForm,
...copiedFields
};
this.$message.success('已复制源卷信息,请根据需要修改');
}
},
}
</script>
<style scoped>
.split-coil-container {
padding: 20px;
}
.coil-info-card {
height: 100%;
display: flex;
flex-direction: column;
gap: 10px;
}
.split-form-card,
.split-detail-card {
height: 100%;
}
.empty-tip {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
min-height: 400px;
}
.abnormal-container {
display: flex;
flex-wrap: wrap;
gap: 10px;
margin-top: 5px;
}
.abnormal-item {
width: 120px;
height: 80px;
background-color: #fff1f0;
border: 1px solid #ff4d4f;
border-radius: 4px;
cursor: pointer;
transition: all 0.3s ease;
position: relative;
&:hover {
box-shadow: 0 2px 8px rgba(255, 77, 79, 0.2);
transform: translateY(-2px);
}
.abnormal-content {
padding: 8px;
height: 100%;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.abnormal-info {
flex: 1;
}
.abnormal-position {
font-size: 12px;
font-weight: 500;
color: #ff4d4f;
margin-bottom: 4px;
}
.abnormal-code {
font-size: 11px;
color: #666;
line-height: 1.3;
}
.abnormal-delete {
position: absolute;
top: -8px;
right: -8px;
width: 20px;
height: 20px;
padding: 0;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
background-color: #fff;
}
}
.abnormal-add {
width: 120px;
height: 80px;
border: 2px dashed #ff4d4f;
border-radius: 4px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: all 0.3s ease;
color: #ff4d4f;
font-size: 24px;
&:hover {
background-color: #fff1f0;
transform: translateY(-2px);
}
}
</style>