1008 lines
39 KiB
Vue
1008 lines
39 KiB
Vue
<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> |