2025-11-03 13:16:04 +08:00
|
|
|
|
<template>
|
|
|
|
|
|
<div class="split-coil-container">
|
|
|
|
|
|
<!-- 顶部操作栏 -->
|
|
|
|
|
|
<div class="header-bar">
|
|
|
|
|
|
<div class="header-title">
|
|
|
|
|
|
<i class="el-icon-s-operation"></i>
|
2025-11-11 12:21:16 +08:00
|
|
|
|
<span>钢卷分条</span>
|
2025-11-03 13:16:04 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
<div class="header-actions">
|
2025-11-11 12:21:16 +08:00
|
|
|
|
<el-button v-if="!readonly" type="primary" size="small" @click="handleSave" :loading="loading">保存分条</el-button>
|
2025-11-03 17:03:03 +08:00
|
|
|
|
<el-button size="small" @click="handleCancel" :disabled="loading">{{ readonly ? '返回' : '取消' }}</el-button>
|
2025-11-03 13:16:04 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
2026-05-29 13:00:33 +08:00
|
|
|
|
<!-- 最近排产单 -->
|
|
|
|
|
|
<div class="plan-sheet-container">
|
2026-06-08 10:22:30 +08:00
|
|
|
|
<div class="plan-sheet-section">
|
|
|
|
|
|
<PlanSheetViewer :line-name="planSheetLineName" />
|
2026-05-29 13:00:33 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
2025-11-03 13:16:04 +08:00
|
|
|
|
<!-- 流程图区域 -->
|
|
|
|
|
|
<div class="flow-container">
|
2026-05-28 17:43:04 +08:00
|
|
|
|
<!-- 左侧:母卷信息 + 排产信息 -->
|
2025-11-03 13:16:04 +08:00
|
|
|
|
<div class="flow-left">
|
|
|
|
|
|
<div class="flow-section-title">
|
|
|
|
|
|
<span>母卷信息</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="coil-card mother-coil">
|
|
|
|
|
|
<div class="coil-header">
|
|
|
|
|
|
<i class="el-icon-s-grid"></i>
|
2025-11-03 17:03:03 +08:00
|
|
|
|
<span class="coil-title">钢卷信息</span>
|
2025-11-03 13:16:04 +08:00
|
|
|
|
</div>
|
2026-05-28 17:43:04 +08:00
|
|
|
|
<div class="coil-body two-col">
|
2025-11-03 13:16:04 +08:00
|
|
|
|
<div class="coil-info-row">
|
2025-11-03 17:03:03 +08:00
|
|
|
|
<span class="label">入场钢卷号:</span>
|
|
|
|
|
|
<span class="value">{{ motherCoil.enterCoilNo || '—' }}</span>
|
2025-11-03 13:16:04 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
<div class="coil-info-row">
|
2025-11-03 17:03:03 +08:00
|
|
|
|
<span class="label">当前钢卷号:</span>
|
|
|
|
|
|
<span class="value">{{ motherCoil.currentCoilNo || '—' }}</span>
|
2025-11-03 13:16:04 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
<div class="coil-info-row">
|
2025-11-03 17:03:03 +08:00
|
|
|
|
<span class="label">当前库区:</span>
|
|
|
|
|
|
<span class="value">{{ motherCoil.warehouseName || '未分配' }}</span>
|
2025-11-03 13:16:04 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
<div class="coil-info-row">
|
2025-11-03 17:03:03 +08:00
|
|
|
|
<span class="label">班组:</span>
|
|
|
|
|
|
<span class="value">{{ motherCoil.team || '—' }}</span>
|
2025-11-03 13:16:04 +08:00
|
|
|
|
</div>
|
2025-11-03 17:03:03 +08:00
|
|
|
|
<div class="coil-info-row">
|
|
|
|
|
|
<span class="label">毛重:</span>
|
|
|
|
|
|
<span class="value">{{ motherCoil.grossWeight ? motherCoil.grossWeight + ' t' : '—' }}</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="coil-info-row">
|
|
|
|
|
|
<span class="label">净重:</span>
|
|
|
|
|
|
<span class="value">{{ motherCoil.netWeight ? motherCoil.netWeight + ' t' : '—' }}</span>
|
|
|
|
|
|
</div>
|
2026-01-15 11:01:41 +08:00
|
|
|
|
<div class="coil-info-row">
|
|
|
|
|
|
<span class="label">长度:</span>
|
|
|
|
|
|
<span class="value">{{ motherCoil.length ? motherCoil.length + ' m' : '—' }}</span>
|
|
|
|
|
|
</div>
|
2026-01-22 10:20:58 +08:00
|
|
|
|
<div class="coil-info-row">
|
|
|
|
|
|
<span class="label">调制度:</span>
|
|
|
|
|
|
<span class="value">{{ motherCoil.temperGrade || '—' }}</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="coil-info-row">
|
|
|
|
|
|
<span class="label">镀层种类:</span>
|
|
|
|
|
|
<span class="value">{{ motherCoil.coatingType || '—' }}</span>
|
|
|
|
|
|
</div>
|
2026-04-01 14:50:56 +08:00
|
|
|
|
<div class="coil-info-row">
|
|
|
|
|
|
<span class="label">钢卷表面处理:</span>
|
|
|
|
|
|
<span class="value">{{ motherCoil.coilSurfaceTreatment || '—' }}</span>
|
|
|
|
|
|
</div>
|
2026-05-28 17:43:04 +08:00
|
|
|
|
<div class="coil-info-row" v-if="motherCoil.itemName || motherCoil.productName">
|
2026-01-15 11:01:41 +08:00
|
|
|
|
<span class="label">物料名称:</span>
|
2026-05-28 17:43:04 +08:00
|
|
|
|
<span class="value">{{ motherCoil.itemName || motherCoil.productName || '—' }}</span>
|
2026-01-15 11:01:41 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
<div class="coil-info-row">
|
|
|
|
|
|
<span class="label">规格:</span>
|
|
|
|
|
|
<span class="value">{{ motherCoil.itemSpecification || '—' }}</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="coil-info-row">
|
|
|
|
|
|
<span class="label">材质:</span>
|
|
|
|
|
|
<span class="value">{{ motherCoil.itemMaterial || '—' }}</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="coil-info-row">
|
|
|
|
|
|
<span class="label">厂家:</span>
|
|
|
|
|
|
<span class="value">{{ motherCoil.itemManufacturer || '—' }}</span>
|
|
|
|
|
|
</div>
|
2025-11-03 13:16:04 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 右侧:子卷列表 -->
|
|
|
|
|
|
<div class="flow-right">
|
|
|
|
|
|
<div class="flow-section-title">
|
2026-01-15 11:01:41 +08:00
|
|
|
|
<span>子卷列表 ({{ splitList.length }} 个)</span>
|
2025-11-03 17:03:03 +08:00
|
|
|
|
<div>
|
2025-11-14 09:49:33 +08:00
|
|
|
|
<el-button v-if="!readonly" type="text" size="mini" @click="copyToAllSubCoils"
|
|
|
|
|
|
icon="el-icon-document-copy">复制到全部</el-button>
|
|
|
|
|
|
<el-button v-if="!readonly" type="text" size="mini" @click="addSplitItem"
|
|
|
|
|
|
icon="el-icon-plus">添加子卷</el-button>
|
2025-11-03 17:03:03 +08:00
|
|
|
|
</div>
|
2025-11-03 13:16:04 +08:00
|
|
|
|
</div>
|
2025-11-03 17:03:03 +08:00
|
|
|
|
|
2025-11-03 13:16:04 +08:00
|
|
|
|
<div class="split-list">
|
|
|
|
|
|
<div class="sub-coil-card" v-for="(item, index) in splitList" :key="index">
|
|
|
|
|
|
<div class="sub-coil-header">
|
|
|
|
|
|
<span class="sub-coil-number">{{ index + 1 }}</span>
|
2025-11-14 09:49:33 +08:00
|
|
|
|
<el-button v-if="!readonly" type="text" size="mini" icon="el-icon-delete" @click="removeSplitItem(index)"
|
|
|
|
|
|
class="btn-remove"></el-button>
|
2025-11-03 13:16:04 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
<div class="sub-coil-body">
|
2026-05-29 13:00:33 +08:00
|
|
|
|
<el-form size="small" label-width="80px">
|
2026-05-28 17:43:04 +08:00
|
|
|
|
<div class="form-row">
|
|
|
|
|
|
<el-form-item label="卷号" required class="form-item-half">
|
2026-06-15 10:56:28 +08:00
|
|
|
|
<el-input v-model.trim="item.currentCoilNo" placeholder="输入子卷卷号" :disabled="readonly"></el-input>
|
2026-05-28 17:43:04 +08:00
|
|
|
|
<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>
|
|
|
|
|
|
|
|
|
|
|
|
<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>
|
|
|
|
|
|
|
|
|
|
|
|
<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">
|
2026-05-29 13:00:33 +08:00
|
|
|
|
<el-select v-model="item.trimmingRequirement" placeholder="请选择" style="width: 100%"
|
|
|
|
|
|
:disabled="readonly">
|
2026-05-28 17:43:04 +08:00
|
|
|
|
<el-option label="净边料" value="净边料" />
|
|
|
|
|
|
<el-option label="毛边料" value="毛边料" />
|
|
|
|
|
|
</el-select>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<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">
|
2026-05-29 13:00:33 +08:00
|
|
|
|
<el-select v-model="item.packagingRequirement" placeholder="请选择" style="width: 100%"
|
|
|
|
|
|
:disabled="readonly">
|
2026-05-28 17:43:04 +08:00
|
|
|
|
<el-option label="裸包" value="裸包" />
|
|
|
|
|
|
<el-option label="普包" value="普包" />
|
|
|
|
|
|
<el-option label="简包" value="简包" />
|
|
|
|
|
|
<el-option label="精包" value="精包" />
|
|
|
|
|
|
</el-select>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="form-row">
|
|
|
|
|
|
<el-form-item label="毛重(t)" required class="form-item-half">
|
2026-06-08 10:22:30 +08:00
|
|
|
|
<el-input-number :precision="3" :controls="false" v-model="item.grossWeight" placeholder="请输入毛重"
|
2026-05-28 17:43:04 +08:00
|
|
|
|
: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">
|
2026-06-08 10:22:30 +08:00
|
|
|
|
<el-input-number :precision="3" :controls="false" v-model="item.netWeight" placeholder="请输入净重"
|
2026-05-28 17:43:04 +08:00
|
|
|
|
:step="0.01" :disabled="readonly">
|
|
|
|
|
|
<template slot="append">吨</template>
|
|
|
|
|
|
</el-input-number>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="form-row">
|
|
|
|
|
|
<el-form-item label="实测长度(m)" prop="actualLength" class="form-item-half">
|
2026-05-29 13:00:33 +08:00
|
|
|
|
<el-input-number :controls="false" v-model="item.actualLength" placeholder="实测长度" :step="0.01"
|
|
|
|
|
|
:disabled="readonly">
|
2026-05-28 17:43:04 +08:00
|
|
|
|
<template slot="append">m</template>
|
|
|
|
|
|
</el-input-number>
|
|
|
|
|
|
</el-form-item>
|
2026-06-10 17:22:12 +08:00
|
|
|
|
<el-form-item label="排产厚度(mm)" prop="scheduleThickness">
|
|
|
|
|
|
<el-input-number :controls="false" v-model="item.scheduleThickness" placeholder="请输入排产厚度"
|
|
|
|
|
|
type="number" :step="0.001">
|
|
|
|
|
|
<template slot="append">mm</template>
|
|
|
|
|
|
</el-input-number>
|
|
|
|
|
|
</el-form-item>
|
2026-05-28 17:43:04 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="form-row">
|
|
|
|
|
|
<el-form-item label="实测厚度(mm)" prop="actualThickness" class="form-item-half">
|
2026-05-29 13:00:33 +08:00
|
|
|
|
<el-input-number :controls="false" v-model="item.actualThickness" placeholder="实测厚度" :step="0.01"
|
|
|
|
|
|
:disabled="readonly">
|
2026-05-28 17:43:04 +08:00
|
|
|
|
<template slot="append">mm</template>
|
|
|
|
|
|
</el-input-number>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
<el-form-item label="实测宽度(mm)" prop="actualWidth" class="form-item-half">
|
2026-05-29 13:00:33 +08:00
|
|
|
|
<el-input-number :controls="false" v-model="item.actualWidth" placeholder="实测宽度" :step="0.01"
|
|
|
|
|
|
:disabled="readonly">
|
2026-05-28 17:43:04 +08:00
|
|
|
|
<template slot="append">mm</template>
|
|
|
|
|
|
</el-input-number>
|
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<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>
|
|
|
|
|
|
|
|
|
|
|
|
<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>
|
|
|
|
|
|
|
|
|
|
|
|
<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">
|
2026-06-05 10:45:37 +08:00
|
|
|
|
<div style="display: flex; align-items: center; gap: 8px;">
|
|
|
|
|
|
<div class="abnormal-container">
|
|
|
|
|
|
<div v-for="(abnormal, abnormalIndex) in item.abnormals" :key="abnormalIndex"
|
|
|
|
|
|
:class="['abnormal-item', { inherited: abnormal._inherited }]"
|
|
|
|
|
|
@click="editAbnormal(index, abnormalIndex)">
|
|
|
|
|
|
<div class="abnormal-content">
|
|
|
|
|
|
<div class="abnormal-info">
|
|
|
|
|
|
<div class="abnormal-position">{{ getAbnormalPositionText(abnormal.position) }}</div>
|
|
|
|
|
|
<div class="abnormal-code">{{ getAbnormalCodeText(abnormal.defectCode) }}</div>
|
2026-06-10 17:22:12 +08:00
|
|
|
|
<div v-if="abnormal._inherited" class="abnormal-inherit-tip">继承 · {{ abnormal.processSource
|
|
|
|
|
|
}}</div>
|
2026-06-05 10:45:37 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
<el-button type="danger" size="mini" icon="el-icon-close" class="abnormal-delete"
|
|
|
|
|
|
@click.stop="deleteAbnormal(index, abnormalIndex)"></el-button>
|
2026-03-19 17:50:37 +08:00
|
|
|
|
</div>
|
2026-06-05 10:45:37 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
<div class="abnormal-add" @click="addAbnormal(index)">
|
|
|
|
|
|
<i class="el-icon-plus"></i>
|
2026-03-19 17:50:37 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
2026-06-05 10:45:37 +08:00
|
|
|
|
<el-button v-if="!readonly" type="text" size="mini" icon="el-icon-download"
|
|
|
|
|
|
style="color: #409eff; white-space: nowrap;" @click="handleInheritAbnormal(index)">
|
|
|
|
|
|
继承异常
|
|
|
|
|
|
</el-button>
|
2026-03-19 17:50:37 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</el-form-item>
|
2025-11-03 13:16:04 +08:00
|
|
|
|
</el-form>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
2026-03-19 17:50:37 +08:00
|
|
|
|
|
|
|
|
|
|
<!-- 异常表单弹窗 -->
|
2026-05-12 10:40:02 +08:00
|
|
|
|
<el-dialog :title="currentAbnormalIndex === -1 ? '新增异常' : '编辑异常'" :visible.sync="abnormalDialogVisible"
|
|
|
|
|
|
width="600px">
|
|
|
|
|
|
<abnormal-form ref="abnormalForm" v-model="abnormalForm" :show-coil-selector="false"></abnormal-form>
|
2026-03-19 17:50:37 +08:00
|
|
|
|
<div slot="footer" class="dialog-footer">
|
|
|
|
|
|
<el-button @click="abnormalDialogVisible = false">取 消</el-button>
|
|
|
|
|
|
<el-button type="primary" @click="saveAbnormal">确 定</el-button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</el-dialog>
|
2026-06-05 10:45:37 +08:00
|
|
|
|
|
|
|
|
|
|
<!-- 异常继承弹窗 -->
|
|
|
|
|
|
<el-dialog title="异常继承" :visible.sync="inheritDialogVisible" width="1200px" append-to-body top="5vh"
|
|
|
|
|
|
:close-on-click-modal="false">
|
|
|
|
|
|
<div v-loading="inheritLoading">
|
|
|
|
|
|
<template v-if="parentCoils.length > 0">
|
|
|
|
|
|
<el-alert title="以下为母卷的异常记录,请选择要继承的异常" type="info" :closable="false" show-icon style="margin-bottom: 16px;" />
|
|
|
|
|
|
<div v-for="(parent, pIdx) in parentCoils" :key="parent.coilId" class="parent-coil-section">
|
|
|
|
|
|
<div class="parent-header">
|
|
|
|
|
|
<span class="parent-title">母卷 #{{ pIdx + 1 }}:{{ parent.currentCoilNo || parent.coilId }}</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<el-table :data="parent.abnormalList" border stripe size="small" style="width: 100%">
|
|
|
|
|
|
<el-table-column width="50">
|
|
|
|
|
|
<template slot="header">
|
2026-06-10 17:22:12 +08:00
|
|
|
|
<el-checkbox :indeterminate="parent.isIndeterminate" :value="parent.checkedAll"
|
2026-06-05 10:45:37 +08:00
|
|
|
|
@change="val => handleParentSelectAll(parent, val)" />
|
|
|
|
|
|
</template>
|
|
|
|
|
|
<template slot-scope="scope">
|
2026-06-10 17:22:12 +08:00
|
|
|
|
<el-checkbox v-model="scope.row._selected" @change="() => recalcParentCheckState(parent)" />
|
2026-06-05 10:45:37 +08:00
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
<el-table-column label="缺陷描述" prop="remark" show-overflow-tooltip />
|
|
|
|
|
|
<el-table-column label="开始位置" prop="startPosition" width="80" />
|
|
|
|
|
|
<el-table-column label="结束位置" prop="endPosition" width="80" />
|
|
|
|
|
|
<el-table-column label="长度" width="70">
|
|
|
|
|
|
<template slot-scope="scope">{{ scope.row.endPosition - scope.row.startPosition }}</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
<el-table-column label="上下版面" prop="plateSurface" width="100" />
|
|
|
|
|
|
<el-table-column label="断面位置" prop="position" width="160" />
|
|
|
|
|
|
<el-table-column label="缺陷代码" prop="defectCode" width="80" />
|
|
|
|
|
|
<el-table-column label="程度" prop="degree" width="60" />
|
|
|
|
|
|
<el-table-column label="主缺陷" width="60">
|
|
|
|
|
|
<template slot-scope="scope">{{ scope.row.mainMark === 1 ? '是' : '否' }}</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
</el-table>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
<el-empty v-else description="未找到母卷的异常记录" />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<span slot="footer">
|
|
|
|
|
|
<el-button @click="inheritDialogVisible = false">取消</el-button>
|
|
|
|
|
|
<el-button type="primary" :loading="inheritButtonLoading" @click="confirmInherit"
|
|
|
|
|
|
:disabled="selectedInheritCount === 0">
|
|
|
|
|
|
确认继承 ({{ selectedInheritCount }})
|
|
|
|
|
|
</el-button>
|
|
|
|
|
|
</span>
|
|
|
|
|
|
</el-dialog>
|
2025-11-03 13:16:04 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script>
|
2026-05-12 10:40:02 +08:00
|
|
|
|
import { getMaterialCoil, splitMaterialCoil, getFirstHeatCoilMaterial } from '@/api/wms/coil';
|
2026-06-05 10:45:37 +08:00
|
|
|
|
import { listCoilAbnormal } from '@/api/wms/coilAbnormal';
|
2025-11-03 17:03:03 +08:00
|
|
|
|
import { listWarehouse } from '@/api/wms/warehouse';
|
2026-03-18 10:24:28 +08:00
|
|
|
|
import { completeAction, getPendingAction } from '@/api/wms/pendingAction';
|
2025-11-04 09:42:59 +08:00
|
|
|
|
import ActualWarehouseSelect from "@/components/KLPService/ActualWarehouseSelect";
|
2025-11-18 15:15:05 +08:00
|
|
|
|
import RawMaterialSelect from "@/components/KLPService/RawMaterialSelect";
|
|
|
|
|
|
import ProductSelect from "@/components/KLPService/ProductSelect";
|
2025-12-23 10:23:12 +08:00
|
|
|
|
import WarehouseSelect from "@/components/KLPService/WarehouseSelect";
|
2026-03-17 18:01:46 +08:00
|
|
|
|
import TimeInput from "@/components/TimeInput";
|
2026-03-19 17:50:37 +08:00
|
|
|
|
import AbnormalForm from './components/AbnormalForm';
|
2026-06-08 10:22:30 +08:00
|
|
|
|
import PlanSheetViewer from './components/PlanSheetViewer.vue';
|
2026-03-03 14:15:45 +08:00
|
|
|
|
import { generateCoilNoPrefix } from "@/utils/coil/coilNo";
|
2026-04-18 16:18:22 +08:00
|
|
|
|
import ContractSelect from "@/components/KLPService/ContractSelect";
|
|
|
|
|
|
import { addCoilContractRel } from "@/api/wms/coilContractRel";
|
2025-11-03 13:16:04 +08:00
|
|
|
|
|
|
|
|
|
|
export default {
|
|
|
|
|
|
name: 'SplitCoil',
|
|
|
|
|
|
components: {
|
2025-11-18 15:15:05 +08:00
|
|
|
|
ActualWarehouseSelect,
|
|
|
|
|
|
RawMaterialSelect,
|
|
|
|
|
|
ProductSelect,
|
2025-12-23 10:23:12 +08:00
|
|
|
|
WarehouseSelect,
|
2026-03-17 18:01:46 +08:00
|
|
|
|
TimeInput,
|
2026-04-18 16:18:22 +08:00
|
|
|
|
AbnormalForm,
|
2026-06-08 10:22:30 +08:00
|
|
|
|
ContractSelect,
|
|
|
|
|
|
PlanSheetViewer,
|
2025-11-03 13:16:04 +08:00
|
|
|
|
},
|
2026-04-08 17:55:30 +08:00
|
|
|
|
dicts: ['coil_quality_status', 'coil_abnormal_position', 'coil_abnormal_code', 'coil_abnormal_degree', 'coil_business_purpose'],
|
2025-11-03 13:16:04 +08:00
|
|
|
|
data() {
|
2026-03-03 14:15:45 +08:00
|
|
|
|
const currentCoilNoPrefix = generateCoilNoPrefix()
|
2025-11-03 13:16:04 +08:00
|
|
|
|
return {
|
2026-03-03 14:15:45 +08:00
|
|
|
|
currentCoilNoPrefix,
|
2025-11-03 13:16:04 +08:00
|
|
|
|
// 母卷信息
|
|
|
|
|
|
motherCoil: {
|
|
|
|
|
|
coilId: null,
|
2025-11-03 17:03:03 +08:00
|
|
|
|
enterCoilNo: '',
|
2025-11-03 13:16:04 +08:00
|
|
|
|
currentCoilNo: '',
|
2025-11-03 17:03:03 +08:00
|
|
|
|
team: '',
|
2025-11-03 13:16:04 +08:00
|
|
|
|
warehouseId: null,
|
2025-11-03 17:03:03 +08:00
|
|
|
|
warehouseName: '',
|
2025-11-03 13:16:04 +08:00
|
|
|
|
itemType: null,
|
|
|
|
|
|
itemId: null,
|
2025-11-03 17:03:03 +08:00
|
|
|
|
materialName: '',
|
|
|
|
|
|
productName: '',
|
|
|
|
|
|
grossWeight: null,
|
|
|
|
|
|
netWeight: null,
|
2026-01-15 11:01:41 +08:00
|
|
|
|
itemName: null,
|
|
|
|
|
|
itemManufacturer: null,
|
|
|
|
|
|
itemMaterial: null,
|
|
|
|
|
|
itemSpecification: null,
|
2025-11-03 13:16:04 +08:00
|
|
|
|
},
|
|
|
|
|
|
// 子卷列表
|
|
|
|
|
|
splitList: [
|
2025-11-03 17:03:03 +08:00
|
|
|
|
{
|
2026-03-03 14:15:45 +08:00
|
|
|
|
currentCoilNo: currentCoilNoPrefix,
|
2025-11-03 17:03:03 +08:00
|
|
|
|
team: '',
|
2025-11-11 12:21:16 +08:00
|
|
|
|
materialType: null,
|
2025-11-03 17:03:03 +08:00
|
|
|
|
itemType: null,
|
|
|
|
|
|
itemId: null,
|
2026-01-09 13:37:18 +08:00
|
|
|
|
grossWeight: undefined,
|
|
|
|
|
|
netWeight: undefined,
|
2025-11-04 09:42:59 +08:00
|
|
|
|
warehouseId: null,
|
2025-12-29 16:22:18 +08:00
|
|
|
|
actualWarehouseId: null,
|
2026-01-09 13:37:18 +08:00
|
|
|
|
length: undefined,
|
2026-01-22 10:20:58 +08:00
|
|
|
|
temperGrade: '',
|
|
|
|
|
|
coatingType: '',
|
2026-03-12 17:03:02 +08:00
|
|
|
|
actualLength: undefined,
|
|
|
|
|
|
actualWidth: undefined,
|
2026-03-17 18:01:46 +08:00
|
|
|
|
productionStartTime: '',
|
|
|
|
|
|
productionEndTime: '',
|
|
|
|
|
|
productionDuration: '',
|
|
|
|
|
|
formattedDuration: '',
|
2026-03-19 17:50:37 +08:00
|
|
|
|
abnormals: []
|
2025-11-03 17:03:03 +08:00
|
|
|
|
}
|
2025-11-03 13:16:04 +08:00
|
|
|
|
],
|
|
|
|
|
|
loading: false,
|
|
|
|
|
|
// 钢卷选择器可见性
|
2025-11-03 17:03:03 +08:00
|
|
|
|
coilSelectorVisible: false,
|
|
|
|
|
|
// 库区列表
|
|
|
|
|
|
warehouseList: [],
|
2025-11-17 11:58:42 +08:00
|
|
|
|
// 原材料和产品列表(实时搜索,不再保存完整备份)
|
2025-11-03 17:03:03 +08:00
|
|
|
|
rawMaterialList: [],
|
|
|
|
|
|
productList: [],
|
|
|
|
|
|
itemSearchLoading: false,
|
|
|
|
|
|
// 只读模式
|
2025-11-05 22:18:10 +08:00
|
|
|
|
readonly: false,
|
|
|
|
|
|
// 待操作ID
|
2026-03-18 10:24:28 +08:00
|
|
|
|
actionId: null,
|
2026-03-19 17:50:37 +08:00
|
|
|
|
currentAction: {},
|
|
|
|
|
|
// 异常表单弹窗
|
|
|
|
|
|
abnormalDialogVisible: false,
|
|
|
|
|
|
// 当前编辑的子卷索引
|
|
|
|
|
|
currentSubCoilIndex: -1,
|
|
|
|
|
|
// 当前编辑的异常索引
|
|
|
|
|
|
currentAbnormalIndex: -1,
|
|
|
|
|
|
// 异常表单数据
|
|
|
|
|
|
abnormalForm: {
|
|
|
|
|
|
coilId: null,
|
|
|
|
|
|
position: null,
|
|
|
|
|
|
startPosition: 0,
|
|
|
|
|
|
endPosition: 0,
|
|
|
|
|
|
length: 0,
|
|
|
|
|
|
defectCode: null,
|
|
|
|
|
|
degree: null,
|
|
|
|
|
|
remark: null
|
2026-05-12 10:40:02 +08:00
|
|
|
|
},
|
|
|
|
|
|
// 最早热轧卷板材质
|
|
|
|
|
|
firstHeatMaterial: null,
|
2026-06-05 10:45:37 +08:00
|
|
|
|
// 异常继承
|
|
|
|
|
|
inheritDialogVisible: false,
|
|
|
|
|
|
inheritLoading: false,
|
|
|
|
|
|
inheritButtonLoading: false,
|
|
|
|
|
|
parentCoils: [],
|
|
|
|
|
|
currentInheritSubCoilIndex: -1,
|
2025-11-03 13:16:04 +08:00
|
|
|
|
};
|
|
|
|
|
|
},
|
|
|
|
|
|
computed: {
|
2026-05-28 17:43:04 +08:00
|
|
|
|
planSheetLineName() {
|
|
|
|
|
|
return '酸轧线'
|
|
|
|
|
|
},
|
|
|
|
|
|
todayDateStr() {
|
|
|
|
|
|
const d = new Date()
|
|
|
|
|
|
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`
|
|
|
|
|
|
},
|
2026-06-05 10:45:37 +08:00
|
|
|
|
selectedInheritCount() {
|
|
|
|
|
|
let count = 0
|
|
|
|
|
|
for (const parent of this.parentCoils) {
|
|
|
|
|
|
for (const row of parent.abnormalList) {
|
|
|
|
|
|
if (row._selected) count++
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return count
|
|
|
|
|
|
},
|
2025-11-03 13:16:04 +08:00
|
|
|
|
},
|
2025-11-03 17:03:03 +08:00
|
|
|
|
async created() {
|
|
|
|
|
|
// 先加载库区列表
|
|
|
|
|
|
await this.loadWarehouses();
|
|
|
|
|
|
|
2025-11-17 11:58:42 +08:00
|
|
|
|
// 不再一次性加载所有数据,改为实时搜索
|
|
|
|
|
|
// await this.loadAllItems();
|
2025-11-11 12:21:16 +08:00
|
|
|
|
|
2025-11-05 22:18:10 +08:00
|
|
|
|
// 从路由参数获取coilId、actionId和readonly
|
2025-11-03 13:16:04 +08:00
|
|
|
|
const coilId = this.$route.query.coilId;
|
2025-11-05 22:18:10 +08:00
|
|
|
|
const actionId = this.$route.query.actionId;
|
2025-11-03 17:03:03 +08:00
|
|
|
|
const readonly = this.$route.query.readonly;
|
2025-11-14 09:49:33 +08:00
|
|
|
|
|
2026-03-18 10:24:28 +08:00
|
|
|
|
// 获取待操作详情
|
|
|
|
|
|
getPendingAction(actionId).then(res => {
|
|
|
|
|
|
// 填写生产开始时间
|
|
|
|
|
|
this.currentAction = res.data
|
|
|
|
|
|
this.$set(this.splitList[0], 'productionStartTime', res.data.createTime)
|
|
|
|
|
|
})
|
|
|
|
|
|
|
2025-11-03 13:16:04 +08:00
|
|
|
|
if (coilId) {
|
2025-11-03 17:03:03 +08:00
|
|
|
|
await this.loadMotherCoil(coilId);
|
|
|
|
|
|
}
|
2025-11-14 09:49:33 +08:00
|
|
|
|
|
2025-11-05 22:18:10 +08:00
|
|
|
|
// 保存待操作ID
|
|
|
|
|
|
if (actionId) {
|
|
|
|
|
|
this.actionId = actionId;
|
|
|
|
|
|
}
|
2025-11-14 09:49:33 +08:00
|
|
|
|
|
2025-11-03 17:03:03 +08:00
|
|
|
|
// 设置只读模式
|
|
|
|
|
|
if (readonly === 'true' || readonly === true) {
|
|
|
|
|
|
this.readonly = true;
|
2025-11-03 13:16:04 +08:00
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
methods: {
|
2025-11-11 14:21:46 +08:00
|
|
|
|
// 处理材料类型变化
|
|
|
|
|
|
handleMaterialTypeChange(item, index) {
|
|
|
|
|
|
// 清空物品选择
|
|
|
|
|
|
this.$set(item, 'itemId', null);
|
2025-11-14 09:49:33 +08:00
|
|
|
|
|
2025-11-17 11:58:42 +08:00
|
|
|
|
// 根据材料类型设置物品类型
|
2025-11-11 14:21:46 +08:00
|
|
|
|
if (item.materialType === '成品') {
|
|
|
|
|
|
this.$set(item, 'itemType', 'product');
|
2025-11-17 11:58:42 +08:00
|
|
|
|
// 清空列表,等待用户搜索
|
|
|
|
|
|
this.productList = [];
|
2026-01-13 14:36:32 +08:00
|
|
|
|
} else if (item.materialType === '原料') {
|
2025-11-11 14:21:46 +08:00
|
|
|
|
this.$set(item, 'itemType', 'raw_material');
|
2025-11-17 11:58:42 +08:00
|
|
|
|
// 清空列表,等待用户搜索
|
|
|
|
|
|
this.rawMaterialList = [];
|
2025-11-11 14:21:46 +08:00
|
|
|
|
}
|
|
|
|
|
|
},
|
2025-11-14 09:49:33 +08:00
|
|
|
|
|
2025-11-11 12:21:16 +08:00
|
|
|
|
// 动态获取标签
|
|
|
|
|
|
getItemLabel(materialType) {
|
|
|
|
|
|
if (materialType === '成品') {
|
|
|
|
|
|
return '产品类型';
|
2026-01-13 14:36:32 +08:00
|
|
|
|
} else if (materialType === '原料') {
|
2025-11-11 12:21:16 +08:00
|
|
|
|
return '原料类型';
|
|
|
|
|
|
}
|
|
|
|
|
|
return '物品';
|
|
|
|
|
|
},
|
|
|
|
|
|
// 动态获取占位符
|
|
|
|
|
|
getItemPlaceholder(materialType) {
|
|
|
|
|
|
if (materialType === '成品') {
|
|
|
|
|
|
return '请选择产品类型';
|
|
|
|
|
|
} else if (materialType === '原料') {
|
|
|
|
|
|
return '请选择原料类型';
|
|
|
|
|
|
}
|
|
|
|
|
|
return '请先选择材料类型';
|
|
|
|
|
|
},
|
2025-11-03 17:03:03 +08:00
|
|
|
|
|
2025-11-13 13:29:19 +08:00
|
|
|
|
// 格式化物品名称(添加规格和参数信息)
|
2025-11-05 22:18:10 +08:00
|
|
|
|
formatItemName(item) {
|
|
|
|
|
|
if (!item) return '';
|
2025-11-14 09:49:33 +08:00
|
|
|
|
|
2025-11-05 22:18:10 +08:00
|
|
|
|
// 获取名称(原材料或产品)
|
|
|
|
|
|
const name = item.rawMaterialName || item.productName || '';
|
|
|
|
|
|
if (!name) return '';
|
2025-11-14 09:49:33 +08:00
|
|
|
|
|
2025-11-05 22:18:10 +08:00
|
|
|
|
let displayName = name;
|
|
|
|
|
|
const specs = [];
|
2025-11-14 09:49:33 +08:00
|
|
|
|
|
2025-11-05 22:18:10 +08:00
|
|
|
|
// 1. 优先显示规格(从对象的specification字段)
|
|
|
|
|
|
if (item.specification) {
|
|
|
|
|
|
specs.push(item.specification);
|
|
|
|
|
|
}
|
2025-11-14 09:49:33 +08:00
|
|
|
|
|
2025-11-13 13:29:19 +08:00
|
|
|
|
// 2. 添加参数参数(最多2个)
|
2025-11-05 22:18:10 +08:00
|
|
|
|
if (item.bomItems && item.bomItems.length > 0) {
|
|
|
|
|
|
const bomParams = item.bomItems
|
|
|
|
|
|
.filter(bomItem => bomItem.attrKey && bomItem.attrValue)
|
2025-11-13 13:29:19 +08:00
|
|
|
|
.slice(0, 2); // 最多2个参数参数
|
2025-11-14 09:49:33 +08:00
|
|
|
|
|
2025-11-05 22:18:10 +08:00
|
|
|
|
bomParams.forEach(param => {
|
|
|
|
|
|
specs.push(`${param.attrKey}:${param.attrValue}`);
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
2025-11-14 09:49:33 +08:00
|
|
|
|
|
2025-11-05 22:18:10 +08:00
|
|
|
|
// 3. 拼接成最终格式
|
|
|
|
|
|
if (specs.length > 0) {
|
|
|
|
|
|
displayName += `(${specs.join(' ')})`;
|
|
|
|
|
|
}
|
2025-11-14 09:49:33 +08:00
|
|
|
|
|
2025-11-05 22:18:10 +08:00
|
|
|
|
return displayName;
|
|
|
|
|
|
},
|
|
|
|
|
|
|
2025-11-03 13:16:04 +08:00
|
|
|
|
// 加载母卷信息
|
|
|
|
|
|
async loadMotherCoil(coilId) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
this.loading = true;
|
|
|
|
|
|
const response = await getMaterialCoil(coilId);
|
|
|
|
|
|
if (response.code === 200 && response.data) {
|
|
|
|
|
|
const data = response.data;
|
|
|
|
|
|
this.motherCoil = {
|
|
|
|
|
|
coilId: data.coilId,
|
2025-11-03 17:03:03 +08:00
|
|
|
|
enterCoilNo: data.enterCoilNo || '',
|
2025-11-03 13:16:04 +08:00
|
|
|
|
currentCoilNo: data.currentCoilNo || '',
|
2025-11-03 17:03:03 +08:00
|
|
|
|
team: data.team || '',
|
2025-11-03 13:16:04 +08:00
|
|
|
|
warehouseId: data.warehouseId,
|
2025-11-03 17:03:03 +08:00
|
|
|
|
warehouseName: data.warehouseName || (data.warehouse ? data.warehouse.warehouseName : ''),
|
2025-11-03 13:16:04 +08:00
|
|
|
|
itemType: data.itemType,
|
|
|
|
|
|
itemId: data.itemId,
|
2026-01-14 15:11:39 +08:00
|
|
|
|
materialType: data.materialType,
|
2026-03-24 13:55:10 +08:00
|
|
|
|
itemName: data.itemName || '',
|
2025-11-03 17:03:03 +08:00
|
|
|
|
grossWeight: data.grossWeight,
|
|
|
|
|
|
netWeight: data.netWeight,
|
2025-12-29 16:22:18 +08:00
|
|
|
|
length: data.length,
|
2026-03-24 13:55:10 +08:00
|
|
|
|
itemManufacturer: data?.manufacturer || '',
|
|
|
|
|
|
itemMaterial: data?.material || '',
|
|
|
|
|
|
itemSpecification: data?.specification || '',
|
2025-11-03 13:16:04 +08:00
|
|
|
|
};
|
2026-05-12 10:40:02 +08:00
|
|
|
|
|
|
|
|
|
|
// 获取最早的热轧卷板材质
|
|
|
|
|
|
try {
|
|
|
|
|
|
const firstHeatMaterial = await getFirstHeatCoilMaterial(this.motherCoil.enterCoilNo);
|
|
|
|
|
|
if (firstHeatMaterial.code === 200 && firstHeatMaterial.msg) {
|
|
|
|
|
|
this.firstHeatMaterial = firstHeatMaterial.msg
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for (const item of this.splitList) {
|
|
|
|
|
|
item.packingStatus = this.firstHeatMaterial || ''
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
// console.error('获取最早的热轧卷板材质失败', error);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-03 13:16:04 +08:00
|
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
this.$message.error('加载母卷信息失败');
|
|
|
|
|
|
console.error(error);
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
this.loading = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
|
2025-11-03 17:03:03 +08:00
|
|
|
|
// 加载库区列表
|
|
|
|
|
|
async loadWarehouses() {
|
|
|
|
|
|
try {
|
|
|
|
|
|
const response = await listWarehouse({ pageNum: 1, pageSize: 1000 });
|
|
|
|
|
|
if (response.code === 200) {
|
|
|
|
|
|
this.warehouseList = response.rows || response.data || [];
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('加载库区列表失败', error);
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
|
2025-11-03 13:16:04 +08:00
|
|
|
|
// 添加子卷
|
|
|
|
|
|
addSplitItem() {
|
|
|
|
|
|
this.splitList.push({
|
2026-03-03 14:15:45 +08:00
|
|
|
|
currentCoilNo: this.currentCoilNoPrefix,
|
2025-11-03 17:03:03 +08:00
|
|
|
|
team: '',
|
2025-11-11 12:21:16 +08:00
|
|
|
|
materialType: null,
|
2025-11-03 17:03:03 +08:00
|
|
|
|
itemType: null,
|
|
|
|
|
|
itemId: null,
|
|
|
|
|
|
grossWeight: null,
|
|
|
|
|
|
netWeight: null,
|
2025-12-29 16:22:18 +08:00
|
|
|
|
length: null,
|
2025-11-04 09:42:59 +08:00
|
|
|
|
warehouseId: null,
|
2025-11-14 10:31:55 +08:00
|
|
|
|
actualWarehouseId: null,
|
|
|
|
|
|
qualityStatus: '',
|
|
|
|
|
|
packagingRequirement: '',
|
2026-05-12 10:40:02 +08:00
|
|
|
|
packingStatus: this.firstHeatMaterial || '',
|
2026-01-22 10:20:58 +08:00
|
|
|
|
trimmingRequirement: '',
|
|
|
|
|
|
temperGrade: '',
|
|
|
|
|
|
coatingType: '',
|
2026-03-12 17:03:02 +08:00
|
|
|
|
actualLength: undefined,
|
|
|
|
|
|
actualWidth: undefined,
|
2026-03-18 10:24:28 +08:00
|
|
|
|
productionStartTime: this.currentAction.createTime,
|
2026-03-17 18:01:46 +08:00
|
|
|
|
productionEndTime: '',
|
|
|
|
|
|
productionDuration: '',
|
|
|
|
|
|
formattedDuration: '',
|
2026-03-19 17:50:37 +08:00
|
|
|
|
abnormals: []
|
2025-11-03 13:16:04 +08:00
|
|
|
|
});
|
|
|
|
|
|
},
|
2025-11-03 17:03:03 +08:00
|
|
|
|
|
2025-11-03 13:16:04 +08:00
|
|
|
|
// 删除子卷
|
|
|
|
|
|
removeSplitItem(index) {
|
|
|
|
|
|
if (this.splitList.length > 1) {
|
|
|
|
|
|
this.splitList.splice(index, 1);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
this.$message.warning('至少保留一个子卷');
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
2025-11-03 17:03:03 +08:00
|
|
|
|
|
2025-11-11 12:21:16 +08:00
|
|
|
|
// 保存分条
|
2025-11-03 13:16:04 +08:00
|
|
|
|
async handleSave() {
|
|
|
|
|
|
// 验证母卷信息
|
|
|
|
|
|
if (!this.motherCoil.coilId) {
|
|
|
|
|
|
this.$message.error('请先选择母卷');
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 验证子卷数量
|
|
|
|
|
|
if (this.splitList.length < 1) {
|
|
|
|
|
|
this.$message.error('至少需要一个子卷');
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 验证子卷信息
|
|
|
|
|
|
for (let i = 0; i < this.splitList.length; i++) {
|
|
|
|
|
|
const item = this.splitList[i];
|
|
|
|
|
|
if (!item.currentCoilNo || item.currentCoilNo.trim() === '') {
|
|
|
|
|
|
this.$message.error(`第${i + 1}个子卷的卷号不能为空`);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2025-11-03 17:03:03 +08:00
|
|
|
|
if (!item.team || item.team.trim() === '') {
|
|
|
|
|
|
this.$message.error(`第${i + 1}个子卷的班组不能为空`);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (!item.itemType) {
|
|
|
|
|
|
this.$message.error(`第${i + 1}个子卷的物品类型不能为空`);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (!item.itemId) {
|
|
|
|
|
|
this.$message.error(`第${i + 1}个子卷的物品不能为空`);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (item.grossWeight === null || item.grossWeight === undefined || item.grossWeight === '') {
|
|
|
|
|
|
this.$message.error(`第${i + 1}个子卷的毛重不能为空`);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (item.netWeight === null || item.netWeight === undefined || item.netWeight === '') {
|
|
|
|
|
|
this.$message.error(`第${i + 1}个子卷的净重不能为空`);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2025-11-04 09:42:59 +08:00
|
|
|
|
if (!item.warehouseId) {
|
2025-11-03 17:03:03 +08:00
|
|
|
|
this.$message.error(`第${i + 1}个子卷的目标库区不能为空`);
|
2025-11-03 13:16:04 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-14 09:49:33 +08:00
|
|
|
|
const loadingInstance = this.$loading({
|
|
|
|
|
|
lock: true,
|
|
|
|
|
|
text: '正在分条,请稍后...',
|
|
|
|
|
|
background: 'rgba(0, 0, 0, 0.7)'
|
|
|
|
|
|
})
|
2025-11-04 09:42:59 +08:00
|
|
|
|
|
2025-11-03 13:16:04 +08:00
|
|
|
|
try {
|
|
|
|
|
|
this.loading = true;
|
|
|
|
|
|
|
2025-11-11 12:21:16 +08:00
|
|
|
|
// 构造分条数据
|
2025-11-03 13:16:04 +08:00
|
|
|
|
const splitData = {
|
|
|
|
|
|
coilId: this.motherCoil.coilId,
|
2025-11-03 17:03:03 +08:00
|
|
|
|
enterCoilNo: this.motherCoil.enterCoilNo, // 入场钢卷号(必填)
|
2025-11-03 13:16:04 +08:00
|
|
|
|
currentCoilNo: this.motherCoil.currentCoilNo,
|
2026-01-14 15:02:39 +08:00
|
|
|
|
materialType: this.motherCoil.materialType,
|
2025-11-11 12:21:16 +08:00
|
|
|
|
hasMergeSplit: 1, // 1表示分条
|
2025-11-03 13:16:04 +08:00
|
|
|
|
newCoils: this.splitList.map(item => ({
|
2025-11-14 10:31:55 +08:00
|
|
|
|
...item,
|
2025-11-03 17:03:03 +08:00
|
|
|
|
itemType: item.itemType || this.motherCoil.itemType,
|
|
|
|
|
|
itemId: item.itemId || this.motherCoil.itemId,
|
|
|
|
|
|
hasMergeSplit: 1
|
2025-11-03 13:16:04 +08:00
|
|
|
|
}))
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2026-05-19 15:39:53 +08:00
|
|
|
|
const response = await splitMaterialCoil({ ...splitData, actionId: this.actionId });
|
2025-11-03 13:16:04 +08:00
|
|
|
|
if (response.code === 200) {
|
2025-11-11 12:21:16 +08:00
|
|
|
|
this.$message.success('分条保存成功');
|
2025-11-14 09:49:33 +08:00
|
|
|
|
|
2026-04-18 16:18:22 +08:00
|
|
|
|
// 拿到多个子卷的coilId
|
|
|
|
|
|
const newCoilIds = response.msg.split(',');
|
2026-04-20 11:04:14 +08:00
|
|
|
|
// 先构建所有的请求体,并移除合同为空为空的项
|
|
|
|
|
|
const requests = newCoilIds.map((coilId, index) => ({
|
|
|
|
|
|
coilId,
|
|
|
|
|
|
contractId: this.splitList[index].contractId
|
|
|
|
|
|
}))
|
2026-05-12 10:40:02 +08:00
|
|
|
|
.filter(req => req.contractId);
|
2026-04-18 16:18:22 +08:00
|
|
|
|
// 为每个子卷添加合同关联
|
2026-04-20 11:04:14 +08:00
|
|
|
|
Promise.all(requests.map(async (req, index) => {
|
|
|
|
|
|
addCoilContractRel(req);
|
2026-04-18 16:18:22 +08:00
|
|
|
|
}));
|
|
|
|
|
|
|
2025-11-05 22:18:10 +08:00
|
|
|
|
// 如果是从待操作列表进来的,标记操作为完成
|
2026-05-19 15:39:53 +08:00
|
|
|
|
// if (this.actionId) {
|
|
|
|
|
|
// await completeAction(this.actionId, response.msg);
|
|
|
|
|
|
// }
|
2025-11-14 09:49:33 +08:00
|
|
|
|
|
2025-11-03 13:16:04 +08:00
|
|
|
|
// 延迟返回,让用户看到成功提示
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
|
this.$router.back();
|
2025-11-18 15:15:05 +08:00
|
|
|
|
}, 100);
|
2025-11-03 13:16:04 +08:00
|
|
|
|
} else {
|
2025-11-11 12:21:16 +08:00
|
|
|
|
this.$message.error(response.msg || '分条保存失败');
|
2025-11-03 13:16:04 +08:00
|
|
|
|
}
|
2025-11-14 09:49:33 +08:00
|
|
|
|
|
2025-11-03 13:16:04 +08:00
|
|
|
|
} catch (error) {
|
2025-11-11 12:21:16 +08:00
|
|
|
|
this.$message.error('分条保存失败');
|
2025-11-03 13:16:04 +08:00
|
|
|
|
console.error(error);
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
this.loading = false;
|
2025-11-04 09:42:59 +08:00
|
|
|
|
loadingInstance.close();
|
2025-11-03 13:16:04 +08:00
|
|
|
|
}
|
|
|
|
|
|
},
|
2025-11-03 17:03:03 +08:00
|
|
|
|
|
2025-11-03 13:16:04 +08:00
|
|
|
|
// 取消操作
|
|
|
|
|
|
handleCancel() {
|
|
|
|
|
|
this.$router.back();
|
2025-11-03 17:03:03 +08:00
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 复制到全部子卷
|
|
|
|
|
|
copyToAllSubCoils() {
|
|
|
|
|
|
if (!this.motherCoil.coilId) {
|
|
|
|
|
|
this.$message.warning('请先加载母卷信息');
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 复制到所有子卷
|
|
|
|
|
|
this.splitList.forEach((item, index) => {
|
|
|
|
|
|
// 自动生成卷号:母卷号-1, 母卷号-2, 母卷号-3...
|
|
|
|
|
|
if (!item.currentCoilNo) {
|
|
|
|
|
|
item.currentCoilNo = `${this.motherCoil.currentCoilNo}-${index + 1}`;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 复制班组
|
|
|
|
|
|
if (!item.team) {
|
|
|
|
|
|
item.team = this.motherCoil.team;
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2025-11-17 11:58:42 +08:00
|
|
|
|
// 不再预加载物品列表,改为实时搜索
|
2025-11-03 17:03:03 +08:00
|
|
|
|
|
|
|
|
|
|
this.$message.success('已复制到所有子卷');
|
2026-03-17 18:01:46 +08:00
|
|
|
|
},
|
|
|
|
|
|
// 格式化毫秒值为xx天xx小时xx分钟
|
|
|
|
|
|
formatDuration(milliseconds) {
|
|
|
|
|
|
if (!milliseconds || milliseconds < 0) return '';
|
2026-05-12 10:40:02 +08:00
|
|
|
|
|
2026-03-17 18:01:46 +08:00
|
|
|
|
const seconds = Math.floor(milliseconds / 1000);
|
|
|
|
|
|
const minutes = Math.floor(seconds / 60);
|
|
|
|
|
|
const hours = Math.floor(minutes / 60);
|
|
|
|
|
|
const days = Math.floor(hours / 24);
|
2026-05-12 10:40:02 +08:00
|
|
|
|
|
2026-03-17 18:01:46 +08:00
|
|
|
|
const remainingHours = hours % 24;
|
|
|
|
|
|
const remainingMinutes = minutes % 60;
|
2026-05-12 10:40:02 +08:00
|
|
|
|
|
2026-03-17 18:01:46 +08:00
|
|
|
|
let result = '';
|
|
|
|
|
|
if (days > 0) result += `${days}天`;
|
|
|
|
|
|
if (remainingHours > 0) result += `${remainingHours}小时`;
|
|
|
|
|
|
if (remainingMinutes > 0) result += `${remainingMinutes}分钟`;
|
2026-05-12 10:40:02 +08:00
|
|
|
|
|
2026-03-17 18:01:46 +08:00
|
|
|
|
return result || '0分钟';
|
|
|
|
|
|
},
|
|
|
|
|
|
// 计算生产耗时
|
|
|
|
|
|
calculateProductionDuration(item) {
|
|
|
|
|
|
if (!item) return;
|
2026-05-12 10:40:02 +08:00
|
|
|
|
|
2026-03-17 18:01:46 +08:00
|
|
|
|
const { productionStartTime, productionEndTime } = item;
|
|
|
|
|
|
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(item, 'productionDuration', '');
|
|
|
|
|
|
this.$set(item, 'formattedDuration', '');
|
|
|
|
|
|
} else {
|
|
|
|
|
|
const durationMs = end - start;
|
|
|
|
|
|
const durationMinutes = Math.round(durationMs / (1000 * 60));
|
|
|
|
|
|
this.$set(item, 'productionDuration', durationMinutes);
|
|
|
|
|
|
this.$set(item, 'formattedDuration', this.formatDuration(durationMinutes * 60 * 1000));
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
this.$set(item, 'productionDuration', '');
|
|
|
|
|
|
this.$set(item, 'formattedDuration', '');
|
|
|
|
|
|
}
|
2026-03-19 17:50:37 +08:00
|
|
|
|
},
|
2026-05-12 10:40:02 +08:00
|
|
|
|
|
2026-03-19 17:50:37 +08:00
|
|
|
|
// 新增异常
|
|
|
|
|
|
addAbnormal(subCoilIndex) {
|
|
|
|
|
|
this.currentSubCoilIndex = subCoilIndex;
|
|
|
|
|
|
this.currentAbnormalIndex = -1;
|
|
|
|
|
|
this.abnormalForm = {
|
|
|
|
|
|
coilId: null,
|
|
|
|
|
|
position: null,
|
|
|
|
|
|
startPosition: 0,
|
|
|
|
|
|
endPosition: 0,
|
|
|
|
|
|
length: 0,
|
|
|
|
|
|
defectCode: null,
|
|
|
|
|
|
degree: null,
|
|
|
|
|
|
remark: null
|
|
|
|
|
|
};
|
|
|
|
|
|
this.abnormalDialogVisible = true;
|
|
|
|
|
|
},
|
2026-05-12 10:40:02 +08:00
|
|
|
|
|
2026-03-19 17:50:37 +08:00
|
|
|
|
// 编辑异常
|
|
|
|
|
|
editAbnormal(subCoilIndex, abnormalIndex) {
|
|
|
|
|
|
this.currentSubCoilIndex = subCoilIndex;
|
|
|
|
|
|
this.currentAbnormalIndex = abnormalIndex;
|
|
|
|
|
|
this.abnormalForm = { ...this.splitList[subCoilIndex].abnormals[abnormalIndex] };
|
|
|
|
|
|
this.abnormalDialogVisible = true;
|
|
|
|
|
|
},
|
2026-05-12 10:40:02 +08:00
|
|
|
|
|
2026-03-19 17:50:37 +08:00
|
|
|
|
// 保存异常
|
|
|
|
|
|
saveAbnormal() {
|
|
|
|
|
|
this.$refs.abnormalForm.validate(valid => {
|
|
|
|
|
|
if (valid) {
|
|
|
|
|
|
// 计算缺陷长度
|
|
|
|
|
|
this.abnormalForm.length = this.abnormalForm.endPosition - this.abnormalForm.startPosition;
|
2026-05-12 10:40:02 +08:00
|
|
|
|
|
2026-03-19 17:50:37 +08:00
|
|
|
|
if (this.currentAbnormalIndex === -1) {
|
|
|
|
|
|
// 新增异常
|
|
|
|
|
|
this.splitList[this.currentSubCoilIndex].abnormals.push({ ...this.abnormalForm });
|
|
|
|
|
|
} else {
|
|
|
|
|
|
// 编辑异常
|
|
|
|
|
|
this.splitList[this.currentSubCoilIndex].abnormals[this.currentAbnormalIndex] = { ...this.abnormalForm };
|
|
|
|
|
|
}
|
2026-05-12 10:40:02 +08:00
|
|
|
|
|
2026-03-19 17:50:37 +08:00
|
|
|
|
this.abnormalDialogVisible = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
},
|
2026-05-12 10:40:02 +08:00
|
|
|
|
|
2026-03-19 17:50:37 +08:00
|
|
|
|
// 删除异常
|
|
|
|
|
|
deleteAbnormal(subCoilIndex, abnormalIndex) {
|
|
|
|
|
|
this.$confirm('确定要删除这个异常信息吗?', '提示', {
|
|
|
|
|
|
confirmButtonText: '确定',
|
|
|
|
|
|
cancelButtonText: '取消',
|
|
|
|
|
|
type: 'warning'
|
|
|
|
|
|
}).then(() => {
|
|
|
|
|
|
this.splitList[subCoilIndex].abnormals.splice(abnormalIndex, 1);
|
|
|
|
|
|
});
|
|
|
|
|
|
},
|
2026-05-12 10:40:02 +08:00
|
|
|
|
|
2026-03-19 17:50:37 +08:00
|
|
|
|
// 获取异常位置文本
|
|
|
|
|
|
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;
|
|
|
|
|
|
},
|
2026-05-12 10:40:02 +08:00
|
|
|
|
|
2026-03-19 17:50:37 +08:00
|
|
|
|
// 获取异常代码文本
|
|
|
|
|
|
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;
|
2026-05-28 17:43:04 +08:00
|
|
|
|
},
|
|
|
|
|
|
|
2026-06-05 10:45:37 +08:00
|
|
|
|
// 异常继承
|
|
|
|
|
|
handleInheritAbnormal(subCoilIndex) {
|
|
|
|
|
|
const parentId = this.motherCoil.coilId
|
|
|
|
|
|
if (!parentId) {
|
|
|
|
|
|
this.$message.info('母卷信息未加载,无法继承异常')
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
this.currentInheritSubCoilIndex = subCoilIndex
|
|
|
|
|
|
this.inheritDialogVisible = true
|
|
|
|
|
|
this.parentCoils = []
|
|
|
|
|
|
this.inheritLoading = true
|
|
|
|
|
|
getMaterialCoil(parentId).then(res => {
|
|
|
|
|
|
const coil = res.data || {}
|
|
|
|
|
|
return listCoilAbnormal({ coilId: parentId, pageSize: 999 }).then(res2 => {
|
|
|
|
|
|
const list = (res2.rows || []).map(item => ({ ...item, _selected: false }))
|
|
|
|
|
|
return { coil, abnormalList: list, checkedAll: false, isIndeterminate: false }
|
|
|
|
|
|
})
|
|
|
|
|
|
}).catch(() => null).then(result => {
|
|
|
|
|
|
this.parentCoils = result ? [result] : []
|
|
|
|
|
|
if (this.parentCoils.length === 0) {
|
|
|
|
|
|
this.$message.info('未找到母卷异常记录')
|
|
|
|
|
|
}
|
|
|
|
|
|
}).finally(() => {
|
|
|
|
|
|
this.inheritLoading = false
|
|
|
|
|
|
})
|
|
|
|
|
|
},
|
|
|
|
|
|
recalcParentCheckState(parent) {
|
|
|
|
|
|
const selected = parent.abnormalList.filter(r => r._selected)
|
|
|
|
|
|
const total = parent.abnormalList.length
|
|
|
|
|
|
parent.checkedAll = selected.length === total && total > 0
|
|
|
|
|
|
parent.isIndeterminate = selected.length > 0 && selected.length < total
|
|
|
|
|
|
},
|
|
|
|
|
|
handleParentSelectAll(parent, val) {
|
|
|
|
|
|
parent.abnormalList.forEach(row => { row._selected = val })
|
|
|
|
|
|
parent.checkedAll = val
|
|
|
|
|
|
parent.isIndeterminate = false
|
|
|
|
|
|
},
|
|
|
|
|
|
confirmInherit() {
|
|
|
|
|
|
const selected = []
|
|
|
|
|
|
for (const parent of this.parentCoils) {
|
|
|
|
|
|
for (const row of parent.abnormalList) {
|
|
|
|
|
|
if (row._selected) {
|
|
|
|
|
|
const end = Number(row.endPosition) || 0
|
|
|
|
|
|
const start = Number(row.startPosition) || 0
|
|
|
|
|
|
selected.push({
|
|
|
|
|
|
position: row.position,
|
|
|
|
|
|
plateSurface: row.plateSurface,
|
|
|
|
|
|
startPosition: start,
|
|
|
|
|
|
endPosition: end,
|
|
|
|
|
|
length: end - start,
|
|
|
|
|
|
defectCode: row.defectCode,
|
|
|
|
|
|
degree: row.degree,
|
|
|
|
|
|
mainMark: row.mainMark,
|
|
|
|
|
|
remark: row.remark,
|
|
|
|
|
|
attachmentFiles: row.attachmentFiles,
|
|
|
|
|
|
productionLine: row.productionLine,
|
|
|
|
|
|
processSource: this.planSheetLineName,
|
|
|
|
|
|
_inherited: true,
|
|
|
|
|
|
parentAbnormalId: row.abnormalId
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (selected.length === 0) {
|
|
|
|
|
|
this.$message.info('请选择要继承的异常')
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
const subCoil = this.splitList[this.currentInheritSubCoilIndex]
|
|
|
|
|
|
if (subCoil) {
|
|
|
|
|
|
subCoil.abnormals.push(...selected)
|
|
|
|
|
|
}
|
|
|
|
|
|
this.$message.success(`成功继承 ${selected.length} 条异常记录`)
|
|
|
|
|
|
this.inheritDialogVisible = false
|
|
|
|
|
|
},
|
2025-11-03 13:16:04 +08:00
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style scoped lang="scss">
|
|
|
|
|
|
.split-coil-container {
|
2026-05-29 13:00:33 +08:00
|
|
|
|
padding: 12px;
|
2025-11-03 13:16:04 +08:00
|
|
|
|
background: #f5f7fa;
|
|
|
|
|
|
min-height: calc(100vh - 84px);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 顶部操作栏 */
|
|
|
|
|
|
.header-bar {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
background: #fff;
|
2026-05-29 13:00:33 +08:00
|
|
|
|
padding: 10px 16px;
|
|
|
|
|
|
margin-bottom: 12px;
|
2025-11-03 13:16:04 +08:00
|
|
|
|
border-radius: 4px;
|
|
|
|
|
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.header-title {
|
|
|
|
|
|
font-size: 18px;
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
color: #303133;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 8px;
|
2025-11-03 17:03:03 +08:00
|
|
|
|
|
2025-11-03 13:16:04 +08:00
|
|
|
|
i {
|
|
|
|
|
|
color: #0066cc;
|
|
|
|
|
|
font-size: 20px;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 流程图容器 */
|
|
|
|
|
|
.flow-container {
|
|
|
|
|
|
display: flex;
|
2026-05-29 13:00:33 +08:00
|
|
|
|
gap: 12px;
|
2025-11-03 13:16:04 +08:00
|
|
|
|
background: #fff;
|
2026-05-29 13:00:33 +08:00
|
|
|
|
padding: 12px;
|
2025-11-03 13:16:04 +08:00
|
|
|
|
border-radius: 4px;
|
|
|
|
|
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
2026-05-29 13:00:33 +08:00
|
|
|
|
min-height: 500px;
|
2025-11-03 13:16:04 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.flow-left {
|
2026-05-29 13:00:33 +08:00
|
|
|
|
flex: 0 0 320px;
|
2026-05-28 17:43:04 +08:00
|
|
|
|
overflow-y: auto;
|
2025-11-03 13:16:04 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.flow-right {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
min-width: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.flow-section-title {
|
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
color: #303133;
|
2026-05-29 13:00:33 +08:00
|
|
|
|
margin-bottom: 10px;
|
|
|
|
|
|
padding-left: 10px;
|
2025-11-03 13:16:04 +08:00
|
|
|
|
border-left: 4px solid #0066cc;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
align-items: center;
|
2025-11-03 17:03:03 +08:00
|
|
|
|
|
2025-11-03 13:16:04 +08:00
|
|
|
|
.el-button--text {
|
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 母卷卡片 */
|
|
|
|
|
|
.mother-coil {
|
|
|
|
|
|
border: 2px solid #0066cc;
|
|
|
|
|
|
box-shadow: 0 4px 12px rgba(0, 102, 204, 0.15);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.coil-card {
|
|
|
|
|
|
background: #fff;
|
|
|
|
|
|
border: 1px solid #e4e7ed;
|
|
|
|
|
|
border-radius: 8px;
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.coil-header {
|
|
|
|
|
|
background: #0066cc;
|
|
|
|
|
|
color: #fff;
|
2026-05-29 13:00:33 +08:00
|
|
|
|
padding: 10px 14px;
|
2025-11-03 13:16:04 +08:00
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 10px;
|
2025-11-03 17:03:03 +08:00
|
|
|
|
|
2025-11-03 13:16:04 +08:00
|
|
|
|
i {
|
2026-05-29 13:00:33 +08:00
|
|
|
|
font-size: 18px;
|
2025-11-03 13:16:04 +08:00
|
|
|
|
}
|
2025-11-03 17:03:03 +08:00
|
|
|
|
|
|
|
|
|
|
.coil-title {
|
|
|
|
|
|
flex: 1;
|
2026-05-29 13:00:33 +08:00
|
|
|
|
font-size: 14px;
|
2025-11-03 13:16:04 +08:00
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.coil-body {
|
2026-05-29 13:00:33 +08:00
|
|
|
|
padding: 12px;
|
2026-05-28 17:43:04 +08:00
|
|
|
|
|
|
|
|
|
|
&.two-col {
|
|
|
|
|
|
display: grid;
|
|
|
|
|
|
grid-template-columns: 1fr 1fr;
|
|
|
|
|
|
gap: 0 12px;
|
|
|
|
|
|
}
|
2025-11-03 13:16:04 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.coil-info-row {
|
|
|
|
|
|
display: flex;
|
2025-11-03 17:03:03 +08:00
|
|
|
|
align-items: flex-start;
|
2026-05-29 13:00:33 +08:00
|
|
|
|
margin-bottom: 8px;
|
2025-11-03 17:03:03 +08:00
|
|
|
|
|
2025-11-03 13:16:04 +08:00
|
|
|
|
&:last-child {
|
|
|
|
|
|
margin-bottom: 0;
|
|
|
|
|
|
}
|
2025-11-03 17:03:03 +08:00
|
|
|
|
|
2025-11-03 13:16:04 +08:00
|
|
|
|
.label {
|
|
|
|
|
|
color: #909399;
|
2026-05-29 13:00:33 +08:00
|
|
|
|
font-size: 13px;
|
|
|
|
|
|
min-width: 90px;
|
2025-11-03 17:03:03 +08:00
|
|
|
|
flex-shrink: 0;
|
2025-11-03 13:16:04 +08:00
|
|
|
|
}
|
2025-11-03 17:03:03 +08:00
|
|
|
|
|
2025-11-03 13:16:04 +08:00
|
|
|
|
.value {
|
|
|
|
|
|
color: #303133;
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
font-weight: 500;
|
2025-11-03 17:03:03 +08:00
|
|
|
|
flex: 1;
|
|
|
|
|
|
word-break: break-all;
|
|
|
|
|
|
|
2025-11-03 13:16:04 +08:00
|
|
|
|
&.highlight {
|
|
|
|
|
|
color: #0066cc;
|
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-13 13:29:19 +08:00
|
|
|
|
/* 参数参数展示 */
|
2025-11-03 17:03:03 +08:00
|
|
|
|
.bom-params {
|
|
|
|
|
|
display: grid;
|
|
|
|
|
|
grid-template-columns: repeat(2, 1fr);
|
|
|
|
|
|
gap: 10px;
|
|
|
|
|
|
margin-top: 10px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.param-item {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
font-size: 13px;
|
|
|
|
|
|
|
|
|
|
|
|
.param-name {
|
|
|
|
|
|
color: #909399;
|
|
|
|
|
|
min-width: 80px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.param-value {
|
|
|
|
|
|
color: #303133;
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-03 13:16:04 +08:00
|
|
|
|
/* 流程箭头 */
|
|
|
|
|
|
.flow-label {
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
bottom: 20px;
|
|
|
|
|
|
left: 50%;
|
|
|
|
|
|
transform: translateX(-50%);
|
|
|
|
|
|
background: #ecf5ff;
|
|
|
|
|
|
color: #0066cc;
|
|
|
|
|
|
padding: 8px 16px;
|
|
|
|
|
|
border-radius: 20px;
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
gap: 6px;
|
|
|
|
|
|
border: 1px solid #d9ecff;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 子卷列表 */
|
|
|
|
|
|
.split-list {
|
2026-05-29 13:00:33 +08:00
|
|
|
|
max-height: calc(100vh - 280px);
|
2025-11-03 13:16:04 +08:00
|
|
|
|
overflow-y: auto;
|
2026-05-29 13:00:33 +08:00
|
|
|
|
margin-bottom: 0;
|
2025-11-03 13:16:04 +08:00
|
|
|
|
padding-right: 10px;
|
2025-11-03 17:03:03 +08:00
|
|
|
|
|
2025-11-03 13:16:04 +08:00
|
|
|
|
&::-webkit-scrollbar {
|
|
|
|
|
|
width: 6px;
|
|
|
|
|
|
}
|
2025-11-03 17:03:03 +08:00
|
|
|
|
|
2025-11-03 13:16:04 +08:00
|
|
|
|
&::-webkit-scrollbar-thumb {
|
|
|
|
|
|
background: #dcdfe6;
|
|
|
|
|
|
border-radius: 3px;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.sub-coil-card {
|
|
|
|
|
|
background: #fff;
|
|
|
|
|
|
border: 1px solid #e4e7ed;
|
|
|
|
|
|
border-radius: 8px;
|
2026-05-29 13:00:33 +08:00
|
|
|
|
margin-bottom: 10px;
|
2025-11-03 13:16:04 +08:00
|
|
|
|
transition: all 0.3s;
|
2025-11-03 17:03:03 +08:00
|
|
|
|
|
2025-11-03 13:16:04 +08:00
|
|
|
|
&:hover {
|
|
|
|
|
|
border-color: #0066cc;
|
|
|
|
|
|
box-shadow: 0 2px 8px rgba(0, 102, 204, 0.15);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.sub-coil-header {
|
|
|
|
|
|
background: #f5f7fa;
|
2026-05-29 13:00:33 +08:00
|
|
|
|
padding: 8px 12px;
|
2025-11-03 13:16:04 +08:00
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
border-bottom: 1px solid #e4e7ed;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.sub-coil-number {
|
2026-05-29 13:00:33 +08:00
|
|
|
|
font-size: 14px;
|
2025-11-03 13:16:04 +08:00
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
color: #0066cc;
|
2026-05-29 13:00:33 +08:00
|
|
|
|
width: 28px;
|
|
|
|
|
|
height: 28px;
|
2025-11-03 13:16:04 +08:00
|
|
|
|
border-radius: 50%;
|
|
|
|
|
|
background: #ecf5ff;
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
justify-content: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.btn-remove {
|
|
|
|
|
|
color: #f56c6c;
|
|
|
|
|
|
padding: 0;
|
2025-11-03 17:03:03 +08:00
|
|
|
|
|
2025-11-03 13:16:04 +08:00
|
|
|
|
&:hover {
|
|
|
|
|
|
color: #f56c6c;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.sub-coil-body {
|
2026-05-29 13:00:33 +08:00
|
|
|
|
padding: 12px;
|
2025-11-03 17:03:03 +08:00
|
|
|
|
}
|
2026-03-19 17:50:37 +08:00
|
|
|
|
|
2026-05-28 17:43:04 +08:00
|
|
|
|
/* 双列表单布局 */
|
|
|
|
|
|
.form-row {
|
|
|
|
|
|
display: flex;
|
2026-05-29 13:00:33 +08:00
|
|
|
|
gap: 10px;
|
2026-05-28 17:43:04 +08:00
|
|
|
|
margin-bottom: 0;
|
|
|
|
|
|
|
|
|
|
|
|
&:last-child {
|
|
|
|
|
|
margin-bottom: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.form-item-half {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
min-width: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.form-item-full {
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 排产单区域 */
|
2026-05-29 13:00:33 +08:00
|
|
|
|
.plan-sheet-container {
|
|
|
|
|
|
background: #fff;
|
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
|
|
|
|
padding: 12px;
|
|
|
|
|
|
margin-bottom: 12px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-28 17:43:04 +08:00
|
|
|
|
.plan-sheet-section {
|
2026-05-29 13:00:33 +08:00
|
|
|
|
margin-top: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 减少表单项间距
|
|
|
|
|
|
::v-deep .el-form-item {
|
|
|
|
|
|
margin-bottom: 10px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
::v-deep .el-form-item--small .el-form-item__content,
|
|
|
|
|
|
::v-deep .el-form-item--small .el-form-item__label {
|
|
|
|
|
|
line-height: 32px;
|
2026-05-28 17:43:04 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-19 17:50:37 +08:00
|
|
|
|
// 异常信息样式
|
|
|
|
|
|
.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);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-06-05 10:45:37 +08:00
|
|
|
|
|
|
|
|
|
|
.abnormal-item.inherited {
|
|
|
|
|
|
background-color: #f0f9ff;
|
|
|
|
|
|
border-color: #1890ff;
|
|
|
|
|
|
|
|
|
|
|
|
.abnormal-position {
|
|
|
|
|
|
color: #1890ff;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.abnormal-inherit-tip {
|
|
|
|
|
|
font-size: 10px;
|
|
|
|
|
|
color: #909399;
|
|
|
|
|
|
line-height: 1.2;
|
|
|
|
|
|
margin-top: 1px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.parent-coil-section {
|
|
|
|
|
|
margin-bottom: 20px;
|
|
|
|
|
|
padding: 12px;
|
|
|
|
|
|
background-color: #fafafa;
|
|
|
|
|
|
border: 1px solid #e4e7ed;
|
|
|
|
|
|
border-radius: 4px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.parent-header {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
margin-bottom: 10px;
|
|
|
|
|
|
padding-bottom: 8px;
|
|
|
|
|
|
border-bottom: 1px solid #e4e7ed;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.parent-title {
|
|
|
|
|
|
font-size: 14px;
|
|
|
|
|
|
font-weight: 600;
|
|
|
|
|
|
color: #303133;
|
|
|
|
|
|
}
|
2025-11-03 13:16:04 +08:00
|
|
|
|
</style>
|