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

View File

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

View File

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

View File

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