<template>
|
<div>
|
<!-- 弹窗组件:v-model绑定showDetialBox,确保双向绑定正常 -->
|
<vol-box
|
v-model="showDetialBox"
|
:lazy="false"
|
width="1300px"
|
height="700px"
|
:padding="20"
|
title="添加成品超期报废明细"
|
>
|
<div style="max-height: 700px; overflow-y: auto;">
|
<el-form ref="form" :model="form" label-width="130px">
|
<!-- 仓库选择:保留原生v-for,兼容性更高 -->
|
<el-form-item required label="所属仓库:">
|
<el-select
|
v-model="form.warehouseId"
|
filterable
|
placeholder="请选择仓库"
|
@change="handleWarehouseChange"
|
style="width: 100%;"
|
>
|
<el-option
|
v-for="item in warehouses"
|
:key="item.key"
|
:label="item.value"
|
:value="item.key"
|
>
|
<span style="float: left">{{ item.value }}</span>
|
<span style="float: right; color: #8492a6; font-size: 13px">{{ item.key }}</span>
|
</el-option>
|
</el-select>
|
</el-form-item>
|
|
<!-- 单据编号(只读) -->
|
<el-form-item required label="单据编号:">
|
<el-input
|
v-model="form.orderNo"
|
placeholder="系统将自动生成"
|
readonly
|
style="width: 100%;"
|
></el-input>
|
</el-form-item>
|
|
<el-form-item label="报废明细:">
|
<div
|
v-for="(detail, index) in detailList"
|
:key="`detail-${index}-${detail.materielCode || ''}`"
|
class="detail-item"
|
>
|
<div class="detail-header">
|
<span>明细 {{ index + 1 }}</span>
|
<el-button
|
type="text"
|
size="mini"
|
color="#f56c6c"
|
@click="removeDetail(index)"
|
:disabled="detailList.length <= 1"
|
>
|
删除
|
</el-button>
|
</div>
|
|
<el-row :gutter="20" class="detail-row">
|
<!-- 产品编码:改回原生v-for,避免虚拟列表依赖问题 -->
|
<el-col :span="6">
|
<el-form-item required label="产品编码:">
|
<el-select
|
v-model="detail.materielCode"
|
filterable
|
placeholder="产品编码"
|
@change="handleProCodeChange(detail, index)"
|
clearable
|
style="width: 100%;"
|
>
|
<el-option
|
v-for="(code, idx) in proCodeOptions"
|
:key="`code-${idx}-${code}`"
|
:label="code"
|
:value="code"
|
></el-option>
|
</el-select>
|
</el-form-item>
|
</el-col>
|
|
<!-- 版本:原生v-for,确保稳定 -->
|
<el-col :span="6">
|
<el-form-item required label="物料名称:">
|
<el-select
|
v-model="detail.materielName"
|
filterable
|
placeholder="物料名称"
|
clearable
|
style="width: 100%;"
|
>
|
<el-option
|
v-for="(item, idx) in detail.versionOptions"
|
:key="`version-${idx}-${item}`"
|
:label="item"
|
:value="item"
|
></el-option>
|
</el-select>
|
</el-form-item>
|
</el-col>
|
|
<el-col :span="5">
|
<el-form-item required label="供应商批次号:">
|
<el-input
|
v-model="detail.supplierBatch"
|
placeholder="请输入批次号"
|
style="width: 100%;"
|
clearable
|
@blur="formatLotNo(detail,'supplierBatch')"
|
></el-input>
|
</el-form-item>
|
</el-col>
|
|
<!-- PCS数量:保留格式校验 -->
|
<el-col :span="4">
|
<el-form-item required label="单据数量:">
|
<el-input
|
v-model="detail.orderQuantity"
|
placeholder="单据数量"
|
style="width: 100%;"
|
@blur="formatNumber(detail, 'orderQuantity')"
|
></el-input>
|
</el-form-item>
|
</el-col>
|
</el-row>
|
|
<!-- 备注:保留原样 -->
|
<el-row :gutter="20" class="detail-row">
|
<el-col :span="24">
|
<el-form-item label="备注:">
|
<el-input
|
v-model="detail.remark"
|
placeholder="请输入备注信息"
|
type="textarea"
|
rows="2"
|
style="width: 100%;"
|
></el-input>
|
</el-form-item>
|
</el-col>
|
</el-row>
|
</div>
|
|
<!-- 添加明细按钮:保留禁用逻辑 -->
|
<el-button
|
type="dashed"
|
size="small"
|
class="add-detail-btn"
|
@click="addDetail"
|
:disabled="detailList.length >= 10"
|
style="width: 100%; margin-top: 15px;"
|
>
|
<i class="el-icon-plus"></i> 添加明细
|
</el-button>
|
</el-form-item>
|
</el-form>
|
</div>
|
|
<!-- 底部按钮:确保点击事件正常 -->
|
<template #footer>
|
<el-button type="primary" size="mini" @click="submitForm" style="padding: 8px 20px;">确认提交</el-button>
|
<el-button type="danger" size="mini" @click="close" style="padding: 8px 20px; margin-left: 10px;">关闭</el-button>
|
</template>
|
</vol-box>
|
</div>
|
</template>
|
|
<script>
|
// 仅引入必要组件:VolBox(弹窗核心),移除虚拟列表避免依赖冲突
|
import VolBox from "@/components/basic/VolBox.vue";
|
|
export default {
|
// 明确注册组件:仅注册用到的组件,避免冗余
|
components: { VolBox },
|
data() {
|
return {
|
showDetialBox: false, // 弹窗控制开关:初始false(隐藏)
|
// 仓库枚举:本地模拟(若从父组件传入,可改用props,此处保留本地避免依赖)
|
warehouses: [
|
{ key: "0", value: "板材仓" },
|
{ key: "3", value: "药水仓" },
|
],
|
proCodeOptions: [], // 产品编码列表:从接口加载
|
form: {
|
warehouseId: "", // 选中的仓库ID
|
orderNo: "" // 单据编号(只读)
|
},
|
// 明细列表:初始1条空明细
|
detailList: [this.createEmptyDetail()]
|
};
|
},
|
methods: {
|
// 打开弹窗:核心方法,确保同步执行
|
open() {
|
this.initForm(); // 初始化表单(清空旧数据)
|
this.showDetialBox = true; // 同步设置为true,触发弹窗显示
|
console.log("弹窗已触发显示,showDetialBox:", this.showDetialBox); // 调试日志:可在控制台确认
|
},
|
|
// 初始化表单:简化逻辑,确保无异步阻塞
|
initForm() {
|
// 重置表单数据
|
this.form = {
|
warehouseId: "",
|
orderNo: ""
|
};
|
this.proCodeOptions = []; // 清空产品编码
|
this.detailList = [this.createEmptyDetail()]; // 重置明细
|
|
// 仓库唯一时默认选中(同步逻辑,不阻塞弹窗)
|
if (this.warehouses.length === 1) {
|
this.form.warehouseId = this.warehouses[0].key;
|
this.handleWarehouseChange(this.warehouses[0].key);
|
}
|
},
|
|
// 创建空明细:结构清晰,避免冗余字段
|
createEmptyDetail() {
|
return {
|
materielCode: "", // 产品编码
|
materielName: "", // 版本
|
supplierBatch: "", // 批次号(手动输入)
|
orderQuantity: "", // PCS数量
|
remark: "", // 备注
|
versionOptions: [] // 版本下拉列表
|
};
|
},
|
|
// 仓库变更:加载产品编码(保留原逻辑,确保接口正常)
|
handleWarehouseChange(warehouseId) {
|
if (!warehouseId) {
|
this.proCodeOptions = []; // 仓库为空时清空产品编码
|
return;
|
}
|
// 调用接口加载产品编码(若接口地址有变动,需同步修改)
|
this.http
|
.post(`api/InboundOrder/GetMaterielCode?warehouseId=${warehouseId}`, null, "加载产品数据中")
|
.then((res) => {
|
if (res.status) {
|
this.proCodeOptions = [...new Set(res.data)]; // 去重后赋值
|
} else {
|
this.$message.error(res.message); // 接口失败提示
|
}
|
})
|
.catch(err => {
|
console.error("加载产品编码失败:", err); // 捕获错误,避免阻塞
|
this.$message.error("加载产品编码失败,请重试");
|
});
|
},
|
|
// 产品编码变更:加载版本(保留原逻辑)
|
handleProCodeChange(detail, index) {
|
// 清空关联数据(同步逻辑)
|
detail.versionOptions = [];
|
detail.materielName = "";
|
detail.supplierBatch = "";
|
|
if (!detail.materielCode) return; // 无产品编码时返回
|
|
// 加载版本列表(接口调用:若地址变动需修改)
|
this.http
|
.post(
|
`api/InboundOrder/GetMaterielName?materielCode=${detail.materielCode}&warehouseId=${this.form.warehouseId}`,
|
null,
|
"加载版本数据中"
|
)
|
.then((res) => {
|
if (res.status) {
|
detail.versionOptions = [...new Set(res.data)]; // 去重赋值
|
}
|
})
|
.catch(err => {
|
console.error("加载版本失败:", err);
|
this.$message.error("加载版本失败,请重试");
|
});
|
},
|
|
// 数量格式化:保留原逻辑,确保输入合法
|
formatNumber(detail, field) {
|
if (!detail[field]) return;
|
// 仅保留数字和小数点,且小数点后最多2位
|
let value = detail[field].replace(/[^0-9.]/g, '');
|
const decimalIndex = value.indexOf('.');
|
if (decimalIndex !== -1) {
|
value = value.substring(0, decimalIndex + 1) + value.substring(decimalIndex + 1).replace(/\./g, '');
|
}
|
const parts = value.split('.');
|
if (parts.length > 1 && parts[1].length > 2) {
|
parts[1] = parts[1].substring(0, 2);
|
value = parts.join('.');
|
}
|
detail[field] = value;
|
// 若输入为空或0,提示错误
|
if (value && (parseFloat(value) <= 0 || isNaN(parseFloat(value)))) {
|
this.$message.warning("单据数量必须为正数");
|
}
|
},
|
|
// 批次号格式化:保留原逻辑
|
formatLotNo(detail) {
|
if (!detail.scrapProLotNo) return;
|
// 去除空格,仅保留字母、数字、横杠和下划线
|
const formatted = detail.scrapProLotNo.replace(/\s+/g, '').replace(/[^a-zA-Z0-9_\-]/g, '');
|
detail.scrapProLotNo = formatted;
|
// 格式不合法时提示
|
if (formatted !== detail.scrapProLotNo) {
|
this.$message.warning("批次号仅支持字母、数字、横杠和下划线,已自动过滤无效字符");
|
}
|
},
|
|
// 添加明细:简单push,确保无逻辑冲突
|
addDetail() {
|
this.detailList.push(this.createEmptyDetail());
|
},
|
|
// 删除明细:splice删除,确保索引正确
|
removeDetail(index) {
|
if (this.detailList.length <= 1) return; // 至少保留1条
|
this.detailList.splice(index, 1);
|
},
|
|
// 提交表单:保留原验证逻辑
|
submitForm() {
|
let isValid = true;
|
let errorMessage = '';
|
|
// 验证仓库
|
if (!this.form.warehouseId) {
|
isValid = false;
|
errorMessage = '请选择所属仓库';
|
}
|
|
// 验证明细
|
if (isValid) {
|
const invalidDetail = this.detailList.find(item =>
|
!item.materielCode ||
|
!item.materielName ||
|
!item.supplierBatch.trim() ||
|
!item.orderQuantity ||
|
isNaN(parseFloat(item.orderQuantity)) ||
|
parseFloat(item.orderQuantity) <= 0
|
);
|
if (invalidDetail) {
|
isValid = false;
|
errorMessage = '提交数据存在空值或输入数量不合法,请检查批次号是否填写完整!';
|
}
|
}
|
|
if (!isValid) {
|
this.$message.error(errorMessage);
|
return;
|
}
|
|
// 构造提交数据
|
const submitData = {
|
warehouseId: this.form.warehouseId,
|
details: this.detailList.map(item => ({
|
materielCode: item.materielCode,
|
materielName: item.materielName,
|
supplierBatch: item.supplierBatch.trim(),
|
orderQuantity: parseFloat(item.orderQuantity),
|
remark: item.remark
|
}))
|
};
|
|
// 提交接口
|
this.http
|
.post("api/InboundOrder/Save", submitData, "提交中")
|
.then((res) => {
|
if (!res.status) return this.$message.error(res.message);
|
this.$message.success("操作成功");
|
this.close(); // 提交成功后关闭弹窗
|
this.$emit("parentCall", ($vue) => $vue.refresh()); // 通知父组件刷新
|
})
|
.catch(err => {
|
console.error("提交失败:", err);
|
this.$message.error("提交失败,请重试");
|
});
|
},
|
|
// 关闭弹窗:同步设置为false,确保弹窗隐藏
|
close() {
|
this.showDetialBox = false;
|
this.proCodeOptions = []; // 清空数据,避免下次打开残留
|
}
|
},
|
};
|
</script>
|
|
<style scoped>
|
.detail-item {
|
border: 1px solid #e4e7ed;
|
border-radius: 6px;
|
padding: 15px;
|
margin-bottom: 20px;
|
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
|
}
|
|
.detail-header {
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
margin-bottom: 15px;
|
padding-bottom: 10px;
|
border-bottom: 1px dashed #e4e7ed;
|
font-weight: 500;
|
}
|
|
.detail-row {
|
margin-bottom: 15px;
|
}
|
|
.add-detail-btn {
|
height: 40px;
|
line-height: 38px;
|
}
|
|
::-webkit-scrollbar {
|
width: 8px;
|
height: 8px;
|
}
|
::-webkit-scrollbar-thumb {
|
background-color: #ddd;
|
border-radius: 4px;
|
}
|
::-webkit-scrollbar-track {
|
background-color: #f5f5f5;
|
}
|
|
.el-select {
|
width: 100% !important;
|
min-width: 150px !important;
|
padding-right:10px;
|
}
|
.el-input {
|
width: 100% !important;
|
min-width: 150px !important;
|
padding-right:10px;
|
}
|
</style>
|