Vue 表格自定義樹形組件,行,列表可傳入等


1.組件,BaseTable 下有兩個文件,index.vue ,extend.js

index.vue代碼

<template>
  <div class="crud">
    <!--crud頭部,包含列表標題和可操作按鈕-->
    <el-row class="crud-header">
      <!--<el-col :span="8">{{formTitle}}列表</el-col>-->
      <el-col :span="24">
        <el-button type="success" size="mini" v-if="gridBtnConfig.create" @click="createOrUpdate(null)">
          <i class="el-icon-plus"></i> 新增
        </el-button>

        <!-- 標記為single的按鈕不需要禁用,不依賴選擇數據-->
        <el-button :disabled="!item.single && multipleSelection.length === 0" size="mini"
                   @click="handleEmit(item.emitName,'outer')"
                   v-for="(item,index) in outerButton" :key="index" :type="item.type?item.type:'primary'">
          <svg-icon v-if="item.icon" :icon-class="item.icon"></svg-icon>
          {{item.name}}
        </el-button>
        <el-button :disabled="multipleSelection.length === 0" size="mini" v-if="gridBtnConfig.delete" type="danger"
                   @click="remove(2)">
          <svg-icon icon-class="delete"></svg-icon>
          刪除
        </el-button>
      </el-col>
    </el-row>

    <!--crud主體內容區,展示表格內容-->
    <el-table
      ref="multipleTable"
      v-loading="listLoading" element-loading-text="請等待"
      :data="showGridData"
      @selection-change="handleSelectionChange"
      border
      :stripe="true"
      :header-cell-style="{'textAlign':'center'}"
      style="width: 100%">
      <el-table-column
        v-if="!hideMultiple"
        fixed="left"
        type="selection"
        width="55">
      </el-table-column>
      <el-table-column
        v-if="hideMultiple"
        fixed="left"
        label="序號"
        type="index"
        width="55">
      </el-table-column>
      <el-table-column
        v-for="(item,index) in gridConfig"
        :key="index"
        :prop="item.prop"
        :label="item.label"
        :align="nameLeft(item.label)"
        show-overflow-tooltip
        :width="item.width?item.width:''">
        <template slot-scope="scope">
          <span v-if="item.filter" ref="yifutian">{{walkProperty(item.prop,scope.row)||walkProperty(item.prop,scope.row)==0? item.filter(walkProperty(item.prop,scope.row)) : '--'}}</span>
          <Cell
            v-if="item.render"
            :row="scope.row"
            :column="item"
            :index="scope.$index"
            :render="item.render"></Cell>
          <span v-if="!item.render&&!item.filter">
            <span v-if="!item.template" ref="yifutian">{{walkProperty(item.prop,scope.row)||walkProperty(item.prop,scope.row)==0 ? walkProperty(item.prop,scope.row) : '--'}}</span>
            <a style="color: #1582cf;cursor: pointer;" v-else @click="handleEmit(item.emitName,'inner',scope.row)">{{walkProperty(item.prop,scope.row)||walkProperty(item.prop,scope.row)==0 ? walkProperty(item.prop,scope.row) : '--'}}</a>
          </span>
        </template>
      </el-table-column>
      <el-table-column v-if="!hideEditArea" label="操作" :width="gridEditWidth?gridEditWidth:200" fixed="right">
        <template slot-scope="scope">
          <el-tooltip v-if="gridBtnConfig.update" effect="dark" content="修改" placement="top">
            <span style="color: #409EFF" class="edit-icon" @click="createOrUpdate(scope.row)"><svg-icon
              icon-class="xg"></svg-icon></span>
          </el-tooltip>
          <el-tooltip v-if="gridBtnConfig.view" effect="dark" content="查看" placement="top">
            <span style="color: #409EFF" class="edit-icon" @click="viewDetail(scope.row)"><svg-icon
              icon-class="view"></svg-icon></span>
          </el-tooltip>
          <!--擴展按鈕,如果擴展按鈕設置了動態顯示隱藏的條件,則需要根據條件顯示隱藏-->
          <el-tooltip v-for="(item,index) in innerButton" :key="index" :type="item.type?item.type:'primary'"
                      v-if="(!item.hideJudge)||(item.hideJudge &&  walkProperty(item.hideJudge.key,scope.row) === item.hideJudge.val && (item.hideJudge.key2 ? walkProperty(item.hideJudge.key2,scope.row) === item.hideJudge.val2 : true))"
                      effect="dark" :content="item.name" placement="top">
            <span :style="{color:item.iconColor?item.iconColor:'#409EFF'}" class="edit-icon"
                  @click="handleEmit(item.emitName,'inner',scope.row)"><svg-icon
              :icon-class="item.icon?item.icon:'xg'"></svg-icon></span>
          </el-tooltip>
          <el-tooltip v-if="gridBtnConfig.singleDelete" effect="dark" content="刪除" placement="top">
            <span style="color: #F56C6C" class="edit-icon" @click="remove(1,scope.row)"><svg-icon
              icon-class="delete"></svg-icon></span>
          </el-tooltip>
        </template>
      </el-table-column>

    </el-table>

    <!--crud的分頁組件-->
    <div class="crud-pagination">
      <!--如果不是異步請求展示數據,需要隱藏分頁-->
      <el-pagination
        v-if="isAsync"
        @size-change="handleSizeChange"
        @current-change="handleCurrentChange"
        :current-page="currentPage"
        :page-sizes="pageSizes?pageSizes:[10, 20, 30, 40]"
        :page-size="currentPageSize"
        layout="total, sizes, prev, pager, next, jumper"
        :total="dataTotal">
      </el-pagination>
    </div>

    <!--crud按鈕觸發的表單彈窗-->
    <BaseDialogForm :width="dialogWidth" :label-width="dialogLabelWidth" :title="dialogTitle" ref="dialogForm"
                    :config="formConfig"
                    :form-data="formModel"
                    @submit="dialogSubmit"></BaseDialogForm>

    <!--查看詳情模態框-->
    <gx-dialog
      title="查看詳情"
      :visible.sync="detailDialogVisible"
      :width="dialogWidth ? dialogWidth : '1300px'">
      <ViewDetail :config="infoConfig?infoConfig:formConfig" :data="detailData"></ViewDetail>
    </gx-dialog>

    <el-dialog
      title="提示"
      :close-on-click-modal="false"
      :visible.sync="deletess"
      width="400px">
      <i class="el-icon-info" style="color:#E6A23C;"></i>
      <span>此操作將永久刪除數據, 是否繼續?</span>
      <span slot="footer" class="dialog-footer">
         <el-button type="primary" @click="deletes" size="mini">確 定</el-button>
         <el-button @click="qxss" size="mini">取 消</el-button>
      </span>
    </el-dialog>
  </div>
