vue+elementUI实现自动化列表生成

最近遇到一个需求:需要实现前端列表页根据后端配置实现自动化生成。期初这个需求是没有头绪的因为就目前接触到的页面来看,用到的列表出了长的比较像意外其实没有完全一样的,基本上没有两个完全没有自定义操作且产品给的原型还是一样的列表。但是遇到需求吗没法的时候就得上。
一般列表页 基本都会含有以下几个结构
一.搜索区(分为条件区域 + 按钮区域)
1)条件区域一般常用的有 输入框,选择框,单选按钮组,多选按钮组,还有联级选择器等、因为要做的是配置所以这里必须尽可能的把每一个条件可能出现的情况考虑到。但是这样的话整个模块就会变得很臃肿。所以第一个版本打算先固定样式和页面风格,同时忽略掉正则这些验证实现简单的版本 大体条件区域的配置可以是这样的

<el-form-item :label="item.label" :key="index" v-for="(item,index) in formList">
<el-input v-if="item.type=='input'||item.type==''" v-model="params[item.param]" :placeholder="item.placeholder"></el-input>
                <el-select :disabled="item.disabled" v-if="item.type=='select'" @change="search" clearable filterable v-model="params[item.param]" :placeholder="item.placeholder">
                  <el-option
                    v-for="(it,inde) in selectionConfig[item.param] || item.data || []"
                    :key="inde"
                    :label="it.value"
                    :value="it.key">
                  </el-option>
                </el-select>
<el-form-item>
{
          "type": "需要使用的条件类型 比如input或者selet等",
          "placeholder": "提示语",
          "label": "表单的label",
          "param": "接口接收此参数的字段名称"
        },

这里给一个对象params 接口需要的参数都会挂载到这个对象上 有些条件的选择是需要从接口拿回来数据的 那么拿回来的数据会统一挂载到selectionConfig对象上 相应的selectionConfig的key值最好和查询接口需要的key统一 这样有利于直接取值也比较有规律,要不写接口的人换一下就还得协商一次比较麻烦。当然这里我们也可以写一个转换器来转换拿回来的数据

{
        "接口需要的关键值key":"条件对应的关键值key",
        "id":"ids",
      },

选择的条件大多是从接口拿回来的数据那么配置里面肯定还有一个参数是回去条件的接口地址。这里为了方便处理我们默认一个页面只有一个获取条件的接口,不然接口多了要处理同步异步的话就比较麻烦 我们给这个信息取名为getSelectUrl 而他的转化器配置则为getSelectUrlConfig,
而那些需要实时搜索的下拉我们可以单独进行封装,然后给这个组件定义一个type remote
组件结构

<template>
    <el-select 
        clearable
        filterable
        remote
        :remote-method="getCreaterList"
        v-model="val" @change="$emit('input',val)" :placeholder="placeholder?placeholder:''">
        <el-option
        v-for="(item,index) in selectArr"
        :key="index"
        :label="item.value"
        :value="item.key">
        </el-option>
    </el-select>
</template>

组件js

<script>
import { api } from "@/api/api";
export default {
  props: {
    /**
     * 支持v-model形式绑定
     */
    value: {
      type: String,
      required: false
    },
    placeholder:{
      type: String,
      required: false
    },
    url:{
      type: String,
      required: true
    }
  },
  name: "employees",
  data() {
    return {
      selectArr: [],
      val:this.value || ""
    };
  },
  computed: {
  },
  methods: {
    /**
     * 多太获取列表数据
     *@param keyword  {String} 搜索关键字
     */
    getCreaterList(keyword) {
      if (!keyword || keyword.trim() == "") return false;
      let self = this;
      let config = {
        //请求需要的配置信息
      };
      setTimeout(() => {
        //请求处理
        self.selectArr = res.data.list || [];
        self.$restful.post(config, self, res => {
          if (res.code == 200) {
            self.selectArr = res.data|| [];
          }
        });
      }, 300);
    }
  }
};
</script>

那么条件配置也基本成型

