refactor(组件): 重构产品和原材料选择组件为对话框模式

重构产品选择(RawMaterialSelect)和原材料选择(ProductSelect)组件,将原有的下拉选择模式改为对话框模式
优化组件props处理,将required改为default空对象
新增分页、搜索和表格展示功能,提升用户体验
统一多选和单选模式的操作逻辑
This commit is contained in:
砂糖
2025-11-15 16:39:05 +08:00
parent 4d7ad302ee
commit 0e1017c7ab
4 changed files with 615 additions and 382 deletions

View File

@@ -1,251 +1,361 @@
<template> <template>
<span> <div class="product-selector">
<el-select v-model="selected" :placeholder="placeholder" :disabled="disabled" filterable clearable size="mini" <!-- 触发器按钮 -->
@change="onChange" :value-key="'productId'" :multiple="multiple" collapse-tags style="width: 100%;"> <el-button
<template #empty> v-if="!readonly"
<el-button v-if="canAdd" @click="add" icon="el-icon-plus">未搜索到产品点击添加</el-button> type="text"
<div v-else style="padding: 10px;">未搜索到产品</div> :icon="multiple ? 'el-icon-checks' : 'el-icon-check'"
</template> @click="dialogVisible = true"
<el-option v-for="item in productList" :key="item.productId" >
:label="getLabel(item)" :value="item.productId"> {{ buttonText }}
<div> </el-button>
<div class="option-label"> <span v-else class="readonly-text">{{ displayText }}</span>
{{ getLabel(item) }}
<!-- <span class="product-name">{{ item.productName }}[{{ item.specification }}]</span>
<span class="product-code">{{ getSku(item) }}</span> -->
</div>
</div>
</el-option>
</el-select>
<el-dialog v-if="canAdd" :visible.sync="addDialogVisible" title="添加产品" width="700px" append-to-body> <!-- 选择对话框 -->
<el-steps align-center :active="activeStep" finish-status="success"> <el-dialog
<!-- 新增产品的步骤 --> append-to-body
<el-step title="创建产品"></el-step> title="选择产品"
<!-- 创建参数的步骤 --> :visible.sync="dialogVisible"
<el-step title="填写参数信息"></el-step> width="1200px"
</el-steps> :close-on-click-modal="false"
@close="handleClose"
<el-form ref="form" v-if="activeStep === 0" :model="addForm" :rules="rules" label-width="120px"> >
<el-row :gutter="20"> <!-- 搜索区域 -->
<el-col :span="12"> <el-form :inline="true" :model="queryParams" class="search-form" size="small">
<el-form-item label="产品编号" prop="productCode"> <el-form-item label="产品编号">
<el-input v-model="addForm.productCode" placeholder="请输入产品编号" /> <el-input
v-model="queryParams.productCode"
placeholder="请输入产品编号"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item> </el-form-item>
</el-col> <el-form-item label="产品名称">
<el-col :span="12"> <el-input
<el-form-item label="产品名称" prop="productName"> v-model="queryParams.productName"
<el-input v-model="addForm.productName" placeholder="请输入产品名称" /> placeholder="请输入产品名称"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item> </el-form-item>
</el-col> <el-form-item label="负责人">
<el-col :span="12"> <el-input
<el-form-item label="负责人" prop="owner"> v-model="queryParams.owner"
<el-input v-model="addForm.owner" :multiple="false" placeholder="请填写负责人" /> placeholder="请填写负责人"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item> </el-form-item>
</el-col> <el-form-item label="规格">
<el-col :span="12"> <el-input
<el-form-item label="计量单位" prop="unit"> v-model="queryParams.specification"
<el-input v-model="addForm.unit" placeholder="请输入计量单位" /> placeholder="请输入规格"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="材质">
<el-input
v-model="queryParams.material"
placeholder="请输入材质"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
</el-form-item> </el-form-item>
</el-col>
</el-row>
</el-form> </el-form>
<div v-if="activeStep === 0" slot="footer" class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitForm">创建产品</el-button>
<el-button @click="cancel"> </el-button>
</div>
<!-- <BomPanel v-if="activeStep === 1" :id="bomId" :itemId="itemId" :type="addForm.type" @addBom="handleBom" /> --> <!-- 数据表格 -->
<el-table
v-loading="loading"
:data="productList"
@row-click="handleRowClick"
@selection-change="handleSelectionChange"
:select-on-indeterminate="multiple"
highlight-current-row
height="400px"
style="width: 100%"
>
<el-table-column
type="selection"
width="55"
align="center"
v-if="multiple"
/>
<el-table-column type="index" width="50" align="center" label="序号" />
<el-table-column label="产品编号" align="center" prop="productCode" :show-overflow-tooltip="true" />
<el-table-column label="产品名称" align="center" prop="productName" :show-overflow-tooltip="true" width="180" />
<el-table-column label="负责人" align="center" prop="owner" width="100" />
<el-table-column label="规格" align="center" prop="specification" width="120" />
<el-table-column label="材质" align="center" prop="material" width="100" />
<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="dialogVisible = false">取消</el-button>
<el-button
type="primary"
@click="confirmSelection"
v-if="multiple"
>
确认选择
</el-button>
</div>
</el-dialog> </el-dialog>
</span> </div>
</template> </template>
<script> <script>
// import { listProductWithBom, addProduct } from '@/api/wms/product'; import { listProduct } from '@/api/wms/product';
// import BomPanel from '../BomPanel/index.vue';
import { mapGetters } from 'vuex';
export default { export default {
name: 'ProductSelect', name: 'ProductSelector',
props: { props: {
value: [String, null, Array], // 双向绑定值
disabled: Boolean, value: {
placeholder: {
type: String, type: String,
default: '请选择产品' default: ''
}, },
canAdd: { // 是否只读
default: false, readonly: {
type: Boolean type: Boolean,
default: false
}, },
// 是否允许多选
multiple: { multiple: {
default: false, type: Boolean,
type: Boolean default: false
},
// 过滤条件
filters: {
type: Object,
default: () => ({})
} }
}, },
// components: {
// BomPanel
// },
data() { data() {
return { return {
// productOptions: [], dialogVisible: false,
selected: this.value, loading: false,
addForm: { productList: [],
total: 0,
queryParams: {
pageNum: 1,
pageSize: 10,
productCode: undefined, productCode: undefined,
productName: undefined, productName: undefined,
owner: undefined, owner: undefined,
unit: undefined, specification: undefined,
type: undefined, material: undefined,
manufacturer: undefined,
surfaceTreatmentDesc: undefined,
zincLayer: undefined
}, },
addDialogVisible: false, // 内部选中的ID数组
rules: { selectedIds: [],
productCode: [ // 内部选中的行数据
{ required: true, message: "产品编号不能为空", trigger: "blur" } selectedRows: []
],
productName: [
{ required: true, message: "产品名称不能为空", trigger: "blur" }
],
owner: [
{ required: true, message: "负责人不能为空", trigger: "blur" }
],
},
buttonLoading: false,
itemId: undefined,
activeStep: 0,
bomId: undefined,
}; };
}, },
watch: {
value(val) {
console.log(val, 'value');
if (!val) {
this.selected = '';
return;
}
if (this.multiple) {
this.selected = val.split(',') || undefined;
} else {
this.selected = val || undefined;
}
},
selected(val) {
console.log(val, 'selected');
if (this.multiple) {
this.$emit('input', val.join(','));
} else {
this.$emit('input', val);
}
}
},
computed: { computed: {
...mapGetters(['productList']), // 按钮显示文本
buttonText() {
if (this.multiple) {
return this.selectedIds.length > 0
? `已选 ${this.selectedIds.length}`
: '选择产品';
} else {
return this.selectedRows[0]?.productName || '选择产品';
}
}, },
created() { // 只读状态显示文本
// this.getProductOptions(); displayText() {
if (this.multiple) {
return this.selectedIds.length > 0
? `已选 ${this.selectedIds.length}`
: '未选择';
} else {
return this.selectedRows[0]?.productName || '未选择';
}
}
},
watch: {
// 监听外部值变化,同步到内部选中状态
value: {
immediate: true,
handler(val) {
this.selectedIds = val ? val.split(',').filter(id => id) : [];
// 当列表已加载时,同步选中状态
if (this.productList.length > 0) {
this.syncTableSelection();
}
}
},
// 监听对话框显示状态,加载数据
dialogVisible(val) {
if (val) {
this.getList().then(() => {
this.syncTableSelection();
});
}
}
}, },
methods: { methods: {
// getProductOptions() { // 获取产品列表
// listProductWithBom({ pageNum: 1, pageSize: 1000 }).then(res => { async getList() {
// this.productOptions = res.rows || []; try {
// }); this.loading = true;
// }, const params = { ...this.queryParams, ...this.filters };
getLabel(item) { const response = await listProduct(params);
// 产品名称[规格](参数),如果有则写,没有则省略 if (response.code === 200) {
const sku = this.getSku(item); this.productList = response.rows || [];
let str = item.productName; this.total = response.total || 0;
if (item.specification) {
str += `[${item.specification}]`
} }
return this.productList;
} catch (error) {
console.error('获取产品列表失败', error);
this.$message.error('获取产品列表失败');
} finally {
this.loading = false;
}
},
if (sku) { // 搜索
str += `(${sku})` handleQuery() {
} this.queryParams.pageNum = 1;
return str; this.getList().then(() => {
this.syncTableSelection();
});
}, },
getSku(item) {
// 查询item的材质(material),表面处理(surfaceTreatmentDesc),厂家(manufacturer),锌层(zincLayer),如果有则添加到sku字符串中 // 重置
let sku = ''; resetQuery() {
if (item.material) { this.queryParams = {
sku += '材质:' + item.material + ''; pageNum: 1,
} pageSize: 10,
if (item.surfaceTreatmentDesc) {
sku += '表面处理:' + item.surfaceTreatmentDesc + '';
}
if (item.manufacturer) {
sku += '厂家:' + item.manufacturer + '';
}
if (item.zincLayer) {
sku += '锌层:' + item.zincLayer + '';
}
return sku;
},
onChange(val) {
// 通过val找到item
const product = this.productOptions.find(p => p.productId === val);
this.$emit('change', product);
},
add() {
this.addDialogVisible = true;
this.addForm = {
productCode: undefined, productCode: undefined,
productName: undefined, productName: undefined,
owner: undefined, owner: undefined,
unit: undefined, specification: undefined,
type: 'product' material: undefined,
manufacturer: undefined,
surfaceTreatmentDesc: undefined,
zincLayer: undefined
}; };
this.bomId = undefined; this.getList().then(() => {
this.itemId = undefined; this.syncTableSelection();
});
}, },
handleBom(bom) {
this.bomId = bom.bomId; // 行点击事件
handleRowClick(row) {
if (!this.multiple) {
this.selectedIds = [row.productId];
this.selectedRows = [row];
this.confirmSelection();
}
}, },
submitForm() {
this.$refs["form"].validate(valid => { // 选择项变化(多选)
if (valid) { handleSelectionChange(rows) {
this.buttonLoading = true; this.selectedRows = rows;
// console.log(this.addForm); this.selectedIds = rows.map(row => row.productId);
addProduct(this.addForm).then(res => { },
this.$modal && this.$modal.msgSuccess("创建产品成功");
this.getProductOptions(); // 单个选择按钮
console.log(res); handleSelect(row) {
this.itemId = res.productId; if (this.multiple) {
this.$emit('input', res.productId); // 多选模式下切换选中状态
this.activeStep = 1; const index = this.selectedIds.indexOf(row.productId);
}).finally(() => { if (index > -1) {
this.buttonLoading = false; this.selectedIds.splice(index, 1);
this.selectedRows.splice(index, 1);
} else {
this.selectedIds.push(row.productId);
this.selectedRows.push(row);
}
this.syncTableSelection();
} else {
// 单选模式直接确认
this.selectedIds = [row.productId];
this.selectedRows = [row];
this.confirmSelection();
}
},
// 同步表格选中状态
syncTableSelection() {
this.$nextTick(() => {
if (this.multiple && this.$refs.table) {
this.productList.forEach(row => {
const isSelected = this.selectedIds.includes(row.productId);
if (isSelected) {
this.$refs.table.toggleRowSelection(row, true);
} else {
this.$refs.table.toggleRowSelection(row, false);
}
}); });
} }
}); });
}, },
cancel() {
this.addDialogVisible = false; // 确认选择
this.addForm = { confirmSelection() {
productCode: undefined, const emitValue = this.selectedIds.join(',');
productName: undefined, this.$emit('input', emitValue);
owner: undefined, this.$emit('change', emitValue, this.selectedRows);
unit: undefined, this.dialogVisible = false;
type: 'product' },
};
// 关闭对话框
handleClose() {
// 关闭时重新同步选中状态(避免临时选择影响)
this.selectedIds = this.value ? this.value.split(',').filter(id => id) : [];
this.dialogVisible = false;
} }
} }
}; };
</script> </script>
<style scoped> <style scoped lang="scss">
.option-label { .product-selector {
display: flex; display: inline-block;
justify-content: space-between;
align-items: center;
} }
.product-name { .search-form {
font-size: 14px; margin-bottom: 20px;
color: #333; flex-wrap: wrap;
} }
.product-code { .readonly-text {
font-size: 12px; color: #606266;
color: #999; line-height: 1;
margin-left: 10px; padding: 8px 0;
display: inline-block;
}
::v-deep .el-dialog__body {
padding: 20px;
overflow-x: auto;
}
::v-deep .el-form-item {
margin-bottom: 15px;
margin-right: 15px;
} }
</style> </style>

