一、效果
封装后的表格,分为3个部分:查询区域、表格主题内容区域、分页器
二、ISearchElTable组件
js
<!--suppress ALL -->
<template>
<div>
<div class="my-3 subheading" v-show="showPageTitle">
<span class="menu-header">{{ $route.meta.title }}</span>
</div>
<div class="search-form mb-3" v-if="showSearchForm && modeType == 1">
<el-form @submit.native.prevent ref="searchForm" :inline="true" :model="queryForm" label-width="140px" :label-position="labelPosition">
<div class="clearfix">
<slot name="simple-form"> </slot>
<div class="right mr-0 mb-3" v-if="modeType == 1">
<slot name="action-button" />
</div>
<el-form-item v-if="advanceQuery && advanceQueryButton">
<el-link type="primary" :underline="false" @click="toggleQuery">
{{ advanceQueryTxt }}
<i :class="toggle ? 'el-icon-caret-top' : 'el-icon-caret-bottom'"></i>
</el-link>
</el-form-item>
</div>
<div v-if="firstGlance">
<slot name="search-form" />
<el-form-item v-if="advanceQueryButton" label=" ">
<el-button type="primary" plain @click="resetForm()" icon="el-icon-refresh">重置</el-button>
<el-button type="primary" @click="handleFilter()" icon="el-icon-search">搜索 </el-button>
</el-form-item>
</div>
</el-form>
</div>
<div class="app-container" :class="[tableClass]">
<div class="filter-container i-data-table">
<div class="search-form" v-if="showSearchForm && modeType == 2">
<el-form @submit.native.prevent ref="searchForm" :inline="true" :model="queryForm" label-width="140px" :label-position="labelPosition">
<div class="clearfix">
<slot name="simple-form"> </slot>
<el-form-item class="right mr-0">
<slot name="action-button" />
</el-form-item>
</div>
</el-form>
</div>
<div>
<slot name="extra-header" />
</div>
<el-table
:default-sort="defaultSort"
@sort-change="sortChange"
v-loading="loading"
v-bind="$attrs"
:data="data.rows"
:row-class-name="getRowClass"
style="width: 100%"
@selection-change="selectionChange"
v-on="$listeners"
>
<el-table-column v-if="isExpand" type="expand" align="center" fixed="left" width="24">
<template slot-scope="scope">
<slot :scope="scope" name="expand-column"> </slot>
</template>
</el-table-column>
<el-table-column v-if="hasCheckBox" type="selection" align="center" width="45" />
<el-table-column v-if="index" label="序号" type="index" align="left" width="50" />
<el-table-column
:sortable="item.sortable"
v-for="item in columns"
:label="item.label"
:key="item.key"
:min-width="item['min-width'] ? item['min-width'] : item.width ? item.width : '200'"
:align="item.align || 'center'"
:show-overflow-tooltip="item.hasOwnProperty('show-overflow-tooltip') ? item['show-overflow-tooltip'] : true"
:fixed="item.fixed || false"
:header-align="item.headerAlign"
>
<template slot-scope="scope">
<slot :scope="scope" :name="item.key">
{{ scope.row[item.key] | isNullOrEmpty('-') }}
</slot>
</template>
<el-table-column
v-for="item in item.childrens"
:label="item.label"
:key="item.key"
:min-width="item['min-width'] ? item['min-width'] : item.width ? item.width : '200'"
:align="item.align || 'center'"
:show-overflow-tooltip="item.hasOwnProperty('show-overflow-tooltip') ? item['show-overflow-tooltip'] : true"
:fixed="item.fixed || false"
:header-align="item.headerAlign"
>
<template slot-scope="scope">
<slot :scope="scope" :name="item.key">
{{ scope.row[item.key] }}
</slot>
</template>
</el-table-column>
</el-table-column>
</el-table>
<pagination
v-if="total > 0 && showPagination"
:total="total"
v-bind="$attrs"
:page.sync="queryForm.pageNum"
:limit.sync="queryForm.pageSize"
:page-sizes="pageSizes"
@pagination="pagination"
/>
</div>
</div>
</div>
</template>
<script>
import Pagination from '@/components/Pagination';
import dataTableMixin from '@/mixins/dataTableMixin';
import { mappingData } from '@/utils';
import store from '@/store';
export default {
name: 'ISearchElTable',
components: {
Pagination,
},
mixins: [dataTableMixin],
props: {
defaultSort: {
type: Object,
default: () => {},
},
tableClass: {
type: String,
default: '',
},
columns: {
type: Array,
default: () => [],
},
data: {
type: Object,
default: () => {},
},
queryForm: {
type: Object,
default: () => {},
},
labelPosition: {
type: String,
default: 'right',
},
advanceQuery: {
type: Boolean,
default: () => false,
},
advanceQueryButton: {
type: Boolean,
default: () => true,
},
loading: {
type: Boolean,
default: () => false,
},
index: {
type: Boolean,
default: () => false,
},
hasCheckBox: {
type: Boolean,
default: () => true,
},
showSearchForm: {
type: Boolean,
default: () => true,
},
isPage: {
type: Boolean,
default: () => true,
},
iswidth: {
type: Boolean,
default: () => false,
},
isExpand: {
type: Boolean,
default: () => false,
},
showPageTitle: {
type: Boolean,
default: () => true,
},
showPagination: {
type: Boolean,
default: () => true,
},
noQuery: {
type: Boolean,
default: () => false,
},
pageSizes: {
type: Array,
default: () => [10, 20, 50, 100],
},
modeType: {
type: String | Number,
default: () => 1,
},
},
data() {
return {
advanceQueryTxt: '高级搜索',
toggle: false,
queryLoading: false,
clientHeight: document.body.clientHeight,
showDetail: {
show: false,
applyId: null,
idCard: null,
},
// pageSizes: [10, 20, 50, 100],
};
},
watch: {
data: {
handler(val) {
if (val && val.rows && this.data.rows.length < 1) {
if (this.queryForm && this.queryForm.pageNum && this.queryForm.pageNum > 1) {
this.queryForm.pageNum = Math.ceil((val.total * 1) / this.queryForm.pageSize);
this.pagination();
}
}
},
deep: true,
immediate: true,
},
},
computed: {
total() {
if (this.isPage) {
return this.data.total ? parseInt(this.data.total) : 0;
} else {
return 0;
}
},
tableData() {
return this.data.rows;
},
firstGlance() {
return this.advanceQuery ? this.toggle : true;
},
tableHeight() {
return this.clientHeight - 320;
},
},
mounted() {
window.addEventListener('resize', this.onResize, false);
this.isColumnInit();
},
destroyed() {
window.removeEventListener('resize', this.onResize, false);
},
methods: {
isColumnInit() {
let curentUrl = null;
let buttons = null;
let isExist = false;
let isOpt = false;
if (this.$route.meta.url) {
curentUrl = this.$route.meta.url;
buttons = store.getters.buttons[curentUrl];
if (buttons === undefined || buttons === null) {
return false;
}
if (buttons.findIndex(el => el == 'btn-opt') !== -1) {
isExist = true;
}
}
this.columns.filter(item => {
if (item.label == '操作' && !item.isNoUrl) {
// isNoUrl 针对不是配置在资源管理的列表资源:为true
isOpt = true;
}
});
if (isOpt && !isExist) {
var index = _.findIndex(this.columns, { label: '操作' });
this.columns.splice(index, 1);
} else {
this.columns;
console.log(this.columns);
}
},
onResize() {
this.clientHeight = document.body.clientHeight;
},
toggleQuery() {
// this.advanceQueryTxt = this.toggle ? '高级搜索' : '基本搜索'
this.toggle = !this.toggle;
},
pagination() {
this.$emit('pagination');
},
handleFilter() {
this.queryForm.pageNum = 1;
this.pagination();
},
resetForm() {
if (this.$parent.queryForm) {
this.queryForm.pageNum = 1;
Object.keys(this.$parent.queryForm).forEach(field => {
if (field !== 'pageNum' && field !== 'pageSize') {
this.$parent.queryForm[field] = null;
}
});
this.pagination();
} else if (this.$parent.$parent.queryForm) {
this.queryForm.pageNum = 1;
Object.keys(this.$parent.$parent.queryForm).forEach(field => {
if (field !== 'pageNum' && field !== 'pageSize') {
this.$parent.$parent.queryForm[field] = null;
}
});
this.pagination();
} else if (this.$parent.$children && this.$parent.$children[0].queryForm) {
// 兼容dialog中引用次组件,重置方法失效的问题
Object.keys(this.$parent.$children[0].queryForm).forEach(field => {
if (field !== 'pageNum' && field !== 'pageSize') {
this.$parent.$children[0].queryForm[field] = null;
}
});
this.pagination();
} else {
console.warn('数据列表自定义组件,未发现queryForm');
}
},
getRowClass({ row, rowIndex }) {
if (!row.children || row.children.length == 0) {
return 'row-expand-hide';
} else {
return null;
}
},
toDetail(item, data) {
var dataList = {
$parent_path: this.$route.path,
};
Object.assign(dataList, data, item);
this.$router.push({
path: '/components/public-detail',
query: dataList,
});
},
sortChange(column, prop, order) {
this.$emit('sortChange', { column, prop, order });
},
collectionDetail(item, data) {
let collectionDataList = {
$parent_path: this.$route.path,
};
Object.assign(collectionDataList, data, item);
this.$router.push({
path: '/components/CollectionDetail',
query: collectionDataList,
});
},
},
};
</script>
<style lang="scss">
.el-tooltip__popper {
left: 250px;
max-width: 400px;
}
</style>
<style scoped lang="scss">
.search-form {
background-color: #fff;
border-radius: 6px;
padding: 20px 20px 0;
}
.menu-header {
display: inline-block;
&:after {
content: '';
width: 40px;
height: 5px;
display: block;
margin: 0 auto;
margin-top: 4px;
background-color: #3f79fe;
border-radius: 30px;
}
}
.checked-tips {
border: 1px solid #1e88e5;
margin-bottom: 10px;
padding: 5px 10px;
border-radius: 3px;
font-size: 14px;
.el-icon-info {
color: #1e88e5;
margin-right: 6px;
font-size: 15px;
}
.num {
color: #1e88e5;
}
}
.fade-in-active {
transition: all 1s ease;
}
.fade-in-enter,
.fade-out-active {
opacity: 0;
}
.app-container {
min-height: 100%;
height: auto !important;
height: 100%;
border-radius: 6px;
::v-deep .pagination-container {
padding: 8px 12px;
}
}
//::v-deep .el-table .row-expand-hide .cell .el-table__expand-icon {
// display: none;
//}
</style>
三、使用
js
// 农户名单数据管理
<template>
<div style="height: 100%" class="position-relative">
<i-search-el-table
ref="table"
:hasCheckBox="true"
:query-form="queryForm"
:columns="columns"
:data="data"
advanceQuery
:loading="loading"
:index="true"
@pagination="getList"
>
<template slot="simple-form">
<el-form-item @submit.native.prevent>
<el-input v-model.trim="queryForm.name" size="small" placeholder="请输入姓名" maxlength="20" clearable>
<el-button slot="append" icon="el-icon-search" @click="$refs.table.handleFilter()" />
</el-input>
</el-form-item>
</template>
<template slot="search-form">
<el-form-item label-width="120px" label="户号:" prop="phone">
<el-input v-model.trim="queryForm.houseNum" maxlength="9" placeholder="请输入" clearable />
</el-form-item>
<el-form-item label-width="120px" label="身份证号:" prop="phone">
<el-input v-model.trim="queryForm.idCard" maxlength="18" placeholder="请输入" clearable />
</el-form-item>
<el-form-item label="户籍地址:" label-width="120px" prop="code">
<el-cascader
ref="cascader"
v-model="queryForm.villages"
:options="regionList"
:emitPath="false"
:props="{ label: 'name', value: 'name', children: 'children' }"
clearable
placeholder="全部"
filterable
@change="handleChange"
></el-cascader>
</el-form-item>
<el-form-item label="初筛结果:" label-width="120px">
<el-select filterable v-model="queryForm.creditResultStr" clearable placeholder="全部">
<el-option v-for="item in creditResultList" :key="item.code" :label="item.name" :value="item.code" />
</el-select>
</el-form-item>
<el-form-item label="所属机构:" label-width="120px" prop="code">
<treeselect
filterable
:appendToBody="true"
:options="assignOrgCodeList"
v-model="queryForm.assignOrgCode"
:normalizer="normalizer"
style="width: 191px"
no-results-text="暂无数据"
placeholder="全部"
/>
</el-form-item>
<el-form-item label="客户经理:" label-width="120px">
<el-select filterable v-model="queryForm.assignUserCode" :disabled="!queryForm.assignOrgCode" clearable placeholder="全部">
<el-option v-for="item in assignUserCodeList" :key="item.userCode" :label="item.userName" :value="item.userCode" />
</el-select>
</el-form-item>
</template>
<template slot="action-button">
<el-button v-has="'btn-del'" type="primary" @click="handleClick('del')" plain> 删除 </el-button>
<el-button v-has="'btn-export'" type="primary" @click="handleClick('export')" plain> 导出 </el-button>
<el-button v-has="'btn-import'" type="primary" @click="handleClick('import')" plain> 导入 </el-button>
<el-button v-has="'btn-download-template'" type="primary" @click="handleClick('importDownload')" plain> 导入模板下载 </el-button>
</template>
<template slot="creditResult" slot-scope="{ scope }">
{{ scope.row.creditResult ? creditResultListMap[scope.row.creditResult] : '-' }}
</template>
<template slot="opt" slot-scope="{ scope }">
<el-link v-has="'btn-view'" class="mr-2" type="primary" :underline="true" @click="handleClick('view', scope.row)"> 查看 </el-link>
<el-link v-if="scope.row.creditResult === 2" v-has="'btn-edit'" class="mr-2" type="primary" :underline="true" @click="handleClick('edit', scope.row)">
编辑
</el-link>
<el-link v-if="scope.row.creditResult !== 1" v-has="'btn-del'" class="mr-2" type="primary" :underline="true" @click="handleClick('delRow', scope.row)">
删除
</el-link>
</template>
</i-search-el-table>
<import v-model="importDialog" @success="init" />
</div>
</template>
<script>
import Treeselect from '@riophae/vue-treeselect';
import '@riophae/vue-treeselect/dist/vue-treeselect.css';
import ISearchElTable from '@/components/ISearchElTable';
import { deepClone, deleteChildrens, getDictEntrysByCode, GLOBAL, filterData, clearTreeChildren } from '@/utils';
import importOrExport from '@/mixins/importOrExport';
import { getToken } from '@/utils/auth';
import Import from './import';
import { mapGetters } from 'vuex';
export default {
name: 'farmer-data-management',
mixins: [importOrExport],
components: { ISearchElTable, Import, Treeselect },
data() {
return {
columns: [
{ label: '户号', key: 'houseNum', align: 'center', 'min-width': 100 },
{ label: '姓名', key: 'name', align: 'center', 'min-width': 100 },
{ label: '身份证号', key: 'idCard', align: 'center', 'min-width': 200 },
{ label: '手机号', key: 'phone', align: 'center', 'min-width': 140 },
{ label: '户籍地址', key: 'address', align: 'center', 'min-width': 140 },
{ label: '初筛结果', key: 'creditResult', align: 'center', 'min-width': 140 },
{ label: '所属机构', key: 'orgName', align: 'center', 'min-width': 165 },
{ label: '客户经理', key: 'custManager', align: 'center', 'min-width': 100 },
{ label: '操作', key: 'opt', align: 'center', 'min-width': 150 },
],
queryForm: {
pageNum: 1,
pageSize: 10,
name: null,
idCard: null,
houseNum: null,
creditResultStr: null,
assignOrgCode: null,
assignUserCode: null,
town: null,
village: null,
villageGroup: '',
villages: [],
},
regionList: [],
assignOrgCodeList: [],
assignUserCodeList: [],
normalizer(node) {
return {
id: node.orgCode,
label: node.orgName,
children: node.children,
};
},
importDialog: false,
data: {},
loading: false,
};
},
computed: {
...mapGetters(['user']),
//角色信息
userEntity() {
return typeof this.user === 'string' ? JSON.parse(this.user) : this.user || {};
},
roleCode() {
return this.userEntity.roleCode;
},
//获得荣誉
obtailHonorList() {
return getDictEntrysByCode('ZCSX_IMPORT_HONOR');
},
//行业
industryList() {
return getDictEntrysByCode('ZCSX_IMPORT_INDUSTRY');
},
//初筛结果
creditResultList() {
// [{"name": "系统初筛中", "code": "1"},
// {"name": "待评议采集", "code": "2"},
// {"name": "年龄不符合", "code": "3"},
// {"name": "命中黑名单", "code": "4"},
// {"name": "已评议采集", "code": "5,6,7,8,9,10,11"},
return getDictEntrysByCode('ZCSX_CREDIT_RESULT');
},
//返显初筛结果 支持"code": "5,6,7,8,9,10,11"
creditResultListMap() {
const Map = {};
this.creditResultList.forEach(item => {
const codeArr = item.code.split(',');
if (codeArr.length === 1) {
Map[item.code] = item.name;
} else {
codeArr.forEach(i => {
Map[i] = item.name;
});
}
});
return Map;
},
},
watch: {
'queryForm.assignOrgCode'(val) {
this.orgCodeChange(val);
},
},
mounted() {
this.getList();
this.getRegionList();
this.getOrgData();
},
activated() {
this.getList();
},
methods: {
/**
* 操作
* @param type
* @param row
*/
handleClick(type, row = {}) {
switch (type) {
case 'del':
if (this.$refs.table.isChecked()) {
const selection = this.$refs.table.selection;
this.delHandler(selection);
}
break;
case 'delRow':
this.delHandler([row]);
break;
case 'importDownload':
this.exportFile2(`/village/exportTemplete?token=${getToken()}`, {});
break;
case 'import':
this.importDialog = true;
break;
case 'export':
this.exportHandler();
break;
case 'view':
case 'edit':
this.$router.push({
path: '/village-credit/farmer-data-management/farmerInformation',
query: {
type,
houseNum: row.houseNum,
},
});
break;
}
},
/**
* 导出
*/
async exportHandler() {
await this.$refs.table.delConfirm({
message: '确定要导出当前条件的所有数据吗?',
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning',
title: '操作提示',
});
await this.exportFile(`/village/exportFarmer`, this.queryForm);
},
/**
* 删除
* @param rows
*/
async delHandler(rows) {
if (rows.some(item => item.creditResult === 1)) {
this.$message.warning('系统初筛中数据不可删除!');
return;
}
const ids = rows.map(row => {
return row.farmerId;
});
await this.$refs.table.delConfirm({
message: `点击确定后,这${ids.length === 1 ? '' : ids.length}条信息将被删除,确定删除?`,
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
title: '删除提示',
});
await this.$api.farmerDataManagement.deleteFarmers({ farmerIds: ids });
this.$message({
message: GLOBAL.OPERATE_SUCCESS,
type: 'success',
});
this.init();
},
/**
* 获取列表
* @returns {Promise<void>}
*/
async getList() {
try {
this.loading = true;
const params = deepClone(this.queryForm);
delete params.villages;
this.data = await this.$api.farmerDataManagement.findFarmerByPage(params);
} finally {
this.loading = false;
}
},
/**
* 初始化
*/
init() {
this.queryForm.pageNum = 1;
this.getList();
},
/**
* 获取地址列表
* @returns {Promise<void>}
*/
async getRegionList() {
const res = await this.$api.localAddress.getAreaTree({});
let tree = filterData(res);
tree = clearTreeChildren(tree);
this.regionList = tree;
// this.regionList = res.map((item, index) => {
// item.village = item.town;
// item.id = item.town + index;
// return item;
// });
},
/**
* 地址改变
* @param value
*/
handleChange(value) {
this.queryForm.town = value[0];
this.queryForm.village = value[1];
this.queryForm.villageGroup = value[2];
},
/**
* 获取所属机构
* @returns {Promise<void>}
*/
async getOrgData() {
const getOrgTreeList = this.$api.incomingParts.getOrgTree({ roleCode: this.roleCode });
const [orgTreeList] = await Promise.all([getOrgTreeList]);
this.assignOrgCodeList = deleteChildrens(orgTreeList ? [orgTreeList] : []);
},
/**
* 所属机构改变获取客户经理
* @returns {Promise<void>}
*/
async orgCodeChange(val) {
if (val) {
const custManagerList = await this.$api.incomingParts.getOrgUser({ orgCode: this.queryForm.assignOrgCode });
this.assignUserCodeList = custManagerList || [];
} else {
this.queryForm.assignUserCode = null;
}
},
},
};
</script>