美文网首页Vue.js前端Vue专辑
vue+element-ui后台系统实现可配置报表组件

vue+element-ui后台系统实现可配置报表组件

作者: Ever月亮 | 来源:发表于2019-11-27 15:28 被阅读0次
    背景:

    目前在做的一个后台系统,因为投入市场使用,开始有很多数据报表需求。页面结构大同小异,所以想将其模块化,开发一个可复用的报表组件。因为是后台系统,样式只要求简介不乱就行。

    组件主要分三个模块:

    • 条件查询区 + 按钮
    • 表格数据显示区
    • 分页条区域

    查询条件和表格的列名通过配置传入,页面初始化时塞入配置。
    表格具体动态数据一般是通过请求,如需二次封装在对应页面进行处理

    组件代码

    <!-- 可配置的动态报表页面 -->
    <!--
      三个功能块:条件查询区,列表数据区,数据分页区
     -->
    <template>
     <div class="dynamic-report-mod">
       <el-card :body-style="{ padding: '10px' }">
         <el-row>
           <!--条件查询区域 -->
           <el-col class="dynamic-search" :span="24" align="left">
             <!-- 参数配置 -->
             <template v-for="item in list.queryList">
               <!-- 查询按钮 -->
               <el-button v-if="item.type==='button'" :type="item.config.type" @click="handleClickQueryBtn(item.key)">{{ item.label }}</el-button>
    
               <el-input v-if="item.type==='input'" v-model="query[item.key]" type="text" :placeholder="item.config.placeholder" clearable></el-input>
    
               <template v-if="item.type==='select'">
                 {{item.label}}
                 <el-select v-model="query[item.key]" :placeholder="item.config.placeholder" clearable>
                   <el-option
                     v-for="option in item.options"
                     :key="option.key"
                     :label="option.val"
                     :value="option.key">
                   </el-option>
                 </el-select>
               </template>
    
               <template v-if="item.type==='datePicker'">
                 {{item.label}}
                 <el-date-picker v-model="query[item.key]" :range-separator="item.config.separator" :value-format="item.config.format" :type="item.config.type" :placeholder="item.config.placeholder" :start-placeholder="item.config.startPlaceholder" :end-placeholder="item.config.endPlaceholder":picker-options="item.config.pickerOption"/>
               </template>
             </template>
           </el-col>
         </el-row>
    
         <el-row style="margin-top:10px;">
           <!-- 表格查询模块 -->
           <el-table class="dynamic-table" v-loading="tableLoading" border :data="tableData" style="width: 100%" size='mini'>
             <!-- <el-table-column type="index" label="序号" align="center"></el-table-column> -->
             <template v-for="item in list.tableColumns">
               <el-table-column align="center" :prop="item.key" :label="item.label" min-width="80" :key="Math.random()">
                 <template slot-scope="scope">
                   <el-button v-if="item.type === 'event'" type="primary" size="mini" @click="handleClickTableOptBtn(item.key, scope.row)" plain>{{item.name}}</el-button>
                   <span v-else-if="item.type==='text'">{{scope.row[item.key]}}</span>
                 </template>
               </el-table-column>
             </template>
           </el-table>
    
           <!-- 分页条模块 -->
           <el-row v-if="showPage" type="flex" justify="center" class="list-pagination" style="margin-top:10px;">
             <el-pagination
               background
               @size-change="handlePageSizeChange"
               @current-change="handlePageCurrentChange"
               :current-page.sync="curPage"
               :page-sizes="$store.state.app.page.size"
               :page-size="curLimit"
               :layout="$store.state.app.page.layout"
               :total="total">
             </el-pagination>
           </el-row>
         </el-row>
       </el-card>
     </div>
    </template>
    <script>
    export default {
        props: [
            'list', //查询条件和返回结果列信息
            'tableData', //查询结果 需拼接对应的操作按钮
            'tableLoading',//表格加载状态
            'showPage',//是否需要分页
            'total', //分页条参数-总条数
            'currentPage',  //分页条参数-页数
            'limit', //分页条参数-分页条数
            'query',  //查询条件对象封装
            'listenHandleClickQueryBtn',    //查询条件区 按钮事件监听
            'listenHandleClickTableOptBtn', //表格操作区 按钮事件监听
            'listenHandlePageSizeChange', //分页条数监听
            'listenHandlePageCurrentChange'   //分页码修改
        ],
        data() {
            return {
                curPage: this.currentPage,
                curLimit: this.limit
            }
        },
        methods: {
            //查询区域 事件监听
            handleClickQueryBtn(queryKey) {
                this.$emit('listenHandleClickQueryBtn', queryKey)
            },
    
            //表格区域 操作按钮 事件监听
            handleClickTableOptBtn(columnKey, row) {
                this.$emit('listenHandleClickTableOptBtn', columnKey, row)
            },
            //每页条数 修改事件监听
            handlePageSizeChange(val) {
                this.curPage = 1
                this.curLimit = val
                this.$emit('listenHandlePageSizeChange', val)
            },
            handlePageCurrentChange(val) {
                this.curPage = val
                this.$emit('listenHandlePageCurrentChange', val)
            }
        }
    }
    </script>
    <style>
    .dynamic-report-mod{
      margin:10px;
    }
    .dynamic-search .el-button,
    .dynamic-search .el-input,
    .dynamic-search .el-date-editor,
    .dynamic-search .el-select{
      margin-left:10px;
    }
    </style>
    

    备注:因报表的标题行存在二级,后续对el-table-column做过相应的逻辑判断和代码调整。分页条里的page-sizes和layout参数放在全局变量,也可参考element api写死处理。代码的注释说明写的还是比较详细的,如有不明白的问题可留言

    组件使用Demo

    demo是一个普通报表,筛选条件仅时间区间框【仅可选昨日以前的日期】,列表无操作按钮仅数据展示,且无分页数据。后续扩展按照初始配置依样画葫芦即可!

    <!-- 综合统计报表 -->
    <template>
      <dynamicReport
        :list="list"
        :query="query"
        :tableLoading="loading"
        :tableData="tableData"
        :showPage="showPage"
        :currentPage="currentPage"
        :limit="limit"
        :total="total"
        @listenHandleClickQueryBtn="handleClickQueryBtn"
        @listenHandleClickTableOptBtn="handleClickTableOptBtn"
        @listenHandlePageSizeChange="handlePageSizeChange"
        @listenHandlePageCurrentChange="handlePageCurrentChange"
      ></dynamicReport>
    </template>
    <script>
    import dynamicReport from '@/components/query/dynamic-report'
    export default {
        name: "StatisticReport",
        components: {
            dynamicReport
        },
        data() {
            return {
                showPage:false,
                currentPage: 1,
                limit: 10,
                total: 0,
                loading:false,
                tableData: [],
                list:{},
                query:{}
            }
        },
        methods: {
            handleClickQueryBtn(_type) {
                if (_type === 'query') {
                    this.handleClickQuery()
                }
            },
            handleClickTableOptBtn(_type, rowInfo) {
                console.log('click column '+_type)
            },
            handlePageSizeChange(size) {
                this.currentPage = 1
                this.limit = size
                this.handleClickQuery()
            },
            handlePageCurrentChange(num) {
                this.currentPage = num
                this.handleClickQuery()
            },
    
            async handleClickQuery() {
              const _this = this;
              let _params = {..._this.query};
              if(_params.datePeriod.length==0){
                _this.$message.error("请先选择时间!");
                return false;
              }
              _this.loading = true;
    
              _params.startTime = _params.datePeriod[0]
              _params.endTime = _params.datePeriod[1];
              //====S 此处为数据请求   具体代码删除 此处仅做赋值操作
               _this.tableData = [{'aaa':'111','bbb':'222','ccc':'333','ddd':'444'}]
               _this.loading = false;
               //====E 此处为数据请求   具体代码删除 此处仅做赋值操作
            }
        },
        created(){
          //初始化报表配置数据
          this.list ={
            queryList: [
                  {
                      label: '时间周期',
                      key: 'datePeriod',
                      type: 'datePicker',
                      config: {
                          type: 'daterange',
                          rangeSeparator: '-',
                          startPlaceholder: '开始日期',
                          endPlaceholder: '结束日期',
                          format:"yyyyMMdd",
                          pickerOption:{
                            disabledDate(time) {
                              return time.getTime() > Date.now()-24*60*60*1000;
                            }
                          }
                      },
                  },
                  {
                      label: '查询',
                      key: 'query',
                      type: 'button',
                      config: {
                          type: 'primary'
                      }
                  }
              ],
              tableColumns: [
                  {
                      label: '字段1',
                      key: 'aaa',
                      type:"text"
                  },
                  {
                      label: '字段2',
                      key: 'bbb',
                      type:"text"
                  },
                  {
                      label: '字段3',
                      key: 'ccc',
                      type:"text"
                  },
                  {
                      label: '字段4',
                      key: 'ddd',
                      type:"text"
                  }
              ]
            }
    
          //初始化查询条件
          this.query = this.list.queryList.reduce((obj, item) => {
              if (item.type !== 'button') {
                  obj[item.key] = ''
              }
              return obj;   //返回的是 {datePeriod:""}
          }, {})
        }
    }
    </script>
    
    效果预览

    做完后可以用类似的思维进行表单的动态配置,单独table渲染的配置等

    完...

    相关文章

      网友评论

        本文标题:vue+element-ui后台系统实现可配置报表组件

        本文链接:https://www.haomeiwen.com/subject/sxrywctx.html