</template>

<script>
  import BaseDialogForm from '@/components/BaseDialogForm/index.vue'
  import ViewDetail from '@/components/ViewDetail/index.vue'
  import GxDialog from "../GxDialog/index"
  /*用render渲染自定義template*/
  import Cell from './expand';

  export default {
    name: "base-crud",
    components: {
      BaseDialogForm,
      ViewDetail,
      GxDialog,
      Cell
    },
    props: [
      //
      'pageSizes',
      // 表單標題,例如用戶、角色
      'formTitle',
      // 表單配置
      'formConfig',
      //詳情的字段配置
      'infoConfig',
      // 表單的model數據
      'formData',
      // 表格配置
      'gridConfig',
      // 表格按鈕配置
      'gridBtnConfig',
      // 表格死數據
      'gridData',
      // 數據接口
      'apiService',
      // 判斷是否是異步數據
      'isAsync',
      //  表格編輯區域寬度
      'gridEditWidth',
      //  是否隱藏表格操作
      'hideEditArea',
      // 自定義新增和修改操作,覆蓋組件內的新增和刪除邏輯
      'selfCreateAndUpdate',
      //是否顯示多選,若不顯示多選,則顯示列表序號
      'hideMultiple',
      //數據的id標識字符串
      'idKey',
      //表格獲取數據默認傳入的參數
      'gridParams',
      //
      'Update',
      //  禁止刪除的條件配置
      'forbiddenData',
      //  操作的模態框寬度
      'dialogWidth',
      // 操作模態框中的表單label寬度
      'dialogLabelWidth',
      //  狀態顏色區別配置數組:[[未處理],[已處理],[已過期],[其它狀態]]
      'statusobj'
    ],
    data() {
      return {
        // 新增修改模態框title
        dialogTitle: '',
        // 展示的表格數據,數據來源可能是父組件傳遞的固定數據,可能是接口請求數據
        showGridData: [],
        // 當前頁碼
        currentPage: 1,
        // 每頁顯示數量
        currentPageSize: 10,
        // 列表數據總數
        dataTotal: 0,
        // 選中行數據
        selectedRow: '',
        // 表單數據
        formModel: {},
        //  保留多選的表格數據
        multipleSelection: [],
        //  擴展按鈕,包括表格內按鈕和表格外的批量操作按鈕
        innerButton: [],
        outerButton: [],
        //  詳情數據
        detailData: {},
        detailDialogVisible: false,
        //  是否是新增
        isCreate: true,
        // 數據加載
        listLoading: false,
        //  查詢參數
        searchParams: {},
        //刪除的數據
        ids: [],
        //刪除的彈框
        deletess: false,
        color: true,
        statusObj: ''
      }
    },
    mounted() {
      //初始化擴展按鈕
      if (this.gridBtnConfig.expands && this.gridBtnConfig.expands.length > 0) {
        //內部按鈕,只操作單行數據
        this.innerButton = this.gridBtnConfig.expands.filter(item => item.editType === 'inner');
        //外部按鈕,操作批量數據
        this.outerButton = this.gridBtnConfig.expands.filter(item => item.editType === 'outer');
      }
      this.getData();
      this.statusObj = this.statusobj ? this.statusobj : [['未提交'], ['已提交', '已批復', '審批通過', '待上報', '已批復', '已撤回'], ['審核中', '返回修改'], ['已上報', '待批復'], ['審批不通過']];
    },
    methods: {
      nameLeft(name) {
        let a = name.substr(name.length - 2, 2);
        // console.log(name.indexOf('名稱'),a);
        if (a == '名稱') {
          return 'left'
        } else {
          return 'center'
        }
      },
      // 獲取列表數據
      getData() {
        this.listLoading = true;
        //沒有定義api,直接返回,不進行請求
        if (!this.apiService) {
          this.listLoading = false;
          this.showGridData = this.gridData;
          return;
        }
        let params = {
          current: this.currentPage,
          size: this.currentPageSize
        };

        params = Object.assign({}, params, this.gridParams, this.searchParams);

        this.apiService.list(params).then(res => {
          this.showGridData = res.page.list;
          this.dataTotal = res.page.totalCount;
          this.listLoading = false;
          //請求數據完成
          this.$emit('getDataOver', res.page.list);
        });
      },
      //查詢
      search(params) {
        this.currentPage = 1
        this.currentPageSize = 10
        this.searchParams = Object.assign({}, params);
        this.getData();
      },
      //清空查詢
      clearSearch() {
        this.searchParams = {};
        this.getData();
      },
      // 查看詳情
      viewDetail(row) {
        this.detailData = Object.assign({}, row);
        this.detailDialogVisible = true;
      },
      createOrUpdate(item) {
        // 如果配置了覆蓋組件內新增和修改按鈕時執行
        if (this.selfCreateAndUpdate) {
          this.$emit('createOrUpdate', item);
          return;
        }

        this.$refs.dialogForm.resetForm();

        this.formModel = item ? Object.assign({}, item) : Object.assign({}, this.formData);
        this.dialogTitle = (item ? '修改' : '新增') + this.formTitle;
        this.isCreate = !item;

        this.$refs.dialogForm.showDialog();
      },
      // 處理相應父組件的事件方法
      handleEmit(emitName, type, row) {
        // 如果是表格內按鈕,只需要回傳單行數據,表格外按鈕,則需要回傳批量數據
        if (type === 'inner') {
          this.$emit(emitName, row);
        }
        else {
          this.$emit(emitName, this.multipleSelection);
        }
      },
      handleCurrentChange(page) {
        this.currentPage = page;
        this.getData();
      },
      handleSizeChange(size) {
        this.currentPageSize = size;
        this.getData();
      },
      // 處理點擊行
      handleRowClick(row, event, column) {
        this.selectedRow = Object.assign({}, row);
      },
      // 模態框數據提交
      dialogSubmit(data) {
        if (this.Update) {
          this.$emit('Update', data);
          return;
        }
        this.apiService[this.isCreate ? 'create' : 'update'](data).then(res => {
          this.$message.success(this.dialogTitle + '成功!');
          this.getData();
          this.$refs.dialogForm.hideDialog();
        })
      },
      hideDialog() {
        this.$refs.dialogForm.hideDialog();
      },
      //處理多選改變時
      handleSelectionChange(val) {
        this.multipleSelection = val;
      },
      // 切換當前行的選中狀態
      toggleSelection(rows) {
        if (rows) {
          this.$nextTick(()=>{
            rows.forEach(row => {
              this.$refs.multipleTable.toggleRowSelection(row);
            });
          })
        } else {
          this.$refs.multipleTable.clearSelection();
        }
      },
      //刪除方法
      remove(type, data) {
        this.ids = [];

        //type為1代表單個刪除,2代表批量刪除
        if (type === 1) {
          this.ids = [data[this.idKey ? this.idKey : 'id']];
        } else {
          //如果上傳了禁止刪除的條件,進入下面條件處理
          if (this.forbiddenData) {
            let key = this.forbiddenData.key;
            let arr = this.forbiddenData.data;

            let boolean = false;
            this.multipleSelection.forEach(item => {
              arr.forEach(val => {
                if (val === item[key]) {
                  return (boolean = true);
                }
              });
              //如果已經有禁止刪除項,退出遍歷,優化性能
              if (boolean) {
                return false;
              }
            });

            if (boolean) {
              return this.$notify({
                title: '警告',
                message: '您選擇的數據包含禁止刪除項,請重新選擇數據進行刪除!!!',
                type: 'warning',
                position: 'top-left',
                duration: 2000
              });
            }
          }

          this.ids = this.multipleSelection.map(item => item[this.idKey ? this.idKey : 'id']);
        }

        // this.$confirm('此操作將永久刪除數據, 是否繼續?', '提示', {
        //   showCancelButton: true,
        //   confirmButtonText: '確定',
        //   cancelButtonText: '取消',
        //   confirmButtonClass:'confirmButtonClass',
        //   type: 'warning'
        // }).then(() => {
        //   this.apiService.delete(ids).then(res => {
        //     this.$message({
        //       type: 'success',
        //       message: '刪除成功!'
        //     });
        //
        //     this.getData();
        //   })
        // }).catch(() => {
        //   this.$message({
        //     type: 'info',
        //     message: '已取消刪除'
        //   });
        //
        //
        // });
        this.deletess = true
      },
      deletes() {
        this.apiService.delete(this.ids).then(res => {
          this.$message({
            type: 'success',
            message: '刪除成功!'
          });

          this.getData();
          this.deletess = false
        })

      },
      qxss() {
        this.deletess = false
        this.$message({
          type: 'info',
          message: '已取消刪除'
        });

      },

      walkProperty(prop, data) {
        //a.b
        if (prop && prop.indexOf('.') !== -1) {
          let path = prop.split('.'), i, v = data;//[a, b]
          while (i = path.shift()) {
            if (v && v[i]) {
              v = v[i];
            }
            else {
              v = '';
            }
          }
          return v;
        }
        else {
          return data[prop];
        }
      },
      //清空多選
      clearSelection() {
        //清空多選的選中
        this.$refs.multipleTable && this.$refs.multipleTable.clearSelection();
      },
      shangse() {
        let i = 1;
        let elementArrays = this.$refs.yifutian;
        if (!elementArrays) {
          return;
        }
        this.statusObj.forEach(obj => {
          obj.forEach(obj2 => {
            elementArrays.forEach(item => {
              let str = item.innerText;
              if (str === obj2) {
                item.setAttribute('class', 'class' + i);
              }
            })
          });
          i++;
        });
      },
      setGridParams(data) {
        this.search(data);
      }
    },
    watch: {
      // 防止表格預置數據不成功,涉及生命周期問題
      gridData() {
        this.showGridData = this.gridData;
        this.dataTotal = this.showGridData.length;
      },
      showGridData: function () {
        this.$nextTick(function () {
          this.shangse();
        })
      }
    },
  }

