123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340 |
- <template>
- <div
- v-loading="loading"
- element-loading-text="拼命加载中"
- element-loading-spinner="el-icon-loading"
- element-loading-background="rgba(0, 0, 0, 0.8)"
- class="table-wrapper"
- >
- <el-table
- ref="table"
- v-el-table-infinite-scroll="load"
- :data="dealedTableData"
- :header-cell-class-name="headerCellClass"
- :row-class-name="rowClass"
- :cell-class-name="cellClass"
- :span-method="tableSpanMethod"
- :show-summary="showSummary"
- :summary-method="tableSummaryMethod"
- :height="height"
- stripe
- fit
- border
- @cell-click="cellClickHandler"
- >
- <el-table-column
- v-for="col in filteredTableCols"
- :key="col.columnName"
- :prop="col.columnName"
- :label="col.columnLabel"
- :width="col.width"
- :show-overflow-tooltip="showOverflowTooltip"
- :formatter="tableFormatter"
- >
- <template #header>
- <el-tooltip
- :content="col.columnDescribe || col.columnLabel"
- placement="top"
- >
- <TableHeaderCell
- :label="col.columnLabel"
- :filter-options="tableDataFilters[col.columnName]"
- :filter-values.sync="filterValues[col.columnName]"
- filter-style="arrow"
- :sortable="!!col.needSort"
- :sort-rule.sync="tableDataSortRules[col.columnName]"
- />
- </el-tooltip>
- </template>
- </el-table-column>
- </el-table>
- </div>
- </template>
- <script>
- import TableHeaderCell from '../TableHeaderCell'
- import { setTableFilters } from '@/utils/table'
- import { mapGetters } from 'vuex'
- export default {
- name: 'SimpleTable',
- components: { TableHeaderCell },
- props: {
- loading: {
- type: Boolean,
- default: false
- },
- height: {
- type: [String, Number],
- default: '100%'
- },
- tableCols: {
- type: Array,
- default: () => []
- },
- data: {
- type: Array,
- default: () => []
- },
- headerCellClassName: {
- type: Function
- },
- rowClassName: {
- type: Function
- },
- cellClassName: {
- type: Function
- },
- spanMethod: {
- type: Function
- },
- // 是否显示合计行
- showSummary: {
- type: Boolean,
- default: false
- },
- summaryMethod: {
- type: Function
- },
- // 不换行,溢出隐藏
- showOverflowTooltip: {
- type: Boolean,
- default: false
- },
- formatter: {
- type: Function
- }
- },
- data() {
- return {
- tableData: [],
- tableDataFilters: {}, // 表头-下拉数据
- filterValues: {}, // 表头-下拉-选中数据
- tableDataSortRules: {}, // 表头-排序
- tableGroups: [], // 表格分组规则
- spanArr: [] // 表格分组数据缓存
- }
- },
- computed: {
- ...mapGetters(['clickedCells']),
- filteredTableCols() {
- return this.tableCols.filter(col => col.needShow)
- },
- dealedTableData() {
- const filtered = this.tableData.filter(item => {
- let flag = true
- Object.entries(this.filterValues).forEach(([key, arr]) => {
- if (arr.length && !arr.includes(item[key])) {
- flag = false
- }
- })
- return flag
- })
- const sortRules = Object.entries(this.tableDataSortRules).reduce(
- (pre, [key, value]) => {
- if (value) {
- pre[0].push(key)
- value = value === 'ascending' ? 'asc' : 'desc'
- pre[1].push(value)
- }
- return pre
- },
- [[], []]
- )
- return this._.orderBy(filtered, sortRules[0], sortRules[1])
- }
- },
- watch: {
- data: {
- handler(arr) {
- this.tableData = arr
- },
- deep: true
- },
- tableData: {
- handler() {
- this.setTableFilters()
- },
- deep: true
- },
- tableCols: {
- handler() {
- this.setTableFilters()
- },
- deep: true
- },
- dealedTableData: {
- handler(arr) {
- const spanArr = []
- let pos = 0
- arr.forEach((item, index, arr) => {
- if (index === 0) {
- spanArr.push(1)
- } else {
- if (this.tableGroups.every(prop => arr[index][prop] === arr[index - 1][prop])) {
- spanArr[pos] += 1
- spanArr.push(0)
- } else {
- spanArr.push(1)
- pos = index
- }
- }
- })
- this.spanArr = spanArr
- },
- deep: true
- },
- headerCellClassName: {
- handler(func) {
- if (func) {
- this.headerCellClass = func.bind(this)
- }
- },
- deep: true
- },
- rowClassName: {
- handler(func) {
- if (func) {
- this.rowClass = func.bind(this)
- }
- },
- deep: true
- },
- cellClassName: {
- handler(func) {
- if (func) {
- this.cellClass = func.bind(this)
- }
- },
- deep: true
- },
- spanMethod: {
- handler(func) {
- if (func) {
- this.tableSpanMethod = func.bind(this)
- }
- },
- deep: true
- },
- summaryMethod: {
- handler(func) {
- if (func) {
- this.tableSummaryMethod = func.bind(this)
- }
- },
- deep: true
- },
- formatter: {
- handler(func) {
- if (func) {
- this.tableFormatter = func
- }
- }
- }
- },
- updated() {
- this.$refs['table']?.doLayout()
- },
- methods: {
- load() {
- this.$emit('load')
- },
- headerCellClass({ row, column, rowIndex, columnIndex }) {
- const classes = []
- const rule = this.tableDataSortRules[column.property]
- if (rule) {
- classes.push(rule)
- }
- return classes.join(' ')
- },
- rowClass() {
- return ''
- },
- cellClass() {
- return ''
- },
- tableSpanMethod({ row, column, rowIndex, columnIndex }) {
- if (this.tableGroups.includes(column.property)) {
- const _row = this.spanArr[rowIndex]
- const _col = _row > 0 ? 1 : 0
- return {
- rowspan: _row,
- colspan: _col
- }
- }
- },
- tableSummaryMethod(param) {
- const { columns, data } = param
- const sums = []
- columns.forEach((column, index) => {
- this.tableCols.forEach(p => {
- if (column.property === p.columnName && p.needCount) {
- const values = data.map(item => Number(item[column.property]))
- if (!values.every(value => isNaN(value))) {
- sums[index] = values.reduce((prev, curr) => {
- const value = Number(curr)
- if (!isNaN(value)) {
- return prev + curr
- } else {
- return prev
- }
- }, 0)
- sums[index] += ''
- }
- }
- })
- })
- return sums
- },
- cellClickHandler(...params) {
- this.$emit('cell-click', ...params)
- },
- tableFormatter(row, column, cellValue) {
- return cellValue
- },
- setTableFilters() {
- this.tableDataFilters = {}
- this.filteredTableCols.forEach(col => {
- this.tableDataFilters[col.columnName] = []
- if (col.needGroup) {
- this.tableGroups.push(col.columnName)
- }
- })
- setTableFilters(this.tableData, this.tableDataFilters)
- }
- }
- }
- </script>
- <style lang="scss" scoped>
- .table-wrapper {
- width: 100%;
- height: 100%;
- ::v-deep .el-table {
- width: 100%;
- .cell {
- padding: 0;
- text-align: center;
- font-size: 14px;
- font-family: Helvetica, 'Microsoft YaHei';
- letter-spacing: 0;
- }
- .cell-click {
- cursor: pointer;
- color: #2d7cff;
- &.cell-clicked {
- color: purple;
- }
- }
- .el-table__header-wrapper {
- .cell {
- font-weight: bold;
- color: #101116;
- > .el-checkbox {
- display: none;
- }
- }
- }
- }
- }
- </style>
|