{
          "type": "remote",
          "placeholder": "id",
          "label": "",
          "param": "id",
           //用来转换查询接口和最终参数的配置
          "transform":{
            "key":"admin_id",
            "value":"cn_name",
            "secondValue":"admin_name"
          }
          "url":"动态获取的url"
        },

处理当前列表是否默认查询

searchConfig.immediatelySearch = true;//true,默认进入页面就查询,false默认不查询

到这里基本需要配置也完成了
list 完整 代码

<!-- 查询列表模板 -->
<template>
  <el-container class="search__list_for_table">
    <el-main v-loading="pageLoading ||loading">
      <!-- 条件和搜索结果 若无直接 v-if="0" 或者直接删除-->
      <el-row class="select_conditions mgt10">
        <!--搜索条件部分 若无直接 v-if="0" 或者直接删除-->
        <el-row class="text-left el-collapse-item active" :class="!isShowMoreSearch?'active':''">
          <el-form :inline="true" :label-position="labelPosition" :model="params">
            <template >             
              <el-form-item :label="item.label" :key="index" v-for="(item,index) in formList">
                <!-- 挂载在 searchConfig.model对象上-->
                <el-input v-if="item.type=='input'||item.type==''" v-model="params[item.param]" :placeholder="item.placeholder"></el-input>
                <Employees v-if="item.type=='employees'" v-model="params[item.param]" :placeholder="item.placeholder"></Employees>
                <RemoteCommon :url="item.url" v-if="item.type=='remote'" :transform="item.transform" v-model="params[item.param]" :placeholder="item.placeholder"></RemoteCommon>
                <el-select :disabled="item.disabled" v-if="item.type=='select'" @change="search" clearable filterable v-model="params[item.param]" :placeholder="item.placeholder">
                  <el-option
                    v-for="(it,inde) in selectionConfig[item.param] || item.data || []"
                    :key="inde"
                    :label="it.value"
                    :value="it.key">
                  </el-option>
                </el-select>
                <el-cascader
                  v-if="item.type=='cascader'"
                  v-model="params[item.param]"
                  :options="selectionConfig[item.param] || item.data || []"    
                  :placeholder="item.placeholder"             
                  :change-on-select="item.changeOnSelect?true:false"
                  :props="{
                    value:'key',
                    label:'value'
                  }"
                ></el-cascader>
                <el-radio-group   @change="search" v-if="item.type=='radio_group'" v-model="params[item.param]" size="small">
                  <template>
                    <el-radio-button :label="it.key" :key="ind" v-for="(it,ind) in selectionConfig[item.param] || item.data">{{it.value}}</el-radio-button>
                  </template>
                </el-radio-group>
                <el-date-picker
                    v-if="item.type=='date_picker'"
                    v-model="params[item.param]"
                    size="mini"
                    style="width:280px"
                    @change="search"
                    type="daterange"
                    format="yyyy-MM-dd" 
                    value-format="yyyy-MM-dd"
                    :picker-options="pickerOptions"
                    :range-separator="$t('message.time.to')"
                    :start-placeholder="$t('message.time.start_time')"
                    :end-placeholder="$t('message.time.end_time')"
                    align="right">
                </el-date-picker>            
              </el-form-item>           
            </template>
            <el-form-item label="">
                <el-button type="primary"  @click="search">{{$t("message.button.search")}}</el-button>
                <el-button type="" @click="reset">{{$t("message.button.reset")}}</el-button>
                <!--导出Excel-->
                <el-button size="mini" type="" v-if="showMoreSearch"  @click="isShowMoreSearch = !isShowMoreSearch">{{$t("message.button.more")}} 
                        <i class="el-icon-arrow-up pd0" style="font-size:12px;" :class="!isShowMoreSearch?'spreed-up':'spreed-down'"></i>
                        </el-button>
                <el-button type="" v-if="searchConfig.exportUrl" @click="exportFn">
                    {{$t("message.closeAccount_button.export")}}{{searchConfig.exportUrl}}
                </el-button>                              
            </el-form-item>            
            <el-form-item label="" v-if="searchConfig.operations">
                <component @search="search" @setLoading="setLoading" :params ="params" :multipleSelection="multipleSelection" :is="components[searchConfig.operations]"></component>
            </el-form-item>         
          <!-- el-collapse-transition 若需要展开和收起不可以省略或者删除 -->
          <el-collapse-transition>
            <!-- 纯条件部分 默认展开 若无直接 v-if="0" 或者直接删除-->
            <div v-show="isShowMoreSearch" class="more-options ">
              <!-- 此处为条件根据实际项目情况填写内容 -->
              <template >             
                <el-form-item :label="item.label" :key="index" v-for="(item,index) in formListMore">
                  <!-- 挂载在 searchConfig.model对象上-->
                  <el-input v-if="item.type=='input'||item.type==''" v-model="params[item.param]" :placeholder="item.placeholder"></el-input>
                  <el-select :disabled="item.disabled" v-if="item.type=='select'" @change="search" clearable filterable v-model="params[item.param]" :placeholder="item.placeholder">
                    <el-option
                      v-for="(it,inde) in selectionConfig[item.param] || item.data || []"
                      :key="inde"
                      :label="it.value"
                      :value="it.key">
                    </el-option>
                  </el-select>
                  <Employees v-if="item.type=='employees'" v-model="params[item.param]" :placeholder="item.placeholder"></Employees>
                  <RemoteCommon :url="item.url" v-if="item.type=='remote'" :transform="item.transform" v-model="params[item.param]" :placeholder="item.placeholder"></RemoteCommon>
                  <el-cascader
                  v-if="item.type=='cascader'"
                  v-model="params[item.param]"
                  :options="selectionConfig[item.param] || item.data || []"
                  :placeholder="item.placeholder"                 
                  change-on-select
                  :props="{
                    value:'key',
                    label:'value'
                  }"
                ></el-cascader>
                  <el-radio-group   @change="search" v-if="item.type=='radio_group'" v-model="params[item.param]" size="small">
                    <template>
                      <el-radio-button :label="it.key" :key="ind" v-for="(it,ind) in selectionConfig[item.param] || item.data">{{it.value}}</el-radio-button>
                    </template>
                  </el-radio-group>
                  <el-date-picker
                      v-if="item.type=='date_picker'"
                      v-model="params[item.param]"
                      size="mini"
                      style="width:280px"
                      @change="search"
                      type="daterange"
                      format="yyyy-MM-dd" 
                      value-format="yyyy-MM-dd"
                      :picker-options="pickerOptions"
                      :range-separator="$t('message.time.to')"
                      :start-placeholder="$t('message.time.start_time')"
                      :end-placeholder="$t('message.time.end_time')"
                      align="right">
                  </el-date-picker>
                </el-form-item>           
              </template>
            </div>
          </el-collapse-transition>
          </el-form>
        </el-row>
        <!-- 需要展示的结果页面 不可以删除 没有结果 做什么搜索 -->
        <el-row class=" result__tabel">
          <!-- 表格展示区 如果是其他的内容不是表格就把下面换了吧 -->
          <!-- v-loading='loading' -->
          <el-table
            :data="listData"            
            style="width: 100%"
            :border="tableConfig.border?true:false"
            size="mini"
            :empty-text="$t('message.label.no_data')"
            :max-height="tableConfig.tableHeight?tableConfig.tableHeight:maxHeight"  
            @selection-change="handleSelectionChange"          
          >
            <el-table-column  v-if="tableConfig.selection" type="selection" width="55"></el-table-column>
            <el-table-column
              v-for="(item,index) in tableConfig.tableHeaderArr"
              :width="item.width || ''"
              :prop="item.key"
              :key="index"                          
              :label="item.value">
              <template slot-scope="scope">                
                <component @setLoading="setLoading" v-if="item.components" :data="scope.row"  @search="search" :is="components[item.components]"></component>                                
                <div v-else >
                    <el-popover v-if="item.showOverflowTooltip && scope.row[item.key]" trigger="hover" placement="top" :width="item.width || 300">
                      <p> {{ scope.row[item.key] }}</p>
                      <div slot="reference" class="name-wrapper" style="cursor:pointer;">
                        <el-tag size="medium"
                          :style="`max-width: ${item.width-10 || 280}px;overflow: hidden;text-overflow: ellipsis; white-space: nowrap;`"> <span> {{ scope.row[item.key] }}</span></el-tag>
                      </div>
                    </el-popover>
                    <div v-else v-html="scope.row[item.key]"></div>
                </div>
              </template>
            </el-table-column>
            <el-table-column :label="$t('message.label.operations')" v-if="tableConfig.operations" :width="tableConfig.operationsWidth||'200px'">
              <template slot-scope="scope">
                <component @setLoading="setLoading" :data="scope.row" @search="search"  :is="components[tableConfig.operations]"></component>
              </template>
            </el-table-column>
          </el-table>
          <!-- 页码处理模块 若无页码处理则直接省略 或者v-if="0" -->
          <el-row class="pdt40" v-if="tableConfig.isNeedPage!=false">
            <el-pagination
              @size-change="handleSizeChange"
              @current-change="handleCurrentChange"
              :current-page="page"
              :page-sizes="[20, 40, 60, 100]"
              :page-size="page_size"
              :total='page_info.total'
              layout="total, sizes, prev, pager, next, jumper"
              :page-count='Math.ceil(page_info.total/page_size)'
              style="text-align: right;"
              class="pt20"
            ></el-pagination>
          </el-row>
        </el-row>
      </el-row>
      <DownloadExcel ref="downloadExcel" :url="searchConfig.exportUrl"></DownloadExcel>
    </el-main>
  </el-container>
