需求
1.单选、多选统一样式,含checkbox选框
2.可跨页多选
商品选择示例
单选时通过样式类 “hidden-checkbox-all” 隐藏checkbox全选框
<template>
<el-dialog :title="title" v-model="visible" width="1000px" @closed="close">
<div class="dialog-content">
<div class="search-box">
<el-form :inline="true" :model="searchParams" label-width="72px">
<el-form-item label="商品分类:">
<el-cascader v-model="searchParams.category" clearable style="width: 200px;" size="large" placeholder="请选择"
:options="categoryOptions"
:props="{
label: 'name',
value: 'id',
checkStrictly: true
}"
filterable
@change="onSearch()"
/>
</el-form-item>
<el-form-item label="商品编号:">
<el-input v-model="searchParams.no" size="large" style="width: 200px;" placeholder="请输入" />
</el-form-item>
<el-form-item label="商品名称:">
<el-input v-model="searchParams.name" size="large" style="width: 200px;" placeholder="请输入" />
</el-form-item>
<el-form-item label="规格型号:">
<el-input v-model="searchParams.specification" size="large" style="width: 200px;" placeholder="请输入" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSearch">查询</el-button>
<el-button @click="onReset">重置</el-button>
</el-form-item>
</el-form>
</div>
<div class="table-box">
<el-table
:class="{'hidden-checkbox-all': props.isRadio}"
ref="multipleTableRef"
:data="tableData"
height="400px"
:loading="loading"
@select="handleSelectItem"
@select-all="(selection)=>{
handleSelectAll(selection, tableData)
}"
>
<el-table-column type="selection" width="55px" />
<el-table-column min-width="150px" prop="no" label="商品编号" show-overflow-tooltip :formatter="formatterTableCell"></el-table-column>
<el-table-column min-width="150px" prop="name" label="商品名称" show-overflow-tooltip :formatter="formatterTableCell"></el-table-column>
<el-table-column min-width="150px" prop="specification" label="规格型号" show-overflow-tooltip :formatter="formatterTableCell"></el-table-column>
<el-table-column min-width="150px" prop="unitName" label="单位" show-overflow-tooltip :formatter="formatterTableCell"></el-table-column>
</el-table>
<div class="pagination-box">
<div class="selected-num">已选{{ multipleSelection.length }}项</div>
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="paginationConfig.currentPage"
:page-sizes="[10, 30, 50, 100, 200, 500]"
:page-size="paginationConfig.pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="paginationConfig.total"
></el-pagination>
</div>
</div>
</div>
<template #footer>
<div class="dialog-footer">
<el-button @click="visible = false">取 消</el-button>
<el-button type="primary" @click="submit">确 认</el-button>
</div>
</template>
</el-dialog>
<!-- 图片预览 -->
<el-image-viewer v-if="previewImgShow" :zoom-rate="1.2" :url-list="[previewImg]"
@close="previewImgShow = false; previewImg = ''" fit="cover" />
</template>
<script lang='ts' setup>
import { ref, reactive, nextTick } from 'vue';
import { getProductPagePublic } from '@/api/commodityApi/storeApi'
import { categoryTreePublic } from '@/api/commodityApi/classifyApi'
type goodsType = {
id: string
}
const props = defineProps({
title: {
type: String,
default: '选择商品'
},
isRadio: { // 是否单选
type: Boolean,
default: false,
},
})
const emit = defineEmits<{
(e: 'submit', data: any[]): void
}>()
let visible = ref(false)
let loading = ref(false)
let searchParams = ref({
no: '',
name: '',
category: [],
publishStatus: 1, // 上架状态
specification: '', // 规格型号
})
let categoryOptions = ref<any[]>([])
let tableData = ref<any>([])
let multipleSelection = ref<any[]>([])
let paginationConfig = reactive({
currentPage: 1,
pageSize: 10,
total: 0
})
let previewImgShow = ref(false)
let previewImg = ref('')
let multipleTableRef = ref()
const formatterTableCell = (row, column, cellValue, index) => {
return ['', null].includes(cellValue) ? '- -' : cellValue
}
const show = (checkedGoods?: goodsType[]) => {
multipleSelection.value = checkedGoods ? JSON.parse(JSON.stringify(checkedGoods)) : []
visible.value = true;
onSearch()
getCategoryTree()
}
const previewImage = url => {
previewImg.value = url
previewImgShow.value = true
}
const getCategoryTree = () => {
categoryTreePublic({ name: '' }).then(res => {
categoryOptions.value = res.items
})
}
// 选中状态处理
const initCheckedStatus = () => {
nextTick(() => {
let checkedIds = multipleSelection.value.map(v => v.id);
multipleTableRef.value!.clearSelection(); // 清空所有选中
if (checkedIds.length) {
let checkedArr = tableData.value.filter(item => { return checkedIds.includes(item.id) })
checkedArr.forEach(row => {
multipleTableRef.value!.toggleRowSelection(row, undefined);
})
}
})
}
const handleSelectAll = (selection: any[], pageSelectionData: any[]) => {
let checked = selection.length ? true : false; // selection为空数组时代表取消全选
if(checked){
let mIds = multipleSelection.value.map(v=>v.id);
let filterData = pageSelectionData.filter(v=>{ // 筛选出非重复项
return !mIds.includes(v.id)
})
multipleSelection.value = multipleSelection.value.concat(filterData);
}else{
let pIds = pageSelectionData.map(v=>v.id);
multipleSelection.value = multipleSelection.value.filter(v => !pIds.includes(v.id))
}
}
const handleSelectItem = (selection: any[], row) => {
console.log(selection)
let checked = !multipleSelection.value.map(v=>v.id).includes(row.id); // 选项原先是否存在于已选数组中,取反表示当前操作
if (props.isRadio) {
// 单选
multipleTableRef.value!.clearSelection();
multipleTableRef.value!.toggleRowSelection(row, checked);
multipleSelection.value = checked ? [row] : [];
} else {
// 多选
multipleTableRef.value!.toggleRowSelection(row, checked);
multipleSelection.value = checked ? multipleSelection.value.filter(v => v.id !== row.id).concat([row]) : multipleSelection.value.filter(v => v.id !== row.id)
}
}
const handleSizeChange = val => {
paginationConfig.currentPage = 1
paginationConfig.pageSize = val
getList()
}
const handleCurrentChange = val => {
paginationConfig.currentPage = val
getList()
}
const getList = () => {
let { category } = searchParams.value
let params = {
...searchParams.value,
categoryId: category && category.length ? category[category.length - 1] : null,
skipCount: (paginationConfig.currentPage - 1) * paginationConfig.pageSize,
maxResultCount: paginationConfig.pageSize
}
loading.value = true
getProductPagePublic(params)
.then(res => {
tableData.value = res.items
paginationConfig.total = res.totalCount
initCheckedStatus()
}).finally(() => {
loading.value = false
})
}
const onSearch = () => {
paginationConfig.currentPage = 1
getList()
}
const onReset = () => {
searchParams.value = {
no: '',
name: '',
category: [],
publishStatus: 1, // 上架状态
specification: '', // 规格型号
}
onSearch();
}
const submit = () => {
console.log('选中商品:', multipleSelection.value)
emit('submit', multipleSelection.value)
visible.value = false;
}
const close = () => {
tableData.value = [];
multipleSelection.value = [];
};
defineExpose({
show,
})
</script>
<style lang='scss' scoped>
.dialog-content {
.table-box {
padding: 20px;
background-color: #ffffff;
border: 1px solid #d8e2f0;
box-shadow: 0px 12px 36px 0px rgba(211, 215, 221, 0.4);
border-radius: 8px;
.hidden-checkbox-all :deep(.el-table__header .el-table-column--selection .el-checkbox){ // 隐藏全选checkbox
display: none;
}
.pagination-box {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 10px;
.selected-num {
font-size: 14px;
color: #666;
}
:deep(.el-pagination) {
margin-top: 0;
}
}
}
}
</style>