Files
klp-oa/klp-ui/src/views/wms/coil/panels/stepSplit.vue

994 lines
38 KiB
Vue
Raw Normal View History

<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="净重">{{ 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="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="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.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'],
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 < 10) {
callback(new Error('当前钢卷号必须大于等于10位'));
} 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) {
// 根据材料类型设置itemType
this.splitForm.itemType = val === '成品' ? 'product' : val === '原料' ? '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 }
// 同步材料类型和长度显示状态
this.handleMaterialTypeChange(row.materialType)
},
// 新增/编辑分条
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)
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
};
// 同步材料类型和长度显示状态
if (this.splitForm.materialType) {
this.handleMaterialTypeChange(this.splitForm.materialType);
}
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>