elementUI 搜索条件、table、页脚封装
一共分成了两个组件:
组件一:搜索条件 =>SearchParams.vue
组件二:el-table和el-pagination =>TablePagintion
考虑到业务的使用场景没用做过多的封装。
(1)组件一:搜索条件代码如下:
<template>
<div class="wrap">
<div class="top_item">
<el-input
placeholder="企业名称"
v-model.trim="searchForm.companyName"
clearable
@keyup.enter.native="getList(undefined)"
/>
</div>
<div class="top_item">
<el-select style="width: 130px" placeholder="企业类别" v-model="searchForm.companyType" clearable>
<el-option :label="'排污许可'" value="排污许可"></el-option>
<el-option :label="'排污登记'" value="排污登记"></el-option>
</el-select>
</div>
<div class="top_item">
<el-select style="width: 130px" v-model="searchForm.management" placeholder="请选择管理类别" clearable>
<el-option label="简化管理" value="简化管理"></el-option>
<el-option label="重点管理" value="重点管理"></el-option>
</el-select>
</div>
<div class="top_item">
<a-tree-select
v-model="searchForm.countys"
style="width: 200px"
:tree-data="districtData"
tree-checkable
:allow-clear="true"
:max-tag-count="1"
:tree-default-expand-all="true"
placeholder="行政区域"
dropdown-class-name="drop-style"
/>
</div>
<div class="top_item">
<a-tree-select
showCheckedStrategy="SHOW_PARENT"
v-model="searchForm.hyCode"
style="width: 240px"
:allow-clear="true"
tree-node-filter-prop="title"
:tree-data="industryData"
tree-checkable
:max-tag-count="1"
placeholder="行业类别(国民经济代码)"
:replace-fields="{
children: 'childList',
title: 'name',
value: 'code',
key: 'id',
}"
dropdown-class-name="drop-style"
/>
</div>
<div class="top_item">
<el-date-picker
style="width: 240px"
value-format="yyyy-MM-dd"
v-model="searchForm.limitDate"
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
>
</el-date-picker>
</div>
<el-button icon="el-icon-search" type="primary" @click="getListPage" :loading="loading">查 询</el-button>
<el-button icon="el-icon-refresh-left" @click="resetParam">重 置</el-button>
<el-button icon="el-icon-document" type="primary" @click="exportFile" :loading="exportLoading">导 出</el-button>
</div>
</template>
<script>
import { getParamIndustry } from '@/api/api_jneep.js'
import { getDistrictList } from '@/api/api.js'
export default {
components: {},
props: ['regionCode', 'loading', 'exportLoading'],
data() {
return {
searchForm: {
companyName: '',
companyType: '',
management: '',
countys: [],
hyCode: [],
limitDate: null,
},
districtData: [],
industryData: [],
}
},
mounted() {
this.initPage()
},
methods: {
//页面初始化
initPage() {
this.getIndustryData()
this.getDistrictData()
},
//查询
getListPage() {
this.$emit('getListPage', this.getParamData())
},
//导出
exportFile() {
this.$emit('exportFile', this.getParamData())
},
//参数处理
getParamData() {
const len = this.searchForm.countys.length
const params = {
companyName: this.searchForm.companyName,
companyType: this.searchForm.companyType,
management: this.searchForm.management,
countys: len > 0 ? this.searchForm.countys : this.regionCode,
hyCode: this.searchForm.hyCode,
startTime: this.searchForm.limitDate?.[0] || '',
endTime: this.searchForm.limitDate?.[1] || '',
}
return params
},
//重置
resetParam() {
this.searchForm.companyName = ''
this.searchForm.companyType = ''
this.searchForm.management = ''
this.searchForm.countys = []
this.searchForm.hyCode = []
this.searchForm.limitDate = null
this.$emit('getListPage', this.getParamData())
},
// 获取行业数据
getIndustryData() {
getParamIndustry()
.then((res) => {
if (!!res.data && res.data.code === 0) {
if (!!res.data.data && !!res.data.data.treeList) {
this.industryData = res.data.data.treeList
} else {
this.industryData = []
}
} else {
this.industryData = []
}
})
.catch((err) => {
console.log('getIndustryData -> err', err)
this.industryData = []
})
},
// 获取行政区域数据
getDistrictData() {
getDistrictList()
.then((res) => {
if (!!res.data && res.data.code === 200) {
let districtData = []
for (let d of res.data.data) {
if (!this.regionCode.includes(d['code'])) {
continue
}
districtData.push({
key: d['code'],
value: d['code'],
title: d['name'],
})
}
this.districtData = [
{
title: '济南市',
value: '济南市',
key: '济南市',
children: districtData,
},
]
}
})
.catch((err) => {
console.log('getDistrictData -> err', err)
this.districtData = []
})
},
},
}
</script>
<style lang="less" scoped>
.top_item {
display: inline-block;
margin-right: 5px;
margin-bottom: 10px;
}
.sync-dialog__div {
// height: 600px;
overflow: auto;
}
/deep/ .ant-select-selection--multiple {
padding-bottom: 7px !important;
padding-top: 3px !important;
}
</style>
(2)组件二:el-table和el-pagination代码如下:

<template>
<div class="wrap">
<!-- 列设置 -->
<div class="wrap_columnsConfig">
<div style="display: flex; justify-content: flex-end; margin-bottom: 5px">
<el-popover placement="bottom" width="300" trigger="click">
<el-checkbox
:indeterminate="isIndeterminate"
v-model="checkAll"
@change="changeAll"
style="font-size: 18px"
>列展示</el-checkbox
>
<el-divider />
<el-tree
draggable
:data="tableHeaderCopy"
:props="defaultProps"
:allow-drop="allowDrop"
@node-drop="handleDrop"
>
<span class="tree-table-setting" slot-scope="{ node, data }">
<!-- <el-switch @change="saveTableColumns" v-model="data.show"> </el-switch>
<span>{{ node.label }}</span> -->
<el-checkbox-group v-model="columnsGroup">
<el-checkbox @change="danSelect(data)" :label="data.prop" :key="data.prop">{{
data.label
}}</el-checkbox>
</el-checkbox-group>
</span>
</el-tree>
<el-button type="primary" size="small" slot="reference"
><i class="el-icon-setting">列设置</i></el-button
>
</el-popover>
</div>
</div>
<!-- 表格 -->
<el-table
:data="tableData"
style="width: 100%"
:header-cell-style="{ 'text-align': 'center' }"
v-loading="loading"
element-loading-text="拼命加载中"
border
:key="tableKey"
ref="table"
>
<!-- 循环表头数据,判断列显示类型 -->
<template v-for="(item, index) in tableHeaderCopy">
<!-- 序号 -->
<el-table-column
:key="item.prop"
:fixed="item.fixed"
label="序号"
width="70px"
align="center"
v-if="item.prop == 'index' && item.show"
>
<template slot-scope="scope">
<div>
{{ scope.$index + (pageConfig.currentPage - 1) * pageConfig.pageSize + 1 }}
</div>
</template>
</el-table-column>
<!-- 其他列 -->
<el-table-column
v-else-if="item.show"
:key="index"
:label="item.label"
:min-width="item.width"
:prop="item.prop"
:align="item.align"
:width="item.width"
:show-overflow-tooltip="item.showOverflowTooltip"
>
</el-table-column>
</template>
</el-table>
<!-- 分页 -->
<div style="margin-top: 10px; display: flex; justify-content: flex-end">
<el-pagination
v-if="pageConfig.total"
background
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page.sync="pageConfig.currentPage"
:page-sizes="pageConfig.pageArray"
:page-size.sync="pageConfig.pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="pageConfig.total"
>
</el-pagination>
</div>
</div>
</template>
<script>
var _ = require('lodash')
export default {
components: {},
props: {
loading: {
type: Boolean,
default: false,
},
tableHeader: {
type: Array,
default: () => [],
},
tableData: {
type: Array,
default: () => [],
},
pageConfig: {
type: Object,
default: () => {},
},
},
data() {
return {
tableKey: 1,
isIndeterminate: false, //全选/半选状态
checkAll: true, //全选
defaultProps: {
label: 'label',
},
columnsGroup: [],
tableHeaderCopy: [],
}
},
beforeUpdate() {
/** 在数据加载完,重新渲染表格 */
this.$nextTick(() => {
this.$refs.table.doLayout()
})
},
mounted() {
this.initColumn()
},
methods: {
//每页显示条目个数变化
handleSizeChange(pageSize) {
this.$emit('handlePageChange', pageSize, this.pageConfig.currentPage)
},
//当前页数变化
handleCurrentChange(currentPage) {
this.$emit('handlePageChange', this.pageConfig.pageSize, currentPage)
},
//初始化列=》用于列设置
initColumn() {
this.tableHeaderCopy = _.cloneDeep(this.tableHeader)
let arr = []
this.tableHeaderCopy.forEach((item) => {
item.show = true
arr.push(item.prop)
})
this.columnsGroup = arr
},
//全选/全不选=》用于列设置
changeAll(val) {
this.columnsGroup = []
if (val) {
this.tableHeaderCopy.forEach((item) => {
item.show = true
this.columnsGroup.push(item.prop)
})
this.checkAll = true
this.isIndeterminate = false
} else {
this.tableHeaderCopy.forEach((item) => {
item.show = false
this.columnsGroup.push(item.prop)
})
this.columnsGroup = []
this.checkAll = false
}
},
//单选事件=》用于列设置
danSelect(val, index) {
let flag = this.columnsGroup.indexOf(val.prop)
console.log(flag)
this.tableHeaderCopy.forEach((item) => {
if (item.prop == val.prop) {
item.show = flag == -1 ? false : true
}
})
let checkedCount = this.columnsGroup.length
this.isIndeterminate = checkedCount > 0 && checkedCount < this.tableHeaderCopy.length
this.checkAll = checkedCount === this.tableHeaderCopy.length
},
// 拖拽时判定目标节点能否被放置。=》用于列设置
allowDrop(draggingNode, dropNode, type) {
return type !== 'inner' && dropNode.data && !dropNode.data.fixed
},
//拖拽成功完成时触发的事件; Tree 拖动时更新表格=》用于列设置
handleDrop() {
this.tableKey++
},
},
}
</script>
<style scoped lang="less">
.el-divider--horizontal {
margin: 2px 0 !important;
}
</style>
(3)在父组件中使用组件一和组件二:

