ISearchElTable

一、效果

封装后的表格,分为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>
相关推荐
秦jh_11 分钟前
【Linux】多线程(概念,控制)
linux·运维·前端
蜗牛快跑21324 分钟前
面向对象编程 vs 函数式编程
前端·函数式编程·面向对象编程
Dread_lxy25 分钟前
vue 依赖注入(Provide、Inject )和混入(mixins)
前端·javascript·vue.js
涔溪1 小时前
Ecmascript(ES)标准
前端·elasticsearch·ecmascript
榴莲千丞1 小时前
第8章利用CSS制作导航菜单
前端·css
奔跑草-1 小时前
【前端】深入浅出 - TypeScript 的详细讲解
前端·javascript·react.js·typescript
羡与2 小时前
echarts-gl 3D柱状图配置
前端·javascript·echarts
guokanglun2 小时前
CSS样式实现3D效果
前端·css·3d
咔咔库奇2 小时前
ES6进阶知识一
前端·ecmascript·es6
渗透测试老鸟-九青2 小时前
通过投毒Bingbot索引挖掘必应中的存储型XSS
服务器·前端·javascript·安全·web安全·缓存·xss