Files
xgy-oa/klp-ui/src/components/KLPService/RawMaterialSelect/index.vue
砂糖 0e1017c7ab refactor(组件): 重构产品和原材料选择组件为对话框模式
重构产品选择(RawMaterialSelect)和原材料选择(ProductSelect)组件,将原有的下拉选择模式改为对话框模式
优化组件props处理,将required改为default空对象
新增分页、搜索和表格展示功能,提升用户体验
统一多选和单选模式的操作逻辑
2025-11-15 16:39:05 +08:00

369 lines
11 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="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-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>
<!-- 数据表格同步原料管理页面核心字段 -->
<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>
</el-dialog>
</div>
</template>
<script>
// 替换为原材料接口
import { listRawMaterial } from '@/api/wms/rawMaterial';
export default {
name: 'RawMaterialSelector',
props: {
// 双向绑定值逗号分隔的rawMaterialId字符串
value: {
type: String,
default: ''
},
// 是否只读
readonly: {
type: Boolean,
default: false
},
// 是否允许多选
multiple: {
type: Boolean,
default: false
},
// 过滤条件(继承原料管理页面筛选逻辑)
filters: {
type: Object,
default: () => ({})
}
},
data() {
return {
dialogVisible: false,
loading: false,
rawMaterialList: [], // 原材料列表数据
total: 0,
// 查询参数(同步原料管理页面核心筛选字段)
queryParams: {
pageNum: 1,
pageSize: 10,
rawMaterialCode: undefined,
rawMaterialName: undefined,
specification: undefined,
material: undefined,
manufacturer: undefined,
surfaceTreatmentDesc: undefined,
zincLayer: undefined
},
// 内部选中的原材料ID数组关联rawMaterialId
selectedIds: [],
// 内部选中的行数据
selectedRows: []
};
},
computed: {
// 按钮显示文本
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: {
// 获取原材料列表(调用原料接口)
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;
}
},
// 搜索(逻辑不变,同步筛选参数)
handleQuery() {
this.queryParams.pageNum = 1;
this.getList().then(() => {
this.syncTableSelection();
});
},
// 重置(重置为原材料查询参数)
resetQuery() {
this.queryParams = {
pageNum: 1,
pageSize: 10,
rawMaterialCode: undefined,
rawMaterialName: undefined,
specification: undefined,
material: undefined,
manufacturer: undefined,
surfaceTreatmentDesc: undefined,
zincLayer: undefined
};
this.getList().then(() => {
this.syncTableSelection();
});
},
// 行点击事件(单选直接确认)
handleRowClick(row) {
if (!this.multiple) {
this.selectedIds = [row.rawMaterialId];
this.selectedRows = [row];
this.confirmSelection();
}
},
// 选择项变化(多选)
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);
});
}
});
},
// 确认选择触发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 lang="scss">
.raw-material-selector {
display: inline-block;
}
.search-form {
margin-bottom: 20px;
flex-wrap: wrap; // 适配多筛选字段换行
}
.readonly-text {
color: #606266;
line-height: 1;
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>