vue表格封装——动态展示表格列、多条件查询


以下代码有部分是看开源eladmin-web项目改写的,不足之处请大家多多指教,共同学习。
eladmin-web项目地址:https://github.com/elunez/eladmin
1、 index.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
<template>
  <div class="app-container">
    <!-- 多条件查询组件 -->
    <queryForm ref="queryForm" />
    <!-- 筛选组件 -->
    <buttonGroup :table-columns="tableColumns" @initCol="initCol" @toQuery="toQuery" @refresh="refresh"/>
    <!--表格组件-->
    <tables ref="table" :loading="loading" :data="data" :table-columns="tableColumns" :height="height" @clickRow="clickRow" @selectData="selectData" @edit="edit" />
    <!--分页组件-->
    <el-pagination
      :total="total"
      :current-page="page + 1"
      :page-sizes="[20, 40, 80, 100]"
      :page-size="size"
      style="margin-top: 8px;"
      layout="total, prev, pager, next, sizes"
      @size-change="sizeChange"
      @current-change="pageChange"/>
  </div>
</template>
<script>
import tables from '@/components/ViewComponents/table'// 引入组件
import buttonGroup from '@/components/ViewComponents/buttonGroup' // 筛选组件
import queryForm from './multiQuery' // 多条件查询组件
import initData from '@/mixins/requestInit'
export default {
  // 注册组件
  components: { tables, buttonGroup, queryForm },
  mixins: [initData],
  data() {
    return {
      height: 625,
      columns: this.obColumns(),
      tableColumns: [{
        hasSort: false,
        isShow: true,
        prop: 'number',
        label: '数量',
        align: 'center',
        mwidth: 100
      }, {
        hasSort: false,
        isShow: true,
        prop: 'materialCoded',
        label: '物料编码',
        align: 'center',
        mwidth: 100
      }, {
        hasSort: false,
        isShow: true,
        prop: 'failureCause',
        label: '故障原因',
        align: 'center',
        mwidth: 100
      }, {
        hasSort: false,
        isShow: true,
        prop: 'returnReson',
        label: '退库理由',
        align: 'center',
        mwidth: 100
      }]
    }
  },
  created() {
    this.$nextTick(() => {
      this.height = document.documentElement.clientHeight - 240
    })
    this.init()
  },
  methods: {
    beforeInit() {
      this.url = 'api/repairRequest'
      const sort = 'id,desc'
      this.params = { page: this.page, size: this.size, sort: sort }
      return true
    },
    // 双击编辑
    edit() {
      console.log(arguments[0], '表格编辑数据')
    },
    // 表格多选
    selectData(arr) {
      console.log(arr, '表格组件返回值')
    },
    // 表格单选
    clickRow(row, event, column) {
      console.log('单击表格行数据')
    },
    // 条件查询
    toQuery() {
      this.$refs.queryForm.dialog = true
    },
    // 刷新
    refresh() {
      this.init()
    },
    initCol() {
      const that = this.$refs.table
      that.initCol(arguments[0])
    },
    obColumns(columns) {
      return {
        visible(col) {
          return !columns || !columns[col] ? true : columns[col].visible
        }
      }
    }
  }
}
</script>

2、表格组件(table.vue)
在这里插入图片描述

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
<template>
  <div style="padding-top:30px;">
    <el-table
      v-loading="loading"
      ref="table"
      :data="data"
      :height="height"
      :span-method="arraySpanMethod"
      :row-class-name="tableRowClassName"
      resizable
      border
      style="width: 100%"
      @filter-change="handleFilterChange"
      @row-click="clickRow"
      @row-dblclick="edit"
      @selection-change = "selectData">
      <!-- 明细 -->
      <el-table-column
        type="selection"
        width="40"/>
      <!--数据源-->
      <el-table-column
        v-for="(column, index) in tableColumns"
        v-if="columns.visible(`${column.prop}`)"
        :sortable="column.hasSort"
        :key="index"
        :prop="column.prop"
        :label="column.label"
        :align="column.align"
        :width="column.width"
        :min-width="column.mwidth"
        header-align="center">
        <template slot-scope="scope">
          <span v-if="column.prop === 'returnDate'" >{{ parseTime1(scope.row.returnDate) }}</span>
          <span v-else-if="column.prop === 'demandTime'" >{{ parseTime1(scope.row.demandTime) }}</span>
          <template v-else>
            <span>{{ scope.row[column.prop] }}</span>
          </template>
        </template>
      </el-table-column>
    </el-table>
  </div>