</template>

<script>
// 混合查询的方法
import { listSearchMixin } from "@/script/mixin/mixin";
import { api } from "@/api/api";
import { components } from "@/config/components";
import store from "@/store/store";
import DownloadExcel from "@/components/common/upload/downloadExcel";
import RemoteCommon from "@/components/common/remoteSearch/common";
import Employees from "@/components/common/remoteSearch/employees";
export default {
  // 组件名称
  name: "componentName",
  // 混合模式, 复用组件的内容
  mixins: [listSearchMixin],
  // 父子通信
  props: {},
  components: { DownloadExcel,Employees,RemoteCommon},
  watch: {},
  computed: {
    formList() {
      return this.searchConfig.formCom;
    },
    formListMore() {
      return this.searchConfig.formComMore;
    },
    // 是否需要收起展开搜索条件的 条件
    showMoreSearch() {
      return this.searchConfig.isShowMoreSearch ? true : false;
    },
    // 适配小屏幕显示器,列表页尽量在一个页面展示完
    maxHeight(){
      let height = document.body.clientHeight      
      return this.isShowMoreSearch ?parseInt(height*(height <= 800 ?0.45:0.6)):parseInt(height*(height <= 800 ?0.6:0.70))
    }
  },
  beforeOpen(resolve, reject) {
    // 组件实例化之前需要进行的操作-比如获取配置 这里以获取banner配置为例
    //store.dispatch("getBannerConfig").then(resolve); // 获取apponly的配置
    resolve();
  },
  // 数据绑定
  data() {
    return {
      //组件库
      components: components,
      // 页面缓冲
      pageLoading: false,
      // 查询条件
      selectionConfig: {},
      // 搜索配置
      /*
         * */
      // 查询地址
      searchUrl: "",
      // 配置地址
      configUrl: "",
      // 配置
      searchConfig: {
        export_url: api.closeAccDownloadExcel,
        // 当前操作部分组件名称
        operations: "starListOperations",
        // 是否显示多选框
        selection: true,
        // 接收参数的名称
        model: "params",
        // 搜索条件
        formCom: []
      },
      tableConfig: {
        // 最后操作组件名称
        operations: "starListOperations",
        // 当前表格高度
        tableHeight: 600,
        // 当前表格头部
        tableHeaderArr: [
          {
            value: "表格头显示的内容",
            key: "表格头对应的后端返回字段",
            width: "表格列的宽度",
            components: "当前列对应的组件名称"
          }
        ]
      },
      /*数据按照最简单模型, todo 下拉走接口。radio默认值处理*/
      // 查询参数 具体自定义内容
      params: {},
      paramsArr: [],
      //表格缓冲动画显示条件
      loading: false,
      // 展示更多控制区
      isShowMoreSearch: false,
      // 表格区多选后的结果存储数组
      multipleSelection: [],
      // 页码
      page: 1,
      // 一页显示多少条数据
      page_size: 20,
      // 接受后台返回的页数据
      page_info: {},
      // label对齐方式
      labelPosition: "left",
      // 连选日期快捷变量
      pickerOptions: {
        shortcuts: [
          {
            text: this.$t("message.time.in_seven"),
            onClick(picker) {
              const end = new Date();
              const start = new Date();
              start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
              picker.$emit("pick", [start, end]);
            }
          },
          {
            text: this.$t("message.time.in_fifteen"),
            onClick(picker) {
              const end = new Date();
              const start = new Date();
              start.setTime(start.getTime() - 3600 * 1000 * 24 * 15);
              picker.$emit("pick", [start, end]);
            }
          },
          {
            text: this.$t("message.time.in_month"),
            onClick(picker) {
              const end = new Date();
              const start = new Date();
              start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
              picker.$emit("pick", [start, end]);
            }
          }
        ]
      }
    };
  },
  // 方法 查询方法默认为 search方法 无需再次定义 直接使用即可
  methods: {
    /**
     * @desc 设置页面是否为缓冲状态
     * @param bool {Boolean}缓冲状态值
     */
    setLoading(bool){
      this.pageLoading = bool
    },
    // 重置查询条件 在这里重置查询条件吧
    reset() {
      this.params = Object.assign({},this.com.defaultParam ||{});
      // 页码
      this.page = 1;
      // 一页显示多少条数据
      this.page_size = 20;
    },
    /*
       * 获取参数,必须在组件定义 使用混合查询不可省略否则无法获取查询参数
       */
    getParams() {
      let self = this;
      // 若有查询条件需要判断的可以在此处判断
      let data = {};
      data =
        self.tableConfig.isNeedPage == false
          ? {
              ...self.params
            }
          : {
              ...self.params,
              ...{
                page_size: self.page_size,
                page: self.page
              }
            };
      return {
        url: api.baseUrl + self.searchUrl + api.token,
        contentType:self.searchConfig.searchContentType || "form",
        data: data
      };
    },
    // 导出Excel
    exportFn() {
      let self = this;
      let arr = [];
      for (let key in self.params) {
        let obj = {
          key: key,
          value: self.params[key]
        };
        arr.push(obj);
      }
      this.$refs["downloadExcel"].init(arr);
    },
    /**
     * 多选框操作
     *@param val  {Array} 当前选中的内容
     */
    handleSelectionChange(val) {
      this.multipleSelection = val;
    },
    // 刷新-通用方法
    refresh() {
      this.search();
    },
    init(config) {
      this.config = config;
    }
  },
  beforeCreate() {},
  created() {
    let self = this;
    self.pageLoading = true;
    new Promise((resolve, reject) => {
      let idx = self.com.configUrl.indexOf(".json");
      let url = "";
      if (idx > -1) {
        let lang = localStorage.getItem("lang") || "zh-CN"
        url = "/static/AUTOListConfig/"+
          self.com.configUrl.split(".json")[0] +
          lang +
          ".json";
      } else {
        url = api.getConfigOfList;
      }
      
      self.$restful.get(
        {
          url: url,
          param: {
            filename: idx == -1 ? self.com.configUrl : ""
          }
        },
        self,
        res => {
          if (res.code == 200) {
            self.tableConfig = res.data.tableConfig;
            self.searchConfig = res.data.searchConfig;
            self.searchUrl = res.data.searchConfig.searchUrl;
            let defaultParam = {};
            if(res.data.searchConfig.default){
              defaultParam = res.data.searchConfig.default
            }else if(self.com.defaultParam){
              defaultParam = JSON.parse(JSON.stringify(self.com.defaultParam))
            }
            if(defaultParam){
              self.params = Object.assign(defaultParam)
            }            
            if (res.data.searchConfig.getSelectUrl) {
              self.$restful.get(
                { url:api.baseUrl + res.data.searchConfig.getSelectUrl + api.token, param: res.data.searchConfig.getSelectParams||{} },
                self,
                resp => {
                  if (resp.code == 200) {
                    if(res.data.searchConfig.getSelectConfig){
                      let o =  res.data.searchConfig.getSelectConfig
                      for(let key in o){
                        self.selectionConfig[key] = resp.data[o[key]]
                      }
                      
                    }else{
                      self.selectionConfig = resp.data;
                    }
                    resolve(res.data.searchConfig.immediatelySearch?true:false);
                  } else {
                    reject();
                  }
                },
                error => {
                  reject();
                }
              );
            } else {
              resolve(res.data.searchConfig.immediatelySearch?true:false);
            }
          } else {
            reject();
          }
        },
        error => {
          reject();
        }
      );
    })
      .then(function(res) {
        self.pageLoading = false;
        res && self.search()
      })
      .catch(function(rej) {
        self.pageLoading = true;
      });
  },
  mounted() {
    let self = this;
  }
};
</script>

