feat(发货单明细): 重构钢卷选择组件并优化表单自动填充

- 将钢卷选择器重构为独立组件,支持触发器模式和外部控制模式
- 添加自动填充表单功能,选中钢卷后自动填充相关字段
- 优化表单布局,移除冗余字段和校验规则
- 增强钢卷选择器的交互和样式,支持显示选中钢卷信息
This commit is contained in:
砂糖
2025-11-26 13:14:30 +08:00
parent 8517180ebb
commit fa493f943c
2 changed files with 310 additions and 143 deletions

View File

@@ -1,73 +1,64 @@
<template>
<el-dialog
title="选择钢卷"
:visible.sync="dialogVisible"
width="900px"
:close-on-click-modal="false"
@close="handleClose"
>
<!-- 搜索区域 -->
<el-form :inline="true" :model="queryParams" class="search-form">
<el-form-item label="卷号">
<el-input
v-model="queryParams.currentCoilNo"
placeholder="请输入卷号"
clearable
size="small"
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="钢种">
<el-input
v-model="queryParams.grade"
placeholder="请输入钢种"
clearable
size="small"
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="small" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="small" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<div class="coil-selector-container">
<div v-if="useTrigger" class="trigger-container">
<!-- 选择按钮 -->
<slot>
<el-button type="primary" size="small" @click="handleOpen" class="select-button">
<i class="el-icon-search"></i>
<span v-if="selectedCoil">
<span>{{ selectedCoil.currentCoilNo }} </span>
<!-- 数据表格 -->
<el-table
v-loading="loading"
:data="coilList"
@row-click="handleRowClick"
highlight-current-row
height="400px"
style="width: 100%"
>
<el-table-column type="index" width="50" align="center" label="序号" />
<el-table-column label="卷号" align="center" prop="currentCoilNo" :show-overflow-tooltip="true" />
<el-table-column label="钢种" align="center" prop="grade" width="100" />
<el-table-column label="厚度(mm)" align="center" prop="thickness" width="100" />
<el-table-column label="宽度(mm)" align="center" prop="width" width="100" />
<el-table-column label="重量(t)" align="center" prop="weight" width="100" />
<el-table-column label="库区" align="center" prop="warehouseName" width="120" :show-overflow-tooltip="true" />
<el-table-column label="操作" align="center" width="100">
<template slot-scope="scope">
<el-button type="text" size="small" @click.stop="handleSelect(scope.row)">选择</el-button>
</template>
</el-table-column>
</el-table>
<span>({{ selectedCoil.itemName }}) </span>
<!-- 分页 -->
<pagination
v-show="total>0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
<div slot="footer" class="dialog-footer">
<el-button @click="handleClose">取消</el-button>
<span>[{{ selectedCoil.netWeight }}t]</span>
</span>
<span v-else>请选择钢卷</span>
</el-button>
</slot>
</div>
</el-dialog>
<el-dialog title="选择钢卷" :visible.sync="dialogVisible" width="900px" :close-on-click-modal="false"
@close="handleClose" append-to-body>
<!-- 搜索区域 -->
<el-form :inline="true" :model="queryParams" class="search-form">
<el-form-item label="卷号">
<el-input v-model="queryParams.currentCoilNo" placeholder="请输入卷号" clearable size="small"
@keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item label="钢种">
<el-input v-model="queryParams.grade" placeholder="请输入钢种" clearable size="small"
@keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="small" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="small" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<!-- 数据表格 -->
<el-table v-loading="loading" :data="coilList" @row-click="handleRowClick" highlight-current-row height="400px"
style="width: 100%">
<el-table-column type="index" width="50" align="center" label="序号" />
<el-table-column label="卷号" align="center" prop="currentCoilNo" :show-overflow-tooltip="true" />
<el-table-column label="物料" align="center" prop="itemName" width="100" />
<el-table-column label="重量(t)" align="center" prop="netWeight" width="100" />
<el-table-column label="库区" align="center" prop="warehouseName" width="120" :show-overflow-tooltip="true" />
<el-table-column label="操作" align="center" width="100">
<template slot-scope="scope">
<el-button type="text" size="small" @click.stop="handleSelect(scope.row)">选择</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize"
@pagination="getList" />
<div slot="footer" class="dialog-footer">
<el-button @click="handleClose">取消</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
@@ -76,6 +67,7 @@ import { listMaterialCoil } from '@/api/wms/coil';
export default {
name: 'CoilSelector',
props: {
// 非触发器模式下,外部控制显隐(触发器模式下无效)
visible: {
type: Boolean,
default: false
@@ -84,6 +76,20 @@ export default {
filters: {
type: Object,
default: () => ({})
},
value: {
type: [String, Number],
default: ''
},
// 是否使用内部触发器(按钮)
useTrigger: {
type: Boolean,
default: true
},
// 初始选中的钢卷数据(支持外部传入已选数据)
initialCoil: {
type: Object,
default: null
}
},
data() {
@@ -91,6 +97,10 @@ export default {
loading: false,
coilList: [],
total: 0,
// 内部显隐控制变量(触发器模式下使用)
innerVisible: false,
// 选中的钢卷数据
selectedCoil: null,
queryParams: {
pageNum: 1,
pageSize: 10,
@@ -101,21 +111,68 @@ export default {
};
},
computed: {
// 根据模式决定对话框显隐逻辑
dialogVisible: {
get() {
// 触发器模式:使用内部变量
if (this.useTrigger) {
return this.innerVisible;
}
// 非触发器模式使用外部传入的visible属性
return this.visible;
},
set(val) {
this.$emit('update:visible', val);
if (this.useTrigger) {
// 触发器模式:更新内部变量
this.innerVisible = val;
} else {
// 非触发器模式:通知父组件更新
this.$emit('update:visible', val);
}
}
}
},
watch: {
visible(val) {
// 监听对话框显隐状态变化,触发数据加载
dialogVisible(val) {
if (val) {
this.resetQuery();
this.getList();
}
},
// 非触发器模式下监听外部visible属性变化
visible(val) {
if (!this.useTrigger && val !== this.dialogVisible) {
this.dialogVisible = val;
}
},
// 监听初始钢卷数据变化
initialCoil(val) {
if (val && typeof val === 'object') {
this.selectedCoil = val;
// 同步到v-model
if (this.useTrigger && val.coilId) {
this.$emit('input', val.coilId);
this.$emit('change', val.coilId);
}
}
},
// 监听v-model值变化外部修改时同步
value(val) {
if (!val) {
this.handleClearSelection();
return;
}
if (val && !this.selectedCoil?.coilId) {
// 如果传入了coilId但还没有选中数据尝试通过id匹配可选功能
this.matchCoilById(val);
}
}
},
created() {
// 初始化时如果有初始钢卷数据,设置选中状态
if (this.initialCoil) {
this.selectedCoil = this.initialCoil;
}
},
methods: {
@@ -128,22 +185,41 @@ export default {
if (response.code === 200) {
this.coilList = response.rows || [];
this.total = response.total || 0;
// 如果有初始coilId尝试匹配数据
if (this.value && !this.selectedCoil) {
this.matchCoilById(this.value);
}
} else {
this.$message.warning(`获取钢卷列表失败:${response.msg || '未知错误'}`);
}
} catch (error) {
console.error('获取钢卷列表失败', error);
this.$message.error('获取钢卷列表失败');
console.error('获取钢卷列表异常', error);
this.$message.error('获取钢卷列表失败,请重试');
} finally {
this.loading = false;
}
},
// 根据coilId匹配钢卷数据
matchCoilById(coilId) {
const matchedCoil = this.coilList.find(item => item.coilId == coilId);
if (matchedCoil) {
this.selectedCoil = matchedCoil;
}
},
// 触发器模式:打开对话框
handleOpen() {
this.innerVisible = true;
},
// 搜索
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
// 重置
// 重置搜索条件
resetQuery() {
this.queryParams = {
pageNum: 1,
@@ -155,32 +231,154 @@ export default {
this.getList();
},
// 点击
// 点击表格行选择
handleRowClick(row) {
this.handleSelect(row);
},
// 选择钢卷
// 选择钢卷(确认选择)
handleSelect(row) {
if (!row) {
this.$message.warning('请选择有效的钢卷数据');
return;
}
// 存储选中的钢卷数据
this.selectedCoil = row;
// 触发自定义事件,通知父组件选中结果(返回完整行数据)
this.$emit('select', row);
// 触发器模式下支持v-model双向绑定
if (this.useTrigger) {
this.$emit('input', row.coilId);
this.$emit('change', row.coilId); // 兼容v-model的change事件
}
// 选择后关闭对话框
this.handleClose();
},
// 清除选中状态
handleClearSelection() {
this.selectedCoil = null;
this.$emit('input', '');
this.$emit('change', '');
this.$emit('clear', true); // 触发清除事件
},
// 关闭对话框
handleClose() {
this.dialogVisible = false;
// 触发关闭事件,通知父组件
this.$emit('close');
}
}
};
</script>
<style scoped lang="scss">
.coil-selector-container {
width: 100%;
}
.trigger-container {
display: flex;
flex-direction: column;
gap: 8px;
}
// 未选择状态样式
.no-selection {
padding: 8px 12px;
border: 1px dashed #dcdcdc;
border-radius: 4px;
color: #999;
background-color: #f9f9f9;
width: fit-content;
}
// 已选择状态样式
.selected-coil-info {
padding: 12px;
border: 1px solid #e6f7ff;
border-radius: 6px;
background-color: #f0f9ff;
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 16px 24px;
width: fit-content;
max-width: 100%;
.info-item {
display: flex;
align-items: center;
gap: 6px;
.label {
color: #666;
font-size: 13px;
}
.value {
color: #333;
font-size: 14px;
font-weight: 500;
white-space: nowrap;
max-width: 150px;
overflow: hidden;
text-overflow: ellipsis;
}
}
.clear-selection {
color: #f56c6c;
margin-left: 12px;
padding: 0 8px;
&:hover {
color: #ff4d4f;
background-color: transparent;
}
}
}
// 选择按钮样式
.select-button {
margin-top: 4px;
}
.search-form {
margin-bottom: 20px;
display: flex;
align-items: center;
gap: 16px;
}
::v-deep .el-dialog__body {
padding: 20px;
max-height: calc(100vh - 200px);
overflow-y: auto;
}
</style>
::v-deep .el-table {
--el-table-row-hover-bg-color: var(--el-color-primary-light-9);
}
::v-deep .el-table__row.current-row {
background-color: var(--el-color-primary-light-8) !important;
}
.dialog-footer {
text-align: right;
}
// 响应式调整
@media (max-width: 768px) {
.selected-coil-info {
gap: 12px;
padding: 10px;
}
.info-item {
flex: 1 1 calc(50% - 12px);
}
}
</style>

View File

@@ -1,5 +1,5 @@
<template>
<div v-loading="loading" >
<div v-loading="loading">
<div v-if="waybillId">
<el-row :gutter="10" class="mb8">
<el-col :span="2" style="font-weight: 900;">发货单明细</el-col>
@@ -46,19 +46,25 @@
<!-- 添加或修改发货单明细对话框 -->
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="80px">
<el-form-item label="关联发货单主表ID" prop="waybillId">
<el-input v-model="form.waybillId" placeholder="请输入关联发货单主表ID" />
</el-form-item>
<el-form-item label="关联钢卷表ID" prop="coilId">
<el-input v-model="form.coilId" placeholder="请输入关联钢卷表ID" />
<el-form ref="form" :model="form" label-width="80px">
<el-form-item label="发货钢卷" prop="coilId">
<div style="display: flex; gap: 10px;">
<coil-selector v-model="form.coilId" :use-trigger="true" @select="handleSelect" />
<el-checkbox v-model="autoFillForm" label="自动填写表单信息" />
</div>
</el-form-item>
<el-form-item label="品名" prop="productName">
<el-input v-model="form.productName" placeholder="请输入品名" />
</el-form-item>
<el-form-item label="切边" prop="edgeType">
<el-input v-model="form.edgeType" placeholder="请输入切边" />
</el-form-item>
<el-form-item label="包装" prop="packaging">
<el-input v-model="form.packaging" placeholder="请输入包装" />
</el-form-item>
<el-form-item label="结算方式" prop="settlementType">
<el-input v-model="form.settlementType" placeholder="请输入结算方式" />
</el-form-item>
<el-form-item label="原料厂家" prop="rawMaterialFactory">
<el-input v-model="form.rawMaterialFactory" placeholder="请输入原料厂家" />
</el-form-item>
@@ -94,6 +100,7 @@
<script>
import { listDeliveryWaybillDetail, getDeliveryWaybillDetail, delDeliveryWaybillDetail, addDeliveryWaybillDetail, updateDeliveryWaybillDetail } from "@/api/wms/deliveryWaybillDetail";
import CoilSelector from "@/components/CoilSelector";
export default {
name: "DeliveryWaybillDetail",
@@ -103,6 +110,9 @@ export default {
default: '',
}
},
components: {
CoilSelector
},
watch: {
waybillId: {
handler(newVal, oldVal) {
@@ -155,63 +165,8 @@ export default {
},
// 表单参数
form: {},
// 表单校验
rules: {
detailId: [
{ required: true, message: "明细唯一ID不能为空", trigger: "blur" }
],
waybillId: [
{ required: true, message: "关联发货单主表ID不能为空", trigger: "blur" }
],
coilId: [
{ required: true, message: "关联钢卷表ID不能为空", trigger: "blur" }
],
productName: [
{ required: true, message: "品名不能为空", trigger: "blur" }
],
edgeType: [
{ required: true, message: "切边不能为空", trigger: "change" }
],
packaging: [
{ required: true, message: "包装不能为空", trigger: "blur" }
],
settlementType: [
{ required: true, message: "结算方式不能为空", trigger: "change" }
],
rawMaterialFactory: [
{ required: true, message: "原料厂家不能为空", trigger: "blur" }
],
coilNo: [
{ required: true, message: "卷号不能为空", trigger: "blur" }
],
specification: [
{ required: true, message: "规格不能为空", trigger: "blur" }
],
material: [
{ required: true, message: "材质不能为空", trigger: "blur" }
],
quantity: [
{ required: true, message: "数量不能为空", trigger: "blur" }
],
weight: [
{ required: true, message: "重量不能为空", trigger: "blur" }
],
unitPrice: [
{ required: true, message: "单价不能为空", trigger: "blur" }
],
remark: [
{ required: true, message: "备注不能为空", trigger: "blur" }
],
delFlag: [
{ required: true, message: "删除标志不能为空", trigger: "blur" }
],
createTime: [
{ required: true, message: "创建时间不能为空", trigger: "blur" }
],
updateTime: [
{ required: true, message: "更新时间不能为空", trigger: "blur" }
],
}
// 自动填写表单信息
autoFillForm: true,
};
},
created() {
@@ -232,6 +187,25 @@ export default {
this.open = false;
this.reset();
},
handleSelect(coil) {
// 填充钢卷信息到表单中,
console.log(coil);
if (!this.autoFillForm) {
return;
}
this.form = {
...this.form,
productName: coil.itemName,
edgeType: coil.surfaceTreatmentDesc,
packaging: coil.packagingId,
rawMaterialFactory: coil.manufacturer,
coilNo: coil.currentCoilNo,
specification: coil.specification,
material: coil.material,
quantity: 1,
weight: coil.netWeight,
}
},
// 表单重置
reset() {
this.form = {
@@ -250,11 +224,6 @@ export default {
weight: undefined,
unitPrice: undefined,
remark: undefined,
delFlag: undefined,
createTime: undefined,
createBy: undefined,
updateTime: undefined,
updateBy: undefined
};
this.resetForm("form");
},