</template>
<script>
import { parseTime1 } from '@/utils/index'
import Vue from 'vue'
export default {
  filters: {
    getStatus(val) {
      switch (val) {
        case 0:
          return '未审'
        case 1:
          return '一审'
        case 2:
          return '二审'
      }
    }
  },
  props: {
    loading: {
      type: Boolean,
      default: () => false
    },
    data: {// 表格数据源 默认为空数组
      type: Array,
      default: () => []
    },
    tableColumns: {// 表格的字段展示 默认为空数组
      type: Array,
      default: () => []
    },
    height: {// 表格高度
      type: Number,
      default: () => 625
    },
    formatter: {// 单据信息行数据显示
      type: Function,
      default: () => {
        return
      }
    }
  },
  data() {
    return {
      columns: this.obColumns(),
      listLoading: false,
      visible: false,
      delLoading: false,
      rowIds: [],
      deleteIds: [],
      detailIds: [],
      isAdd: true,
      multipleSelection: []
    }
  },
  created() {
    this.$nextTick(() => {
      this.initColData()
    })
  },
  methods: {
    parseTime1,
    initColData() {
      const columns = {}
      this.$refs.table.columns.forEach(e => {
        if (!e.property || e.type !== 'default') {
          return
        }
        columns[e.property] = {
          label: e.label,
          visible: true
        }
      })
      this.columns = this.obColumns(columns)
      this.updateProp('tableColumns', columns)
    },
    initCol(columns) {
      this.columns = this.obColumns(columns)
      this.updateProp('tableColumns', columns)
    },
    handleCurrentChange(row) {
      this.currentRow = JSON.parse(JSON.stringify(row))
    },
    // 选择改变
    selectionChangeHandler(val) {
      this.selections = val
    },
    obColumns(columns) {
      return {
        visible(col) {
          return !columns || !columns[col] ? true : columns[col].visible
        }
      }
    },
    // Vue.set( target, key, value )
    // 在对象上设置一个属性。如果属性还不存在,则添加新属性并触发更改通知
    // target:要更改的数据源(可以是对象或者数组)
    // key:要更改的具体数据
    // value :重新赋的值
    updateProp(name, value) {
      console.log(name === 'tableColumns', 'name名字', value)
      // const table = this.$refs.table
      Vue.set(this.tableColumns, name, value)
    },
    // 表头点击
    handleFilterChange() {
      console.log(arguments, '表头点击')
    },
    // 双击编辑
    edit() {
      this.$emit('edit', arguments[0])
    },
    // 单击行时触发方法
    clickRow(row, event, column) {
      // this.$emit('clickRow', row, event, column)
      this.$refs.table.clearSelection()
      const index = this.rowIds.indexOf(row.id)
      if (index === -1) {
        this.$refs.table.toggleRowSelection(row, true)
      } else {
        this.rowIds = []
        this.$refs.table.toggleRowSelection(row, false)
      }
    },
    // 多选改变时触发方法
    selectData(arr) {
      this.multipleSelection = arr
      this.$emit('selectData', arr)
    },
    // 合并表格行
    arraySpanMethod({ row, column, rowIndex, columnIndex }) {
      const length = this.tableColumns.length + 2
      if (columnIndex === 0 && this.dataSource[rowIndex].isShow) {
        return [1, length]
      }
      for (let i = 1; i < length; i++) {
        if (columnIndex === i && this.dataSource[rowIndex].isShow) {
          return [1, 0]
        }
      }
    },
    // 斑马纹表格样式
    tableRowClassName({ row, rowIndex }) {
      let color = ''
      if (rowIndex % 2 === 0) {
        color = 'warning-row'
      } else {
        color = 'success-row'
      }
      if (row.isShow) {
        color = 'table-row'
      }
      for (let i = 0; i < this.multipleSelection.length; i++) {
        if (row === this.multipleSelection[i]) {
          color = 'select-row'
        }
      }
      return color
    }
  }
}
</script>
<style lang="scss">
@import "@/styles/table.scss";
</style>