<style lang="less" rel="stylesheet/less">
</style>

配置模拟返回json文件

{
  "code": 200,
  "data": {
    "tableConfig": {
      "addConfigUrl":"",
      "addSaveUrl":"",
      "editSaveUrl":"",
      "detailUrl":"",
      "editConfigUrl":"",
      "operations": "labelListHandel",
      "isNeedPage":true,
      "border":false,
      "tableHeaderArr": [{
          "value": "在线邮寄方式",
          "key": "shipping_service",
          "width":""
        },
        {
          "value": "仓库",
          "key": "warehouse_name",
          "components": "",
          "width":"150"
        },
        {
          "value": "状态",
          "key": "is_use",
          "components":"changeStatus",
          "width":"200"
        },
        {
          "value": "更新人",
          "key": "oa_create_user_name",
          "width":"150"
        },
        {
          "value": "更新时间",
          "key": "edit_date",
          "width":"300"
        }
      ]
    },
    "searchConfig": {
      "isShowMoreSearch":false,
      "immediatelySearch":true,
      "exportUrl": "",
      "searchUrl":"/shipment/shippingList",
      "getSelectUrl":"/shipment/getSearchFields",
      "getSelectConfig":{
        "shipping_method_id":"shipping_method_list",
        "warehouse_id":"warehouse_list"
      },
      "getSelectParams":{
        "shipping_method_list":1,
        "warehouse_list":1,
        "country_list":1,
        "tag_list":1,
        "tag_type_list":1,
        "country_type_list":1
      },
      "default":{
        "status":"1"
      },
      "operations": "openLabelSearch",
      "operationsWidth":"300px",
      "model": "params",
      "formCom": [{
          "type": "select",
          "placeholder": "在线邮寄方式",
          "label": "",
          "param": "shipping_method_id"
        },
        {
          "type": "select",
          "placeholder": "仓库",
          "label": "",
          "param": "warehouse_id",
          "data": []
          
        },
        {
          "type": "select",
          "placeholder": "是否启用",
          "label": "",
          "param": "status",
          "data": [{
              "key": "1",
              "value": "是"
            },
            {
              "key": "0",
              "value": "否"
            }
          ]
        },
        {
          "type": "employees",
          "placeholder": "更新人",
          "label": "",
          "param": "admin_id"
        }
      ],
      "formComMore":[
        
      ]
    }

  }
}