View File

@@ -1,248 +1,369 @@
<template> <template>
<span> <div class="raw-material-selector">
<el-select v-model="selected" :placeholder="placeholder" filterable clearable :loading="loading" size="mini" <!-- 触发器按钮 -->
style="width: 100%" :value-key="'rawMaterialId'" :multiple="multiple" collapse-tags> <el-button
<template #empty> v-if="!readonly"
<el-button v-if="canAdd" @click="add" icon="el-icon-plus">未搜索到原材料点击添加</el-button> type="text"
<div v-else style="padding: 10px;">未搜索到原材料</div> :icon="multiple ? 'el-icon-checks' : 'el-icon-check'"
</template> @click="dialogVisible = true"
<el-option v-for="item in rawMaterialList" :key="item.rawMaterialId" >
:label="getLabel(item)" :value="item.rawMaterialId"> {{ buttonText }}
<div> </el-button>
<div class="option-label"> <span v-else class="readonly-text">{{ displayText }}</span>
{{ getLabel(item) }}
<!-- <span class="material-name">{{ item.rawMaterialName }}[{{ item.specification }}]</span>
<span class="material-code">{{ getSku(item) }}</span> -->
</div>
</div>
</el-option>
</el-select>
<el-dialog v-if="canAdd" :visible.sync="addDialogVisible" title="添加原材料" width="700px" append-to-body>
<el-steps align-center :active="activeStep" finish-status="success">
<!-- 新增原材料的步骤 -->
<el-step title="创建原材料"></el-step>
<!-- 创建参数的步骤 -->
<el-step title="填写参数信息"></el-step>
</el-steps>
<el-form ref="form" v-if="activeStep === 0" :model="addForm" :rules="rules" label-width="120px"> <!-- 选择对话框 -->
<el-row :gutter="20"> <el-dialog
<el-col :span="12"> title="选择原材料"
<el-form-item label="原材料编号" prop="rawMaterialCode"> :visible.sync="dialogVisible"
<el-input v-model="addForm.rawMaterialCode" placeholder="请输入原材料编号" /> width="1200px"
:close-on-click-modal="false"
@close="handleClose"
append-to-body
>
<!-- 搜索区域同步原料管理页面筛选字段 -->
<el-form :inline="true" :model="queryParams" class="search-form" size="small">
<el-form-item label="原材料编号">
<el-input
v-model="queryParams.rawMaterialCode"
placeholder="请输入原材料编号"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item> </el-form-item>
</el-col> <el-form-item label="原材料名称">
<el-col :span="12"> <el-input
<el-form-item label="原材料名称" prop="rawMaterialName"> v-model="queryParams.rawMaterialName"
<el-input v-model="addForm.rawMaterialName" placeholder="请输入原材料名称" /> placeholder="请输入原材料名称"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item> </el-form-item>
</el-col> <el-form-item label="规格">
<el-col :span="12"> <el-input
<el-form-item label="负责人" prop="owner"> v-model="queryParams.specification"
<el-input v-model="addForm.owner" :multiple="false" placeholder="请填写负责人" /> placeholder="请输入规格"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item> </el-form-item>
</el-col> <el-form-item label="材质">
<el-col :span="12"> <el-input
<el-form-item label="计量单位" prop="unit"> v-model="queryParams.material"
<el-input v-model="addForm.unit" placeholder="请输入计量单位" /> placeholder="请输入材质"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="厂家">
<el-input
v-model="queryParams.manufacturer"
placeholder="请输入厂家"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="表面处理">
<el-input
v-model="queryParams.surfaceTreatmentDesc"
placeholder="请输入表面处理"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="锌层">
<el-input
v-model="queryParams.zincLayer"
placeholder="请输入锌层"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
</el-form-item> </el-form-item>
</el-col>
</el-row>
</el-form> </el-form>
<div v-if="activeStep === 0" slot="footer" class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitForm">创建原材料</el-button> <!-- 数据表格同步原料管理页面核心字段 -->
<el-button @click="cancel"> </el-button> <el-table
ref="table"
v-loading="loading"
:data="rawMaterialList"
@row-click="handleRowClick"
@selection-change="handleSelectionChange"
:select-on-indeterminate="multiple"
highlight-current-row
height="400px"
style="width: 100%"
>
<el-table-column
type="selection"
width="55"
align="center"
v-if="multiple"
/>
<el-table-column label="原材料编号" align="center" prop="rawMaterialCode" :show-overflow-tooltip="true" />
<el-table-column label="原材料名称" align="center" prop="rawMaterialName" :show-overflow-tooltip="true" width="180" />
<el-table-column label="规格" align="center" prop="specification" width="120" />
<el-table-column label="计量单位" align="center" prop="unit" width="100" />
<el-table-column label="材质" align="center" prop="material" />
<el-table-column label="厂家" align="center" prop="manufacturer" width="120" :show-overflow-tooltip="true" />
<el-table-column label="表面处理" align="center" prop="surfaceTreatmentDesc" />
<el-table-column label="锌层" align="center" prop="zincLayer" width="80" />
<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="dialogVisible = false">取消</el-button>
<el-button
type="primary"
@click="confirmSelection"
v-if="multiple"
>
确认选择
</el-button>
</div> </div>
<BomPanel v-if="activeStep === 1" :id="bomId" :itemId="itemId" :type="addForm.type" @addBom="handleBom" />
</el-dialog> </el-dialog>
</span> </div>
</template> </template>
<script> <script>
import { mapGetters } from "vuex"; // 替换为原材料接口
import { addRawMaterial } from '@/api/wms/rawMaterial'; import { listRawMaterial } from '@/api/wms/rawMaterial';
import BomPanel from '../BomPanel/index.vue';
export default { export default {
name: "RawMaterialSelect", name: 'RawMaterialSelector',
props: { props: {
value: [String, null, Array], // 双向绑定值逗号分隔的rawMaterialId字符串
placeholder: { value: {
type: String, type: String,
default: "请选择原材料" default: ''
}, },
canAdd: { // 是否只读
readonly: {
type: Boolean, type: Boolean,
default: false default: false
}, },
// 是否允许多选
multiple: { multiple: {
default: false, type: Boolean,
type: Boolean default: false
}, },
}, // 过滤条件(继承原料管理页面筛选逻辑)
components: { filters: {
BomPanel type: Object,
default: () => ({})
}
}, },
data() { data() {
return { return {
options: [], dialogVisible: false,
selected: this.value,
loading: false, loading: false,
addForm: { rawMaterialList: [], // 原材料列表数据
total: 0,
// 查询参数(同步原料管理页面核心筛选字段)
queryParams: {
pageNum: 1,
pageSize: 10,
rawMaterialCode: undefined, rawMaterialCode: undefined,
rawMaterialName: undefined, rawMaterialName: undefined,
owner: undefined, specification: undefined,
unit: undefined, material: undefined,
type: 'raw_material' manufacturer: undefined,
surfaceTreatmentDesc: undefined,
zincLayer: undefined
}, },
addDialogVisible: false, // 内部选中的原材料ID数组关联rawMaterialId
rules: { selectedIds: [],
rawMaterialCode: [ // 内部选中的行数据
{ required: true, message: "原材料编号不能为空", trigger: "blur" } selectedRows: []
],
rawMaterialName: [
{ required: true, message: "原材料名称不能为空", trigger: "blur" }
],
owner: [
{ required: true, message: "负责人不能为空", trigger: "blur" }
],
},
buttonLoading: false,
itemId: undefined,
activeStep: 0,
bomId: undefined,
}; };
}, },
watch: {
value(val) {
if (!val) {
this.selected = '';
return;
}
if (this.multiple) {
this.selected = val.split(',') || undefined;
} else {
this.selected = val || undefined;
}
},
selected(val) {
if (this.multiple) {
this.$emit("input", val.join(','));
} else {
this.$emit("input", val);
}
this.$emit('change', this.rawMaterialList.find(p => p.rawMaterialId === val));
}
},
mounted() {
if (this.rawMaterialList.length < 0) {
this.$store.dispatch('category/getRawMaterialMap')
}
},
computed: { computed: {
...mapGetters(['rawMaterialList']) // 按钮显示文本
buttonText() {
if (this.multiple) {
return this.selectedIds.length > 0
? `已选 ${this.selectedIds.length}`
: '选择原材料';
} else {
return this.selectedRows[0]?.rawMaterialName || '选择原材料';
}
},
// 只读状态显示文本
displayText() {
if (this.multiple) {
return this.selectedIds.length > 0
? `已选 ${this.selectedIds.length}`
: '未选择';
} else {
return this.selectedRows[0]?.rawMaterialName || '未选择';
}
}
},
watch: {
// 监听外部值变化,同步到内部选中状态
value: {
immediate: true,
handler(val) {
this.selectedIds = val ? val.split(',').filter(id => id) : [];
// 列表已加载时同步表格选中状态
if (this.rawMaterialList.length > 0) {
this.syncTableSelection();
}
}
},
// 监听对话框显示,加载原材料列表
dialogVisible(val) {
if (val) {
this.getList().then(() => {
this.syncTableSelection();
});
}
}
}, },
methods: { methods: {
async onChange(val) { // 获取原材料列表(调用原料接口)
const rawMaterial = this.options.find(p => p.rawMaterialId === val); async getList() {
this.$emit('change', rawMaterial); try {
this.loading = true;
const params = { ...this.queryParams, ...this.filters };
const response = await listRawMaterial(params);
if (response.code === 200) {
this.rawMaterialList = response.rows || [];
this.total = response.total || 0;
}
return this.rawMaterialList;
} catch (error) {
console.error('获取原材料列表失败', error);
this.$message.error('获取原材料列表失败');
} finally {
this.loading = false;
}
}, },
getLabel(item) {
// 原材料名称[规格](参数),如果有则写,没有则省略
// 如果有sku拼接(sku), 有规格则拼接[规格], 否则只拼接原材料名称 // 搜索(逻辑不变,同步筛选参数)
const sku = this.getSku(item); handleQuery() {
let str = item.rawMaterialName; this.queryParams.pageNum = 1;
if (item.specification) { this.getList().then(() => {
str += `[${item.specification}]` this.syncTableSelection();
} });
},
if (sku) { // 重置(重置为原材料查询参数)
str += `(${sku})` resetQuery() {
} this.queryParams = {
return str; pageNum: 1,
}, pageSize: 10,
getSku(item) {
// 查询item的材质(material),表面处理(surfaceTreatmentDesc),厂家(manufacturer),锌层(zincLayer),如果有则添加到sku字符串中
let sku = '';
if (item.material) {
sku += '材质:' + item.material + '';
}
if (item.surfaceTreatmentDesc) {
sku += '表面处理:' + item.surfaceTreatmentDesc + '';
}
if (item.manufacturer) {
sku += '厂家:' + item.manufacturer + '';
}
if (item.zincLayer) {
sku += '锌层:' + item.zincLayer + '';
}
return sku;
},
add() {
this.addDialogVisible = true;
this.addForm = {
rawMaterialCode: undefined, rawMaterialCode: undefined,
rawMaterialName: undefined, rawMaterialName: undefined,
owner: undefined, specification: undefined,
unit: undefined, material: undefined,
type: 'raw_material' manufacturer: undefined,
surfaceTreatmentDesc: undefined,
zincLayer: undefined
}; };
this.bomId = undefined; this.getList().then(() => {
this.itemId = undefined; this.syncTableSelection();
});
}, },
handleBom(bom) {
this.bomId = bom.bomId; // 行点击事件(单选直接确认)
handleRowClick(row) {
if (!this.multiple) {
this.selectedIds = [row.rawMaterialId];
this.selectedRows = [row];
this.confirmSelection();
}
}, },
submitForm() {
this.$refs["form"].validate(valid => { // 选择项变化(多选)
if (valid) { handleSelectionChange(rows) {
this.buttonLoading = true; this.selectedRows = rows;
// console.log(this.addForm); this.selectedIds = rows.map(row => row.rawMaterialId);
addRawMaterial(this.addForm).then(res => { },
this.$modal && this.$modal.msgSuccess("创建原材料成功");
this.$store.dispatch('category/getRawMaterialMap'); // 单个选择按钮(多选切换选中状态,单选直接确认)
console.log(res); handleSelect(row) {
this.itemId = res.rawMaterialId; if (this.multiple) {
this.$emit('input', res.rawMaterialId); const index = this.selectedIds.indexOf(row.rawMaterialId);
this.activeStep = 1; index > -1
}).finally(() => { ? (this.selectedIds.splice(index, 1), this.selectedRows.splice(index, 1))
this.buttonLoading = false; : (this.selectedIds.push(row.rawMaterialId), this.selectedRows.push(row));
this.syncTableSelection();
} else {
this.selectedIds = [row.rawMaterialId];
this.selectedRows = [row];
this.confirmSelection();
}
},
// 同步表格选中状态
syncTableSelection() {
this.$nextTick(() => {
if (this.multiple && this.$refs.table) {
this.rawMaterialList.forEach(row => {
const isSelected = this.selectedIds.includes(row.rawMaterialId);
this.$refs.table.toggleRowSelection(row, isSelected);
}); });
} }
}); });
}, },
cancel() {
this.addDialogVisible = false; // 确认选择触发v-model更新和change事件
this.addForm = { confirmSelection() {
rawMaterialCode: undefined, const emitValue = this.selectedIds.join(',');
rawMaterialName: undefined, this.$emit('input', emitValue);
owner: undefined, this.$emit('change', emitValue, this.selectedRows);
unit: undefined, this.dialogVisible = false;
type: 'raw_material' },
};
// 关闭对话框(恢复原始选中状态)
handleClose() {
this.selectedIds = this.value ? this.value.split(',').filter(id => id) : [];
this.dialogVisible = false;
} }
} }
}; };
</script> </script>
<style scoped> <style scoped lang="scss">
.option-label { .raw-material-selector {
display: flex; display: inline-block;
justify-content: space-between;
align-items: center;
} }
.material-name { .search-form {
font-size: 14px; margin-bottom: 20px;
color: #333; flex-wrap: wrap; // 适配多筛选字段换行
} }
.material-code { .readonly-text {
font-size: 12px; color: #606266;
color: #999; line-height: 1;
margin-left: 10px; padding: 8px 0;
display: inline-block;
}
::v-deep .el-dialog__body {
padding: 20px;
overflow-x: auto; // 适配宽表格横向滚动
}
::v-deep .el-form-item {
margin-bottom: 15px;
margin-right: 15px;
} }
</style> </style>

View File

@@ -1,5 +1,5 @@
<template> <template>
<div v-loading="loading" loading-text="加载中..."> <div>
<span class="product-name" @click.stop="clickHandle"> <span class="product-name" @click.stop="clickHandle">
<slot name="default" :product="product"> <slot name="default" :product="product">
{{ product && product.productName ? product.productName : '--' }} {{ product && product.productName ? product.productName : '--' }}
@@ -58,7 +58,8 @@ export default {
props: { props: {
product: { product: {
type: Object, type: Object,
required: true // required: true,
default: () => ({})
}, },
}, },
// mounted() { // mounted() {

View File

@@ -44,7 +44,8 @@ export default {
props: { props: {
material: { material: {
type: Object, type: Object,
required: true // required: true,
default: () => ({})
} }
}, },
data() { data() {