Files
klp-oa/klp-ui/src/views/wms/coil/do/warehousing.vue
砂糖 a0b283a21e feat(system-menu): 优化菜单样式配置功能
1. 修复收货计划跳转路径错误,将路径从/receive/plan调整为/wip/receive/plan
2. 重构菜单样式编辑区域:将单行输入框改为多行文本编辑器,支持快捷样式预设、格式校验和实时预览
3. 新增菜单样式JSON校验逻辑,支持验证格式合法性和无效CSS属性
2026-07-03 17:15:13 +08:00

1269 lines
43 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">
<el-row :gutter="20">
<el-col :span="8">
<div class="section-card">
<!-- 入库 -->
<div class="section-header">
<h3 class="section-title">新增入库</h3>
</div>
<el-form ref="form" :model="form" :rules="rules" label-width="100px">
<el-row>
<el-col :span="24">
<el-form-item label="收货计划" prop="planId">
<el-select style="width: 100%;" v-model="form.planId" placeholder="请输入计划名称搜索收货计划" filterable remote
:remote-method="remoteMethod">
<el-option v-for="item in planList" :key="item.planId" :label="item.planName"
:value="item.planId" />
</el-select>
<!-- 默认选中今天的收货计划如果今天还没有收货计划提醒创建收货计划 -->
</el-form-item>
<!-- 查找并选择选择收货计划, 使用远程搜索 -->
<el-alert v-if="noPlan" type="warning" title="今天还没有收货计划,点击创建" show-icon
@click.native="$router.push('/wip/receive/plan')"></el-alert>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="入场钢卷号" prop="enterCoilNo">
<el-input v-model="form.enterCoilNo" placeholder="请输入入场钢卷号" :disabled="form.coilId" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="当前钢卷号" prop="currentCoilNo">
<el-input v-model="form.currentCoilNo" placeholder="请输入当前钢卷号" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="厂家原料卷号" prop="supplierCoilNo">
<el-input v-model="form.supplierCoilNo" placeholder="请输入厂家原料卷号" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="所在库位" prop="warehouseId">
<warehouse-select v-model="form.warehouseId" placeholder="请选择仓库/库区/库位" style="width: 100%;"
clearable />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="班组" prop="team">
<el-select v-model="form.team" placeholder="请选择班组" style="width: 100%;" clearable>
<el-option key="甲" label="甲" value="甲" />
<el-option key="乙" label="乙" value="乙" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row v-if="form.materialType === '成品'">
<el-col :span="24">
<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-col>
<el-col :span="24">
<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-col>
<el-col :span="24">
<el-form-item label="原料材质" prop="packingStatus">
<el-input v-model="form.packingStatus" placeholder="请输入原料材质">
</el-input>
</el-form-item>
</el-col>
<el-col :span="24">
<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-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="毛重" prop="grossWeight">
<el-input v-model="form.grossWeight" placeholder="请输入毛重" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="净重" prop="netWeight">
<el-input v-model="form.netWeight" placeholder="请输入净重" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="长度" prop="length">
<el-input v-model="form.length" placeholder="请输入长度" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="调制度" prop="temperGrade">
<el-input v-model="form.temperGrade" placeholder="请输入调制度" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="镀层种类" prop="coatingType">
<MemoInput storageKey="coatingType" v-model="form.coatingType" placeholder="请输入镀层种类" />
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" placeholder="请输入备注" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="材料类型" prop="materialType" v-if="!form.coilId">
<el-select v-model="form.materialType" placeholder="请选择材料类型" @change="handleMaterialTypeChange">
<el-option label="成品" value="成品" />
<el-option label="原料" value="原料" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item :label="getItemLabel" prop="itemId" v-if="!form.coilId">
<product-select v-if="form.itemType == 'product'" @change="handleProductChange" v-model="form.itemId"
clearable />
<raw-material-select v-else-if="form.itemType == 'raw_material'" @change="handleProductChange"
v-model="form.itemId" clearable />
<div v-else>请先选择材料类型</div>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="原料材质" prop="packingStatus" v-if="!form.coilId">
<el-input v-model="form.packingStatus" placeholder="请输入原料材质" />
</el-form-item>
</el-col>
</el-row>
<el-form-item>
<el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</el-form-item>
</el-form>
</div>
</el-col>
<el-col :span="16">
<div class="section-card">
<!-- 入库记录 -->
<div class="section-header">
<h3 class="section-title">入库记录</h3>
<el-button size="mini" icon="el-icon-refresh" @click="getList">刷新</el-button>
</div>
<el-form inline class="query-form">
<el-form-item label="钢卷号" prop="currentCoilNo">
<el-input v-model="queryForm.currentCoilNo" placeholder="请输入钢卷号" />
</el-form-item>
<el-form-item>
<el-checkbox v-model="validateBeforeReceipt" label="在签收前校验">在签收前校验</el-checkbox>
<el-button type="primary" @click="getList" style="margin-left: 10px;">查询</el-button>
</el-form-item>
</el-form>
<!-- 待操作卡片列表 -->
<div v-if="pendingActions.length === 0" v-loading="loading" class="empty-state">
<i class="el-icon-document"></i>
<p>暂无入库记录</p>
</div>
<el-table v-else v-loading="loading" border :data="pendingActions" highlight-current-row>
<el-table-column label="钢卷号" align="center" prop="currentCoilNo" :show-overflow-tooltip="true">
<template slot-scope="scope">
<current-coil-no :current-coil-no="scope.row.currentCoilNo"></current-coil-no>
<!-- <el-tag type="info" size="small">{{ scope.row.currentCoilNo }}</el-tag> -->
</template>
</el-table-column>
<el-table-column label="厂家卷号" align="center" prop="supplierCoilNo" />
<el-table-column label="新增时间" align="center" prop="createTime" width="150" :show-overflow-tooltip="true">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d} {h}:{i}') }}</span>
</template>
</el-table-column>
<el-table-column label="创建人" align="center" prop="createBy" width="100" />
<el-table-column label="操作状态" align="center" prop="actionStatus" width="120">
<template slot-scope="scope">
<el-tag v-if="scope.row.actionStatus === 2" type="success">已收货</el-tag>
<el-tag v-else type="primary">未收货</el-tag>
</template>
</el-table-column>
<el-table-column label="操作">
<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 v-if="scope.row.actionStatus == 0 || scope.row.actionStatus == 1" size="mini" type="text"
icon="el-icon-edit" @click="handleEdit(scope.row)">
编辑
</el-button>
<el-button v-if="scope.row.actionStatus == 0 || scope.row.actionStatus == 1" type="primary"
@click="openReceiptModal(scope.row)" v-loading="buttonLoading">签收</el-button>
<el-button v-if="scope.row.actionStatus == 0 || scope.row.actionStatus == 1" type="danger"
@click="handleReject(scope.row)" v-loading="buttonLoading">拒签</el-button>
<el-button type="warning" v-loading="buttonLoading" @click="handleDelete(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<Pagination v-show="total > 0" :total="total" :page.sync="pagination.pageNum"
:limit.sync="pagination.pageSize" @pagination="getList" />
</div>
</el-col>
</el-row>
<el-dialog title="确认收货" v-loading="loading" :visible.sync="receiptModalVisible" width="30%">
<el-form :model="coilInfo" ref="receiptFormRef" label-width="120px">
<el-form-item label="钢卷号" prop="currentCoilNo">
<el-input v-model="coilInfo.currentCoilNo" disabled placeholder="请输入钢卷号" />
</el-form-item>
<el-form-item label="净重" prop="netWeight">
<el-input v-model="coilInfo.netWeight" disabled placeholder="请输入净重" />
</el-form-item>
<el-form-item label="毛重" prop="grossWeight">
<el-input v-model="coilInfo.grossWeight" disabled placeholder="请输入毛重" />
</el-form-item>
<el-form-item label="实际库区" prop="actualWarehouseId">
<ActualWarehouseSelect v-model="coilInfo.actualWarehouseId" placeholder="请选择实际库区" />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="coilInfo.remark" placeholder="请输入备注" />
</el-form-item>
</el-form>
<template slot="footer" class="dialog-footer">
<el-checkbox v-model="validateBeforeReceipt" label="在签收前校验">在签收前校验</el-checkbox>
<el-button style="margin-left: 10px;" type="primary" @click="confirmReceipt" v-loading="buttonLoading">签收</el-button>
<el-button @click="receiptModalVisible = false">取消</el-button>
</template>
</el-dialog>
<!-- 标签预览弹窗 -->
<el-dialog title="标签预览" :visible.sync="labelRender.visible" append-to-body>
<label-render :content="labelRender.data" :labelType="labelRender.type" v-loading="labelRender.loading" />
</el-dialog>
<label-render ref="labelRender" v-show="false" :content="labelRender.data" :labelType="labelRender.type"
v-loading="labelRender.loading" />
<!-- 差异确认弹窗 -->
<el-dialog title="钢卷信息差异确认" :visible.sync="differenceModalVisible" width="50%" :close-on-click-modal="false">
<el-alert :title="differenceMessage" type="warning" :closable="false" show-icon>
</el-alert>
<el-table :data="differenceTableData" border style="margin-top: 20px;">
<el-table-column prop="field" label="字段" width="150"></el-table-column>
<el-table-column prop="frontendValue" label="实际值"></el-table-column>
<el-table-column prop="databaseValue" label="计划值"></el-table-column>
</el-table>
<template slot="footer" class="dialog-footer">
<el-button style="margin-left: 10px;" type="primary" @click="confirmDifference"
v-loading="buttonLoading">确认差异并强行收货</el-button>
<el-button @click="differenceModalVisible = false">取消收货</el-button>
</template>
</el-dialog>
<el-dialog v-loading="editCoil.loading" title="入库钢卷信息编辑" :visible.sync="editCoil.dialogVisible" width="30%">
<el-form ref="form" :model="editCoil.form" :rules="rules" label-width="100px">
<el-form-item label="入场钢卷号" prop="enterCoilNo">
<el-input v-model="editCoil.form.enterCoilNo" placeholder="请输入入场钢卷号" />
</el-form-item>
<el-form-item label="当前钢卷号" prop="currentCoilNo">
<el-input v-model="editCoil.form.currentCoilNo" placeholder="请输入当前钢卷号" />
</el-form-item>
<el-form-item label="厂家原料卷号" prop="supplierCoilNo">
<el-input v-model="editCoil.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="editCoil.form.actualWarehouseId" placeholder="请选择实际库区" style="width: 100%;"
clearable />
</el-form-item>
<el-form-item label="班组" prop="team">
<el-select v-model="editCoil.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" v-if="!editCoil.form.coilId">
<el-select v-model="editCoil.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="editCoil.form.itemType == 'product' && editCoil.form.materialType === '成品'"
v-model="editCoil.form.itemId" placeholder="请选择成品" style="width: 100%;" clearable />
<raw-material-select
v-else-if="editCoil.form.itemType == 'raw_material' && (editCoil.form.materialType === '原料')"
v-model="editCoil.form.itemId" placeholder="请选择原料" style="width: 100%;" clearable />
<div v-else>请先选择材料类型</div>
</el-form-item>
<el-form-item label="质量状态" prop="qualityStatus">
<el-select v-model="editCoil.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="editCoil.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="editCoil.form.packingStatus" placeholder="请输入原料材质">
</el-input>
</el-form-item>
<el-form-item label="包装要求" prop="packagingRequirement">
<el-select v-model="editCoil.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="editCoil.form.grossWeight" placeholder="请输入毛重" />
</el-form-item>
<el-form-item label="净重" prop="netWeight">
<el-input v-model="editCoil.form.netWeight" placeholder="请输入净重" />
</el-form-item>
<el-form-item label="长度" prop="length">
<el-input v-model="editCoil.form.length" placeholder="请输入长度" />
</el-form-item>
<el-form-item label="调制度" prop="temperGrade">
<el-input v-model="editCoil.form.temperGrade" placeholder="请输入调制度" />
</el-form-item>
<el-form-item label="镀层种类" prop="coatingType">
<MemoInput storageKey="coatingType" v-model="editCoil.form.coatingType" placeholder="请输入镀层种类" />
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="editCoil.form.remark" placeholder="请输入备注" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitEdit"> </el-button>
<el-button @click="cancelEdit"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { getMaterialCoil, listMaterialCoil, updateMaterialCoilSimple, getMaxCoilNo, checkCoilNo, delMaterialCoil } from '@/api/wms/coil'
import { listPendingAction, delPendingAction, updatePendingAction } from '@/api/wms/pendingAction'
import MaterialSelect from "@/components/KLPService/MaterialSelect";
import ActualWarehouseSelect from "@/components/KLPService/ActualWarehouseSelect";
import WarehouseSelect from "@/components/KLPService/WarehouseSelect";
import ProductSelect from "@/components/KLPService/ProductSelect";
import RawMaterialSelect from "@/components/KLPService/RawMaterialSelect";
import { Pagination } from 'element-ui';
import { listDeliveryPlan } from '@/api/wms/deliveryPlan'
import handleCoil, { COIL_ACTIONS } from '../js/coilActions'
import LabelRender from '../panels/LabelRender/index.vue'
import CoilNo from "@/components/KLPService/Renderer/CoilNo.vue";
import { checkReceivePlan } from '@/api/wms/receivePlan'
export default {
components: {
MaterialSelect,
ActualWarehouseSelect,
WarehouseSelect,
ProductSelect,
RawMaterialSelect,
LabelRender,
CoilNo,
},
dicts: ['coil_quality_status'],
data() {
return {
pendingActions: [],
// 表单参数
form: {
materialType: '原料',
enterCoilNo: null,
currentCoilNo: null,
itemId: null,
itemType: 'raw_material',
warehouseId: '1988150044862377986', // 酸连轧原料库
netWeight: null,
grossWeight: null,
remark: null,
dataType: 10, // 表示将要入库但是还未入库的钢卷,一般用于钢卷入库的操作去创建一个无法被检索到的钢卷
trimmingRequirement: null,
packingStatus: null,
packagingRequirement: null,
planId: null,
length: null,
temperGrade: null,
coatingType: null,
},
loading: false,
buttonLoading: false,
queryForm: {
currentCoilNo: null,
},
// 分页参数
pagination: {
pageNum: 1,
pageSize: 10,
},
total: 0,
// 表单校验
rules: {
planId: [
{ required: true, message: "请选择收货计划", trigger: "change" }
],
enterCoilNo: [
{ required: true, message: "入场钢卷号不能为空", trigger: "blur" },
// 自定义校验必须是8位的阿拉伯数字
{
validator: (rule, value, callback) => {
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" },
{
validator: (rule, value, callback) => {
if (!/^\d{8}$/.test(value)) {
callback(new Error('当前钢卷号必须是8位的阿拉伯数字'));
} else {
callback();
}
}, trigger: 'blur'
},
],
supplierCoilNo: [
{ required: true, message: "厂家原料卷号不能为空", trigger: "blur" },
// 远程校验,检查钢卷号是否存在
{
validator: (rule, value, callback) => {
if (this.form.coilId) {
// 新增时触发校验
console.log('编辑时不触发校验');
callback();
} else {
checkCoilNo({ supplierCoilNo: value }).then(res => {
const { duplicateType } = res.data;
if (duplicateType === 'supplier' || duplicateType === 'both') {
// alert('厂家原料卷号重复,请重新输入');
callback(new Error('厂家原料卷号重复,请重新输入'));
} else {
callback();
}
})
}
}, 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" }
],
},
labelRender: {
visible: false,
data: {},
type: '2',
loading: false,
},
planList: [],
noPlan: false,
// 确认收货表单参数
receiptModalVisible: false,
receiptForm: {
currentCoilNo: null,
netWeight: null,
grossWeight: null,
actualWarehouseId: null,
remark: null,
},
coilInfo: {},
todayPlanId: null,
// 是否在签收前进行验证
validateBeforeReceipt: false,
editCoil: {
form: {
},
dialogVisible: false,
loading: false,
},
// 差异确认相关数据
differenceModalVisible: false,
differenceMessage: '',
differenceTableData: [],
dbData: null,
checkResult: null
}
},
mounted() {
this.getList()
this.getTodayPlan()
this.remoteMethod('')
this.getMaxCoilNoByPrefix()
},
computed: {
// 动态显示标签
getItemLabel() {
if (this.form.materialType === '成品') {
return '产品类型';
} else if (this.form.materialType === '原料') {
return '原料类型';
}
return '物品类型';
},
},
methods: {
handleProductChange(value, obj) {
console.log(value, obj.material)
this.form.packingStatus = obj.material || ''
},
// 处理材料类型变化
handleMaterialTypeChange(value) {
// 清空物品选择
this.form.itemId = null;
// 根据材料类型设置物品类型
if (value === '成品') {
this.form.itemType = 'product';
} else if (value === '原料') {
this.form.itemType = 'raw_material';
}
},
handleMaterialTypeChangeInEdit(value) {
// 清空物品选择
this.editCoil.form.itemId = null;
// 根据材料类型设置物品类型
if (value === '成品') {
this.editCoil.form.itemType = 'product';
} else if (value === '原料') {
this.editCoil.form.itemType = 'raw_material';
}
},
remoteMethod(query) {
listDeliveryPlan({ planName: query, pageNum: 1, pageSize: 10, planType: 1 }).then(res => {
this.planList = res.rows
})
},
getTodayPlan() {
// 获取今天的收货计划
// 计划日期格式为yyyy-MM-dd
function getBeijingDate() {
const today = new Date();
const year = today.getFullYear(); // 获取4位完整年份(2026)
const month = String(today.getMonth() + 1).padStart(2, '0'); // 月份是0开始(0-11),所以+1补0成两位(01-12)
const day = String(today.getDate()).padStart(2, '0'); // 日期补0成两位(01-31)
return `${year}-${month}-${day}`;
}
// 调用使用
let today = getBeijingDate();
// let today = '2025-01-01'
listDeliveryPlan({ planDate: today, pageNum: 1, pageSize: 1, planType: 1 }).then(res => {
if (res.rows.length > 0) {
this.form.planId = res.rows[0]?.planId
this.todayPlanId = res.rows[0]?.planId
} else {
this.noPlan = true
}
})
},
handleEdit(row) {
// 编辑操作
this.editCoil.loading = true
// 打开编辑弹窗
this.editCoil.dialogVisible = true
getMaterialCoil(row.coilId).then(res => {
this.editCoil.form = res.data
this.editCoil.loading = false
})
},
submitEdit() {
// 编辑操作
this.editCoil.loading = true
this.buttonLoading = true
updateMaterialCoilSimple(this.editCoil.form).then(res => {
this.$modal.msgSuccess("编辑成功");
this.getList()
this.editCoil.dialogVisible = false
}).finally(() => {
this.buttonLoading = false
this.editCoil.loading = false
})
},
cancelEdit() {
// 关闭编辑弹窗
this.editCoil.dialogVisible = false
this.editCoil.loading = false
},
getList() {
// 获取入库历史
this.loading = true
listPendingAction({ actionType: 401, ...this.pagination, ...this.queryForm }).then(res => {
this.pendingActions = res.rows
this.total = res.total
this.loading = false
})
},
/** 提交按钮 */
submitForm() {
this.$refs["form"].validate(valid => {
if (valid) {
this.buttonLoading = true;
handleCoil(COIL_ACTIONS.RECEIVE, this.form, this.form.planId)
.then(res => {
this.$modal.msgSuccess("入库成功");
this.form = {
itemId: null,
itemType: 'raw_material',
materialType: '原料',
warehouseId: '1988150044862377986', // 酸连轧原料库
netWeight: null,
grossWeight: null,
remark: null,
dataType: 10, // 表示将要入库但是还未入库的钢卷,一般用于钢卷入库的操作去创建一个无法被检索到的钢卷
trimmingRequirement: null,
packingStatus: null,
packagingRequirement: null,
planId: this.form.planId,
length: null,
temperGrade: null,
coatingType: null,
}
this.getMaxCoilNoByPrefix()
this.getList()
}).finally(() => {
this.buttonLoading = false;
});
}
})
},
// 打开收货弹窗
openReceiptModal(row) {
this.loading = true
// 打开确认收货弹窗
this.receiptModalVisible = true;
this.receiptForm = row;
// 根据钢卷id查询钢卷信息
getMaterialCoil(row.coilId).then(res => {
this.coilInfo = res.data;
this.loading = false
})
},
// 确认收货
async confirmReceipt() {
await this.$modal.confirm("确认收货后刚钢卷会进入库存并占用所选的实际库区,是否继续?")
// 二次确认
try {
this.buttonLoading = true;
if (this.validateBeforeReceipt) {
// 先检验是否在代收卷中存在当前的信息
const res = await checkReceivePlan(this.coilInfo)
const { found, message, differences, dbData } = res.data
this.checkResult = res.data
if (!found) {
this.buttonLoading = false;
this.$modal.msgError("钢卷不在代收计划中");
return;
}
// 检查是否有差异
if (differences && Object.keys(differences).length > 0) {
// 有差异,展示差异弹窗
this.differenceMessage = message || '钢卷信息存在差异,请确认后继续收货'
// 处理差异数据,转换为表格格式
this.differenceTableData = Object.entries(differences).map(([field, value]) => {
// 使用正则表达式提取前端值和数据库值
const regex = /前端值[:]\s*(.+?)\s*[,]\s*数据库值[:]\s*(.+)/
const match = value.match(regex)
const frontendValue = match ? match[1] : ''
const databaseValue = match ? match[2] : ''
return { field, frontendValue, databaseValue }
})
this.dbData = dbData
this.buttonLoading = false
this.differenceModalVisible = true
return
}
}
// 没有差异或不需要校验,直接收货
this.doReceipt()
} catch (error) {
this.buttonLoading = false;
}
},
// 执行收货操作
doReceipt() {
this.buttonLoading = true;
handleCoil(COIL_ACTIONS.STORE, this.coilInfo, this.receiptForm)
.then(_ => {
this.$message.success("确认收货成功");
this.getList()
this.receiptModalVisible = false;
this.differenceModalVisible = false;
}).finally(() => {
this.buttonLoading = false;
});
},
// 确认差异并继续收货
confirmDifference() {
this.doReceipt()
},
handleReject(row) {
this.$modal.confirm("确认拒签吗?", "拒签确认", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.buttonLoading = true;
updatePendingAction({
...row,
actionStatus: 3, // 3表示取消操作也就是拒签
}).then(response => {
this.$modal.msgSuccess("拒签成功");
this.getList();
}).finally(() => {
this.buttonLoading = false;
});
});
},
/** 预览标签 */
handlePreviewLabel({ coilId, currentCoilNo, enterCoilNo, itemType }) {
this.labelRender.visible = true;
this.labelRender.loading = true;
listMaterialCoil({ coilId, currentCoilNo, enterCoilNo, itemType }).then(res => {
if (res.rows.length === 0) {
this.$modal.msgError("钢卷不存在");
this.labelRender.visible = false;
return
}
const row = res.rows[0]
this.labelRender.loading = false;
const itemName = row.itemName || '';
this.labelRender.type = row.itemType === 'product' ? '3' : '2'
this.labelRender.data = {
...row,
itemName: itemName,
updateTime: row.updateTime?.split(' ')[0] || '',
};
})
},
handlePrintLabel({ coilId, currentCoilNo, enterCoilNo, itemType }) {
listMaterialCoil({ coilId, currentCoilNo, enterCoilNo, itemType }).then(res => {
if (res.rows.length === 0) {
this.$modal.msgError("钢卷不存在");
this.labelRender.visible = false;
return
}
const row = res.rows[0]
const itemName = row.itemName || '';
this.labelRender.type = row.itemType === 'product' ? '3' : '2'
this.labelRender.data = {
...row,
itemName: itemName,
updateTime: row.updateTime?.split(' ')[0] || '',
};
this.$nextTick(() => {
this.$refs.labelRender.printLabel()
})
// this.$message.success("打印成功");
})
},
handleDelete(row) {
console.log(row.coilId)
this.$modal.confirm("确认删除吗?", "删除确认", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
this.buttonLoading = true;
if (row.coilId) {
delMaterialCoil(row.coilId).catch(err => {
this.$message.error(err.message || '删除钢卷失败')
})
}
delPendingAction(row.actionId).then(response => {
this.$modal.msgSuccess("删除成功");
// delCoilWarehouseOperationLogByCoilId({
// coilId: row.coilId,
// operationType: 1,
// inOutType: 1
// })
this.getList();
}).finally(() => {
this.buttonLoading = false;
});
});
},
// 获取入场钢卷号前缀(四位的字符串)两位年份+两位月份
getEnterCoilNoPrefix() {
const date = new Date();
const year = date.getFullYear().toString().slice(-2);
const month = (date.getMonth() + 1).toString().padStart(2, '0');
return year + month;
},
// 获取当前的最大钢卷号
getMaxCoilNoByPrefix() {
const prefix = this.getEnterCoilNoPrefix()
getMaxCoilNo(prefix).then(res => {
console.log(res)
// 扣掉最后一位
this.$set(this.form, 'enterCoilNo', res.data.maxEnterCoilNo.slice(0, -1));
this.$set(this.form, 'currentCoilNo', res.data.maxEnterCoilNo.slice(0, -1));
})
},
// 检查钢卷号是否合法(后端检查)
// checkCoilNo() {
// checkCoilNo({ currentCoilNo: this.form.currentCoilNo, entryCoilNo: this.form.enterCoilNo }).then(res => {
// console.log(res)
// })
// },
// 取消操作
cancel() {
this.form = {};
this.$refs.form.resetFields();
this.buttonLoading = 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;
}
.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(3, 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>