image.png

默认的我们会把所有的组件挂载到这个对象上


image.png

以下是这个组件的示例 components.js

/**
 * 
 * @desc 列表操作部分使用import 引入 搜索操作使用 require 动态引入
 */
const listButton = r => require(['@/components/pages/hotManSystem/listButton'], r)
// 新增标签
const openLabelSearch = r => require(['@/components/pages/OADelivery/openLabelSearch'], r)
// 新增快递方式
const addMethodDelivery = r => require(['@/components/pages/OADelivery/addMethodDelivery'], r)
//列表内的组件一定要使用import的方式引入 如果动态引入第一次查询的时候将不会渲染组件
// 外部链接
import outLink from "@/components/common/link/outLink";
// 标签操作
import labelListHandel from "@/components/pages/OADelivery/labelListHandel";

// 
export const components = {
  // 公共的的组件
  outLink: outLink,
  "openLabelSearch": openLabelSearch,
  // 查看标签
  "labelListHandel": labelListHandel,
  //快递方式搜索新增
  "addMethodDelivery": addMethodDelivery,
  //列表操作组件
  "methodDeliveryOpptions": methodDeliveryOpptions,

}

在所有的自定义组件上 我们将会挂载列表页可能的数据到组件上 方便在调用到的子组件内使用 并定义回调方法