3、筛选列、刷新、查询按钮组件(multiQuery.vue)
在这里插入图片描述

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
<template>
  <div class="buttonGroup-box">
    <el-button-group class="crud-opts-right">
      <el-button size="mini" icon="el-icon-search" @click="toQuery"/>
      <el-button size="mini" icon="el-icon-refresh" @click="refresh"/>
      <el-popover placement="bottom-end" width="150" trigger="click">
        <el-button slot="reference" size="mini" icon="el-icon-s-grid">
          <i class="fa fa-caret-down" aria-hidden="true"/>
        </el-button>
        <el-checkbox v-model="allColumnsSelected" :indeterminate="allColumnsSelectedIndeterminate" @change="handleCheckAllChange">全选</el-checkbox>
        <el-checkbox v-for="(item,index) in tableColumns" :key="index" v-model="item.visible" @change="handleCheckedTableColumnsChange(item)"> {{ item.label }}</el-checkbox>
      </el-popover>
    </el-button-group>
  </div>
</template>
<script>
export default {
  props: {
    tableColumns: {// 表格数据源 默认为空数组
      type: Array,
      default: () => []
    }
  },
  data() {
    return {
      allColumnsSelected: true,
      allColumnsSelectedIndeterminate: false
    }
  },
  methods: {
    handleCheckAllChange(val) {
      if (val === false) {
        this.allColumnsSelected = true
        return
      }
      for (const key in this.tableColumns) {
        this.tableColumns[key].visible = val
      }
      this.allColumnsSelected = val
      this.allColumnsSelectedIndeterminate = false
    },
    handleCheckedTableColumnsChange(item) {
      let totalCount = 0
      let selectedCount = 0
      for (const key in this.tableColumns) {
        ++totalCount
        selectedCount += this.tableColumns[key].visible ? 1 : 0
      }
      if (selectedCount === 0) {
        this.$notify({
          title: '请至少选择一列',
          type: 'warning',
          duration: 2500
        })
        this.$nextTick(function() {
          item.visible = true
        })
        return
      }
      this.allColumnsSelected = selectedCount === totalCount
      this.allColumnsSelectedIndeterminate = selectedCount !== totalCount && selectedCount !== 0
      const columns = {}
      this.tableColumns.forEach(e => {
        columns[e.prop] = {
          label: e.label,
          visible: e.visible === true
        }
      })
      this.$emit('initCol', columns)
    },
    toQuery() {
      this.$emit('toQuery')
    },
    refresh() {
      this.$emit('refresh')
    }
  }
}
</script>
<style scoped>
.el-button--mini {
    padding: 7px 15px;
    font-size: 14px;
    border-radius: 3px;
}
.buttonGroup-box{
  float: right;
}
</style>

4、多条件查询组件(queryForm.vue)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
<template>
  <!-- <div class="app-container" style="height:800px"> -->
  <el-dialog :append-to-body="true" :close-on-click-modal="false" :before-close="cancel" :visible.sync="dialog" :title="form.table" center width="800px" @open="getCondition">
    <div sclass="button-row" style="margin-top:10px">
      <template>
        <el-button size="mini" type="primary" icon="el-icon-plus" @click="insertEvent">添加查询条件</el-button>
        <el-button size="mini" type="success" icon="el-icon-search" @click="doSubmit" >查询</el-button>
        <el-button size="mini" type="primary" @click="reset" >重置</el-button>
        <el-button type="text" @click="cancel">关闭</el-button>
      </template>
    </div>
    <!-- 表格 -->
    <vxe-table
      ref="queryTable"
      :data="form.conditionVoList"
      :edit-config="{trigger: 'click', mode: 'cell'}"
      show-overflow
      resizable
      max-height="400"
      @edit-actived="editActivedEvent"
      @cell-click="increase">
      <vxe-table-column name="icon" fixed="left" width="60" title="删除" >
        <template slot-scope="scope" >
          <svg-icon icon-class="delete" @click.native="deleteRow(scope.row)" />
        </template>
      </vxe-table-column>
      <vxe-table-column :edit-render="{name: 'input', attrs: {disabled: false}}" width="140" field="associate" title="条件间联系" >
        <template v-if="form.conditionVoList.indexOf(scope.row)!==0 " slot-scope="scope" >
          <el-select v-model="scope.row.associate" placeholder="请选择" @change="autoAdd(scope.row)">
            <el-option
              v-for="item in associates"
              :disabled="form.conditionVoList.indexOf(scope.row)===0"
              :key="item.value"
              :label="item.label"
              :value="item.value"/>
          </el-select>
        </template>
      </vxe-table-column>
      <vxe-table-column :edit-render="{name: 'input', attrs: {disabled: false}}" min-width="140" field="column" title="查询条件"/>
      <vxe-table-column :edit-render="{name: 'input', attrs: {disabled: false}}" width="140" field="type" title="条件值关系" >
        <template slot-scope="scope">
          <el-select v-model="scope.row.type" placeholder="请选择">
            <el-option
              v-for="item in types"
              :key="item.value"
              :label="item.label"
              :value="item.value"/>
          </el-select>
        </template>
      </vxe-table-column>
      <vxe-table-column :edit-render="{name: 'input', attrs: {disabled: false}}" min-width="140" field="value" title="查询值" />
    </vxe-table>

    <template>
      <!-- 查询返回列表 -->
      <el-table
        v-loading="listLoading"
        v-if="query"
        ref="refTable"
        :data="columns"
        height="200px"
        resizable
        border
        style="width: 100%">
        <!-- 单据 -->
        <el-table-column prop="name" width="350px" label="姓名" />
        <el-table-column prop="age" width="350px" label="年龄" />
      </el-table>
    </template>
  </el-dialog>
  <!-- </div> -->
