Files
xgy-oa/klp-ui/src/views/wms/move/correct.vue
砂糖 aacf433462 feat: 修改打包状态为原料材质并优化异常管理功能
修改所有打包状态字段为原料材质,统一业务术语
重构异常管理功能,新增异常记录列表和删除功能
优化分条钢卷面板显示更多物料信息
将切边要求和包装要求改为下拉选择框
2026-03-30 13:13:46 +08:00

1359 lines
46 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

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

<template>
<div class="app-container acid-do-container">
<el-row :gutter="20">
<!-- 左侧物料列表 -->
<el-col :span="24">
<div class="section-card material-section">
<div class="section-header">
<h3 class="section-title">
调拨钢卷
<span class="section-desc">绿色边框表示当前钢卷灰色边框表示历史钢卷, 蓝色边框表示已发货钢卷</span>
</h3>
<el-button size="mini" icon="el-icon-refresh" @click="getMaterialCoil">刷新</el-button>
</div>
<!-- 搜索栏 -->
<el-form :model="materialQueryParams" ref="materialQueryForm" size="small" :inline="true" class="query-form">
<el-form-item label="钢卷类型" prop="dataType">
<el-select v-model="coilType" placeholder="请选择钢卷类型">
<el-option label="全部" value="all" />
<el-option label="当前钢卷" value="now" />
<el-option label="历史钢卷" value="history" />
<el-option label="已发货钢卷" value="trans" />
<el-option label="未入库钢卷" value="unIn" />
</el-select>
</el-form-item>
<el-form-item label="入场钢卷号" prop="enterCoilNo">
<el-input v-model="materialQueryParams.enterCoilNo" placeholder="请输入入场钢卷号" clearable
@keyup.enter.native="handleMaterialQuery" style="width: 150px;" />
</el-form-item>
<el-form-item label="当前钢卷号" prop="currentCoilNo">
<el-input v-model="materialQueryParams.currentCoilNo" placeholder="请输入当前钢卷号" clearable
@keyup.enter.native="handleMaterialQuery" style="width: 150px;" />
</el-form-item>
<el-form-item label="逻辑库区" prop="warehouseId">
<warehouse-select v-model="materialQueryParams.warehouseId" placeholder="请选择逻辑库区" clearable
@keyup.enter.native="handleMaterialQuery" style="width: 150px;" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleMaterialQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetMaterialQuery">重置</el-button>
<el-button type="success" plain icon="el-icon-plus" size="mini" @click="handleAdd">新增</el-button>
</el-form-item>
</el-form>
<!-- 物料卡片列表 -->
<div v-loading="materialLoading" class="card-grid-container">
<div v-if="materialCoilList.length === 0" class="empty-state">
<i class="el-icon-box"></i>
<p>暂无待领物料</p>
</div>
<div v-for="(item, index) in materialCoilList" :key="item.coilId || index" class="material-card"
:style="getBorderStyle(item)">
<div class="card-header">
<div class="header-left">
<current-coil-no :current-coil-no="item.currentCoilNo"></current-coil-no>
<el-tag type="info" size="small" class="coil-no-tag" :style="getBorderStyle(item)">{{
getTypeLabel(item) }}</el-tag>
<span class="material-type">{{ item.materialType || '原料' }}</span>
<el-popover placement="top" width="280" trigger="hover" popper-class="material-params-popover">
<div class="material-params-content">
<div class="params-title">
{{ item.itemName || '—' }}
</div>
<div class="params-list">
<div class="param-item">
<div class="param-row" v-if="item.specification">
<span class="param-label">规格</span>
<span class="param-value">{{ item.specification }}</span>
</div>
<div class="param-row" v-if="item.material">
<span class="param-label">材质</span>
<span class="param-value">{{ item.material }}</span>
</div>
<div class="param-row" v-if="item.surfaceTreatmentDesc">
<span class="param-label">表面处理</span>
<span class="param-value">{{ item.surfaceTreatmentDesc }}</span>
</div>
<div class="param-row" v-if="item.zincLayer">
<span class="param-label">镀层质量</span>
<span class="param-value">{{ item.zincLayer }}</span>
</div>
<div class="param-row" v-if="item.manufacturer">
<span class="param-label">厂家</span>
<span class="param-value">{{ item.manufacturer }}</span>
</div>
</div>
<div class="param-divider"></div>
<div class="param-item">
<div class="param-row" v-if="item.qualityStatus">
<span class="param-label">质量状态</span>
<span class="param-value">{{ item.qualityStatus }}</span>
</div>
<div class="param-row" v-if="item.trimmingRequirement">
<span class="param-label">切边要求</span>
<span class="param-value">{{ item.trimmingRequirement }}</span>
</div>
<div class="param-row" v-if="item.packingStatus">
<span class="param-label">原料材质</span>
<span class="param-value">{{ item.packingStatus }}</span>
</div>
<div class="param-row" v-if="item.packagingRequirement">
<span class="param-label">包装要求</span>
<span class="param-value">{{ item.packagingRequirement }}</span>
</div>
<div class="param-row" v-if="item.grossWeight">
<span class="param-label">毛重</span>
<span class="param-value">{{ item.grossWeight }}t</span>
</div>
<div class="param-row" v-if="item.netWeight">
<span class="param-label">净重</span>
<span class="param-value">{{ item.netWeight }}t</span>
</div>
<div class="param-row" v-if="item.length">
<span class="param-label">长度</span>
<span class="param-value">{{ item.length }}</span>
</div>
<div class="param-row" v-if="item.actualLength">
<span class="param-label">实测长度</span>
<span class="param-value">{{ item.actualLength }}</span>
</div>
<div class="param-row" v-if="item.actualThickness">
<span class="param-label">实测厚度</span>
<span class="param-value">{{ item.actualThickness }}</span>
</div>
<div class="param-row" v-if="item.actualWidth">
<span class="param-label">实测宽度</span>
<span class="param-value">{{ item.actualWidth }}</span>
</div>
<div class="param-row" v-if="item.temperGrade">
<span class="param-label">调制度</span>
<span class="param-value">{{ item.temperGrade }}</span>
</div>
<div class="param-row" v-if="item.coatingType">
<span class="param-label">镀层种类</span>
<span class="param-value">{{ item.coatingType }}</span>
</div>
<div class="param-row" v-if="item.team">
<span class="param-label">班组</span>
<span class="param-value">{{ item.team }}</span>
</div>
<div class="param-row" v-if="item.updateTime">
<span class="param-label">更新时间</span>
<span class="param-value">{{ parseTime(item.updateTime, '{y}-{m}-{d} {h}:{i}') }}</span>
</div>
<div class="param-row" v-if="item.updateBy">
<span class="param-label">更新人</span>
<span class="param-value">{{ item.updateBy }}</span>
</div>
<div class="param-row" v-if="item.remark">
<span class="param-label">备注</span>
<span class="param-value">{{ item.remark }}</span>
</div>
</div>
</div>
</div>
<i slot="reference" class="el-icon-setting param-icon"></i>
</el-popover>
<i class="el-icon-view param-icon" @click="handlePreviewLabel(item)" title="查看标签"></i>
<i class="el-icon-time param-icon" @click="handleTrace(item)" title="追溯"></i>
</div>
</div>
<div class="card-body" style="position: relative;">
<div class="info-list">
<div class="info-item">
<span class="info-label">入场</span>
<span class="info-value" :title="item.enterCoilNo">{{ item.enterCoilNo || '—' }}</span>
</div>
<div class="info-item">
<span class="info-label">厂家</span>
<span class="info-value" :title="item.supplierCoilNo">{{ item.supplierCoilNo || '—' }}</span>
</div>
<div class="info-item">
<span class="info-label">库位</span>
<span class="info-value" :title="item.warehouseName">{{ item.warehouseName || '—' }}</span>
</div>
<div class="info-item">
<span class="info-label">库区</span>
<span class="info-value" :title="item.actualWarehouseName">{{ item.actualWarehouseName || '—'
}}</span>
</div>
<div class="info-item">
<span class="info-label">重量</span>
<span class="info-value">{{ item.netWeight || '—' }}t</span>
</div>
</div>
<el-button v-if="item.dataType == 1 && item.status == 0"
style="position: absolute; bottom: 10px; right: 10px;" type="success" icon="el-icon-refresh"
size="mini" @click="handleRestoreMaterial(item)" :loading="item.cancelling"
class="action-btn">回滚</el-button>
<el-button v-if="item.dataType == 10 && item.status == 0"
style="position: absolute; bottom: 10px; right: 10px;" type="success" icon="el-icon-refresh"
size="mini" @click="handleForceInMaterial(item)" :loading="item.cancelling"
class="action-btn">强制入库</el-button>
</div>
<div class="card-footer">
<el-button type="primary" icon="el-icon-check" size="mini" @click="handleCorrectMaterial(item)"
:loading="item.picking" class="action-btn">调拨</el-button>
<el-button type="danger" icon="el-icon-delete" size="mini" @click="hanleDeleteMaterial(item)"
:loading="item.picking" class="action-btn">删除</el-button>
<el-button type="warning" icon="el-icon-alarm-clock" :plain="item.abnormalCount == 0" size="mini"
@click="handleAddAbnormal(item)" :loading="item.cancelling" class="action-btn">
异常
<span v-if="item.abnormalCount > 0">({{ item.abnormalCount }})</span>
</el-button>
</div>
</div>
</div>
<!-- 分页 -->
<pagination v-show="materialTotal > 0" :total="materialTotal" :page.sync="materialQueryParams.pageNum"
:limit.sync="materialQueryParams.pageSize" @pagination="getMaterialCoil" />
</div>
</el-col>
</el-row>
<el-dialog title="新增异常" :visible.sync="exceptionDialogVisible" width="600px">
<el-form ref="exceptionForm" :model="exceptionForm" label-width="80px">
<el-form-item label="位置" prop="position">
<el-radio-group v-model="exceptionForm.position">
<el-radio-button v-for="dict in dict.type.coil_abnormal_position" :key="dict.value" :label="dict.value">{{
dict.label }}</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="长度坐标" prop="lengthCoord">
<el-input v-model="exceptionForm.lengthCoord" placeholder="请输入长度坐标" />
</el-form-item>
<el-form-item label="缺陷代码" prop="defectCode">
<el-radio-group v-model="exceptionForm.defectCode">
<el-radio-button v-for="dict in dict.type.coil_abnormal_code" :key="dict.value" :label="dict.value">{{
dict.label }}</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="程度" prop="degree">
<el-radio-group v-model="exceptionForm.degree">
<el-radio-button v-for="dict in dict.type.coil_abnormal_degree" :key="dict.value" :label="dict.value">{{
dict.label }}</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input type="textarea" v-model="exceptionForm.remark" placeholder="请输入备注" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="info" @click="handleAbnormal">查看异常</el-button>
<el-button :loading="buttonLoading" type="primary" @click="confirmException"> </el-button>
<el-button @click="cancelException"> </el-button>
</div>
</el-dialog>
<!-- 标签预览弹窗 -->
<el-dialog title="标签预览" :visible.sync="labelRender.visible" append-to-body>
<label-render :content="labelRender.data" :labelType="labelRender.type" />
</el-dialog>
<el-dialog :title="title" :visible.sync="correctVisible" width="600px">
<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="请输入当前钢卷号" disabled />
</el-form-item>
<el-form-item label="厂家原料卷号" prop="supplierCoilNo">
<el-input v-model="form.supplierCoilNo" placeholder="请输入厂家原料卷号" disabled/>
</el-form-item>
<!-- <el-form-item label="实际库区" prop="actualWarehouseId">
<actual-warehouse-select v-model="form.actualWarehouseId" placeholder="请选择实际库区" style="width: 100%;"
clearable />
</el-form-item> -->
<el-form-item label="班组" prop="team">
<el-select v-model="form.team" placeholder="请选择班组" style="width: 100%" disabled>
<el-option key="甲" label="甲" value="甲" />
<el-option key="乙" label="乙" value="乙" />
</el-select>
</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="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" v-loading="itemIdLoading">
<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" disabled>
<el-select disabled 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" disabled>
<el-select disabled 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" disabled>
<el-input disabled v-model="form.packingStatus" placeholder="请输入原料材质">
</el-input>
</el-form-item>
<el-form-item label="包装要求" prop="packagingRequirement" disabled>
<el-select disabled v-model="form.packagingRequirement" placeholder="请选择包装要求" style="width: 100%">
<el-option label="裸包" value="裸包" />
<el-option label="普包" value="普包" />
<el-option label="简包" value="简包" />
</el-select>
</el-form-item>
<el-form-item label="毛重" prop="grossWeight" disabled>
<el-input disabled v-model="form.grossWeight" placeholder="请输入毛重" />
</el-form-item>
<el-form-item label="净重" prop="netWeight" disabled>
<el-input disabled v-model="form.netWeight" placeholder="请输入净重" />
</el-form-item>
<el-form-item label="长度" prop="length" disabled>
<el-input disabled v-model="form.length" placeholder="请输入长度" />
</el-form-item>
<el-form-item label="实测长度(m)" prop="actualLength" disabled>
<el-input-number disabled :controls="false" v-model="form.actualLength" placeholder="请输入实测长度" type="number"
:step="0.01" />
</el-form-item>
<el-form-item label="实测宽度(m)" prop="actualWidth" disabled>
<el-input-number disabled :controls="false" v-model="form.actualWidth" placeholder="请输入实测宽度" type="number"
:step="0.01" />
</el-form-item>
<el-form-item label="调制度" prop="temperGrade" disabled>
<el-input disabled v-model="form.temperGrade" placeholder="请输入调制度" />
</el-form-item>
<el-form-item label="镀层种类" prop="coatingType" disabled>
<MemoInput disabled storageKey="coatingType" v-model="form.coatingType" placeholder="请输入镀层种类" />
</el-form-item>
<el-form-item label="备注" prop="remark" disabled>
<el-input disabled v-model="form.remark" placeholder="请输入备注" />
</el-form-item>
<el-form-item label="创建时间" prop="createTime" v-if="form.coilId" disabled>
<el-date-picker disabled v-model="form.createTime" type="datetime" value-format="yyyy-MM-dd HH:mm:ss"
placeholder="请选择创建时间" style="width: 100%;" />
</el-form-item>
<el-form-item label="创建人" prop="createBy" v-if="form.coilId" disabled>
<el-select disabled v-model="form.createBy" placeholder="请选择创建人" style="width: 100%;" clearable filterable>
<el-option v-for="item in userList" :key="item.userName" :label="item.nickName" :value="item.userName" />
</el-select>
<!-- <el-input v-model="form.createBy" 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>
</div>
</template>
<script>
import { listMaterialCoil, getMaterialCoilTrace, updateMaterialCoilSimple, checkCoilNo, delMaterialCoil, restoreMaterialCoil, addMaterialCoil } from '@/api/wms/coil'
import { listUser } from '@/api/system/user'
import { listPendingAction, startProcess, cancelAction, delPendingAction } from '@/api/wms/pendingAction'
import { parseTime } from '@/utils/klp'
import ProductInfo from '@/components/KLPService/Renderer/ProductInfo'
import RawMaterialInfo from '@/components/KLPService/Renderer/RawMaterialInfo'
import { addCoilAbnormal } from '@/api/wms/coilAbnormal'
import LabelRender from "@/views/wms/coil/panels/LabelRender/index.vue"
import WarehouseSelect from "@/components/KLPService/WarehouseSelect";
import ActualWarehouseSelect from "@/components/KLPService/ActualWarehouseSelect";
import ProductSelect from "@/components/KLPService/ProductSelect";
import RawMaterialSelect from "@/components/KLPService/RawMaterialSelect";
import CoilTraceResult from "@/views/wms/coil/panels/CoilTraceResult.vue";
import { getCoilTagPrintType } from '@/views/wms/coil/js/coilPrint'
import { matchOrCreateMaterial, addTransferOrderItem } from '@/api/wms/transferOrderItem'
export default {
name: 'DoPage',
dicts: ['action_type', 'coil_abnormal_code', 'coil_abnormal_position', 'coil_abnormal_degree', 'coil_quality_status'],
props: {
label: {
type: String,
default: () => '酸连轧工序'
},
tabs: {
type: Array,
default: () => []
}
},
components: {
ProductInfo,
RawMaterialInfo,
LabelRender,
WarehouseSelect,
ActualWarehouseSelect,
ProductSelect,
RawMaterialSelect,
CoilTraceResult,
},
data() {
return {
traceOpen: false,
traceLoading: false,
traceResult: null,
coilType: 'now',
title: '钢卷调拨',
// 物料列表相关
materialLoading: false,
materialCoilList: [],
materialTotal: 0,
currentTab: '',
materialQueryParams: {
pageNum: 1,
pageSize: 20,
enterCoilNo: null,
currentCoilNo: null,
warehouseId: null,
},
labelRender: {
visible: false,
data: {},
type: '2'
},
// 待操作列表相关
actionLoading: false,
pendingActionList: [],
actionTotal: 0,
actionQueryParams: {
pageNum: 1,
pageSize: 20,
currentCoilNo: null,
actionType: null, // 将在created中设置为酸连轧工序的actionType
actionStatus: null
},
exceptionDialogVisible: false,
exceptionForm: {
coilId: null,
position: null,
lengthCoord: null,
defectCode: null,
degree: null,
remark: null
},
// 表单校验
rules: {
planId: [
{ required: true, message: "请选择收货计划", trigger: "change" }
],
enterCoilNo: [
{ required: true, message: "入场钢卷号不能为空", 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" },
],
materialType: [
{ required: true, message: "材料类型不能为空", trigger: "change" }
],
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" }
],
},
form: {},
correctVisible: false,
buttonLoading: false,
userList: [],
itemIdLoading: false,
originCoil: {}
}
},
computed: {
// 获取酸连轧工序的actionType值
acidRollingActionType() {
if (!this.dict.type.action_type) return null
const acidAction = this.dict.type.action_type.find(item => {
const label = item.label || ''
return label.includes(this.label)
})
return acidAction ? parseInt(acidAction.value) : null
},
// 动态显示标签
getItemLabel() {
if (this.form.materialType === '成品') {
return '产品类型';
} else if (this.form.materialType === '原料') {
return '原料类型';
}
return '物品类型';
},
},
watch: {
// 监听字典数据加载当acidRollingActionType有值时自动加载待操作列表
acidRollingActionType(newVal) {
if (newVal && !this.actionQueryParams.actionType) {
this.actionQueryParams.actionType = newVal
// 如果待操作列表为空,则加载数据
if (this.pendingActionList.length === 0) {
this.getPendingAction()
}
}
},
},
created() {
// 加载用户列表
this.getUsers()
},
mounted() {
this.getMaterialCoil()
},
methods: {
parseTime,
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.correctVisible = true;
this.title = "添加钢卷物料";
},
/** 追溯按钮操作 */
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;
});
},
// 表单重置
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,
actualLength: undefined,
actualWidth: undefined,
};
this.resetForm("form");
},
getBorderStyle(row) {
// console.log(row);
// 已发货
if (row.status == 1) {
return { border: '1.5px solid #007bff' }
}
// 历史钢卷
if (row.dataType == 0 || row.dataType == 2) {
return { border: '1.5px solid #6c757d' }
}
// 当前钢卷
if (row.dataType == 1) {
return { border: '1.5px solid #28a745' }
}
// 还未入库的钢卷
if (row.dataType == 10) {
return { border: '1.5px solid #ffc107' }
}
return { border: '1.5px solid #e4e7ed' }
},
getTypeLabel(row) {
if (row.status == 1) {
return '已发货'
}
if (row.dataType == 0 || row.dataType == 2) {
return '历史钢卷'
}
if (row.dataType == 1) {
return '当前钢卷'
}
if (row.dataType == 10) {
return '未入库'
}
return '未知'
},
/** 查询用户列表 */
getUsers() {
listUser({ pageNum: 1, pageSize: 1000 }).then(response => {
this.userList = response.rows || []
})
},
// 处理材料类型变化
handleMaterialTypeChange(value) {
// 清空物品选择
// this.form.itemId = null;
this.itemIdLoading = true;
matchOrCreateMaterial({
itemId: this.form.itemId,
// 这里需要传的是修改前的类型
itemType: value === '成品' ? 'raw_material' : 'product',
}).then(res => {
console.log(res)
if (res.data) {
this.form.itemId = res.data
}
}).finally(() => {
this.itemIdLoading = false;
})
// 根据材料类型设置物品类型
if (value === '成品') {
this.form.itemType = 'product';
} else if (value === '原料') {
this.form.itemType = 'raw_material';
}
},
/** 预览标签 */
handlePreviewLabel(row) {
this.labelRender.visible = true;
const type = getCoilTagPrintType(row);
this.labelRender.type = type;
this.labelRender.data = {
...row,
updateTime: row.updateTime?.split(' ')[0] || '',
};
},
// ========== 物料列表相关方法 ==========
/** 查询物料列表 */
handleRestoreMaterial(row) {
this.$modal.confirm('是否要将改钢卷还原到上次加工的状态(会删除该钢卷并将上一步的历史钢卷还原)').then(_ => {
const loading = this.$loading({
lock: true,
text: '处理中...',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)'
})
restoreMaterialCoil(row.coilId).then(_ => {
this.$modal.msgSuccess("还原成功");
this.getMaterialCoil();
}).finally(() => {
loading.close()
})
})
},
handleForceInMaterial(row) {
this.$modal.confirm('是否要强制入库改钢卷?').then(_ => {
const loading = this.$loading({
lock: true,
text: '处理中...',
spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)'
})
updateMaterialCoilSimple({
...row,
dataType: 1,
}).then(_ => {
this.$modal.msgSuccess("强制入库成功");
this.getMaterialCoil();
}).finally(() => {
loading.close()
})
})
},
getMaterialCoil() {
this.materialLoading = true
const payload = { ...this.materialQueryParams }
if (this.coilType == 'now') {
payload.dataType = 1;
payload.status = 0;
} else if (this.coilType == 'history') {
payload.dataType = 0;
} else if (this.coilType == 'trans') {
payload.status = 1;
} else if (this.coilType == 'unIn') {
payload.dataType = 10;
}
listMaterialCoil(payload).then(response => {
this.materialCoilList = response.rows || []
this.materialTotal = response.total || 0
this.materialLoading = false
}).catch(() => {
this.materialLoading = false
})
},
/** 物料搜索 */
handleMaterialQuery() {
this.materialQueryParams.pageNum = 1
this.getMaterialCoil()
},
/** 重置物料搜索 */
resetMaterialQuery() {
this.resetForm('materialQueryForm')
this.materialQueryParams.enterCoilNo = null
this.materialQueryParams.currentCoilNo = null
this.handleMaterialQuery()
},
// ========== 待操作列表相关方法 ==========
/** 查询待操作列表 */
getPendingAction() {
// 确保只查询酸连轧工序的待操作
if (!this.acidRollingActionType) {
console.warn(`未找到${this.label}操作类型,请检查字典配置`)
this.pendingActionList = []
this.actionTotal = 0
this.actionLoading = false
return
}
this.actionLoading = true
// 强制使用酸连轧工序的 actionType忽略查询参数中的 actionType
const queryParams = {
...this.actionQueryParams,
actionType: this.acidRollingActionType
}
listPendingAction(queryParams).then(response => {
this.pendingActionList = response.rows || []
this.actionTotal = response.total || 0
this.actionLoading = false
}).catch(() => {
this.actionLoading = false
})
},
handleCorrectMaterial(row) {
this.originCoil = { ...row }
this.form = {
...row,
};
this.title = "钢卷调拨";
this.correctVisible = true
},
cancel() {
this.correctVisible = false
},
/** 提交按钮 */
submitForm() {
this.$refs['form'].validate(valid => {
if (!valid) {
this.$message.error('请填写完整信息')
return
}
this.buttonLoading = true;
if (this.form.coilId) {
// 如果更新前和更新后的itemType或者warehouseId发生变化则需要额外创建一条调拨记录
if (this.originCoil.itemType !== this.form.itemType || this.originCoil.warehouseId !== this.form.warehouseId) {
// 调拨记录逻辑
addTransferOrderItem({
coilId: this.form.coilId,
itemIdBefore: this.originCoil.itemId,
itemIdAfter: this.form.itemId,
materialTypeBefore: this.originCoil.itemType == 'product' ? 2 : 1,
materialTypeAfter: this.form.itemType == 'product' ? 2 : 1,
warehouseIdBefore: this.originCoil.warehouseId,
warehouseIdAfter: this.form.warehouseId,
})
}
// 更新
updateMaterialCoilSimple(this.form).then(_ => {
this.$modal.msgSuccess("调拨完成");
this.correctVisible = false;
this.getMaterialCoil();
}).finally(() => {
this.buttonLoading = false;
});
} else {
// 新增
addMaterialCoil(this.form).then(_ => {
this.$modal.msgSuccess("新增成功");
this.correctVisible = false;
this.getMaterialCoil();
}).finally(() => {
this.buttonLoading = false;
});
}
})
},
/** 删除按钮操作 */
hanleDeleteMaterial(row) {
const coilIds = row.coilId;
this.$modal.confirm('是否确认删除钢卷物料编号为"' + coilIds + '"的数据项?').then(() => {
this.loading = true;
return delMaterialCoil(coilIds);
}).then(() => {
this.loading = false;
this.getMaterialCoil();
this.$modal.msgSuccess("删除成功");
}).catch(() => {
}).finally(() => {
this.loading = false;
});
},
/** 处理操作 - 跳转到对应页面 */
handleProcess(row) {
const actionType = parseInt(row.actionType)
// 特殊处理:发货和移库操作不需要跳转
if (actionType === 4 || actionType === 5) {
this.$message.info(actionType === 4 ? '发货操作已在移动端完成' : '移库操作已在移动端完成')
return
}
// 根据操作类型跳转到不同页面
let path = ''
// 分条操作100-199
if (actionType >= 100 && actionType <= 199) {
path = '/wms/split'
}
// 合卷操作200-299
else if (actionType == 200) {
path = '/wms/merge'
}
// 其他操作类型
else {
path = '/wms/typing'
}
if (!path) {
this.$message.error('未知的操作类型: ' + row.actionType)
return
}
// 更新状态为处理中
startProcess(row.actionId).then(response => {
if (response.code !== 200) {
this.$message.error(response.msg || '更新状态失败')
return
}
// 跳转并传递参数
this.$router.push({
path: path,
query: {
coilId: row.coilId,
actionId: row.actionId
}
})
}).catch(error => {
console.error('更新状态失败:', error)
this.$message.error('更新状态失败: ' + (error.message || error))
})
},
/** 取消操作 */
handleCancel(row) {
this.$confirm('是否确认取消该操作?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
return cancelAction(row.actionId)
}).then(() => {
this.$message.success('操作已取消')
this.getPendingAction()
}).catch(() => { })
},
/** 删除待操作 */
handleDeleteAction(row) {
const actionId = row.actionId
this.$confirm('是否确认删除该待操作记录?', '警告', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
return delPendingAction(actionId)
}).then(() => {
this.getPendingAction()
this.$message.success('删除成功')
}).catch(() => { })
},
/** 获取物品名称 */
getItemName(item) {
if (item.itemName) {
return item.itemName
}
return '—'
},
handleAddAbnormal(row) {
this.exceptionForm.coilId = row.coilId
this.exceptionDialogVisible = true
},
confirmException() {
addCoilAbnormal(this.exceptionForm).then(response => {
this.$message.success('异常记录添加成功')
this.cancelException();
// 重置表单
this.getMaterialCoil()
}).catch(error => {
console.error('异常记录添加失败:', error)
this.$message.error('异常记录添加失败: ' + (error.message || error))
})
},
handleAbnormal() {
this.$router.push({
path: '/quality/detail',
query: {
coilId: this.exceptionForm.coilId,
}
})
},
cancelException() {
// 重置表单
this.exceptionForm = {
coilId: null,
position: null,
lengthCoord: null,
defectCode: null,
degree: null,
remark: null
}
this.exceptionDialogVisible = false
},
}
}
</script>
<style scoped lang="scss">
.acid-do-container {
background-color: #f5f7fa;
padding: 20px;
min-height: calc(100vh - 84px);
}
.section-card {
background-color: #ffffff;
border: 1px solid #e4e7ed;
border-radius: 4px;
padding: 16px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
}
.section-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
padding-bottom: 12px;
border-bottom: 2px solid #e4e7ed;
}
.section-title {
margin: 0;
font-size: 16px;
font-weight: 600;
color: #303133;
}
.section-desc {
font-size: 12px;
color: #909399;
}
.material-section {
.section-header {
border-bottom-color: #409eff;
}
.section-title {
color: #409eff;
}
}
.action-section {
.section-header {
border-bottom-color: #67c23a;
}
.section-title {
color: #67c23a;
}
}
.query-form {
margin-bottom: 16px;
padding: 12px;
background-color: #fafafa;
border-radius: 4px;
border: 1px solid #e4e7ed;
}
// 卡片网格容器
.card-grid-container {
display: grid;
grid-template-columns: repeat(5, 1fr);
gap: 8px;
max-height: calc(100vh - 320px);
overflow-y: auto;
padding-right: 4px;
&::-webkit-scrollbar {
width: 6px;
}
&::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 3px;
}
&::-webkit-scrollbar-thumb {
background: #c1c1c1;
border-radius: 3px;
&:hover {
background: #a8a8a8;
}
}
@media (min-width: 1600px) {
grid-template-columns: repeat(4, 1fr);
}
}
// 空状态
.empty-state {
text-align: center;
padding: 60px 20px;
color: #909399;
i {
font-size: 48px;
margin-bottom: 16px;
display: block;
color: #c0c4cc;
}
p {
margin: 0;
font-size: 14px;
}
}
// 物料卡片
.material-card {
background-color: #ffffff;
border: 1px solid #e4e7ed;
border-radius: 3px;
display: flex;
flex-direction: column;
transition: all 0.3s ease;
height: 100%;
&:hover {
border-color: #409eff;
box-shadow: 0 2px 6px rgba(64, 158, 255, 0.12);
}
.card-header {
padding: 6px 8px;
border-bottom: 1px solid #e4e7ed;
background-color: #fafafa;
.header-left {
display: flex;
align-items: center;
gap: 6px;
}
.coil-no-tag {
font-weight: 600;
font-size: 11px;
padding: 2px 6px;
}
.material-type {
font-size: 11px;
color: #606266;
font-weight: 500;
}
.param-icon {
font-size: 13px;
color: #909399;
cursor: pointer;
transition: color 0.3s;
&:hover {
color: #409eff;
}
}
}
.card-body {
padding: 8px;
flex: 1;
.info-list {
.info-item {
display: flex;
align-items: center;
margin-bottom: 4px;
font-size: 11px;
line-height: 1.4;
&:last-child {
margin-bottom: 0;
}
.info-label {
color: #909399;
white-space: nowrap;
margin-right: 4px;
min-width: 40px;
font-size: 11px;
}
.info-value {
color: #303133;
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 11px;
}
}
}
}
.card-footer {
padding: 6px 8px;
border-top: 1px solid #e4e7ed;
background-color: #fafafa;
display: flex;
justify-content: center;
.action-btn {
width: 100%;
padding: 5px 10px;
font-size: 11px;
}
}
}
// 待操作卡片
.action-card {
background-color: #ffffff;
border: 1px solid #e4e7ed;
border-radius: 4px;
display: flex;
flex-direction: column;
transition: all 0.3s ease;
height: 100%;
&:hover {
border-color: #67c23a;
box-shadow: 0 2px 8px rgba(103, 194, 58, 0.15);
}
&.urgent-card {
border-left: 4px solid #f56c6c;
background-color: #fef0f0;
&:hover {
border-color: #f56c6c;
box-shadow: 0 2px 8px rgba(245, 108, 108, 0.2);
}
}
&.important-card {
border-left: 4px solid #e6a23c;
background-color: #fdf6ec;
&:hover {
border-color: #e6a23c;
box-shadow: 0 2px 8px rgba(230, 162, 60, 0.2);
}
}
.card-header {
padding: 10px 12px;
border-bottom: 1px solid #e4e7ed;
background-color: #fafafa;
display: flex;
justify-content: space-between;
align-items: center;
.coil-no-tag {
font-weight: 600;
font-size: 12px;
}
.status-tags {
display: flex;
gap: 4px;
flex-wrap: wrap;
}
}
.card-body {
padding: 12px;
flex: 1;
.info-list {
.info-item {
display: flex;
align-items: center;
margin-bottom: 8px;
font-size: 12px;
&:last-child {
margin-bottom: 0;
}
.info-label {
color: #909399;
white-space: nowrap;
margin-right: 6px;
min-width: 50px;
}
.info-value {
color: #303133;
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.action-type-tag {
font-size: 11px;
}
}
}
}
.card-footer {
padding: 10px 12px;
border-top: 1px solid #e4e7ed;
background-color: #fafafa;
display: flex;
justify-content: center;
gap: 6px;
.action-btn {
flex: 1;
font-size: 12px;
padding: 6px 8px;
}
}
}
// 分页样式
::v-deep .pagination-container {
margin-top: 16px;
padding: 12px;
background-color: #fafafa;
border-radius: 4px;
border: 1px solid #e4e7ed;
}
// 参数弹出框样式
::v-deep .material-params-popover {
.material-params-content {
.params-title {
font-size: 14px;
font-weight: 600;
color: #303133;
margin-bottom: 12px;
padding-bottom: 8px;
border-bottom: 1px solid #e4e7ed;
}
.params-list {
.param-item {
.param-row {
display: flex;
margin-bottom: 6px;
font-size: 12px;
line-height: 1.5;
&:last-child {
margin-bottom: 0;
}
.param-label {
color: #909399;
min-width: 70px;
margin-right: 8px;
}
.param-value {
color: #303133;
flex: 1;
word-break: break-all;
}
}
}
.param-divider {
height: 1px;
background-color: #e4e7ed;
margin: 10px 0;
}
}
}
}
</style>