</script>
<style rel="stylesheet/scss" lang="scss" scoped>
  .crud {
    .crud-header {
      margin-bottom: 10px;
      line-height: 40px;
    }

    .crud-pagination {
      text-align: right;
      margin-top: 10px;
    }

    /*表格內編輯圖標*/
    .edit-icon {
      font-size: 20px;
      margin-right: 10px;
      cursor: pointer;
    }
    /*未處理*/
    .class1 {
      color: #999999;
      padding: 5px;
    }
    /*已處理*/
    .class2 {
      color: #06AC4D;
      padding: 5px;
    }
    /*已過期*/
    .class3 {
      color: #FBBE42;
      padding: 5px;
    }
    /*其它狀態*/
    .class4 {
      color: #3DB5FC;
      padding: 5px;
    }

    .class5 {
      color: #FC5454;
      padding: 5px;
    }
  }
</style>
<style>
  .confirmButtonClass {
    color: #fff;
    background-color: #0597D2 !important;
    border-color: #0597D2 !important;
  }

</style>

--extend.js代碼

export default {
    name: 'TableExpand',
    functional: true,
    props: {
        row: Object,
        render: Function,
        index: Number,
        column: {
            type: Object,
            default: null
        }
    },
    render: (h, ctx) => {
        const params = {
            row: ctx.props.row,
            index: ctx.props.index
        };
        if (ctx.props.column) params.column = ctx.props.column;
        return ctx.props.render(h, params);
    }
};