image.png
image.png

混合查询的通用方法searchMixin.js

/*
 * 列表搜索的 mixin
 */
import {
  resCode
} from '@/config/consts'
import {
  getExportFormComItem
} from '@/config/tools'
export const listSearch = {
  data () {
    return {
      // 加载中
      loading: false,
      // 页面的列表数据
      listData: []
    }
  },
  methods: {

    /*
     * 处理页面序号的变化
     */
    indexMethod (index) {
      if (this.page === 1 || this.page === 0) return index + 1
      return ((this.page - 1) * this.page_size) + index + 1
    },

    /*
     * 搜索函数
     */
    search () {
      let self = this
      let params = self.getParams()
      if (!params) return false
      self.loading = true
      let config = {
        url:params.url,
        loading:params.loading || "loading",
        contentType:params.contentType || "form",
        param:params.data || {}
      }
      // 若为单选则更新
      self.$restful.sendMyData(config,self, (res)=> {
        if(res.code === 200)
        self.listData = res.data.rows || []
        if (res.data.total || res.data.total ===0) {self.page_info.total = Number(res.data.total)}
      })
      // self.elForm 为导出组件的引用,如果有用到,需要在组件的mounted中定义如: self.elForm = self.$refs['elForm']
      // 调用导出插件的刷新函数
      // getExportFormComItem 的参数为【页面搜索的条件】,为 {} 类型
      self.elForm && self.elForm.refresh(getExportFormComItem(params.data))
    },

    /*
     * 改变页面显示的条数
     */
    handleSizeChange (page_size) {
      this.page_size = page_size
      this.search()
    },

    /*
     * 改变页码
     */
    handleCurrentChange (page) {
      this.page = page
      this.search()
    },

    /*
     * 获取参数,这个方法必须在组件中去覆盖,不然应该提示错误
     * 可以理解为后台的抽象函数
     */
    getParams () {
      let self = this
      self.$message.error('请在组件的methods中定义获取参数的方法 [ getParams ]')
      return false
    },
  }
}

合并混合查询方法
mixin.js

import { listSearch } from './searchMixin.js'
export const listSearchMixin = { 
    ...listSearch
}

以上就是简单的自动化配置列表的全部代码了 后面的可以根据具体的业务做条件和其他业务模块的扩展

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,457评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,837评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,696评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,183评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,057评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,105评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,520评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,211评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,482评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,574评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,353评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,897评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,489评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,683评论 2 335

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,051评论 25 707
  • 今天儿子感冒好多了,晚上去他舅舅家吃的饭,和妹妹玩的挺开心的,他舅妈今晚给安排了一个任务,明天负责给妹妹买古诗卡,...
    李宇航妈妈阅读 180评论 0 0
  • 付雨潇走的时候说:“你看看拐姐新签名——情深不寿,慧极必伤。” 1 事情还要从去年开始说起。 在我宿舍楼下,付雨潇...
    0bcd92bb2093阅读 903评论 4 10
  • 今天还和往常一样六点十分闹钟醒来和老公一起起床,老公洗漱过后做早饭,我帮儿子女儿找衣服,天气寒冷看着儿子穿衣服,帮...
    瞬间de回忆阅读 160评论 0 2