<template>
|
<el-dialog v-model="visible" title="选择产品" width="900px" destroy-on-close :close-on-click-modal="false">
|
<el-form :inline="true" :model="query" class="mb-2">
|
<el-form-item label="产品分类">
|
<el-input v-model="query.productCategory" placeholder="输入产品分类" clearable @keyup.enter="onSearch" />
|
</el-form-item>
|
|
<el-form-item label="基本单位">
|
<el-input v-model="query.unit" placeholder="输入基本单位" clearable @keyup.enter="onSearch" />
|
</el-form-item>
|
|
<el-form-item>
|
<el-button type="primary" @click="onSearch">搜索</el-button>
|
<el-button @click="columnsDialogVisible = true">列表字段</el-button>
|
</el-form-item>
|
</el-form>
|
|
<!-- 列表 -->
|
<el-table ref="tableRef" v-loading="loading" :data="tableData" height="420" highlight-current-row row-key="id"
|
@selection-change="handleSelectionChange" @select="handleSelect">
|
<el-table-column type="selection" width="55" />
|
<el-table-column type="index" label="序号" width="60" />
|
<template v-for="column in visibleColumns" :key="column.prop">
|
<el-table-column :prop="column.prop" :label="column.label" :min-width="column.minWidth" show-overflow-tooltip align="center" />
|
</template>
|
</el-table>
|
|
<div class="mt-3" style="margin-top: 10px;display: flex; justify-content: flex-end;">
|
|
|
<el-pagination background layout="total, sizes, prev, pager, next, jumper" :total="total"
|
v-model:page-size="page.pageSize" v-model:current-page="page.pageNum" :page-sizes="[10, 20, 50, 100]"
|
@size-change="onPageChange" @current-change="onPageChange" />
|
</div>
|
|
<template #footer>
|
<el-button type="primary" :disabled="multipleSelection.length === 0" @click="onConfirm">
|
确定
|
</el-button>
|
<el-button @click="close()">取消</el-button>
|
</template>
|
</el-dialog>
|
|
<el-dialog v-model="columnsDialogVisible" title="自定义显示列项" width="600px">
|
<el-checkbox-group v-model="selectedColumns">
|
<el-checkbox v-for="column in allColumns" :key="column.prop" :label="column.prop" :disabled="column.disabled">
|
{{ column.label }}
|
</el-checkbox>
|
</el-checkbox-group>
|
<template #footer>
|
<el-button @click="resetColumns">恢复默认</el-button>
|
<el-button type="primary" @click="saveColumns">保存</el-button>
|
</template>
|
</el-dialog>
|
</template>
|
|
<script setup>
|
import { computed, onMounted, reactive, ref, watch, nextTick } from "vue";
|
import { ElMessage } from "element-plus";
|
|
const props = defineProps({
|
modelValue: Boolean,
|
single: Boolean, // 是否只能选择一个,默认false(可选择多个)
|
products: {
|
type: Array,
|
default: () => []
|
},
|
selectedIds: {
|
type: Array,
|
default: () => []
|
}
|
});
|
|
const emit = defineEmits(['update:modelValue', 'confirm']);
|
|
const visible = computed({
|
get: () => props.modelValue,
|
set: (v) => emit("update:modelValue", v),
|
});
|
|
const query = reactive({
|
productName: "",
|
model: "",
|
});
|
|
const page = reactive({
|
pageNum: 1,
|
pageSize: 10,
|
});
|
|
const loading = ref(false);
|
const tableData = ref([]);
|
const total = ref(0);
|
const multipleSelection = ref([]);
|
const tableRef = ref();
|
|
const columnsDialogVisible = ref(false);
|
|
const allColumns = ref([
|
{ prop: 'productCategory', label: '产品分类', selected: true, disabled: false },
|
{ prop: 'unit', label: '基本单位', selected: true, disabled: false },
|
]);
|
|
const selectedColumns = ref(allColumns.value.filter(c => c.selected).map(c => c.prop));
|
|
const visibleColumns = computed(() => {
|
return allColumns.value.filter(c => selectedColumns.value.includes(c.prop));
|
});
|
|
const resetColumns = () => {
|
selectedColumns.value = allColumns.value.filter(c => c.selected).map(c => c.prop);
|
};
|
|
const saveColumns = () => {
|
if (selectedColumns.value.length < 1) {
|
ElMessage.warning("列表项显示不得少于1项");
|
return;
|
}
|
columnsDialogVisible.value = false;
|
};
|
|
function close() {
|
visible.value = false;
|
}
|
|
const handleSelectionChange = (val) => {
|
if (props.single && val.length > 1) {
|
// 如果限制为单个选择,只保留最后一个选中的
|
const lastSelected = val[val.length - 1];
|
multipleSelection.value = [lastSelected];
|
// 清空表格选中状态,然后重新选中最后一个
|
nextTick(() => {
|
if (tableRef.value) {
|
tableRef.value.clearSelection();
|
tableRef.value.toggleRowSelection(lastSelected, true);
|
}
|
});
|
} else {
|
multipleSelection.value = val;
|
}
|
}
|
|
// 处理单个选择
|
const handleSelect = (selection, row) => {
|
if (props.single) {
|
// 如果限制为单个,清空其他选择,只保留当前行
|
if (selection.includes(row)) {
|
// 选中当前行时,清空其他选中
|
multipleSelection.value = [row];
|
nextTick(() => {
|
if (tableRef.value) {
|
tableData.value.forEach((item) => {
|
if (item.id !== row.id) {
|
tableRef.value.toggleRowSelection(item, false);
|
}
|
});
|
}
|
});
|
}
|
}
|
}
|
|
function onSearch() {
|
page.pageNum = 1;
|
loadData();
|
}
|
|
function onReset() {
|
query.productName = "";
|
query.model = "";
|
page.pageNum = 1;
|
loadData();
|
}
|
|
function onPageChange() {
|
loadData();
|
}
|
|
function onConfirm() {
|
if (multipleSelection.value.length === 0) {
|
ElMessage.warning("请选择一条产品");
|
return;
|
}
|
if (props.single && multipleSelection.value.length > 1) {
|
ElMessage.warning("只能选择一个产品");
|
return;
|
}
|
emit("confirm", props.single ? [multipleSelection.value[0]] : multipleSelection.value);
|
close();
|
}
|
|
async function loadData() {
|
loading.value = true;
|
try {
|
multipleSelection.value = []; // 翻页/搜索后清空选择更符合预期
|
|
let filtered = props.products || [];
|
// 本地搜索过滤
|
if (query.productName) {
|
filtered = filtered.filter(item => item.productName && item.productName.includes(query.productName));
|
}
|
if (query.model) {
|
filtered = filtered.filter(item => item.model && item.model.includes(query.model));
|
}
|
|
total.value = filtered.length;
|
// 前端分页
|
const start = (page.pageNum - 1) * page.pageSize;
|
const end = start + page.pageSize;
|
tableData.value = filtered.slice(start, end);
|
|
// 自动回显选中状态
|
nextTick(() => {
|
if (tableRef.value) {
|
tableData.value.forEach(row => {
|
if (props.selectedIds && props.selectedIds.includes(row.id)) {
|
tableRef.value.toggleRowSelection(row, true);
|
}
|
});
|
}
|
});
|
} finally {
|
loading.value = false;
|
}
|
}
|
|
// 监听弹窗打开,重置选择
|
watch(() => props.modelValue, (visible) => {
|
if (visible) {
|
// 每次打开时重新初始化选中状态(multipleSelection 会通过 loadData 中的回显逻辑自动更新,但初始需置空避免重复)
|
multipleSelection.value = [];
|
page.pageNum = 1;
|
loadData();
|
}
|
});
|
|
// 监听数据源变化
|
watch(() => props.products, () => {
|
loadData();
|
}, { deep: true });
|
|
onMounted(() => {
|
loadData()
|
})
|
</script>
|