2547 lines
99 KiB
Vue
2547 lines
99 KiB
Vue
<template>
|
||
<div class="app-container">
|
||
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="80px">
|
||
<el-form-item label="发货计划" prop="planId" v-if="showWaybill">
|
||
<el-select v-model="queryParams.planId" placeholder="请输入发货计划名称搜索" filterable remote clearable
|
||
:remote-method="remoteSearchWaybill" :loading="waybillLoading" style="width: 220px" @change="handleQuery">
|
||
<el-option v-for="item in waybillOptions" :key="item.planId" :label="item.planName" :value="item.planId" />
|
||
</el-select>
|
||
</el-form-item>
|
||
<el-form-item label="入场卷号" prop="enterCoilNo">
|
||
<el-input v-model="queryParams.enterCoilNo" placeholder="请输入入场钢卷号" clearable
|
||
@keyup.enter.native="handleQuery" />
|
||
</el-form-item>
|
||
<el-form-item label="当前卷号" prop="currentCoilNo">
|
||
<el-input v-model="queryParams.currentCoilNo" placeholder="请输入当前钢卷号" clearable
|
||
@keyup.enter.native="handleQuery" />
|
||
</el-form-item>
|
||
<el-form-item label="逻辑库位" prop="warehouseId" v-if="useWarehouseIds">
|
||
<muti-select v-model="warehouseIds" placeholder="请选择逻辑库位" style="width: 100%; display: inline-block;" clearable
|
||
:options="warehouseOptions">
|
||
</muti-select>
|
||
</el-form-item>
|
||
<el-form-item label="逻辑库位" prop="warehouseId" v-else-if="!hideWarehouseQuery && !leftWarehouseQuery">
|
||
<warehouse-select v-model="queryParams.warehouseId" placeholder="请选择逻辑库位"
|
||
style="width: 100%; display: inline-block;" clearable />
|
||
</el-form-item>
|
||
|
||
<el-form-item label="实际库区" prop="actualWarehouseId" v-if="!hideWarehouseQuery">
|
||
<actual-warehouse-select v-model="queryParams.actualWarehouseId" placeholder="请选择仓库/库区/库位"
|
||
style="width: 100%; display: inline-block;" clearable :canSelectDisabled="true" :canSelectLevel2="true"
|
||
:clearInput="false" :showEmpty="true" />
|
||
</el-form-item>
|
||
|
||
<el-form-item v-if="showMaterialType" label="物料类型" prop="materialType">
|
||
<el-select v-model="queryParams.materialType" placeholder="请选择物料类型" clearable>
|
||
<el-option label="原料" value="原料"></el-option>
|
||
<el-option label="成品" value="成品"></el-option>
|
||
</el-select>
|
||
</el-form-item>
|
||
|
||
<el-form-item label="产品名称" prop="itemName">
|
||
<muti-select v-model="queryParams.itemName" :options="dict.type.coil_itemname" placeholder="请选择物料" clearable />
|
||
</el-form-item>
|
||
|
||
<el-form-item label="规格" prop="itemSpecification">
|
||
<memo-input v-model="queryParams.itemSpecification" storageKey="coilSpec" placeholder="请选择规格" clearable
|
||
@keyup.enter.native="handleQuery" />
|
||
</el-form-item>
|
||
|
||
<el-form-item label="材质" prop="itemMaterial">
|
||
<muti-select v-model="queryParams.itemMaterial" :options="dict.type.coil_material" placeholder="请选择材质" clearable
|
||
@keyup.enter.native="handleQuery" />
|
||
</el-form-item>
|
||
|
||
<el-form-item label="厂家" prop="itemManufacturer">
|
||
<muti-select v-model="queryParams.itemManufacturer" :options="dict.type.coil_manufacturer" placeholder="请选择厂家"
|
||
clearable @keyup.enter.native="handleQuery" />
|
||
</el-form-item>
|
||
|
||
<el-form-item label="表面处理">
|
||
<el-input v-model="queryParams.itemSurfaceTreatmentDesc" placeholder="请输入表面处理" clearable size="small" />
|
||
</el-form-item>
|
||
<el-form-item label="切边" prop="trimmingRequirement">
|
||
<el-select v-model="queryParams.trimmingRequirement" placeholder="请选择切边" clearable style="width: 100%">
|
||
<el-option label="净边" value="净边" />
|
||
<el-option label="毛边" value="毛边" />
|
||
</el-select>
|
||
</el-form-item>
|
||
<el-form-item label="包装" prop="packagingRequirement">
|
||
<el-select v-model="queryParams.packagingRequirement" placeholder="请选择包装" clearable style="width: 100%">
|
||
<el-option label="裸包" value="裸包" />
|
||
<el-option label="普包" value="普包" />
|
||
<el-option label="简包" value="简包" />
|
||
</el-select>
|
||
</el-form-item>
|
||
<el-form-item label="品质">
|
||
<muti-select v-model="queryParams.qualityStatusCsv" :options="dict.type.coil_quality_status" placeholder="请选择品质"
|
||
clearable />
|
||
</el-form-item>
|
||
|
||
<el-form-item label="备注">
|
||
<el-input v-model="queryParams.remark" placeholder="请输入备注" clearable
|
||
@keyup.enter.native="handleQuery" />
|
||
</el-form-item>
|
||
|
||
<el-form-item v-if="showWaybill" label="发货状态">
|
||
<el-radio-group v-model="queryParams.status" @change="handleQuery">
|
||
<el-radio-button label="">全部</el-radio-button>
|
||
<el-radio-button label="0">未发货【{{ unshippedCount }}】</el-radio-button>
|
||
<el-radio-button label="1">已发货【{{ shippedCount }}】</el-radio-button>
|
||
</el-radio-group>
|
||
</el-form-item>
|
||
|
||
<el-form-item v-if="isShipView" label="货单状态">
|
||
<el-radio-group v-model="shipViewModel.status" @change="handleQuery">
|
||
<el-radio-button label="all">全部</el-radio-button>
|
||
<el-radio-button label="has">有货单【{{ shipViewModel.hasCount }}】</el-radio-button>
|
||
<el-radio-button label="none">无货单【{{ shipViewModel.noneCount }}】</el-radio-button>
|
||
</el-radio-group>
|
||
</el-form-item>
|
||
|
||
<el-form-item v-if="showWaybill" label="发货单时间">
|
||
<el-date-picker v-model="queryParams.shipmentTime" type="daterange" value-format="yyyy-MM-dd"
|
||
range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" />
|
||
</el-form-item>
|
||
|
||
<el-form-item v-if="editNext" label="显示流程图" prop="showProcessFlow">
|
||
<el-checkbox v-model="showProcessFlow" @change="handleShowProcessFlowChange"></el-checkbox>
|
||
</el-form-item>
|
||
|
||
<el-form-item>
|
||
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
|
||
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
|
||
<el-button icon="el-icon-download" size="mini" @click="handleNewExport" v-if="showNewExport">导出</el-button>
|
||
<el-button type="danger" v-if="showWaybill" plain icon="el-icon-close" size="mini" :disabled="multiple"
|
||
:loading="buttonLoading" @click="handleBatchRemoveFromWaybill">批量移出发货单</el-button>
|
||
</el-form-item>
|
||
|
||
<!-- <el-form-item style="float: right;" v-if="showWaybill" v-loading="loading">
|
||
<el-descriptions :column="2" border>
|
||
<el-descriptions-item label="已发货数量">{{ shippedCount }}</el-descriptions-item>
|
||
<el-descriptions-item label="未发货数量">{{ unshippedCount }}</el-descriptions-item>
|
||
</el-descriptions>
|
||
</el-form-item> -->
|
||
</el-form>
|
||
|
||
<el-row :gutter="10" class="mb8" v-if="showControl">
|
||
<!-- <el-col :span="1.5">
|
||
<el-button type="success" plain icon="el-icon-edit" size="mini" :disabled="single"
|
||
@click="handleCheck">修正</el-button>
|
||
</el-col> -->
|
||
<el-col :span="1.5">
|
||
<el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExportAll">导出当前</el-button>
|
||
</el-col>
|
||
<el-col :span="1.5">
|
||
<el-button type="info" plain icon="el-icon-download" size="mini" @click="handleExportAllProps">导出全部</el-button>
|
||
</el-col>
|
||
|
||
<el-col :span="2" v-if="canExportAll">
|
||
<el-button type="info" plain icon="el-icon-printer" size="mini" :disabled="multiple"
|
||
@click="handleBatchPrintLabel">批量打印标签</el-button>
|
||
</el-col>
|
||
<!-- <el-col :span="2" v-if="showWaybill">
|
||
|
||
</el-col> -->
|
||
<el-col :span="1.5" v-if="showOrderBy">
|
||
<el-checkbox v-model="queryParams.orderBy" v-loading="loading" @change="getList"
|
||
label="orderBy">按实际库区排序</el-checkbox>
|
||
</el-col>
|
||
|
||
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
|
||
</el-row>
|
||
|
||
<div style="display: flex; align-items: flex-start;">
|
||
<div v-if="leftWarehouseQuery" :style="{
|
||
width: '220px',
|
||
height: showAbnormal ? 'calc(100vh - 400px)' : 'calc(100vh - 300px)',
|
||
backgroundColor: '#ffffff',
|
||
overflowY: 'auto',
|
||
overflowX: 'hidden'
|
||
}">
|
||
<warehouse-tree warehouseType="logic" @node-click="handleWarehouseNodeClick" />
|
||
</div>
|
||
<div style="flex: 1; width: 100%; overflow: hidden;">
|
||
<KLPTable v-loading="loading" :data="materialCoilList" @selection-change="handleSelectionChange"
|
||
:floatLayer="true" :floatLayerConfig="floatLayerConfig" @row-click="handleRowClick"
|
||
:height="showAbnormal ? 'calc(100vh - 400px)' : 'calc(100vh - 300px)'" border>
|
||
<el-table-column v-if="showWaybill" type="selection" width="55" align="center" />
|
||
<el-table-column label="入场钢卷号" align="center" prop="enterCoilNo">
|
||
<template slot-scope="scope">
|
||
<coil-no :coil-no="scope.row.enterCoilNo"></coil-no>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="当前钢卷号" align="center" prop="currentCoilNo">
|
||
<template slot-scope="scope">
|
||
<current-coil-no :current-coil-no="scope.row.currentCoilNo"></current-coil-no>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="净重" align="center" prop="netWeight" v-if="!hideWarehouseQuery" />
|
||
<el-table-column label="逻辑库位" width="120" align="center" prop="warehouseName" v-if="!hideWarehouseQuery" />
|
||
<el-table-column label="实际库区" width="100" align="center" prop="actualWarehouseName"
|
||
v-if="!hideWarehouseQuery && !showExportTime" />
|
||
<el-table-column label="产品类型" align="center" width="180" v-if="!moreColumn">
|
||
<template slot-scope="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 label="业务员" align="center" prop="saleName" width="60" />
|
||
<el-table-column v-if="showAbnormal" label="异常数量" align="center" prop="abnormalCount"></el-table-column>
|
||
<el-table-column label="长度 (米)" align="center" prop="length" v-if="showLength" />
|
||
<el-table-column label="发货时间" v-if="showExportTime" align="center" prop="exportTime" width="205">
|
||
<template slot-scope="scope">
|
||
<el-date-picker @change="handleExportTimeChange(scope.row)" v-if="canEditExportTime" style="width: 100%"
|
||
v-model="scope.row.exportTime" type="datetime" value-format="yyyy-MM-dd HH:mm:ss"
|
||
placeholder="选择发货时间" />
|
||
<div v-else>{{ scope.row.exportTime }}</div>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="发货人" v-if="showExportTime" align="center" prop="exportByName" width="150">
|
||
<template slot-scope="scope">
|
||
<el-select v-model="scope.row.exportBy" placeholder="请选择发货人" filterable
|
||
@change="handleExportByNameChange(scope.row)">
|
||
<el-option v-for="item in userList" :key="item.userName" :value="item.userName"
|
||
:label="item.nickName" />
|
||
</el-select>
|
||
</template>
|
||
</el-table-column>
|
||
|
||
<el-table-column v-if="showGrade" label="质量状态" align="center" prop="qualityStatus">
|
||
</el-table-column>
|
||
<el-table-column label="逻辑库位" align="center" prop="warehouseId" v-if="editWarehouse">
|
||
<template slot-scope="scope">
|
||
<warehouse-select @change="handleWarehouseChange(scope.row)" v-model="scope.row.warehouseId"
|
||
placeholder="请选择仓库/库区/库位" style="width: 100%;" clearable />
|
||
</template>
|
||
</el-table-column>
|
||
|
||
<el-table-column v-if="hasTransferType" label="实际库区" align="center" prop="actualWarehouseName" />
|
||
|
||
<el-table-column v-if="moreColumn" label="规格" prop="specification"></el-table-column>
|
||
<el-table-column v-if="moreColumn" label="物料" prop="itemName"></el-table-column>
|
||
<el-table-column v-if="moreColumn" label="材质" prop="material"></el-table-column>
|
||
<el-table-column v-if="moreColumn" label="厂家" prop="manufacturer"></el-table-column>
|
||
<el-table-column v-if="moreColumn" label="表面处理" prop="surfaceTreatmentDesc"></el-table-column>
|
||
<el-table-column v-if="moreColumn" label="品质" prop="qualityStatus"></el-table-column>
|
||
<el-table-column v-if="moreColumn" label="备注" prop="remark" show-overflow-tooltip></el-table-column>
|
||
<el-table-column v-if="moreColumn" label="切边" prop="trimmingRequirement"></el-table-column>
|
||
<el-table-column v-if="moreColumn" label="包装" prop="packagingRequirement"></el-table-column>
|
||
<el-table-column v-if="moreColumn" label="镀层质量" prop="zincLayer"></el-table-column>
|
||
|
||
<el-table-column v-if="hasTransferType" label="调拨类型" align="center" prop="transferType" />
|
||
<el-table-column v-if="hasTransferType" label="改判原因" align="center" prop="rejudgeInfo.rejudgeReason" />
|
||
|
||
<el-table-column label="钢卷去向" align="center" prop="nextWarehouseId" v-if="editNext" width="150">
|
||
<template slot-scope="scope">
|
||
<el-select v-model="scope.row.nextWarehouseId" placeholder="钢卷去向" filterable
|
||
@change="handleNextWarehouseChange(scope.row)">
|
||
<el-option v-for="item in dict.type.wms_next_warehouse" :key="item.value" :value="item.value"
|
||
:label="item.label" />
|
||
</el-select>
|
||
</template>
|
||
</el-table-column>
|
||
|
||
<el-table-column label="业务目的" align="center" prop="businessPurpose" v-if="showBusinessPurpose" width="150">
|
||
<template slot-scope="scope">
|
||
<el-select v-model="scope.row.businessPurpose" placeholder="业务目的" filterable
|
||
@change="handleRowChange(scope.row)">
|
||
<el-option v-for="item in dict.type.coil_business_purpose" :key="item.value" :value="item.value"
|
||
:label="item.label" />
|
||
</el-select>
|
||
</template>
|
||
</el-table-column>
|
||
|
||
<el-table-column label="关联订单" align="center" prop="relatedToOrder" v-if="showRelatedToOrder" width="150">
|
||
<template slot-scope="scope">
|
||
<el-switch @change="handleRowChange(scope.row)" v-model="scope.row.isRelatedToOrder" :active-value="1"
|
||
:inactive-value="0" />
|
||
</template>
|
||
</el-table-column>
|
||
|
||
<el-table-column label="发货计划" align="center" prop="nextWarehouseId" v-if="showWaybill || (isShipView && shipViewModel.status == 'has')" width="150">
|
||
<template slot-scope="scope">
|
||
{{ scope.row.bindPlanName || '-' }}
|
||
</template>
|
||
</el-table-column>
|
||
|
||
<el-table-column label="发货单据" align="center" prop="nextWarehouseId" v-if="showWaybill || (isShipView && shipViewModel.status == 'has')" width="150">
|
||
<template slot-scope="scope">
|
||
<el-popover placement="top" width="400" trigger="hover">
|
||
<div>
|
||
<el-descriptions :column="2" :border="false">
|
||
<el-descriptions-item label="单据名称">
|
||
{{ scope.row.bindWaybillName || '-' }}
|
||
</el-descriptions-item>
|
||
<el-descriptions-item label="车牌号">
|
||
{{ scope.row.bindLicensePlate || '-' }}
|
||
</el-descriptions-item>
|
||
<el-descriptions-item label="收货单位">
|
||
{{ scope.row.bindConsigneeUnit || '-' }}
|
||
</el-descriptions-item>
|
||
<el-descriptions-item label="负责人">
|
||
{{ scope.row.bindPrincipal || '-' }}
|
||
</el-descriptions-item>
|
||
<el-descriptions-item label="单据状态">
|
||
<el-tag v-if="scope.row.bindWaybillStatus === 0" type="info" size="mini">未发货</el-tag>
|
||
<el-tag v-else-if="scope.row.bindWaybillStatus === 1" type="info" size="mini">已发货</el-tag>
|
||
<el-tag v-else-if="scope.row.bindWaybillStatus === 2" type="info" size="mini">未打印</el-tag>
|
||
<el-tag v-else-if="scope.row.bindWaybillStatus === 3" type="info" size="mini">已打印</el-tag>
|
||
<el-tag v-else type="danger" size="mini">未知状态</el-tag>
|
||
</el-descriptions-item>
|
||
</el-descriptions>
|
||
</div>
|
||
<div slot="reference" class="text-ellipsis" v-text>{{ scope.row.bindLicensePlate || '-' }}</div>
|
||
</el-popover>
|
||
</template>
|
||
</el-table-column>
|
||
|
||
<el-table-column label="发货状态" align="center" prop="status" v-if="showWaybill" width="150">
|
||
<template slot-scope="scope">
|
||
<el-tag v-if="scope.row.status === 1" type="success" size="mini">已发货</el-tag>
|
||
<el-tag v-else type="info" size="mini">未发货</el-tag>
|
||
</template>
|
||
</el-table-column>
|
||
|
||
<el-table-column label="实测宽度(mm)" align="center" prop="width" v-if="showWidthEdit" width="150">
|
||
<template slot-scope="scope">
|
||
<el-input v-model="scope.row.actualWidth" placeholder="请输入实测宽度"
|
||
@change="handleRowChange(scope.row)"></el-input>
|
||
</template>
|
||
</el-table-column>
|
||
|
||
<el-table-column label="实测厚度(mm)" align="center" prop="actualThickness" v-if="showWidthEdit" width="150">
|
||
<template slot-scope="scope">
|
||
<el-input v-model="scope.row.actualThickness" placeholder="请输入实测厚度"
|
||
@change="handleRowChange(scope.row)"></el-input>
|
||
</template>
|
||
</el-table-column>
|
||
|
||
<el-table-column label="预留宽度(mm)" align="center" prop="width" v-if="showWidthEdit" width="150">
|
||
<template slot-scope="scope">
|
||
<el-input v-model="scope.row.reservedWidth" placeholder="请输入预留宽度"
|
||
@change="handleRowChange(scope.row)"></el-input>
|
||
</template>
|
||
</el-table-column>
|
||
|
||
<el-table-column label="生产开始" align="center" prop="productionStartTime" v-if="showProductionTimeEdit"
|
||
width="150">
|
||
</el-table-column>
|
||
|
||
<el-table-column label="生产结束" align="center" prop="productionEndTime" v-if="showProductionTimeEdit"
|
||
width="150">
|
||
</el-table-column>
|
||
|
||
<el-table-column label="生产耗时" align="center" prop="productionDuration" v-if="showProductionTimeEdit"
|
||
width="150">
|
||
<template slot-scope="scope">
|
||
{{ formatDuration(scope.row.productionDuration * 60 * 1000) }}
|
||
</template>
|
||
</el-table-column>
|
||
|
||
|
||
<el-table-column prop="action" label="操作" align="center" class-name="small-padding fixed-width"
|
||
v-if="!moreColumn">
|
||
<template slot-scope="scope">
|
||
<el-button size="mini" type="text" icon="el-icon-view" @click="handlePreviewLabel(scope.row)">
|
||
预览标签
|
||
</el-button>
|
||
<el-button size="mini" type="text" icon="el-icon-printer" @click="handlePrintLabel(scope.row)">
|
||
打印标签
|
||
</el-button>
|
||
<el-button size="mini" type="text" icon="el-icon-view" @click="handleNumberCoilClick(scope.row)">
|
||
数字钢卷
|
||
</el-button>
|
||
<el-button size="mini" v-if="showStatus" type="text" icon="el-icon-upload"
|
||
@click="handleExportCoil(scope.row)">
|
||
发货
|
||
</el-button>
|
||
<el-button size="mini" v-if="showExportTime" type="text" icon="el-icon-close"
|
||
@click="handleCancelExport(scope.row)">
|
||
撤回发货
|
||
</el-button>
|
||
<el-button size="mini" v-if="showProductionTimeEdit" type="text" icon="el-icon-close"
|
||
@click="handleProductionTimeEdit(scope.row)">
|
||
加工修正
|
||
</el-button>
|
||
<el-button size="mini" v-if="showExportTime" type="text" icon="el-icon-sold-out"
|
||
@click="handleReturnCoil(scope.row)">
|
||
退货钢卷
|
||
</el-button>
|
||
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleCheck(scope.row)"
|
||
v-if="showControl">修正</el-button>
|
||
<el-button size="mini" type="text" icon="el-icon-search" @click="handleTrace(scope.row)">追溯</el-button>
|
||
<el-button size="mini" v-if="showWaybill" type="text" icon="el-icon-close"
|
||
@click="handleRemoveFromWaybill(scope.row)">
|
||
移出发货单
|
||
</el-button>
|
||
<el-button v-if="showGrade" size="mini" type="text" icon="el-icon-edit" @click="handleJudge(scope.row)">
|
||
改判
|
||
</el-button>
|
||
<el-button size="mini" v-if="hasTransferType" type="text" icon="el-icon-close"
|
||
@click="handleReplaceLabel(scope.row)">
|
||
重贴标签
|
||
</el-button>
|
||
<el-button size="mini" v-if="hasTransferType" type="text" icon="el-icon-document"
|
||
@click="handleViewTransferRecord(scope.row)">
|
||
查看记录
|
||
</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</KLPTable>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
<div v-show="total > 0" style="display: flex; justify-content: flex-end; align-items: flex-end; gap: 10px;">
|
||
<span>
|
||
总净重:{{ statistics.total_net_weight || 0 }}t
|
||
</span>
|
||
|
||
<pagination :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize"
|
||
@pagination="getList" />
|
||
</div>
|
||
|
||
|
||
<!-- 添加或修改钢卷物料对话框 -->
|
||
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
|
||
<el-form ref="form" :model="form" :rules="rules" label-width="100px">
|
||
<el-form-item label="入场钢卷号" prop="enterCoilNo">
|
||
<el-input v-model="form.enterCoilNo" placeholder="请输入入场钢卷号" :disabled="form.coilId" />
|
||
</el-form-item>
|
||
<el-form-item label="当前钢卷号" prop="currentCoilNo">
|
||
<el-input v-model="form.currentCoilNo" placeholder="请输入当前钢卷号" />
|
||
</el-form-item>
|
||
<el-form-item label="厂家原料卷号" prop="supplierCoilNo">
|
||
<el-input v-model="form.supplierCoilNo" placeholder="请输入厂家原料卷号" />
|
||
</el-form-item>
|
||
<el-form-item label="所在库位" prop="warehouseId">
|
||
<warehouse-select v-model="form.warehouseId" placeholder="请选择仓库/库区/库位" style="width: 100%;" clearable />
|
||
</el-form-item>
|
||
<el-form-item label="实际库区" prop="actualWarehouseId">
|
||
<actual-warehouse-select v-model="form.actualWarehouseId" :clearInput="form.coilId != null"
|
||
placeholder="请选择实际库区" style="width: 100%;" clearable />
|
||
</el-form-item>
|
||
<el-form-item label="班组" prop="team">
|
||
<el-select v-model="form.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="form.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="form.itemType == 'product'" v-model="form.itemId" placeholder="请选择成品"
|
||
style="width: 100%;" clearable />
|
||
<raw-material-select v-else-if="form.itemType == 'raw_material'" v-model="form.itemId" placeholder="请选择原料"
|
||
style="width: 100%;" clearable />
|
||
<div v-else>请先选择材料类型</div>
|
||
</el-form-item>
|
||
<!-- <el-form-item label="质量状态" prop="qualityStatus">
|
||
<el-select v-model="form.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="form.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="form.packingStatus" placeholder="请输入原料材质">
|
||
</el-input>
|
||
</el-form-item>
|
||
|
||
<el-form-item label="包装要求" prop="packagingRequirement">
|
||
<el-select v-model="form.packagingRequirement" placeholder="请选择包装要求" style="width: 100%">
|
||
<el-option label="裸包" value="裸包" />
|
||
<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="form.grossWeight" placeholder="请输入毛重" />
|
||
</el-form-item>
|
||
<el-form-item label="净重" prop="netWeight">
|
||
<el-input v-model="form.netWeight" placeholder="请输入净重" />
|
||
</el-form-item>
|
||
<el-form-item label="长度" prop="length" v-if="showLength">
|
||
<el-input v-model="form.length" placeholder="请输入长度" />
|
||
</el-form-item>
|
||
<el-form-item label="实测长度(m)" prop="actualLength">
|
||
<el-input-number :controls="false" v-model="form.actualLength" placeholder="请输入实测长度" type="number"
|
||
:step="0.01" />
|
||
</el-form-item>
|
||
<el-form-item label="实测厚度(mm)" prop="actualThickness" class="form-item-half">
|
||
<el-input-number :controls="false" v-model="form.actualThickness" placeholder="请输入实测厚度" type="number"
|
||
:step="0.01" />
|
||
</el-form-item>
|
||
<el-form-item label="实测宽度(mm)" prop="actualWidth">
|
||
<el-input-number :controls="false" v-model="form.actualWidth" placeholder="请输入实测宽度" type="number"
|
||
:step="0.01" />
|
||
</el-form-item>
|
||
<el-form-item label="业务目的" prop="businessPurpose">
|
||
<el-select v-model="form.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="form.temperGrade" placeholder="请输入调制度" />
|
||
</el-form-item>
|
||
<el-form-item label="镀层种类" prop="coatingType">
|
||
<MemoInput storageKey="coatingType" v-model="form.coatingType" placeholder="请输入镀层种类" />
|
||
</el-form-item>
|
||
<el-form-item label="钢卷表面处理" prop="coilSurfaceTreatment">
|
||
<MemoInput storageKey="surfaceTreatmentDesc" v-model="form.coilSurfaceTreatment" placeholder="请输入钢卷表面处理" />
|
||
</el-form-item>
|
||
<el-form-item label="备注" prop="remark">
|
||
<el-input v-model="form.remark" placeholder="请输入备注" />
|
||
</el-form-item>
|
||
</el-form>
|
||
<div slot="footer" class="dialog-footer">
|
||
<el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
|
||
<el-button @click="cancel">取 消</el-button>
|
||
</div>
|
||
</el-dialog>
|
||
|
||
<!-- 钢卷追溯对话框(使用封装的组件) -->
|
||
<el-dialog title="钢卷追溯" :visible.sync="traceOpen" width="90%" append-to-body>
|
||
<coil-trace-result v-loading="traceLoading" :trace-result="traceResult"></coil-trace-result>
|
||
</el-dialog>
|
||
|
||
<!-- 标签预览弹窗 -->
|
||
<el-dialog title="标签预览" :visible.sync="labelRender.visible" append-to-body>
|
||
<label-render :forceSpecialTag="forceSpecialTag" :content="labelRender.data" :labelType="labelRender.type" />
|
||
</el-dialog>
|
||
|
||
<label-render :forceSpecialTag="forceSpecialTag" ref="labelRender" v-show="false" :content="labelRender.data"
|
||
:labelType="labelRender.type" />
|
||
|
||
<!-- 批量导出标签PDF弹窗 -->
|
||
<el-dialog title="批量导出标签PDF" :visible.sync="batchPrint.visible" width="520px" append-to-body>
|
||
<div style="line-height: 22px; font-size: 12px; color: #909399; margin-bottom: 10px;">
|
||
已选择 <b>{{ batchPrint.list.length }}</b> 个钢卷。点击“生成PDF并打开”将每个标签作为一页(180mm × 100mm)。
|
||
</div>
|
||
<div style="text-align:right;">
|
||
<el-button size="mini" @click="batchPrint.visible = false">取消</el-button>
|
||
<el-button type="primary" size="mini" :loading="batchPrint.loading"
|
||
@click="handleBatchExportLabelPdf">生成PDF并打开</el-button>
|
||
</div>
|
||
|
||
<!-- 渲染容器:屏幕隐藏,仅用于截图生成PDF -->
|
||
<div ref="batchPdfContainer" class="batch-pdf-root" aria-hidden="true">
|
||
<div v-for="(item, idx) in batchPrint.list" :key="item.coilId || idx" class="batch-pdf-page">
|
||
<label-render :content="item" :hideActions="true" :forceSpecialTag="forceSpecialTag" />
|
||
</div>
|
||
</div>
|
||
</el-dialog>
|
||
|
||
<el-dialog title="生产时间修正" :visible.sync="productionTimeFormVisible" width="500px" append-to-body>
|
||
<el-form ref="productionTimeForm" :model="productionTimeForm" :rules="productionTimeFormRules"
|
||
label-width="100px">
|
||
<el-form-item label="生产开始时间" prop="productionStartTime">
|
||
<el-date-picker v-model="productionTimeForm.productionStartTime" type="datetime"
|
||
value-format="yyyy-MM-dd HH:mm:ss" placeholder="请选择生产时间"
|
||
@change="(value) => { productionTimeForm.productionStartTime = value; calculateProductionDuration(); }" />
|
||
</el-form-item>
|
||
<el-form-item label="生产结束时间" prop="productionEndTime">
|
||
<el-date-picker v-model="productionTimeForm.productionEndTime" type="datetime"
|
||
value-format="yyyy-MM-dd HH:mm:ss" placeholder="请选择生产时间"
|
||
@change="(value) => { productionTimeForm.productionEndTime = value; calculateProductionDuration(); }" />
|
||
</el-form-item>
|
||
<el-form-item label="生产耗时" prop="productionDuration">
|
||
<el-input v-model="productionTimeForm.formattedDuration" placeholder="自动计算" disabled />
|
||
</el-form-item>
|
||
</el-form>
|
||
<div slot="footer" class="dialog-footer">
|
||
<el-button :loading="buttonLoading" type="primary" @click="submitProductionTimeForm">确 定</el-button>
|
||
<el-button @click="productionTimeFormVisible = false">取 消</el-button>
|
||
</div>
|
||
</el-dialog>
|
||
|
||
<abnormal-list v-if="showAbnormal && currentCoilId" :coil-id="currentCoilId"></abnormal-list>
|
||
|
||
<log-table v-if="showWareLog && currentCoilId" :coil-id="currentCoilId"></log-table>
|
||
|
||
<DragResizeBox v-if="editNext && showProcessFlow" storageKey="coil-process-flow" @size-change="resizeChart">
|
||
<div style="height: 100%; width: 100%; overflow-y: scroll; display: flex; background-color: #fff;">
|
||
<process-flow v-if="showProcessFlow" ref="processFlow"></process-flow>
|
||
</div>
|
||
</DragResizeBox>
|
||
|
||
<!-- 钢卷改判弹窗 -->
|
||
<el-dialog title="钢卷改判" :visible.sync="judgeDialogVisible" width="800px" append-to-body>
|
||
<CoilInfoRender :column="3" :coilInfo="judgeForm" border />
|
||
|
||
<div style="margin-top: 20px; padding: 15px; background-color: #f5f7fa; border-radius: 4px;">
|
||
<el-form :model="judgeForm" label-width="120px">
|
||
<el-form-item label="修改质量状态">
|
||
<el-select v-model="judgeForm.qualityStatus" placeholder="请选择质量状态" style="width: 200px">
|
||
<el-option v-for="item in dict.type.coil_quality_status" :key="item.value" :value="item.value"
|
||
:label="item.label" />
|
||
</el-select>
|
||
</el-form-item>
|
||
<el-form-item label="改判原因">
|
||
<el-input type="textarea" v-model="judgeForm.rejudgeReason" placeholder="请输入改判原因" />
|
||
</el-form-item>
|
||
<el-form-item label="通知重贴标签">
|
||
<el-checkbox v-model="judgeForm.notifyReLabel">是否通知重贴标签</el-checkbox>
|
||
</el-form-item>
|
||
</el-form>
|
||
</div>
|
||
|
||
<div slot="footer" class="dialog-footer">
|
||
<el-button @click="judgeDialogVisible = false">取消</el-button>
|
||
<el-button :loading="buttonLoading" type="primary" @click="submitJudgeForm">确认</el-button>
|
||
</div>
|
||
</el-dialog>
|
||
|
||
<!-- 调拨记录弹窗 -->
|
||
<el-dialog title="调拨记录" :visible.sync="transferRecordVisible" width="900px" append-to-body>
|
||
<div class="table-wrapper transfer-table" v-loading="loading">
|
||
<div class="table-container">
|
||
<el-table :data="transferRecordList" size="small" border stripe style="width: 100%">
|
||
<el-table-column prop="type" label="类型" min-width="100"></el-table-column>
|
||
<el-table-column label="变更前">
|
||
<template slot-scope="scope">
|
||
{{ scope.row.before }}
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="变更后">
|
||
<template slot-scope="scope">
|
||
{{ scope.row.after }}
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="createTime" label="时间"></el-table-column>
|
||
<el-table-column prop="remark" label="备注" show-overflow-tooltip></el-table-column>
|
||
</el-table>
|
||
</div>
|
||
</div>
|
||
</el-dialog>
|
||
|
||
<!-- 钢卷暂存单据管理 -->
|
||
<el-card v-if="moreColumn" class="box-card" style="margin-top: 20px;" :body-style="{ padding: '20px' }">
|
||
<div slot="header" class="clearfix">
|
||
<span>钢卷暂存单据管理</span>
|
||
<el-button style="float: right; padding: 3px 0" type="text" @click="createTempOrder">创建暂存单据</el-button>
|
||
</div>
|
||
|
||
<!-- 暂存单据列表 -->
|
||
<el-table :data="tempOrderList" style="width: 100%" :height="'calc(100vh - 500px)'">
|
||
<el-table-column prop="orderName" label="单据名称">
|
||
<template slot-scope="scope">
|
||
<div style="display: flex; align-items: center; gap: 5px;">
|
||
<el-link type="primary" @click="viewSelectedCoils(scope.row)">{{ scope.row.orderName }}</el-link>
|
||
<el-button size="mini" type="text" icon="el-icon-edit" @click="editOrderName(scope.row)"></el-button>
|
||
</div>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="createTime" label="创建时间"></el-table-column>
|
||
<el-table-column prop="coilCount" label="钢卷数量">
|
||
<template slot-scope="scope">
|
||
<el-tag size="small">{{ (scope.row.coils && scope.row.coils.length) ? scope.row.coils.length : 0 }}</el-tag>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="totalWeight" label="总重量(t)">
|
||
<template slot-scope="scope">
|
||
{{ calculateTotalWeight(scope.row.coils || []).toFixed(3) }}
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="操作">
|
||
<template slot-scope="scope">
|
||
<el-button size="mini" type="text" @click="openCoilSelection(scope.row)">选择钢卷</el-button>
|
||
<el-button size="mini" type="text" style="color: #f56c6c;"
|
||
@click="deleteTempOrder(scope.row)">删除</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
|
||
<!-- 当没有数据时显示提示 -->
|
||
<div v-if="!tempOrderList || tempOrderList.length === 0"
|
||
style="text-align: center; padding: 50px; color: #909399;">
|
||
<i class="el-icon-document" style="font-size: 48px; margin-bottom: 10px;"></i>
|
||
<div>暂无暂存单据</div>
|
||
<div style="font-size: 12px; margin-top: 5px;">点击右上角"创建暂存单据"开始使用</div>
|
||
</div>
|
||
</el-card>
|
||
|
||
<!-- 钢卷选择对话框 -->
|
||
<el-dialog title="选择钢卷" :visible.sync="coilSelectionVisible" width="95%" append-to-body>
|
||
<!-- 上方:查询条件 -->
|
||
<el-card class="query-card" style="margin-bottom: 15px;">
|
||
<el-form :model="coilQueryParams" size="small" :inline="true">
|
||
<el-form-item label="入场卷号">
|
||
<el-input v-model="coilQueryParams.enterCoilNo" placeholder="请输入入场钢卷号" clearable style="width: 200px;" />
|
||
</el-form-item>
|
||
<el-form-item label="当前卷号">
|
||
<el-input v-model="coilQueryParams.currentCoilNo" placeholder="请输入当前钢卷号" clearable style="width: 200px;" />
|
||
</el-form-item>
|
||
<el-form-item label="产品名称">
|
||
<el-input v-model="coilQueryParams.itemName" placeholder="请选择物料" clearable style="width: 200px;" />
|
||
</el-form-item>
|
||
<el-form-item label="规格">
|
||
<el-input v-model="coilQueryParams.itemSpecification" placeholder="请选择规格" clearable style="width: 200px;" />
|
||
</el-form-item>
|
||
<el-form-item label="材质">
|
||
<el-input v-model="coilQueryParams.itemMaterial" placeholder="请选择材质" clearable style="width: 200px;" />
|
||
</el-form-item>
|
||
<el-form-item>
|
||
<el-button type="primary" @click="searchCoils">查询</el-button>
|
||
<el-button @click="resetCoilQuery">重置</el-button>
|
||
</el-form-item>
|
||
</el-form>
|
||
</el-card>
|
||
|
||
<!-- 下方:钢卷列表 -->
|
||
<div style="height: 500px;">
|
||
<el-table v-loading="coilLoading" :data="availableCoils" @selection-change="handleCoilSelection" border
|
||
height="450">
|
||
<el-table-column type="selection" width="55" align="center" />
|
||
<el-table-column label="入场钢卷号" align="center" prop="enterCoilNo">
|
||
<template slot-scope="scope">
|
||
<coil-no :coil-no="scope.row.enterCoilNo"></coil-no>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="当前钢卷号" align="center" prop="currentCoilNo">
|
||
<template slot-scope="scope">
|
||
<current-coil-no :current-coil-no="scope.row.currentCoilNo"></current-coil-no>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="净重" align="center" prop="netWeight" />
|
||
<el-table-column label="逻辑库位" align="center" prop="warehouseName" />
|
||
<el-table-column label="实际库区" align="center" prop="actualWarehouseName" />
|
||
<el-table-column label="产品类型" align="center" width="180">
|
||
<template slot-scope="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 label="规格" prop="specification"></el-table-column>
|
||
<el-table-column label="物料" prop="itemName"></el-table-column>
|
||
<el-table-column label="材质" prop="material"></el-table-column>
|
||
<el-table-column label="厂家" prop="manufacturer"></el-table-column>
|
||
<el-table-column label="表面处理" prop="surfaceTreatmentDesc"></el-table-column>
|
||
<el-table-column label="品质" prop="qualityStatus"></el-table-column>
|
||
<el-table-column label="切边" prop="trimmingRequirement"></el-table-column>
|
||
<el-table-column label="包装" prop="packagingRequirement"></el-table-column>
|
||
<el-table-column label="状态" align="center" prop="status">
|
||
<template slot-scope="scope">
|
||
<el-tag v-if="scope.row.status === 0" type="info" size="mini">未发货</el-tag>
|
||
<el-tag v-else type="success" size="mini">已发货</el-tag>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="备注" align="center" prop="remark" show-overflow-tooltip />
|
||
</el-table>
|
||
|
||
<div style="margin-top: 10px; text-align: center;">
|
||
<el-pagination @size-change="handleCoilSizeChange" @current-change="handleCoilCurrentChange"
|
||
:current-page="coilQueryParams.pageNum" :page-sizes="[10, 20, 50, 100]"
|
||
:page-size="coilQueryParams.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="coilTotal">
|
||
</el-pagination>
|
||
</div>
|
||
</div>
|
||
|
||
<div slot="footer" class="dialog-footer">
|
||
<div style="margin-bottom: 10px;">
|
||
<span>已选择 {{ selectedCoils.length }} 个钢卷,总重量:{{ calculateSelectedWeight().toFixed(3) }}t</span>
|
||
</div>
|
||
<el-button @click="coilSelectionVisible = false">取消</el-button>
|
||
<el-button type="primary" @click="saveSelectedCoils">确认选择</el-button>
|
||
</div>
|
||
</el-dialog>
|
||
|
||
<!-- 已选钢卷列表对话框 -->
|
||
<el-dialog title="已选钢卷列表" :visible.sync="selectedCoilsVisible" width="90%" append-to-body>
|
||
<el-table :data="currentTempOrder ? (currentTempOrder.coils || []) : []" border>
|
||
<el-table-column label="入场钢卷号" align="center" prop="enterCoilNo">
|
||
<template slot-scope="scope">
|
||
<coil-no :coil-no="scope.row.enterCoilNo"></coil-no>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="当前钢卷号" align="center" prop="currentCoilNo">
|
||
<template slot-scope="scope">
|
||
<current-coil-no :current-coil-no="scope.row.currentCoilNo"></current-coil-no>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="净重" align="center" prop="netWeight" />
|
||
<el-table-column label="逻辑库位" align="center" prop="warehouseName" />
|
||
<el-table-column label="实际库区" align="center" prop="actualWarehouseName" />
|
||
<el-table-column label="产品类型" align="center" width="180">
|
||
<template slot-scope="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 label="规格" prop="specification"></el-table-column>
|
||
<el-table-column label="物料" prop="itemName"></el-table-column>
|
||
<el-table-column label="材质" prop="material"></el-table-column>
|
||
<el-table-column label="厂家" prop="manufacturer"></el-table-column>
|
||
<el-table-column label="表面处理" prop="surfaceTreatmentDesc"></el-table-column>
|
||
<el-table-column label="品质" prop="qualityStatus"></el-table-column>
|
||
<el-table-column label="切边" prop="trimmingRequirement"></el-table-column>
|
||
<el-table-column label="包装" prop="packagingRequirement"></el-table-column>
|
||
<el-table-column label="备注" align="center" prop="remark" show-overflow-tooltip />
|
||
<el-table-column label="操作" align="center" width="100">
|
||
<template slot-scope="scope">
|
||
<el-button size="mini" type="text" style="color: #f56c6c;"
|
||
@click="removeCoilFromOrder(scope.$index)">移除</el-button>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
</el-dialog>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
import {
|
||
listMaterialCoil,
|
||
getMaterialCoil,
|
||
delMaterialCoil,
|
||
addMaterialCoil,
|
||
updateMaterialCoilSimple,
|
||
getMaterialCoilTrace,
|
||
exportCoil,
|
||
cancelExportCoil,
|
||
checkCoilNo,
|
||
returnCoil,
|
||
getCoilStatisticsList,
|
||
listWithAdjustRecordCoil
|
||
} from "@/api/wms/coil";
|
||
import { listBoundCoil, getBoundCoilStatisticsList } from "@/api/wms/deliveryWaybillDetail";
|
||
import { addPendingAction } from "@/api/wms/pendingAction";
|
||
import { listTransferOrderItem } from "@/api/wms/transferOrderItem";
|
||
import { listCoilQualityRejudge } from "@/api/wms/coilQualityRejudge";
|
||
import WarehouseSelect from "@/components/KLPService/WarehouseSelect";
|
||
import QRCode from "@/components/QRCode";
|
||
import * as XLSX from 'xlsx'
|
||
import { saveAsImage } from '@/utils/klp';
|
||
import ProductSelect from "@/components/KLPService/ProductSelect";
|
||
import RawMaterialSelect from "@/components/KLPService/RawMaterialSelect";
|
||
import ProductInfo from "@/components/KLPService/Renderer/ProductInfo";
|
||
import RawMaterialInfo from "@/components/KLPService/Renderer/RawMaterialInfo";
|
||
// 引入封装的追溯结果组件
|
||
import CoilTraceResult from "./CoilTraceResult.vue";
|
||
import LabelRender from './LabelRender/index.vue'
|
||
import OuterTagPreview from './LabelRender/OuterTagPreview.vue'
|
||
import MaterialSelect from "@/components/KLPService/MaterialSelect";
|
||
import ActualWarehouseSelect from "@/components/KLPService/ActualWarehouseSelect";
|
||
import { findItemWithBom } from "@/store/modules/category";
|
||
import CoilNo from "@/components/KLPService/Renderer/CoilNo.vue";
|
||
import MemoInput from "@/components/MemoInput";
|
||
import MutiSelect from "@/components/MutiSelect";
|
||
import html2canvas from 'html2canvas';
|
||
import { PDFDocument } from 'pdf-lib';
|
||
import { listUser } from "@/api/system/user";
|
||
import AbnormalList from "./abnormal.vue";
|
||
import LogTable from "@/views/wms/warehouse/components/LogTable.vue";
|
||
import { getCoilTagPrintType } from '@/views/wms/coil/js/coilPrint';
|
||
import DragResizeBox from '@/components/DragResizeBox/index.vue';
|
||
import ProcessFlow from '../components/ProcessFlow.vue';
|
||
import WarehouseTree from '@/components/KLPService/WarehouseTree/index.vue';
|
||
import { listDeliveryWaybillDetail, delDeliveryWaybillDetail } from "@/api/wms/deliveryWaybillDetail";
|
||
import { listDeliveryPlan } from "@/api/wms/deliveryPlan";
|
||
import { addCoilQualityRejudge } from "@/api/wms/coilQualityRejudge";
|
||
|
||
export default {
|
||
name: "MaterialCoil",
|
||
components: {
|
||
WarehouseSelect,
|
||
QRCode,
|
||
MaterialSelect,
|
||
ProductSelect,
|
||
RawMaterialSelect,
|
||
ProductInfo,
|
||
RawMaterialInfo,
|
||
CoilTraceResult,
|
||
LabelRender,
|
||
ActualWarehouseSelect,
|
||
CoilNo,
|
||
MemoInput,
|
||
MutiSelect,
|
||
OuterTagPreview,
|
||
AbnormalList,
|
||
LogTable,
|
||
ProcessFlow,
|
||
DragResizeBox,
|
||
WarehouseTree,
|
||
},
|
||
dicts: ['product_coil_status', 'coil_material', 'coil_itemname', 'coil_manufacturer', 'coil_quality_status', 'wms_next_warehouse', 'coil_business_purpose'],
|
||
props: {
|
||
qrcode: {
|
||
type: Boolean,
|
||
default: false,
|
||
},
|
||
querys: {
|
||
type: Object,
|
||
default: () => { },
|
||
},
|
||
labelType: {
|
||
type: String,
|
||
default: '2'
|
||
},
|
||
hideWarehouseQuery: {
|
||
type: Boolean,
|
||
default: false,
|
||
},
|
||
showStatus: {
|
||
type: Boolean,
|
||
default: false,
|
||
},
|
||
showMaterialType: {
|
||
type: Boolean,
|
||
default: false,
|
||
},
|
||
showControl: {
|
||
type: Boolean,
|
||
default: true,
|
||
},
|
||
showExportTime: {
|
||
type: Boolean,
|
||
default: false,
|
||
},
|
||
showGrade: {
|
||
type: Boolean,
|
||
default: false,
|
||
},
|
||
showAbnormal: {
|
||
type: Boolean,
|
||
default: false,
|
||
},
|
||
showLength: {
|
||
type: Boolean,
|
||
default: false,
|
||
},
|
||
canExportAll: {
|
||
type: Boolean,
|
||
default: false,
|
||
},
|
||
editNext: {
|
||
type: Boolean,
|
||
default: false,
|
||
},
|
||
forceSpecialTag: {
|
||
type: String,
|
||
required: false,
|
||
},
|
||
editWarehouse: {
|
||
type: Boolean,
|
||
default: false,
|
||
},
|
||
showWaybill: {
|
||
type: Boolean,
|
||
default: false,
|
||
},
|
||
showWareLog: {
|
||
type: Boolean,
|
||
default: false,
|
||
},
|
||
showBusinessPurpose: {
|
||
type: Boolean,
|
||
default: false,
|
||
},
|
||
showRelatedToOrder: {
|
||
type: Boolean,
|
||
default: false,
|
||
},
|
||
showOrderBy: {
|
||
type: Boolean,
|
||
default: false,
|
||
},
|
||
showNewExport: {
|
||
type: Boolean,
|
||
default: false,
|
||
},
|
||
// 展示宽度快捷编辑
|
||
showWidthEdit: {
|
||
type: Boolean,
|
||
default: false,
|
||
},
|
||
// 展示生产时间快捷编辑
|
||
showProductionTimeEdit: {
|
||
type: Boolean,
|
||
default: false,
|
||
},
|
||
leftWarehouseQuery: {
|
||
type: Boolean,
|
||
default: false,
|
||
},
|
||
hasTransferType: {
|
||
type: Boolean,
|
||
default: false,
|
||
},
|
||
useWarehouseIds: {
|
||
type: Boolean,
|
||
default: false,
|
||
},
|
||
warehouseOptions: {
|
||
type: Array,
|
||
default: () => [],
|
||
},
|
||
moreColumn: {
|
||
type: Boolean,
|
||
default: false,
|
||
},
|
||
isShipView: {
|
||
type: Boolean,
|
||
default: false,
|
||
},
|
||
},
|
||
data() {
|
||
return {
|
||
shipViewModel: {
|
||
status: 'all', // all, has, none
|
||
allCount: 0,
|
||
hasCount: 0,
|
||
noneCount: 0,
|
||
},
|
||
// 按钮loading
|
||
buttonLoading: false,
|
||
showProcessFlow: false,
|
||
// 遮罩层
|
||
loading: true,
|
||
waybillLoading: false,
|
||
waybillOptions: [],
|
||
// 追溯加载中
|
||
traceLoading: false,
|
||
// 选中数组
|
||
ids: [],
|
||
// 非单个禁用
|
||
single: true,
|
||
// 非多个禁用
|
||
multiple: true,
|
||
// 显示搜索条件
|
||
showSearch: true,
|
||
// 总条数
|
||
total: 0,
|
||
// 钢卷物料表格数据
|
||
materialCoilList: [],
|
||
// 弹出层标题
|
||
title: "",
|
||
// 是否显示弹出层
|
||
open: false,
|
||
// 追溯对话框显示
|
||
traceOpen: false,
|
||
// 追溯结果数据(传递给组件)
|
||
traceResult: null,
|
||
// 查询参数
|
||
queryParams: {
|
||
pageNum: 1,
|
||
pageSize: 50,
|
||
enterCoilNo: undefined,
|
||
currentCoilNo: undefined,
|
||
supplierCoilNo: undefined,
|
||
warehouseId: undefined,
|
||
nextWarehouseId: undefined,
|
||
actualWarehouseId: undefined,
|
||
qrcodeRecordId: undefined,
|
||
team: undefined,
|
||
hasMergeSplit: undefined,
|
||
parentCoilNos: undefined,
|
||
itemId: undefined,
|
||
itemIds: undefined,
|
||
status: '',
|
||
updateTime: undefined,
|
||
orderBy: false,
|
||
planId: undefined,
|
||
...this.querys,
|
||
},
|
||
// 表单参数
|
||
form: {},
|
||
transferCoilForm: {},
|
||
// 表单校验
|
||
rules: {
|
||
enterCoilNo: [
|
||
{ required: true, message: "入场钢卷号不能为空", trigger: "blur" },
|
||
// 自定义校验,必须是8位的阿拉伯数字
|
||
{
|
||
validator: (rule, value, callback) => {
|
||
if (this.form.coilId) {
|
||
// 新增时触发校验
|
||
callback();
|
||
} else {
|
||
if (!/^\d{8}$/.test(value)) {
|
||
callback(new Error('入场钢卷号必须是8位的阿拉伯数字'));
|
||
} else {
|
||
callback();
|
||
}
|
||
}
|
||
}, trigger: 'blur'
|
||
},
|
||
// 远程校验,检查钢卷号是否存在
|
||
{
|
||
validator: (rule, value, callback) => {
|
||
if (this.form.coilId) {
|
||
// 新增时触发校验
|
||
console.log('新增时触发校验');
|
||
callback();
|
||
} else {
|
||
checkCoilNo({ enterCoilNo: value }).then(res => {
|
||
const { duplicateType } = res.data;
|
||
if (duplicateType === 'enter' || duplicateType === 'both') {
|
||
// alert('入场钢卷号重复,请重新输入');
|
||
callback(new Error('入场钢卷号重复,请重新输入'));
|
||
} else {
|
||
callback();
|
||
}
|
||
})
|
||
}
|
||
}, trigger: 'blur'
|
||
},
|
||
],
|
||
currentCoilNo: [
|
||
{ required: true, message: "当前钢卷号不能为空", trigger: "blur" },
|
||
],
|
||
itemId: [
|
||
{ required: true, message: "物品ID不能为空", trigger: "blur" }
|
||
],
|
||
itemType: [
|
||
{ required: true, message: "物品类型不能为空", trigger: "change" }
|
||
],
|
||
// 净重和毛重
|
||
netWeight: [
|
||
{ required: true, message: "净重不能为空", trigger: "blur" }
|
||
],
|
||
grossWeight: [
|
||
{ required: true, message: "毛重不能为空", trigger: "blur" }
|
||
],
|
||
},
|
||
labelRender: {
|
||
visible: false,
|
||
data: {},
|
||
type: '2'
|
||
},
|
||
batchPrint: {
|
||
visible: false,
|
||
loading: false,
|
||
list: [],
|
||
},
|
||
warehouseIds: '',
|
||
__printOldTitle: document.title,
|
||
floatLayerConfig: {
|
||
columns: [
|
||
{ label: '入场钢卷号', prop: 'enterCoilNo' },
|
||
{ label: '当前钢卷号', prop: 'currentCoilNo' },
|
||
{ label: '厂家卷号', prop: 'supplierCoilNo' },
|
||
{ label: '逻辑库位', prop: 'warehouseName' },
|
||
{ label: '实际库位', prop: 'actualWarehouseName' },
|
||
{ label: '物料类型', prop: 'materialType' },
|
||
{ label: '班组', prop: 'team' },
|
||
{ label: '净重', prop: 'netWeight' },
|
||
{ label: '毛重', prop: 'grossWeight' },
|
||
{ label: '备注', prop: 'remark' },
|
||
{ label: '创建人', prop: 'createBy' },
|
||
{ label: '创建时间', prop: 'createTime' },
|
||
{ label: '更新人', prop: 'updateBy' },
|
||
{ label: '更新时间', prop: 'updateTime' },
|
||
{ label: '质量状态', prop: 'qualityStatus' },
|
||
{ label: '原料材质', prop: 'packingStatus' },
|
||
{ label: '切边要求', prop: 'edgeRequirement' },
|
||
{ label: '包装要求', prop: 'packagingRequirement' },
|
||
{ label: '物料名称', prop: 'itemName' },
|
||
{ label: '材质', prop: 'material' },
|
||
{ label: '规格', prop: 'specification' },
|
||
{ label: '镀层质量', prop: 'zincLayer' },
|
||
{ label: '厂家', prop: 'manufacturer' },
|
||
{ label: '调制度', prop: 'temperGrade' },
|
||
{ label: '镀层种类', prop: 'coatingType' },
|
||
{ label: '实测长度(mm)', prop: 'actualLength' },
|
||
{ label: '实测宽度(mm)', prop: 'actualWidth' },
|
||
{ label: '实测厚度(mm)', prop: 'actualThickness' },
|
||
{ label: '钢卷表面处理', prop: 'coilSurfaceTreatment' },
|
||
],
|
||
title: '详细信息'
|
||
},
|
||
abnormalOpen: false,
|
||
currentCoilId: '',
|
||
userList: [],
|
||
logOpen: false,
|
||
productionTimeForm: {
|
||
productionStartTime: '',
|
||
productionEndTime: '',
|
||
formattedDuration: '',
|
||
productionDuration: 0,
|
||
},
|
||
productionTimeFormRules: {
|
||
productionTime: [
|
||
{ required: true, message: "生产时间不能为空", trigger: "blur" }
|
||
],
|
||
},
|
||
productionTimeFormVisible: false,
|
||
// 统计数据:已发货的数量和未发货的数量
|
||
shippedCount: 0,
|
||
unshippedCount: 0,
|
||
statistics: {},
|
||
// 钢卷改判弹窗
|
||
judgeDialogVisible: false,
|
||
judgeForm: {
|
||
coilId: undefined,
|
||
enterCoilNo: undefined,
|
||
currentCoilNo: undefined,
|
||
netWeight: undefined,
|
||
warehouseName: undefined,
|
||
actualWarehouseName: undefined,
|
||
qualityStatus: undefined,
|
||
itemName: undefined,
|
||
itemMaterial: undefined,
|
||
itemSpecification: undefined,
|
||
itemManufacturer: undefined,
|
||
notifyReLabel: false
|
||
},
|
||
// 调拨记录弹窗
|
||
transferRecordVisible: false,
|
||
transferRecordList: [],
|
||
// 暂存单据管理相关数据
|
||
tempOrderList: [],
|
||
currentTempOrder: null,
|
||
coilSelectionVisible: false,
|
||
selectedCoilsVisible: false,
|
||
coilLoading: false,
|
||
availableCoils: [],
|
||
selectedCoils: [],
|
||
coilTotal: 0,
|
||
coilQueryParams: {
|
||
pageNum: 1,
|
||
pageSize: 20,
|
||
enterCoilNo: '',
|
||
currentCoilNo: '',
|
||
itemName: '',
|
||
itemSpecification: '',
|
||
itemMaterial: '',
|
||
status: 0,
|
||
orderBy: true,
|
||
dataType: 1,
|
||
materialType: '成品',
|
||
itemType: 'product',
|
||
excludeBound: true,
|
||
selectType: 'product'
|
||
},
|
||
};
|
||
},
|
||
computed: {
|
||
// 动态显示标签
|
||
getItemLabel() {
|
||
if (this.form.materialType === '成品') {
|
||
return '产品类型';
|
||
} else if (this.form.materialType === '原料') {
|
||
return '原料类型';
|
||
}
|
||
return '物品类型';
|
||
},
|
||
canEditExportTime() {
|
||
// 徐梦琪和若依管理员
|
||
const canEdit = ['1988841895986642945', 1];
|
||
const currentUserId = this.$store.getters.id;
|
||
return canEdit.includes(currentUserId);
|
||
},
|
||
},
|
||
created() {
|
||
if (this.showExportTime) {
|
||
this.getUserList();
|
||
}
|
||
if (this.useWarehouseIds) {
|
||
this.warehouseIds = this.warehouseOptions.map(item => item.value).join(',');
|
||
}
|
||
if (this.showWaybill) {
|
||
this.remoteSearchWaybill();
|
||
}
|
||
this.getList();
|
||
// 初始化暂存单据列表
|
||
this.loadTempOrderList();
|
||
},
|
||
methods: {
|
||
// === 暂存单据管理相关方法 ===
|
||
// 加载暂存单据列表
|
||
loadTempOrderList() {
|
||
const savedOrders = localStorage.getItem('tempCoilOrders');
|
||
if (savedOrders) {
|
||
this.tempOrderList = JSON.parse(savedOrders);
|
||
} else {
|
||
this.tempOrderList = [];
|
||
}
|
||
},
|
||
|
||
// 保存暂存单据列表到本地存储
|
||
saveTempOrderList() {
|
||
localStorage.setItem('tempCoilOrders', JSON.stringify(this.tempOrderList));
|
||
},
|
||
|
||
// 创建暂存单据
|
||
createTempOrder() {
|
||
const orderName = `暂存单据_${new Date().toLocaleString().replace(/[/:]/g, '-')}`;
|
||
const newOrder = {
|
||
orderId: Date.now().toString(),
|
||
orderName: orderName,
|
||
createTime: new Date().toLocaleString(),
|
||
coils: []
|
||
};
|
||
|
||
this.tempOrderList.unshift(newOrder);
|
||
this.saveTempOrderList();
|
||
|
||
this.$message.success('暂存单据创建成功');
|
||
},
|
||
|
||
// 删除暂存单据
|
||
deleteTempOrder(order) {
|
||
this.$confirm(`确认删除暂存单据"${order.orderName}"吗?`, '提示', {
|
||
confirmButtonText: '确定',
|
||
cancelButtonText: '取消',
|
||
type: 'warning'
|
||
}).then(() => {
|
||
const index = this.tempOrderList.findIndex(item => item.orderId === order.orderId);
|
||
if (index > -1) {
|
||
this.tempOrderList.splice(index, 1);
|
||
this.saveTempOrderList();
|
||
this.$message.success('删除成功');
|
||
}
|
||
}).catch(() => {
|
||
this.$message.info('已取消删除');
|
||
});
|
||
},
|
||
|
||
// 查看已选钢卷列表
|
||
viewSelectedCoils(order) {
|
||
this.currentTempOrder = order;
|
||
this.selectedCoilsVisible = true;
|
||
},
|
||
|
||
// 编辑单据名称
|
||
editOrderName(order) {
|
||
this.$prompt('请输入新的单据名称', '编辑单据名称', {
|
||
confirmButtonText: '确定',
|
||
cancelButtonText: '取消',
|
||
inputValue: order.orderName,
|
||
inputValidator: (value) => {
|
||
if (!value || value.trim() === '') {
|
||
return '单据名称不能为空';
|
||
}
|
||
return true;
|
||
}
|
||
}).then(({ value }) => {
|
||
const newName = value.trim();
|
||
// 检查名称是否重复
|
||
const duplicateOrder = this.tempOrderList.find(item =>
|
||
item.orderId !== order.orderId && item.orderName === newName
|
||
);
|
||
|
||
if (duplicateOrder) {
|
||
this.$message.warning('单据名称已存在,请使用其他名称');
|
||
return;
|
||
}
|
||
|
||
// 更新单据名称
|
||
order.orderName = newName;
|
||
this.saveTempOrderList();
|
||
this.$message.success('单据名称修改成功');
|
||
}).catch(() => {
|
||
this.$message.info('已取消编辑');
|
||
});
|
||
},
|
||
|
||
// 打开钢卷选择对话框
|
||
openCoilSelection(order) {
|
||
this.currentTempOrder = order;
|
||
this.coilSelectionVisible = true;
|
||
this.searchCoils();
|
||
},
|
||
|
||
// 计算总重量
|
||
calculateTotalWeight(coils) {
|
||
if (!coils || coils.length === 0) return 0;
|
||
return coils.reduce((total, coil) => {
|
||
return total + (parseFloat(coil.netWeight) || 0);
|
||
}, 0);
|
||
},
|
||
|
||
// 计算选中钢卷的总重量
|
||
calculateSelectedWeight() {
|
||
return this.calculateTotalWeight(this.selectedCoils);
|
||
},
|
||
|
||
// 查询钢卷
|
||
async searchCoils() {
|
||
this.coilLoading = true;
|
||
try {
|
||
// 构建查询参数
|
||
const params = { ...this.coilQueryParams };
|
||
|
||
// 移除空值参数
|
||
Object.keys(params).forEach(key => {
|
||
if (params[key] === '' || params[key] === null || params[key] === undefined) {
|
||
delete params[key];
|
||
}
|
||
});
|
||
|
||
// 调用接口查询钢卷
|
||
const response = await listMaterialCoil(params);
|
||
this.availableCoils = response.rows || [];
|
||
this.coilTotal = response.total || 0;
|
||
|
||
// 过滤掉所有单据中已选择的钢卷,确保钢卷在所有单据中唯一
|
||
const allExistingCoilIds = [];
|
||
this.tempOrderList.forEach(order => {
|
||
if (order.coils && Array.isArray(order.coils)) {
|
||
order.coils.forEach(coil => {
|
||
if (coil.coilId) {
|
||
allExistingCoilIds.push(coil.coilId);
|
||
}
|
||
});
|
||
}
|
||
});
|
||
|
||
// 如果是当前正在编辑的单据,排除当前单据中的钢卷(因为它们已经在allExistingCoilIds中了)
|
||
// 这样可以确保其他单据不能选择当前单据已选的钢卷
|
||
this.availableCoils = this.availableCoils.filter(coil => !allExistingCoilIds.includes(coil.coilId));
|
||
|
||
} catch (error) {
|
||
console.error('查询钢卷失败:', error);
|
||
this.$message.error('查询钢卷失败');
|
||
} finally {
|
||
this.coilLoading = false;
|
||
}
|
||
},
|
||
|
||
// 重置钢卷查询条件
|
||
resetCoilQuery() {
|
||
this.coilQueryParams = {
|
||
pageNum: 1,
|
||
pageSize: 20,
|
||
enterCoilNo: '',
|
||
currentCoilNo: '',
|
||
itemName: '',
|
||
itemSpecification: '',
|
||
itemMaterial: '',
|
||
status: 0,
|
||
orderBy: true,
|
||
dataType: 1,
|
||
materialType: '成品',
|
||
itemType: 'product',
|
||
excludeBound: true,
|
||
selectType: 'product'
|
||
};
|
||
this.searchCoils();
|
||
},
|
||
|
||
// 处理钢卷选择变化
|
||
handleCoilSelection(selection) {
|
||
this.selectedCoils = selection;
|
||
},
|
||
|
||
// 保存选中的钢卷
|
||
saveSelectedCoils() {
|
||
if (!this.currentTempOrder) {
|
||
this.$message.error('请先选择暂存单据');
|
||
return;
|
||
}
|
||
|
||
if (this.selectedCoils.length === 0) {
|
||
this.$message.warning('请选择要添加的钢卷');
|
||
return;
|
||
}
|
||
|
||
// 确保coils数组存在
|
||
if (!this.currentTempOrder.coils) {
|
||
this.currentTempOrder.coils = [];
|
||
}
|
||
|
||
// 由于在查询阶段已经过滤了所有重复的钢卷,这里不需要再次检查
|
||
// 但为了安全起见,保留基本的检查逻辑
|
||
if (this.currentTempOrder.coils && this.currentTempOrder.coils.length > 0) {
|
||
const existingCoilIds = this.currentTempOrder.coils.map(coil => coil.coilId);
|
||
const duplicateCoils = this.selectedCoils.filter(coil => existingCoilIds.includes(coil.coilId));
|
||
|
||
if (duplicateCoils.length > 0) {
|
||
this.$message.warning(`钢卷 ${duplicateCoils.map(coil => coil.enterCoilNo).join(', ')} 已存在,不能重复添加`);
|
||
return;
|
||
}
|
||
}
|
||
|
||
// 添加钢卷到当前单据
|
||
this.currentTempOrder.coils.push(...this.selectedCoils);
|
||
this.saveTempOrderList();
|
||
|
||
this.$message.success(`成功添加 ${this.selectedCoils.length} 个钢卷`);
|
||
|
||
// 关闭对话框并重置选择
|
||
this.coilSelectionVisible = false;
|
||
this.selectedCoils = [];
|
||
},
|
||
|
||
// 从单据中移除钢卷
|
||
removeCoilFromOrder(index) {
|
||
if (!this.currentTempOrder || !this.currentTempOrder.coils || !this.currentTempOrder.coils[index]) return;
|
||
|
||
this.$confirm('确认移除该钢卷吗?', '提示', {
|
||
confirmButtonText: '确定',
|
||
cancelButtonText: '取消',
|
||
type: 'warning'
|
||
}).then(() => {
|
||
this.currentTempOrder.coils.splice(index, 1);
|
||
this.saveTempOrderList();
|
||
this.$message.success('移除成功');
|
||
}).catch(() => {
|
||
this.$message.info('已取消移除');
|
||
});
|
||
},
|
||
|
||
// 钢卷分页相关方法
|
||
handleCoilSizeChange(val) {
|
||
this.coilQueryParams.pageSize = val;
|
||
this.coilQueryParams.pageNum = 1;
|
||
this.searchCoils();
|
||
},
|
||
|
||
handleCoilCurrentChange(val) {
|
||
this.coilQueryParams.pageNum = val;
|
||
this.searchCoils();
|
||
},
|
||
|
||
// 进入数字钢卷页面
|
||
handleNumberCoilClick(row) {
|
||
this.$router.push({
|
||
path: '/wms/coil/' + row.coilId,
|
||
});
|
||
},
|
||
// 处理行点击事件
|
||
handleRowClick(row) {
|
||
this.currentCoilId = row.coilId;
|
||
this.logOpen = true;
|
||
},
|
||
// 处理大小变化事件
|
||
resizeChart() {
|
||
this.$refs.processFlow.resizeChart();
|
||
},
|
||
// 获取用户列表
|
||
getUserList() {
|
||
listUser({ pageNum: 1, pageSize: 1000 }).then(res => {
|
||
this.userList = res.rows || [];
|
||
});
|
||
},
|
||
handleProductionTimeEdit(row) {
|
||
// 创建一个新对象,避免直接引用row
|
||
this.productionTimeForm = { ...row };
|
||
this.productionTimeFormVisible = true;
|
||
// 初始化时计算一次
|
||
this.calculateProductionDuration();
|
||
},
|
||
// 处理逻辑库位点击事件
|
||
handleWarehouseNodeClick(node) {
|
||
this.queryParams.warehouseId = node.warehouseId;
|
||
this.getList();
|
||
},
|
||
async handleRemoveFromWaybill(row) {
|
||
const coilId = row.coilId;
|
||
// 根据id查询所在的单据明细
|
||
const res = await listDeliveryWaybillDetail({ coilId });
|
||
|
||
if (res.rows.length != 1) {
|
||
this.$message({
|
||
message: '发货单查找失败',
|
||
type: 'error',
|
||
});
|
||
return;
|
||
}
|
||
console.log(res.rows)
|
||
const detailId = res.rows[0].detailId;
|
||
// 二次确认是否移除
|
||
this.$modal.confirm('确认要将该钢卷从发货单中移除吗?', {
|
||
title: '确认移除',
|
||
type: 'warning',
|
||
}).then(() => {
|
||
delDeliveryWaybillDetail(detailId).then(res => {
|
||
this.$message({
|
||
message: '移除成功',
|
||
type: 'success',
|
||
});
|
||
this.getList();
|
||
});
|
||
})
|
||
// 打开一个弹窗列出查询到的所有单据明细
|
||
},
|
||
async handleBatchRemoveFromWaybill() {
|
||
const selectedRows = this.materialCoilList.filter(item => this.ids.includes(item.coilId));
|
||
if (selectedRows.length === 0) {
|
||
this.$message.warning('请先勾选要移除的钢卷');
|
||
return;
|
||
}
|
||
this.$modal.confirm(`确认要将选中的 ${selectedRows.length} 个钢卷从发货单中移除吗?`, {
|
||
title: '批量移除',
|
||
type: 'warning',
|
||
}).then(async () => {
|
||
this.buttonLoading = true;
|
||
const detailIds = [];
|
||
const failCoils = [];
|
||
for (const row of selectedRows) {
|
||
try {
|
||
const res = await listDeliveryWaybillDetail({ coilId: row.coilId });
|
||
if (res.rows.length === 1) {
|
||
detailIds.push(res.rows[0].detailId);
|
||
} else {
|
||
failCoils.push(row.currentCoilNo);
|
||
}
|
||
} catch (e) {
|
||
failCoils.push(row.currentCoilNo);
|
||
}
|
||
}
|
||
if (detailIds.length === 0) {
|
||
this.$message.error('未找到任何可移除的发货单明细');
|
||
this.buttonLoading = false;
|
||
return;
|
||
}
|
||
try {
|
||
await delDeliveryWaybillDetail(detailIds.join(','));
|
||
if (failCoils.length > 0) {
|
||
this.$message.warning(`移除完成:成功 ${detailIds.length} 个,失败 ${failCoils.length} 个(${failCoils.join('、')})`);
|
||
} else {
|
||
this.$message.success(`成功移除 ${detailIds.length} 个钢卷`);
|
||
}
|
||
} catch (e) {
|
||
this.$message.error('批量移除失败');
|
||
}
|
||
this.buttonLoading = false;
|
||
this.getList();
|
||
});
|
||
},
|
||
// 处理重贴标签
|
||
handleReplaceLabel(row) {
|
||
updateMaterialCoilSimple({
|
||
...row,
|
||
transferType: '',
|
||
}).then(res => {
|
||
this.$message({
|
||
message: '标签已重贴,记录移除',
|
||
type: 'success',
|
||
});
|
||
this.getList();
|
||
})
|
||
},
|
||
// 查看调拨记录
|
||
async handleViewTransferRecord(row) {
|
||
this.transferRecordVisible = true;
|
||
this.transferRecordList = [];
|
||
try {
|
||
// 获取批量调拨记录
|
||
this.loading = true;
|
||
const transferOrderRes = await listTransferOrderItem({
|
||
coilId: row.coilId,
|
||
pageNum: 1,
|
||
pageSize: 100
|
||
});
|
||
// 获取技术部改判记录
|
||
const rejudgeRes = await listCoilQualityRejudge({
|
||
coilId: row.coilId,
|
||
pageNum: 1,
|
||
pageSize: 100
|
||
});
|
||
// 合并记录
|
||
const list = [];
|
||
// 添加批量调拨记录
|
||
(transferOrderRes.rows || []).forEach(item => {
|
||
list.push({
|
||
type: '批量调拨',
|
||
before: '逻辑库:' + (item.warehouseNameBefore || '-'),
|
||
after: '逻辑库:' + (item.warehouseNameAfter || '-'),
|
||
createTime: item.createTime || '-',
|
||
remark: item.remark || '-',
|
||
...item
|
||
});
|
||
});
|
||
// 添加技术部改判记录
|
||
(rejudgeRes.rows || []).forEach(item => {
|
||
list.push({
|
||
...item,
|
||
type: '技术部改判',
|
||
before: '质量状态:' + (item.beforeQuality || '-'),
|
||
after: '质量状态:' + (item.afterQuality || '-'),
|
||
createTime: item.createTime || '-',
|
||
remark: item.rejudgeReason,
|
||
});
|
||
});
|
||
// 按时间排序
|
||
list.sort((a, b) => {
|
||
const timeA = new Date(a.createTime || 0).getTime();
|
||
const timeB = new Date(b.createTime || 0).getTime();
|
||
return timeB - timeA;
|
||
});
|
||
this.transferRecordList = list;
|
||
} catch (error) {
|
||
console.error('获取调拨记录失败:', error);
|
||
this.$message.error('获取调拨记录失败');
|
||
} finally {
|
||
this.loading = false;
|
||
}
|
||
},
|
||
// 格式化毫秒值为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.productionTimeForm;
|
||
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.productionTimeForm, 'productionDuration', '');
|
||
this.$set(this.productionTimeForm, 'formattedDuration', '');
|
||
} else {
|
||
const durationMs = end - start;
|
||
const durationMinutes = Math.round(durationMs / (1000 * 60));
|
||
this.$set(this.productionTimeForm, 'productionDuration', durationMinutes);
|
||
// 同时保存格式化后的显示值
|
||
this.$set(this.productionTimeForm, 'formattedDuration', this.formatDuration(durationMinutes * 60 * 1000));
|
||
}
|
||
} else {
|
||
this.$set(this.productionTimeForm, 'productionDuration', '');
|
||
this.$set(this.productionTimeForm, 'formattedDuration', '');
|
||
}
|
||
},
|
||
// 处理生产时间提交
|
||
submitProductionTimeForm() {
|
||
this.$refs.productionTimeForm.validate((valid) => {
|
||
if (valid) {
|
||
// 再次验证时间逻辑
|
||
const { productionStartTime, productionEndTime } = this.productionTimeForm;
|
||
if (productionStartTime && productionEndTime) {
|
||
const start = new Date(productionStartTime).getTime();
|
||
const end = new Date(productionEndTime).getTime();
|
||
if (end < start) {
|
||
this.$message({
|
||
message: '结束时间不能早于开始时间',
|
||
type: 'error',
|
||
});
|
||
return false;
|
||
}
|
||
}
|
||
this.buttonLoading = true;
|
||
updateMaterialCoilSimple(this.productionTimeForm).then(res => {
|
||
this.buttonLoading = false;
|
||
this.$message({
|
||
message: '更新成功',
|
||
type: 'success',
|
||
});
|
||
this.productionTimeFormVisible = false;
|
||
})
|
||
} else {
|
||
return false;
|
||
}
|
||
})
|
||
},
|
||
handleNextWarehouseChange(row) {
|
||
if (!this.editNext) {
|
||
return;
|
||
}
|
||
updateMaterialCoilSimple(row).then(res => {
|
||
if (res.code === 200) {
|
||
this.$message({
|
||
message: '更新成功',
|
||
type: 'success',
|
||
});
|
||
} else {
|
||
this.$message({
|
||
message: res.msg || '更新失败',
|
||
type: 'error',
|
||
});
|
||
}
|
||
})
|
||
},
|
||
// 处理行数据变化
|
||
handleRowChange(row) {
|
||
updateMaterialCoilSimple(row).then(res => {
|
||
this.$message({
|
||
message: '更新成功',
|
||
type: 'success',
|
||
});
|
||
})
|
||
},
|
||
// 打印标签
|
||
handlePrintLabel(row) {
|
||
const type = getCoilTagPrintType(row);
|
||
this.labelRender.type = type;
|
||
|
||
this.labelRender.data = {
|
||
...row,
|
||
updateTime: row.updateTime?.split(' ')[0] || '',
|
||
};
|
||
this.$nextTick(() => {
|
||
this.$refs.labelRender.printLabel();
|
||
})
|
||
},
|
||
// 处理材料类型变化
|
||
handleMaterialTypeChange(value) {
|
||
// 清空物品选择
|
||
this.form.itemId = null;
|
||
|
||
// 根据材料类型设置物品类型
|
||
if (value === '成品') {
|
||
this.form.itemType = 'product';
|
||
} else if (value === '原料') {
|
||
this.form.itemType = 'raw_material';
|
||
}
|
||
},
|
||
/** 查询钢卷物料列表 */
|
||
async getList() {
|
||
this.loading = true;
|
||
const { updateTime, ...query } = {
|
||
...this.queryParams,
|
||
startTime: this.queryParams.updateTime?.[0],
|
||
endTime: this.queryParams.updateTime?.[1],
|
||
}
|
||
// 如果没有设置itemType,则设置为raw_material
|
||
query.selectType = this.querys.materialType === '原料' ? 'raw_material' : 'product';
|
||
if (this.useWarehouseIds) {
|
||
query.warehouseIds = this.warehouseIds;
|
||
}
|
||
|
||
const { orderBy, ...statisticQuery } = query;
|
||
if (this.showWaybill) {
|
||
const { shipmentTime, ...query } = {
|
||
...this.queryParams,
|
||
exportTimeBy: true,
|
||
selectType: this.querys.materialType === '原料' ? 'raw_material' : 'product',
|
||
startTime: this.queryParams.shipmentTime?.[0] && this.queryParams.shipmentTime?.[0] + ' 00:00:00',
|
||
endTime: this.queryParams.shipmentTime?.[1] && this.queryParams.shipmentTime?.[1] + ' 23:59:59',
|
||
}
|
||
listBoundCoil(query).then(res => {
|
||
this.materialCoilList = res.rows || [];
|
||
this.total = res.total;
|
||
this.loading = false;
|
||
})
|
||
// 获取统计数据:已发货的数量和未发货的数量
|
||
listBoundCoil({ ...query, status: 0, pageNum: 1, pageSize: 1 }).then(res => {
|
||
this.unshippedCount = res.total;
|
||
})
|
||
// 获取统计数据:已发货的数量和未发货的数量
|
||
listBoundCoil({ ...query, status: 1, pageNum: 1, pageSize: 1 }).then(res => {
|
||
this.shippedCount = res.total;
|
||
})
|
||
|
||
getBoundCoilStatisticsList(query).then(res => {
|
||
this.statistics = res.data || [];
|
||
})
|
||
return;
|
||
}
|
||
|
||
if (this.hasTransferType) {
|
||
listWithAdjustRecordCoil(query).then(response => {
|
||
this.materialCoilList = response.rows
|
||
this.total = response.total;
|
||
this.loading = false;
|
||
});
|
||
getCoilStatisticsList(statisticQuery).then(res => {
|
||
this.statistics = res.data || [];
|
||
})
|
||
return;
|
||
}
|
||
|
||
if (this.isShipView) {
|
||
// query.status = this.shipViewModel.status;
|
||
query.status = 1;
|
||
if (this.shipViewModel.status === 'all') {
|
||
listMaterialCoil(query).then(response => {
|
||
this.materialCoilList = response.rows
|
||
this.total = response.total;
|
||
this.loading = false;
|
||
});
|
||
getCoilStatisticsList(statisticQuery).then(res => {
|
||
this.statistics = res.data || [];
|
||
})
|
||
} else if (this.shipViewModel.status === 'has') {
|
||
listBoundCoil(query).then(res => {
|
||
this.materialCoilList = res.rows || [];
|
||
this.total = res.total;
|
||
this.loading = false;
|
||
})
|
||
getBoundCoilStatisticsList(query).then(res => {
|
||
this.statistics = res.data || [];
|
||
})
|
||
} else if (this.shipViewModel.status === 'none') {
|
||
query.excludeBound = true;
|
||
listMaterialCoil(query).then(response => {
|
||
this.materialCoilList = response.rows
|
||
this.total = response.total;
|
||
this.loading = false;
|
||
});
|
||
getCoilStatisticsList(statisticQuery).then(res => {
|
||
this.statistics = res.data || [];
|
||
})
|
||
}
|
||
|
||
listBoundCoil({ ...query, pageNum: 1, pageSize: 1 }).then(res => {
|
||
this.shipViewModel.hasCount = res.total;
|
||
})
|
||
|
||
listMaterialCoil({ ...query, pageNum: 1, pageSize: 1, excludeBound: true }).then(response => {
|
||
this.shipViewModel.noneCount = response.total;
|
||
});
|
||
return;
|
||
}
|
||
|
||
listMaterialCoil(query).then(response => {
|
||
this.materialCoilList = response.rows
|
||
this.total = response.total;
|
||
this.loading = false;
|
||
});
|
||
getCoilStatisticsList(statisticQuery).then(res => {
|
||
this.statistics = res.data || [];
|
||
})
|
||
},
|
||
/** 追溯按钮操作 */
|
||
handleTrace(row) {
|
||
this.traceOpen = true;
|
||
this.traceLoading = true;
|
||
this.traceResult = null; // 清空历史数据
|
||
getMaterialCoilTrace({
|
||
coilId: row.coilId,
|
||
currentCoilNo: row.currentCoilNo,
|
||
}).then(res => {
|
||
this.traceResult = res.data; // 将结果传递给组件
|
||
}).catch(err => {
|
||
console.error('溯源查询失败:', err);
|
||
this.$message.error('溯源查询失败,请重试');
|
||
}).finally(() => {
|
||
this.traceLoading = false;
|
||
});
|
||
},
|
||
handleGradeChange(row) {
|
||
updateMaterialCoilSimple(row).then(res => {
|
||
this.$message.success('质量状态更新成功');
|
||
this.getList(); // 刷新列表
|
||
})
|
||
},
|
||
handleWarehouseChange(row) {
|
||
if (!this.editWarehouse) {
|
||
return;
|
||
}
|
||
updateMaterialCoilSimple(row).then(res => {
|
||
this.$message.success('库位更新成功');
|
||
this.getList(); // 刷新列表
|
||
})
|
||
},
|
||
/** 预览标签 */
|
||
handlePreviewLabel(row) {
|
||
this.labelRender.visible = true;
|
||
const itemName = row.itemName || '';
|
||
|
||
this.labelRender.type = row.itemType === 'product' ? '3' : '2';
|
||
this.labelRender.data = {
|
||
...row,
|
||
itemName: itemName,
|
||
updateTime: row.updateTime?.split(' ')[0] || '',
|
||
};
|
||
},
|
||
/** 下载二维码 */
|
||
handleDownloadQRCode(row) {
|
||
try {
|
||
saveAsImage(
|
||
row.qrcodeRecordId,
|
||
'',
|
||
1,
|
||
{
|
||
barcodeWidth: 200,
|
||
barcodeHeight: 200
|
||
}
|
||
);
|
||
this.$message.success('图片保存成功');
|
||
} catch (error) {
|
||
console.error('保存图片失败', error);
|
||
this.$message.error('保存图片失败,请稍后重试');
|
||
}
|
||
},
|
||
handleAbnormal(row) {
|
||
this.currentCoilId = row.coilId;
|
||
this.abnormalOpen = true;
|
||
},
|
||
// 取消按钮
|
||
cancel() {
|
||
this.open = false;
|
||
this.reset();
|
||
},
|
||
// 表单重置
|
||
reset() {
|
||
this.form = {
|
||
coilId: undefined,
|
||
enterCoilNo: undefined,
|
||
currentCoilNo: undefined,
|
||
supplierCoilNo: undefined,
|
||
dataType: 1,
|
||
warehouseId: undefined,
|
||
nextWarehouseId: undefined,
|
||
qrcodeRecordId: undefined,
|
||
actualWarehouseId: undefined,
|
||
team: undefined,
|
||
hasMergeSplit: undefined,
|
||
parentCoilNos: undefined,
|
||
itemId: undefined,
|
||
itemType: undefined,
|
||
status: undefined,
|
||
remark: undefined,
|
||
delFlag: undefined,
|
||
createTime: undefined,
|
||
createBy: undefined,
|
||
updateTime: undefined,
|
||
updateBy: undefined,
|
||
materialType: '原料',
|
||
temperGrade: undefined,
|
||
coatingType: undefined,
|
||
};
|
||
this.resetForm("form");
|
||
},
|
||
remoteSearchWaybill(query) {
|
||
this.waybillLoading = true;
|
||
listDeliveryPlan({ planName: query, pageNum: 1, pageSize: 20, planType: 0 }).then(res => {
|
||
this.waybillOptions = res.rows || [];
|
||
}).finally(() => {
|
||
this.waybillLoading = false;
|
||
});
|
||
},
|
||
/** 搜索按钮操作 */
|
||
handleQuery() {
|
||
this.queryParams.pageNum = 1;
|
||
this.getList();
|
||
},
|
||
/** 重置按钮操作 */
|
||
resetQuery() {
|
||
this.resetForm("queryForm");
|
||
this.queryParams.warehouseId = '';
|
||
this.handleQuery();
|
||
},
|
||
// 多选框选中数据
|
||
handleSelectionChange(selection) {
|
||
this.ids = selection.map(item => item.coilId)
|
||
this.single = selection.length !== 1
|
||
this.multiple = !selection.length
|
||
},
|
||
/** 修改按钮操作 */
|
||
handleUpdate(row) {
|
||
this.isCheck = false;
|
||
this.loading = true;
|
||
this.reset();
|
||
const coilId = row.coilId || this.ids
|
||
getMaterialCoil(coilId).then(response => {
|
||
this.loading = false;
|
||
this.form = response.data;
|
||
|
||
// 设置 materialType(优先级:后端返回 > itemType推断 > 父组件传入)
|
||
if (!this.form.materialType) {
|
||
if (this.form.itemType) {
|
||
// 根据 itemType 推断
|
||
if (this.form.itemType === 'product') {
|
||
this.form.materialType = '成品';
|
||
} else if (this.form.itemType === 'raw_material') {
|
||
this.form.materialType = '原料';
|
||
}
|
||
} else if (this.querys.materialType) {
|
||
// 使用父组件传入的默认值
|
||
this.form.materialType = this.querys.materialType;
|
||
// 同时设置对应的 itemType
|
||
if (this.querys.materialType === '成品') {
|
||
this.form.itemType = 'product';
|
||
} else if (this.querys.materialType === '原料') {
|
||
this.form.itemType = 'raw_material';
|
||
}
|
||
}
|
||
}
|
||
|
||
this.open = true;
|
||
this.title = "修改钢卷物料";
|
||
});
|
||
},
|
||
handleExportCoil(row) {
|
||
exportCoil(row.coilId).then(response => {
|
||
this.$modal.msgSuccess("发货成功");
|
||
// 2. 插入一条已完成的待操作记录
|
||
addPendingAction({
|
||
coilId: row.coilId,
|
||
currentCoilNo: row.currentCoilNo,
|
||
actionType: 402, // 402=发货
|
||
actionStatus: 2, // 直接标记为完成状态
|
||
scanTime: new Date(),
|
||
// scanDevice: ,
|
||
priority: 0, // 0=普通
|
||
sourceType: 'scan',
|
||
warehouseId: row.warehouseId,
|
||
processTime: new Date(),
|
||
completeTime: new Date()
|
||
});
|
||
this.getList();
|
||
}).catch(error => {
|
||
this.$modal.msgError("发货失败");
|
||
});
|
||
},
|
||
async handleNewExport(row) {
|
||
this.loading = true
|
||
let coilIds = ''
|
||
const query = {
|
||
...this.queryParams,
|
||
selectType: 'product',
|
||
pageSize: 9999,
|
||
pageNum: 1,
|
||
}
|
||
if (this.showWaybill) {
|
||
const res = await listBoundCoil(query)
|
||
coilIds = res.rows.map(item => item.coilId).join(',')
|
||
this.loading = false
|
||
this.download('/wms/materialCoil/exportDelivery', {
|
||
coilIds,
|
||
}, 'coil.xlsx')
|
||
} else {
|
||
const { rows: coils } = await listMaterialCoil(query)
|
||
coilIds = coils.map(item => item.coilId).join(',')
|
||
this.loading = false
|
||
this.download('wms/materialCoil/exportAll', {
|
||
coilIds,
|
||
}, 'coil.xlsx')
|
||
}
|
||
},
|
||
async handleNewExportProps(row) {
|
||
this.loading = true
|
||
let coilIds = ''
|
||
const query = {
|
||
...this.querys,
|
||
selectType: 'product',
|
||
pageSize: 9999,
|
||
pageNum: 1,
|
||
}
|
||
if (this.showWaybill) {
|
||
const res = await listBoundCoil(query)
|
||
coilIds = res.rows.map(item => item.coilId).join(',')
|
||
this.loading = false
|
||
this.download('/wms/materialCoil/exportDelivery', {
|
||
coilIds,
|
||
}, 'coil.xlsx')
|
||
} else {
|
||
const { rows: coils } = await listMaterialCoil(query)
|
||
coilIds = coils.map(item => item.coilId).join(',')
|
||
this.loading = false
|
||
this.download('wms/materialCoil/exportAll', {
|
||
coilIds,
|
||
}, 'coil.xlsx')
|
||
}
|
||
},
|
||
handleCheck(row) {
|
||
this.isCheck = true;
|
||
this.loading = true;
|
||
this.reset();
|
||
const coilId = row.coilId || this.ids
|
||
getMaterialCoil(coilId).then(response => {
|
||
this.loading = false;
|
||
this.form = response.data;
|
||
|
||
// 设置 materialType(优先级:后端返回 > itemType推断 > 父组件传入)
|
||
if (!this.form.materialType) {
|
||
if (this.form.itemType) {
|
||
// 根据 itemType 推断
|
||
if (this.form.itemType === 'product') {
|
||
this.form.materialType = '成品';
|
||
} else if (this.form.itemType === 'raw_material') {
|
||
this.form.materialType = '原料';
|
||
}
|
||
} else if (this.querys.materialType) {
|
||
// 使用父组件传入的默认值
|
||
this.form.materialType = this.querys.materialType;
|
||
// 同时设置对应的 itemType
|
||
if (this.querys.materialType === '成品') {
|
||
this.form.itemType = 'product';
|
||
} else if (this.querys.materialType === '原料') {
|
||
this.form.itemType = 'raw_material';
|
||
}
|
||
}
|
||
}
|
||
|
||
this.open = true;
|
||
this.title = "修改钢卷物料";
|
||
});
|
||
},
|
||
handleLog(row) {
|
||
this.logOpen = true;
|
||
this.currentCoilId = row.coilId;
|
||
},
|
||
transferCoil() { },
|
||
/** 提交按钮 */
|
||
submitForm() {
|
||
this.$refs["form"].validate(valid => {
|
||
if (valid) {
|
||
this.buttonLoading = true;
|
||
if (this.form.coilId != null) {
|
||
const { status, exclusiveStatus, dataType, ...payload } = {
|
||
...this.form,
|
||
}
|
||
updateMaterialCoilSimple(payload).then(_ => {
|
||
this.$modal.msgSuccess("修改成功");
|
||
this.open = false;
|
||
this.getList();
|
||
}).finally(() => {
|
||
this.buttonLoading = false;
|
||
});
|
||
} else {
|
||
addMaterialCoil(this.form).then(response => {
|
||
this.$modal.msgSuccess("新增成功");
|
||
this.open = false;
|
||
this.getList();
|
||
}).finally(() => {
|
||
this.buttonLoading = false;
|
||
});
|
||
}
|
||
}
|
||
});
|
||
},
|
||
handleCancelExport(row) {
|
||
// 将相关的action改为已取消,然后将钢卷的已发货状态撤回
|
||
this.$modal.confirm('是否确认撤回钢卷编号为"' + row.currentCoilNo + '"的发货操作?').then(() => {
|
||
this.buttonLoading = true;
|
||
cancelExportCoil(row.coilId).then(response => {
|
||
this.$modal.msgSuccess("撤回发货成功");
|
||
this.getList();
|
||
}).catch(error => {
|
||
this.$modal.msgError("撤回发货失败");
|
||
}).finally(() => {
|
||
this.buttonLoading = false;
|
||
});
|
||
}).catch(() => {
|
||
});
|
||
},
|
||
handleReturnCoil(row) {
|
||
this.$modal.confirm('是否确认退货钢卷编号为"' + row.currentCoilNo + '"的退货操作?').then(() => {
|
||
this.buttonLoading = true;
|
||
returnCoil(row.coilId).then(response => {
|
||
this.$modal.msgSuccess("退货成功");
|
||
this.getList();
|
||
}).catch(error => {
|
||
this.$modal.msgError("退货失败");
|
||
}).finally(() => {
|
||
this.buttonLoading = false;
|
||
});
|
||
})
|
||
},
|
||
handleExportTimeChange(row) {
|
||
if (row.exportTime) {
|
||
row.exportTime = row.exportTime.replace('T', ' ');
|
||
}
|
||
this.buttonLoading = true;
|
||
updateMaterialCoilSimple(row).then(_ => {
|
||
this.$modal.msgSuccess("发货时间修改成功");
|
||
this.getList();
|
||
}).finally(() => {
|
||
this.buttonLoading = false;
|
||
});
|
||
},
|
||
handleExportByNameChange(row) {
|
||
this.buttonLoading = true;
|
||
updateMaterialCoilSimple(row).then(_ => {
|
||
this.$modal.msgSuccess("发货人修改成功");
|
||
this.getList();
|
||
}).finally(() => {
|
||
this.buttonLoading = false;
|
||
});
|
||
},
|
||
/** 改判按钮操作 */
|
||
handleJudge(row) {
|
||
// 填充改判表单数据
|
||
this.judgeForm = {
|
||
...row,
|
||
oldQuality: row.qualityStatus,
|
||
notifyReLabel: true
|
||
};
|
||
this.judgeDialogVisible = true;
|
||
},
|
||
/** 提交改判表单 */
|
||
submitJudgeForm() {
|
||
this.buttonLoading = true;
|
||
const submitData = {
|
||
...this.judgeForm,
|
||
// 如果通知重贴标签,则设置 transferType 为技术部改判
|
||
transferType: this.judgeForm.notifyReLabel ? '技术部改判' : null
|
||
};
|
||
updateMaterialCoilSimple(submitData).then(res => {
|
||
this.buttonLoading = false;
|
||
this.$message({
|
||
message: '改判成功',
|
||
type: 'success'
|
||
});
|
||
this.judgeDialogVisible = false;
|
||
// 记录改判前和改判后的钢卷质量状态
|
||
addCoilQualityRejudge({
|
||
coilId: this.judgeForm.coilId,
|
||
beforeQuality: this.judgeForm.oldQuality,
|
||
afterQuality: this.judgeForm.qualityStatus,
|
||
rejudgeReason: this.judgeForm.rejudgeReason,
|
||
})
|
||
this.getList();
|
||
}).catch(err => {
|
||
this.buttonLoading = false;
|
||
this.$message({
|
||
message: '改判失败',
|
||
type: 'error'
|
||
});
|
||
});
|
||
},
|
||
/** 删除按钮操作 */
|
||
handleDelete(row) {
|
||
const coilIds = row.coilId || this.ids;
|
||
this.$modal.confirm('是否确认删除钢卷物料编号为"' + coilIds + '"的数据项,会同时清理刚钢卷相关的待操作记录且无法恢复!!!是否继续删除?').then(() => {
|
||
this.loading = true;
|
||
return delMaterialCoil(coilIds);
|
||
}).then(() => {
|
||
this.loading = false;
|
||
this.getList();
|
||
this.$modal.msgSuccess("删除成功");
|
||
}).catch(() => {
|
||
}).finally(() => {
|
||
this.loading = false;
|
||
});
|
||
},
|
||
handleExportAll() {
|
||
const { orderBy, ...query } = this.queryParams;
|
||
query.selectType = query.itemType;
|
||
this.download('wms/materialCoil/export', query, `materialCoil_${new Date().getTime()}.xlsx`)
|
||
},
|
||
handleExportAllProps() {
|
||
const query = this.querys;
|
||
this.download('wms/materialCoil/export', query, `materialCoil_${new Date().getTime()}.xlsx`)
|
||
},
|
||
/** 批量打印标签按钮 */
|
||
handleBatchPrintLabel() {
|
||
if (!this.ids || this.ids.length === 0) {
|
||
this.$message.warning('请先勾选要打印标签的钢卷');
|
||
return;
|
||
}
|
||
|
||
// 取出选中行数据,并补齐标签渲染需要的字段
|
||
const selectedData = this.materialCoilList
|
||
.filter(item => this.ids.includes(item.coilId))
|
||
.map(row => {
|
||
const itemName = row.itemName || '';
|
||
|
||
return {
|
||
...row,
|
||
itemName,
|
||
// OuterTagPreview.vue 里字段名使用了 specification/material(而列表里是 itemSpecification/itemMaterial)
|
||
specification: row.itemSpecification || row.specification || '',
|
||
material: row.itemMaterial || row.material || '',
|
||
updateTime: row.updateTime?.split(' ')[0] || row.updateTime || '',
|
||
}
|
||
});
|
||
|
||
this.batchPrint.list = selectedData;
|
||
this.batchPrint.visible = true;
|
||
},
|
||
|
||
/** 批量导出标签PDF:每个标签一页(180mm × 100mm) */
|
||
async handleBatchExportLabelPdf() {
|
||
if (!this.batchPrint.list || this.batchPrint.list.length === 0) {
|
||
this.$message.warning('没有可导出的数据');
|
||
return;
|
||
}
|
||
|
||
const container = this.$refs.batchPdfContainer;
|
||
if (!container) {
|
||
this.$message.error('PDF渲染容器未初始化');
|
||
return;
|
||
}
|
||
|
||
try {
|
||
this.batchPrint.loading = true;
|
||
|
||
await this.$nextTick();
|
||
await new Promise(resolve => setTimeout(resolve, 100));
|
||
|
||
const mmToPt = 72 / 25.4;
|
||
// 纸张尺寸
|
||
const paperWidthMm = 180;
|
||
const paperHeightMm = 100;
|
||
// 边距:左右 4mm,上下对称 2mm,确保垂直居中
|
||
const marginXmm = 4;
|
||
const marginYmm = 0.5; // 上下对称边距(不裁切前提下尽量贴边)
|
||
|
||
const pageWidthPt = paperWidthMm * mmToPt;
|
||
const pageHeightPt = paperHeightMm * mmToPt;
|
||
const marginXPt = marginXmm * mmToPt;
|
||
const marginYPt = marginYmm * mmToPt;
|
||
|
||
const contentWidthPt = pageWidthPt - marginXPt * 2;
|
||
const contentHeightPt = pageHeightPt - marginYPt * 2;
|
||
|
||
const pdfDoc = await PDFDocument.create();
|
||
|
||
// 关键:只截取标签本身(.label-container),不要把外层容器/按钮高度算进去
|
||
const pageEls = container.querySelectorAll('.batch-pdf-page');
|
||
|
||
for (let i = 0; i < pageEls.length; i++) {
|
||
const el = pageEls[i];
|
||
|
||
// 在每一页内部优先查找标签根节点
|
||
const labelEl =
|
||
el.querySelector('.label-container') ||
|
||
el.querySelector('.material-label-container') ||
|
||
el; // 兜底:找不到时退回整页
|
||
|
||
// 强制用标签的实际尺寸作为截图基准,避免被外层布局影响
|
||
const canvas = await html2canvas(labelEl, {
|
||
backgroundColor: '#ffffff',
|
||
scale: 3,
|
||
useCORS: true,
|
||
// 让 html2canvas 为频繁读回优化 Canvas(浏览器会提示 willReadFrequently)
|
||
willReadFrequently: true,
|
||
// 确保按元素尺寸截图
|
||
width: labelEl.offsetWidth,
|
||
height: labelEl.offsetHeight,
|
||
windowWidth: labelEl.scrollWidth,
|
||
windowHeight: labelEl.scrollHeight,
|
||
});
|
||
|
||
const imgDataUrl = canvas.toDataURL('image/png');
|
||
const pngImage = await pdfDoc.embedPng(imgDataUrl);
|
||
|
||
const page = pdfDoc.addPage([pageWidthPt, pageHeightPt]);
|
||
|
||
// 图片铺满页面(保持比例,居中)
|
||
const imgW = pngImage.width;
|
||
const imgH = pngImage.height;
|
||
// 标准适配:确保完整显示且不变形(在内容区域内等比缩放)
|
||
const scale = Math.min(contentWidthPt / imgW, contentHeightPt / imgH);
|
||
const drawW = imgW * scale;
|
||
const drawH = imgH * scale;
|
||
|
||
// 内容区域内居中 + 外层边距(上下对称)
|
||
const x = marginXPt + (contentWidthPt - drawW) / 2;
|
||
const y = marginYPt + (contentHeightPt - drawH) / 2;
|
||
|
||
page.drawImage(pngImage, { x, y, width: drawW, height: drawH });
|
||
}
|
||
|
||
const pdfBytes = await pdfDoc.save();
|
||
const blob = new Blob([pdfBytes], { type: 'application/pdf' });
|
||
const url = URL.createObjectURL(blob);
|
||
|
||
// 尽量避免被浏览器拦截弹窗:优先在当前tab打开;如仍被策略限制,可改为下载
|
||
const win = window.open(url, '_blank');
|
||
if (!win) {
|
||
// fallback:触发下载
|
||
const a = document.createElement('a');
|
||
a.href = url;
|
||
a.download = `钢卷标签_${new Date().getTime()}.pdf`;
|
||
document.body.appendChild(a);
|
||
a.click();
|
||
document.body.removeChild(a);
|
||
}
|
||
} catch (e) {
|
||
console.error(e);
|
||
this.$message.error('生成PDF失败,请重试');
|
||
} finally {
|
||
this.batchPrint.loading = false;
|
||
}
|
||
},
|
||
/** 导出选中数据操作 */
|
||
handleExport() {
|
||
// 1. 判断是否有选中数据
|
||
if (this.ids.length === 0) {
|
||
this.$message.warning('请先选中要导出的数据');
|
||
return;
|
||
}
|
||
|
||
// 2. 筛选选中的数据(通过ids匹配表格数据)
|
||
const selectedData = this.materialCoilList.filter(item =>
|
||
this.ids.includes(item.coilId) // 用选中的coilId匹配表格数据
|
||
);
|
||
|
||
// 3. 处理导出数据格式(和之前一致,转换枚举值)
|
||
const exportData = selectedData.map(item => {
|
||
return {
|
||
'入场钢卷号': item.enterCoilNo || '',
|
||
'当前钢卷号': item.currentCoilNo || '',
|
||
'厂家原料卷号': item.supplierCoilNo || '',
|
||
'物料类型': item.itemType === 'product' ? '成品' : '原料',
|
||
'仓区': item.warehouseName || '',
|
||
'实际库区': item.actualWarehouseName || '',
|
||
'物品': findItemWithBom(item.itemType, item.itemId)?.itemName || '',
|
||
'数据类型': item.dataType === 0 ? '历史数据' : '当前数据',
|
||
'班组': item.team || '',
|
||
'毛重': item.grossWeight || '',
|
||
'净重': item.netWeight || '',
|
||
'备注': item.remark || ''
|
||
};
|
||
});
|
||
|
||
// 4. 生成Excel并下载(复用之前的逻辑)
|
||
const worksheet = XLSX.utils.json_to_sheet(exportData);
|
||
const workbook = XLSX.utils.book_new();
|
||
XLSX.utils.book_append_sheet(workbook, worksheet, '选中钢卷物料');
|
||
|
||
const excelBuffer = XLSX.write(workbook, { bookType: 'xlsx', type: 'array' });
|
||
this.saveExcelFile(excelBuffer, '选中钢卷物料数据');
|
||
},
|
||
|
||
/** 保存Excel文件到本地 */
|
||
saveExcelFile(buffer, fileName) {
|
||
const blob = new Blob([buffer], {
|
||
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8'
|
||
});
|
||
const url = URL.createObjectURL(blob);
|
||
const a = document.createElement('a');
|
||
a.href = url;
|
||
a.download = `${fileName}_${new Date().getTime()}.xlsx`; // 文件名带时间戳
|
||
document.body.appendChild(a);
|
||
a.click(); // 触发下载
|
||
document.body.removeChild(a); // 清理DOM
|
||
URL.revokeObjectURL(url); // 释放URL对象
|
||
}
|
||
}
|
||
};
|
||
</script>
|
||
|
||
<style scoped>
|
||
/* 批量导出PDF:渲染容器屏幕隐藏,但保留真实布局尺寸给 html2canvas 截图 */
|
||
.batch-pdf-root {
|
||
position: fixed;
|
||
left: -100000px;
|
||
top: 0;
|
||
width: 180mm;
|
||
background: #fff;
|
||
}
|
||
|
||
.batch-pdf-page {
|
||
width: 180mm;
|
||
height: 100mm;
|
||
box-sizing: border-box;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.el-table .el-button+.el-button {
|
||
margin-left: 0;
|
||
}
|
||
|
||
::v-deep .el-table {
|
||
margin-top: 0;
|
||
}
|
||
</style>
|