</template>

<script>
import pSelect from '@/components/ViewComponents/select'
import personSelect from '@/components/ViewComponents/select'
import request from '@/utils/request'
export default {
  components: { pSelect, personSelect },
  props: {
  },
  data() {
    return {
      query: false,
      loading: false,
      dialog: false,
      columns: [],
      form: {
        table: 'test',
        conditionVoList: []
      },
      types: [
        {
          label: '大于',
          value: 'gt'
        },
        {
          label: '等于',
          value: 'eq'
        },
        {
          label: '小于',
          value: 'lt'
        }, {
          label: '包含',
          value: 'like'
        }
      ],
      associates: [
        {
          label: '并且',
          value: 'and'
        },
        {
          label: '或者',
          value: 'or'
        }
      ]
    }
  },
  // created() {
  //   this.insertEvent()
  // },
  mounted() {
    this.insertEvent()
    this.insertEvent()
  },
  methods: {
    // 打开dialog的回调方法
    getCondition() {
      this.form.conditionVoList = [{
        column: 'name',
        type: 'like',
        value: '小',
        associate: ''
      }]
    },
    // 增加行
    insertEvent() {
      this.form.conditionVoList.push({
        column: '',
        type: '',
        value: '',
        associate: ''
      })
    },
    // vxe表格   单元格点击事件
    increase(data) {
      const index = this.form.conditionVoList.indexOf(data.row)
      const length = this.form.conditionVoList.length
      if ((index === length - 1) && data.row.value !== '') {
        this.insertEvent()
      }
    },
    // 条件联系选择后就自动增加行
    autoAdd() {
      const index = this.form.conditionVoList.indexOf(arguments[0])
      const length = this.form.conditionVoList.length
      if (index === length - 1) {
        this.insertEvent()
      }
    },
    // vxe表格  控制单元格禁用状态
    editActivedEvent({ row }) {
      const qTable = this.$refs.queryTable
      const aColumn = qTable.getColumnByField('associate') // 条件之间的联系
      if (this.form.conditionVoList.indexOf(row) === 0) {
        aColumn.editRender.attrs.disabled = true
      }
    },
    // 点击查询按钮
    doSubmit() {
      console.log(this.form)
      var arr = []
      for (let i = 0; i < this.form.conditionVoList.length; i++) {
        if (!this.form.conditionVoList[i].value) {
          this.form.conditionVoList.splice(i, 1)
        }
      }
      request({
        method: 'post',
        url: 'api/testQuery',
        data: this.form
      }).then(res => {
        this.query = true
        this.columns = res
        console.log(res, '数据')
      })
      // this.columns = arr
    },
    // 删除行
    deleteRow() {
      const index = this.form.conditionVoList.indexOf(arguments[0])
      this.form.conditionVoList.splice(index, 1)
    },
    // 点击重置按钮 Multiconditional
    reset() {
      this.query = false
      this.form.conditionVoList = [
        {
          column: '',
          type: '',
          value: '',
          associate: ''
        },
        {
          column: '',
          type: '',
          value: '',
          associate: ''
        }
      ]
    },
    // 关闭查询表单
    cancel() {
      this.resetForm()
    },
    resetForm() {
      this.dialog = false //
      this.reset()
    }
  }
}
</script>
<style lang="scss">
  @import "@/styles/form.scss";
</style>