vue+element-ui后臺(tái)系統(tǒng)實(shí)現(xiàn)可配置報(bào)表組件

背景:

目前在做的一個(gè)后臺(tái)系統(tǒng),因?yàn)橥度胧袌鍪褂茫_始有很多數(shù)據(jù)報(bào)表需求。頁面結(jié)構(gòu)大同小異,所以想將其模塊化,開發(fā)一個(gè)可復(fù)用的報(bào)表組件。因?yàn)槭呛笈_(tái)系統(tǒng),樣式只要求簡介不亂就行。

組件主要分三個(gè)模塊:

  • 條件查詢區(qū) + 按鈕
  • 表格數(shù)據(jù)顯示區(qū)
  • 分頁條區(qū)域

查詢條件和表格的列名通過配置傳入,頁面初始化時(shí)塞入配置。
表格具體動(dòng)態(tài)數(shù)據(jù)一般是通過請求,如需二次封裝在對應(yīng)頁面進(jìn)行處理

組件代碼

<!-- 可配置的動(dòng)態(tài)報(bào)表頁面 -->
<!--
  三個(gè)功能塊:條件查詢區(qū),列表數(shù)據(jù)區(qū),數(shù)據(jù)分頁區(qū)
 -->
<template>
 <div class="dynamic-report-mod">
   <el-card :body-style="{ padding: '10px' }">
     <el-row>
       <!--條件查詢區(qū)域 -->
       <el-col class="dynamic-search" :span="24" align="left">
         <!-- 參數(shù)配置 -->
         <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="序號(hào)" 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', //查詢條件和返回結(jié)果列信息
        'tableData', //查詢結(jié)果 需拼接對應(yīng)的操作按鈕
        'tableLoading',//表格加載狀態(tài)
        'showPage',//是否需要分頁
        'total', //分頁條參數(shù)-總條數(shù)
        'currentPage',  //分頁條參數(shù)-頁數(shù)
        'limit', //分頁條參數(shù)-分頁條數(shù)
        'query',  //查詢條件對象封裝
        'listenHandleClickQueryBtn',    //查詢條件區(qū) 按鈕事件監(jiān)聽
        'listenHandleClickTableOptBtn', //表格操作區(qū) 按鈕事件監(jiān)聽
        'listenHandlePageSizeChange', //分頁條數(shù)監(jiān)聽
        'listenHandlePageCurrentChange'   //分頁碼修改
    ],
    data() {
        return {
            curPage: this.currentPage,
            curLimit: this.limit
        }
    },
    methods: {
        //查詢區(qū)域 事件監(jiān)聽
        handleClickQueryBtn(queryKey) {
            this.$emit('listenHandleClickQueryBtn', queryKey)
        },

        //表格區(qū)域 操作按鈕 事件監(jiān)聽
        handleClickTableOptBtn(columnKey, row) {
            this.$emit('listenHandleClickTableOptBtn', columnKey, row)
        },
        //每頁條數(shù) 修改事件監(jiān)聽
        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>

備注:因報(bào)表的標(biāo)題行存在二級,后續(xù)對el-table-column做過相應(yīng)的邏輯判斷和代碼調(diào)整。分頁條里的page-sizes和layout參數(shù)放在全局變量,也可參考element api寫死處理。代碼的注釋說明寫的還是比較詳細(xì)的,如有不明白的問題可留言

組件使用Demo

demo是一個(gè)普通報(bào)表,篩選條件僅時(shí)間區(qū)間框【僅可選昨日以前的日期】,列表無操作按鈕僅數(shù)據(jù)展示,且無分頁數(shù)據(jù)。后續(xù)擴(kuò)展按照初始配置依樣畫葫蘆即可!

<!-- 綜合統(tǒng)計(jì)報(bào)表 -->
<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("請先選擇時(shí)間!");
            return false;
          }
          _this.loading = true;

          _params.startTime = _params.datePeriod[0]
          _params.endTime = _params.datePeriod[1];
          //====S 此處為數(shù)據(jù)請求   具體代碼刪除 此處僅做賦值操作
           _this.tableData = [{'aaa':'111','bbb':'222','ccc':'333','ddd':'444'}]
           _this.loading = false;
           //====E 此處為數(shù)據(jù)請求   具體代碼刪除 此處僅做賦值操作
        }
    },
    created(){
      //初始化報(bào)表配置數(shù)據(jù)
      this.list ={
        queryList: [
              {
                  label: '時(shí)間周期',
                  key: 'datePeriod',
                  type: 'datePicker',
                  config: {
                      type: 'daterange',
                      rangeSeparator: '-',
                      startPlaceholder: '開始日期',
                      endPlaceholder: '結(jié)束日期',
                      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>
效果預(yù)覽

做完后可以用類似的思維進(jìn)行表單的動(dòng)態(tài)配置,單獨(dú)table渲染的配置等

完...

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容