一、下拉框组件:
<template>
<div class="top-select">
<div class="first-select">
<div
v-for="(group, index) in selectGroups"
:key="index"
class="item-select"
>
<div class="title">{{ group.title }}</div>
<el-select
v-model="group.checkedValues"
multiple
clearable
collapse-tags
:reserve-keyword="false"
placeholder="全部"
:max-collapse-tags="1"
@visible-change="group.handleVisibleChange"
popper-class="custom-header"
class="select-box"
>
<template #header>
<div class="header-box">
<el-checkbox
v-model="group.isCheckAll"
:indeterminate="group.isIndeterminate"
@change="group.handleCheckAll"
>
全部
</el-checkbox>
<el-input
v-model.trim="group.searchVal"
:maxlength="6"
:placeholder="`请输入${group.title}`"
clearable
class="ipt"
/>
</div>
</template>
<el-option
v-for="item in group.filteredOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</div>
<el-button class="reset-btn btn" @click="resetSelect">重置</el-button>
<el-button type="primary" class="search-btn btn" @click="searchData"
>搜索</el-button
>
</div>
</div>
</template>
<script setup lang="ts">
import { ElMessage } from 'element-plus'
import { queryIndustrySelect } from './../../monitorApi/jurisdiction/index'
import { useReportStore } from '@/store/modules/report'
const emit = defineEmits([
'getCheckedValues',
'seachTable',
'resetToTop'
])
// 定义通用的全选和部分选中逻辑
const useCheckboxGroup = (options: any, title: string) => {
const checkedValues = ref<any[]>(options.value.map((item: any) => item.value)) // 下拉框多选选中的值
const checkedAllValues = ref<any[]>([]) // 传给后端下拉框多选选中的值
const isCheckAll = ref(true)
const isIndeterminate = ref(false)
const searchVal = ref('')
watch(checkedValues, (val) => {
if (val.length === 0) {
isCheckAll.value = false
isIndeterminate.value = false
checkedAllValues.value = []
} else if (val.length === options.value.length) {
isCheckAll.value = true
isIndeterminate.value = false
checkedAllValues.value = []
} else {
isIndeterminate.value = true
checkedAllValues.value = checkedValues.value
}
emit('getCheckedValues', [
selectGroups.value[0].checkedAllValues,
selectGroups.value[1].checkedAllValues,
selectGroups.value[2].checkedAllValues
])
})
// 点击多选框全选方法
const handleCheckAll = (checked: boolean) => {
isIndeterminate.value = false
checkedValues.value = checked
? options.value.map((item: any) => item.value)
: []
}
// 计算属性实现选项过滤
const filteredOptions = computed(() => {
if (!searchVal.value) return options.value
return options.value.filter((item: any) =>
item.label.includes(searchVal.value)
)
})
// 下拉框显示/隐藏时重置搜索
const handleVisibleChange = (visible: boolean) => {
if (!visible) {
searchVal.value = ''
}
}
return {
title,
options,
filteredOptions,
checkedValues,
checkedAllValues,
isCheckAll,
isIndeterminate,
handleCheckAll,
searchVal,
handleVisibleChange
}
}
// 初始化多选框数据
const selectGroups = ref([
useCheckboxGroup(ref([{ value: '广东局', label: '广东局' }]), '辖区范围'),
useCheckboxGroup(ref([]), '行业范围'),
useCheckboxGroup(
ref([
{ value: 'BSE', label: '北交所' },
{ value: 'SSE', label: '沪主板' },
{ value: 'STAR', label: '科创板' },
{ value: 'SZSE', label: '深主板' },
{ value: 'GEM', label: '创业板' }
]),
'交易板块'
)
])
// 获取行业下拉列表
const getIndustrySelect = () => {
selectGroups.value[1].options = []
queryIndustrySelect().then((res: any) => {
if (res.code === 200) {
res.data.forEach((item: any) => {
let obj = {
value: item.industryCode,
label: item.industryName
}
selectGroups.value[1].options.push(obj)
// 设置行业下拉筛选值
if (useReportStore().topSelectObj.industryCode.length > 0) {
selectGroups.value[1].checkedValues =
useReportStore().topSelectObj.industryCode
selectGroups.value[1].checkedAllValues =
useReportStore().topSelectObj.industryCode
} else {
selectGroups.value[1].checkedValues =
selectGroups.value[1].options.map((item: any) => item.value)
}
})
} else {
ElMessage({
type: 'error',
message: res.message
})
}
})
}
// 重置
const resetSelect = () => {
selectGroups.value[0].checkedValues = selectGroups.value[0].options.map(
(item: any) => item.value
) // 多选框选中的值
selectGroups.value[1].checkedValues = selectGroups.value[1].options.map(
(item: any) => item.value
) // 行业筛选的值
selectGroups.value[2].checkedValues = selectGroups.value[2].options.map(
(item: any) => item.value
) // 多选框选中的值
selectGroups.value[0].checkedAllValues = [] // 传给后端多选框选中的值
selectGroups.value[1].checkedAllValues = [] // 传给后端多选框选中的值
selectGroups.value[2].checkedAllValues = [] // 传给后端多选框选中的值
emit('resetToTop') // 条件重置页面置顶
}
// 搜索
const searchData = () => {
emit('seachTable')
}
onMounted(() => {
getIndustrySelect()
})
onUnmounted(() => {
let obj = {
exchangeCode: [], // 多选框选中的值
industryCode: [], // 多选框选中的值
area: [] // 多选框选中的值
}
useReportStore().setTopSelect(obj)
})
</script>
<style lang="less">
.el-select-dropdown__header {
padding: 5px 10px;
.header-box {
display: flex;
align-items: center;
justify-content: space-between;
.ipt {
width: 120px;
height: 28px;
}
}
}
.el-checkbox__label {
font-size: 12px;
}
</style>
<style lang="less" scoped>
.top-select {
display: flex;
flex-wrap: wrap;
.first-select {
margin-bottom: 10px;
}
.first-select,
.second-select {
display: flex;
align-items: center;
.item-select {
display: flex;
align-items: center;
margin-right: 28px;
.title {
margin-right: 10px;
font-size: 14px;
color: #333333;
}
.select-box {
width: 205px;
}
.select-box1 {
width: 175px;
}
}
.date-select {
margin-right: 30px;
}
.account-select {
margin-right: 0 !important;
margin-left: 28px;
}
.edit-box {
margin-right: 0 !important;
}
.btn {
width: 52px;
border-radius: 4px;
font-size: 12px;
margin-left: 10px;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
}
.reset-btn {
height: 28px;
color: #3a5bb7;
border: 1px solid #3a5bb7;
}
.search-btn {
height: 30px;
}
}
}
</style>
二、下拉框使用组件:
<template>
<!-- 筛选板块 -->
<div class="select-box">
<div class="content">
<topSelect
@getCheckedValues="getCheckedValues"
@seachTable="seachTable"
@resetToTop="resetToTop"
></topSelect>
</div>
</div>
</template>
<script setup lang="ts">
import topSelect from './topSelect.vue'
import { useReportStore } from '@/store/modules/report'
const seleceObj = ref<any>({
exchangeCode: [], // 多选框选中的值
industryCode: [], // 多选框选中的值
area: [] // 多选框选中的值
})
// 获取多选框选中的值
const getCheckedValues = (data: any) => {
seleceObj.value.exchangeCode = data[2]
seleceObj.value.industryCode = data[1]
seleceObj.value.area = data[0]
}
// 搜索
const seachTable = () => {
let selectTopObj = JSON.parse(JSON.stringify(seleceObj.value))
let obj = {
exchangeCode: selectTopObj.exchangeCode, // 多选框选中的值
industryCode: selectTopObj.industryCode, // 多选框选中的值
area: selectTopObj.area // 多选框选中的值
}
useReportStore().setTopSelect(obj)
}
// 重置置顶
const resetToTop = () => {
seleceObj.value = {
exchangeCode: [], // 多选框选中的值
industryCode: [], // 多选框选中的值
area: [] // 多选框选中的值
}
useReportStore().setTopSelect(seleceObj.value)
}
</script>
<style scoped lang="less">
.select-box {
background-color: #fff;
width: 100%;
margin-bottom: 10px;
display: flex;
justify-content: center;
.content {
width: 1450px;
height: 100%;
display: flex;
margin: 10px 0;
}
}
</style>
三、store中report文件方法:
import { ref } from 'vue'
import store from '@/store'
import { defineStore } from 'pinia'
export const useReportStore = defineStore('report', () => {
const topSelectObj = ref({
exchangeCode: [], // 多选框选中的值
industryCode: [], // 多选框选中的值
area: [] // 多选框选中的值
}) // 筛选条件
// 存储筛选条件
const setTopSelect = (data: any) => {
topSelectObj.value = data
}
return {
topSelectObj,
setTopSelect
}
})
/** 在 setup 外使用 */
export function useReportStoreHook() {
return useReportStore(store)
}