2.以上是兩個組件的代碼,下面將介紹調用及傳入數據的格式

--調用組件

引入組件,且注冊組件

import BaseTable from '@/components/BaseTable/index.vue'
注冊加入components
components: {
      BaseTable
    },

調用組件

 <BaseTable :api-service="informationApi" :grid-config="INFO_CONFIG.gridConfig"
                  :grid-btn-config="INFO_CONFIG.gridBtnConfig"
                  ref="crud" :grid-edit-width="80"
                  :is-async="true" :hide-edit-area="true">
        </BaseTable>

傳入數據的Js數據格式:

const INFO_CONFIG = {
  gridConfig: [
    {label: '設備代碼', prop: 'sbdm', width: '150'},
    {label: '設備名稱', prop: 'sbmc'},
    {label: '型號規格', prop: 'xh'},
    {label: '計量單位', prop: 'jldw', filter: equipmentUnitFilter},
    {label: '類型', prop: 'lx'},
    {label: '廠家', prop: 'cj'},
    {label: '是否是計量設備', prop: 'sfjlsb', filter: filterJLSB},
    {label: '籌供單位', prop: 'cgdw', filter: filterGCDW},
    {label: '使用年限(月)', prop: 'synx'},
  ],
  //操作按鈕
  gridBtnConfig: {
    create: false, update: false, delete: false, view: false
  }
}
注意informationApi:是API 調用地址,如果需要直接傳入數據,需要更組件中的邏輯,apiService傳入true,不需要請求數據,出入gridData=[],即表格顯示的數據,組件中傳入的參數都寫了注釋,根據需做出更改吧
關注博客,后期更新Vue表單組件。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2026 CODEPRJ.COM