<template>
<div class="wrap">
<!-- 搜索参数 -->
<div class="search_area">
<search-params
@getListPage="getList"
@exportFile="exportFile"
:regionCode="regionCode"
:loading="loading"
:exportLoading="exportLoading"
>
</search-params>
<table-pagination
@handlePageChange="handlePageChange"
:tableData="tableData"
:tableHeader="tableHeader_vocs"
:pageConfig="pageConfig"
:loading="loading"
></table-pagination>
<!-- <el-table
:data="tableData"
style="width: 100%"
:header-cell-style="{ 'text-align': 'center' }"
v-loading="loading"
element-loading-text="拼命加载中"
border
ref="table"
>
<template v-for="(col,index) in tableHeader_vocs">
<el-table-column
:fixed="col.fixed"
label="序号"
width="70px"
align="center"
:key="col.prop"
v-if="col.type == 'index'"
>
<template slot-scope="scope">
<div>
{{ scope.$index + (pageConfig.currentPage - 1) * pageConfig.pageSize + 1 }}
</div>
</template>
</el-table-column>
<el-table-column
v-else
:key="index"
:label="col.label"
:min-width="col.width"
:prop="col.prop"
:align="col.align"
:width="col.width"
:show-overflow-tooltip="col.showOverflowTooltip"
>
</el-table-column>
</template>
</el-table> -->
<!-- 分页 -->
<!-- <div style="margin-top: 10px; display: flex; justify-content: flex-end">
<el-pagination
v-if="pageConfig.total"
background
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="pageConfig.currentPage"
:page-sizes="pageConfig.pageArray"
:page-size.sync="pageConfig.pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="pageConfig.total"
>
</el-pagination>
</div> -->
</div>
</div>
</template>
<script>
import { getRegionCodeByUser, tableHeader_vocs, exportFile } from '@/utils/utils'
import { getVocsList, exporVoctExcel } from '@/api/LinkageMechanism'
import SearchParams from './components/SearchParams'
import TablePagination from './components/TablePagination'
var _ = require('lodash')
export default {
components: {
SearchParams,
TablePagination,
},
data() {
return {
tableHeader_vocs,
pageConfig: {
pageArray: [10, 20, 50, 100],
total: 0,
currentPage: 1,
pageSize: 10,
},
tableKey: 1,
tableData: [],
loading: false,
exportLoading: false,
regionCode: [],
params: {},
}
},
created() {
this.regionCode = getRegionCodeByUser()
this.initPage()
},
methods: {
//页面初始化
initPage() {
this.getList()
},
//获取table数据
getList(val) {
if (!!val) {
this.pageConfig.currentPage = 1
this.pageConfig.pageSize = 10
}
let params = {
currentPage: this.pageConfig.currentPage,
pageSize: this.pageConfig.pageSize,
params: {},
}
if (!!val) {
Object.assign(this.params, val)
} else {
params['params']['countys'] = this.regionCode
}
Object.assign(params['params'], this.params)
this.tableData = []
this.loading = true
getVocsList(params)
.then((res) => {
const { data, code } = res.data
if (code === 200 && !!data) {
const list = data.list
this.tableData = list
this.pageConfig.total = data.total
} else {
this.tableData = []
this.$message.error('数据获取失败……')
this.pageConfig.total = 0
}
this.loading = false
})
.catch((err) => {
this.loading = false
this.tableData = []
this.pageConfig.total = 0
console.log(err)
})
},
//每页显示条目个数 或者 当前页数变化
handlePageChange(pageSize, currentPage) {
this.pageConfig.pageSize = pageSize
this.pageConfig.currentPage = currentPage
this.getList()
},
//导出
exportFile(param) {
this.exportLoading = true
this.getList(param)
exporVoctExcel({ params: param })
.then((res) => {
const { data } = res
exportFile(data, 'application/vnd.ms-excel', 'Vocs数据详情')
this.$message.success('导出成功!')
this.exportLoading = false
})
.catch((err) => {
console.log(err)
this.exportLoading = false
this.$message.error('导出失败!')
})
},
// //每页显示条目个数变化
// handleSizeChange(val) {
// this.pageConfig.pageSize = val
// this.getList()
// },
// //当前页数变化
// handleCurrentChange(val) {
// this.pageConfig.currentPage = val
// this.getList()
// },
},
}
</script>
<style lang="less" scoped>
.wrap {
.search_area {
margin-top: 10px;
}
.content {
margin-top: 10px;
}
}
.paginationClass {
text-align: right;
margin: 10px;
}
.list-bar {
margin-top: 2px;
// margin-right: 5px;
font-size: 16px;
font-weight: 500;
height: 36px;
line-height: 36px;
display: flex;
align-items: center;
background-image: linear-gradient(to right, #e7f0fd 100%, #accbee 0%);
.list-bar-inner {
line-height: 33px;
height: 33px;
padding-left: 3px;
border-left: 3px solid #4facfe;
// border: 1px solid red;
}
}
/deep/ .my-label {
background: #e1f3d8;
}
.switch-area {
display: flex;
align-items: center;
margin-top: 5px;
div {
margin-left: 5px;
}
}
</style>
<style lang="less" scoped>
.top_item {
display: inline-block;
margin-right: 5px;
margin-bottom: 10px;
}
.sync-dialog__div {
// height: 600px;
overflow: auto;
}
/deep/ .ant-select-selection--multiple {
padding-bottom: 7px !important;
padding-top: 3px !important;
}
</style>
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具