哈喽,最近公司都在赶项目在做的过程中也踩了不少的坑,现在来记录下先来讲下Vue+Element使用table表格的合并功能。最后的效果如下图(主要涉及到表格行列合并):
由于项目后期数据报表模块的日表、月表、年表展示的数据字段不相同并且会继续扩展。这里为了前端后续的维护方便直接将表格以组件的方式封装,然后共用 el-tabs导航和头部搜索 。在开发时候在下面这两处有出现问题:
问题1: 给表头某列加提示语,我这里是使用 table的 :render-header来实现的,听@晟哥说还能通过给表头添加template在其中添加列文字和elementd的Tooltip来实现。
问题2: 将表格中的同一列行数据相同的的数据进行行合并操作,我这边是先将数据进行getSpanArr()函数处理 ,然后使用 table的属性 :span-method 合并。
问题3: 表格的最后一行需要合并前4列并且显示机构合计的文字,一开始通过table自带的属性show-summary,可以实现数据累加,但是没办法在使用列合并了。最后通过最后一行也是数据的方式来实现的在ObjectSpanMethod()函数中判断为最后一项数据时将合并列。(注意:最后一行的数据最好让后端处理,不然由于数据时金额将会出现精度问题!)
index.vue主文件代码:
<template>
<div class="page-layout" >
<el-tabs type="card" >
<!-- 搜索条件Start-->
<div class="search-component" style="margin-top: 10px">
<el-form :inline="true" size="small">
<el-form-item label="查询时间:">
<DataPicker :start_time.sync="start_time" :end_time.sync="end_time"></DataPicker>
</el-form-item>
<transition name="el-fade-in-linear">
<span v-show="is_filtrate">
<areaSelect ref="areaSelect" @success="getAreaSelectData" :existXian="false"></areaSelect>
<el-form-item label="行业类型:">
<el-select :popper-append-to-body="false" v-model="searchDatas.updateState" size="small" filterable
placeholder="请选择行业类型" class="gamesearchW">
<el-option v-for="item in useState" :key="item.value" :label="item.label" :value="item.value"/>
</el-select>
</el-form-item>
<el-form-item label="商户主体:">
<el-select :popper-append-to-body="false" v-model="searchDatas.updateState" size="small" filterable
placeholder="请选择商户主体" class="gamesearchW">
<el-option v-for="item in updateState" :key="item.value" :label="item.label" :value="item.value"/>
</el-select>
</el-form-item>
</span>
</transition>
<el-form-item>
<el-button type="primary" size="small" plain @click="search()" :loading="searchLoding">查询</el-button>
<el-button type="primary" size="small" plain @click="is_filtrate = !is_filtrate" style="margin-right: 10px">
<span v-if="!is_filtrate">更多查询</span>
<span v-if="is_filtrate">收起</span>
</el-button>
<DownLoadExcel></DownLoadExcel>
<el-button type="primary" @click="DetailsFlag = !DetailsFlag" size="small" style="margin-left: 10px">切换明细表</el-button>
</el-form-item>
</el-form>
</div>
<!-- 搜索条件End-->
<el-tab-pane label="日表">
<dayTable v-if="!DetailsFlag" :searchDatas="searchDatas" ></dayTable>
<dayTableDetails v-else :searchDatas="searchDatas"></dayTableDetails>
</el-tab-pane>
<el-tab-pane label="月表">
<dayTable v-if="!DetailsFlag" :searchDatas="searchDatas" ></dayTable>
<dayTableDetails v-else :searchDatas="searchDatas"></dayTableDetails>
</el-tab-pane>
<el-tab-pane label="年表">
<dayTable v-if="!DetailsFlag" :searchDatas="searchDatas" ></dayTable>
<dayTableDetails v-else :searchDatas="searchDatas"></dayTableDetails>
</el-tab-pane>
</el-tabs>
</div>
</template>
<script>
import tabletext from '@/utils/tabletext.js'
import DownLoadExcel from '@/components/DownLoadExcel'
import DataPicker from '@/components/DataPicker'
import dayTable from './components/dayTable';
// import monthTable from './components/monthTable';
// import yearTable from './components/yearTable';
import areaSelect from '../components/area';
import dayTableDetails from './componentsDetails/dayTable';
// import monthTableDetails from './componentsDetails/monthTable';
// import yearTableDetails from './componentsDetails/yearTable';
export default {
name: 'ProxySituation',
components: {
dayTable,
// monthTable,
// yearTable,
DownLoadExcel,
areaSelect,
DataPicker,
dayTableDetails
// monthTableDetails,
// yearTableDetails
},
mixins: [tabletext],
data() {
return {
start_time: new Date().getTime() - 24 * 3600 * 1000 * 7,
end_time: new Date().getTime(),
searchDatas: {
start_time: new Date().getTime() - 24 * 3600 * 1000 * 7,
end_time: new Date().getTime(),
business_no: '',
updateState: 0
},
updateState: [{
value: 0,
label: '全部'
}],
useState: [{
value: 0,
label: '全部'
}],
tableData: [],
is_filtrate: false,
DetailsFlag: false // 是否为明细表
}
},
methods: {
search(){
this.searchDatas.start_time = this.start_time;
this.searchDatas.end_time = this.end_time;
this.searchStartLoding();
this.getTableData();
},
// 获取列表数据
getTableData(){
let sendMessage = {
action: this.$api_proxy.backstageExamineByPage
}
this.tableLoding = true
this.$store.dispatch('Post', sendMessage).then((res) => {
// this.tableData = res.data
setTimeout(()=>{
this.searchStopLoding()
}, 500)
})
},
// 获得子组件传递回来的省市
getAreaSelectData(shen, shi, xian, wang) {
this.shen = shen;
this.shi = shi;
},
exportExcel() {
}
}
}
</script>
<style scoped>
</style>
table表格组件代码:
<template>
<div class="Table-page" ref="table">
<el-table :data="tableData" :header-cell-style="{color: 'black'}" stripe border v-loading="tableLoding"
:max-height="tableHight" style="width: 100%; font-size:14px;" size="small" :span-method="ObjectSpanMethod" >
<el-table-column prop="proxy_id" label="机构号" width="130" label-position="center" align="center" />
<el-table-column prop="proxy_name" label="机构名称" align="center" min-width="150"/>
<el-table-column prop="proxy" label="机构归属" align="center" min-width="140"/>
<el-table-column prop="sub_time" label="日期" align="center" :formatter="formatterTime" width="160"></el-table-column>
<el-table-column :label="changeTimeDay(searchDatas.start_time,1)+'至'+changeTimeDay(searchDatas.end_time,1)" align="center">
<el-table-column label="整体交易情况" align="center">
<el-table-column prop="people" label="结存商户" align="center" width="100" :render-header="renderHeader"/>
<el-table-column prop="total_day_count" label="交易金额" width="140" align="center"/>
<el-table-column prop="total_day_money" label="交易笔数" width="130" align="center" />
<el-table-column prop="total_day_money" label="单日笔均(元)" width="140" align="center" :render-header="renderHeader"/>
</el-table-column>
<el-table-column label="机构商户交易渠道金额占比情况" align="center">
<el-table-column prop="total_day_count" label="微信交易占比" width="130" align="center" :render-header="renderHeader"/>
<el-table-column prop="total_day_num" label="支付宝交易占比" width="140" align="center" :render-header="renderHeader"/>
<el-table-column prop="total_day_money" label="云闪付交易占比" width="140" align="center" :render-header="renderHeader"/>
<el-table-column prop="total_day_num" label="信用卡交易占比" width="140" align="center" :render-header="renderHeader"/>
</el-table-column>
<el-table-column label="微信交易情况" align="center">
<el-table-column prop="total_day_count" label="交易金额" width="100" align="center" />
<el-table-column prop="total_day_num" label="交易笔数" width="140" align="center" />
<el-table-column prop="total_day_money" label="单日笔均(元)" width="140" align="center" :render-header="renderHeader"/>
</el-table-column>
<el-table-column label="支付宝交易情况" align="center">
<el-table-column prop="total_day_count" label="交易金额" width="100" align="center" />
<el-table-column prop="total_day_num" label="交易笔数" width="140" align="center" />
<el-table-column prop="total_day_money" label="单日笔均(元)" width="140" align="center" :render-header="renderHeader"/>
</el-table-column>
<el-table-column label="云闪付交易情况" align="center">
<el-table-column prop="total_day_count" label="交易金额" width="100" align="center" />
<el-table-column prop="total_day_num" label="交易笔数" width="140" align="center" />
<el-table-column prop="total_day_money" label="单日笔均(元)" width="140" align="center" :render-header="renderHeader"/>
</el-table-column>
<el-table-column label="信用卡交易情况" align="center" :render-header="renderHeader">
<el-table-column prop="total_day_count" label="交易金额" width="100" align="center" />
<el-table-column prop="total_day_num" label="交易笔数" width="140" align="center" />
<el-table-column prop="total_day_money" label="单日笔均(元)" width="140" align="center" :render-header="renderHeader"/>
</el-table-column>
</el-table-column>
</el-table>
</div>
</template>
<script>
import tabletext from '@/utils/tabletext.js' //可以不引入
export default {
mixins: [tabletext],
components: {
},
props: {
searchDatas: {
type: Object,
default: function () {
return {
business_no: '',
updateState: 0,
start_time: new Date().getTime() - 24 * 3600 * 1000 * 7,
end_time: new Date().getTime()
}
}
},
tableData: {
type: Array,
default: function () {
return [{
proxy_id: '10215',
sub_time: new Date().getTime(),
proxy_name: '四九八天府网点',
proxy: '福建邮政',
people: '600',
total_day_num: '600',
total_day_money_rate: '5',
total_day_money: '89898',
total_day_count: '523',
tongdao_name: '微信',
pay_type: '微信',
trade_money: '100',
trade_num: '151',
refund_money: '1000',
member_hexiao_money: '120',
rate_money: '1211',
real_money: '200',
memo: 'memo',
trade_no: '2512541254125145',
subsidies_money: '123123'
}, {
proxy_id: '10215',
sub_time: new Date().getTime(),
proxy_name: '四九八天府网点',
proxy: '福建邮政',
people: '600',
total_day_num: '600',
total_day_money_rate: '5',
total_day_money: '89898',
total_day_count: '523',
tongdao_name: '微信',
pay_type: '微信',
trade_money: '100',
trade_num: '151',
refund_money: '1000',
member_hexiao_money: '120',
rate_money: '1211',
real_money: '200',
memo: 'memo',
trade_no: '2512541254125145',
subsidies_money: '123123'
}, {
proxy_id: '10215',
sub_time: new Date().getTime(),
proxy_name: '四九八天府网点',
proxy: '福建邮政',
people: '600',
total_day_num: '600',
total_day_money_rate: '5',
total_day_money: '89898',
total_day_count: '523',
tongdao_name: '微信',
pay_type: '微信',
trade_money: '100',
trade_num: '151',
refund_money: '1000',
member_hexiao_money: '120',
rate_money: '1211',
real_money: '200',
memo: 'memo',
trade_no: '2512541254125145',
subsidies_money: '123123'
}, {
proxy_id: '10214',
sub_time: new Date().getTime(),
proxy_name: '四九八天天网点',
proxy: '福建邮政',
people: '600',
total_day_num: '6593',
total_day_money_rate: '5',
total_day_money: '252223',
total_day_count: '23652',
tongdao_name: '微信',
pay_type: '微信',
trade_money: '100',
trade_num: '151',
refund_money: '1000',
member_hexiao_money: '120',
rate_money: '1211',
real_money: '200',
memo: 'memo',
trade_no: '2512541254125145',
subsidies_money: '123123'
}, {
sub_time: new Date().getTime(),
proxy_id: '机构合计',
proxy_name: '',
total_day_num: '-',
people: '1200',
total_day_money_rate: '10',
total_day_money: '8000',
total_day_count: '23652',
tongdao_name: '微信',
pay_type: '微信',
trade_money: '100',
trade_num: '151',
refund_money: '1000',
member_hexiao_money: '120',
rate_money: '1211',
real_money: '200',
memo: 'memo',
trade_no: '2512541254125145',
subsidies_money: '123123'
}]
}
}
},
data() {
return {
}
},
created() {
this.getSpanArr(this.tableData)
},
methods: {
// label的提示
renderHeader(h, { column }) {
const paymentContent = [h(
'div',
{
slot: 'content'
},
'结存商户:截至筛选时间最后一日的转介成功商户'
)];
const ZFBWX = [h(
'div',
{
slot: 'content'
},
'该类型交易/总交易金额'
)];
const dayMoney = [h(
'div',
{
slot: 'content'
},
'单笔日均(元):平均每笔交易金额'
)];
const XYK = [h(
'div',
{
slot: 'content'
},
'信用卡交易占比:信用卡(含微信、支付宝、云闪付)交易/总交易金额'
)];
const XYKJY = [h(
'div',
{
slot: 'content'
},
'信用卡交易情况:信用卡交易数据/总交易数据'
)];
return h('div', [
h('span', column.label),
h(
'el-tooltip',
{
props: {
placement: 'bottom'
}
},
[
column.label == '结存商户' ? paymentContent : column.label == '单日笔均(元)' ? dayMoney : column.label == '信用卡交易情况' ? XYKJY : (column.label.indexOf('交易占比') !== -1 && column.label !== '信用卡交易占比') ? ZFBWX : XYK,
h('i', {
class: 'el-icon-question',
style: 'color:black;margin-left:5px;'
})
]
)
])
},
// 处理要合并相同行的列
getSpanArr (data) {
this.spanArr = []
this.spanCodeArr = []
this.spanProxyArr = []
for (var i = 0; i < data.length; i++) {
if (i === 0) {
// 如果是第一条记录(即索引是0的时候),向数组中加入1
this.spanArr.push(1)
this.spanCodeArr.push(1);
this.spanProxyArr.push(1);
this.pos = 0
this.codePos = 0
this.proxyPos = 0
} else {
/**
* 例子:
* name:1
* name:1
* name:2
* name:2
* 最终得到的数组spanArr = [2,0,2,0]
*/
// 相同机构号
if (data[i].proxy_id === data[i - 1].proxy_id) {
// 如果proxy_id 相等就累加,并且push 0
this.spanArr[this.pos] += 1
this.spanArr.push(0)
} else {
// 不相等push 1,并且可修改下标指向
this.spanArr.push(1)
this.pos = i
}
// 相同机构名称
if (data[i].proxy_name === data[i - 1].proxy_name) {
// 如果proxy_name 相等就累加,并且push 0
this.spanCodeArr[this.codePos] += 1
this.spanCodeArr.push(0)
} else {
// 不相等push 1
this.spanCodeArr.push(1)
this.codePos = i
}
// 相同机构归属
if (data[i].proxy === data[i - 1].proxy) {
// 如果proxy 相等就累加,并且push 0
this.spanProxyArr[this.proxyPos] += 1
this.spanProxyArr.push(0)
} else {
// 不相等push 1
this.spanProxyArr.push(1)
this.proxyPos = i
}
}
}
},
ObjectSpanMethod({ row, column, rowIndex, columnIndex }){
// 合并相同列数据的行
if(columnIndex == 0 && rowIndex !== this.tableData.length - 1){
const _row = this.spanArr[rowIndex]
const _col = _row > 0 ? 1 : 0
return {
rowspan: _row,
colspan: _col
}
}
// 合并相同列数据的行
if(columnIndex == 1 && rowIndex !== this.tableData.length - 1){
const _row = this.spanCodeArr[rowIndex]
const _col = _row > 0 ? 1 : 0
return {
rowspan: _row,
colspan: _col
}
}
// 合并相同列数据的行
if(columnIndex == 2 && rowIndex !== this.tableData.length - 1){
const _row = this.spanProxyArr[rowIndex]
const _col = _row > 0 ? 1 : 0
return {
rowspan: _row,
colspan: _col
}
}
// 将最后一行进行合并列弄成总计
if(rowIndex == this.tableData.length - 1 && columnIndex == 0){
return [1, 4]
}
// 把第二列、第三列、第四列的列改为0(不占列)
if(rowIndex == this.tableData.length - 1 && (columnIndex == 1 || columnIndex == 2 || columnIndex == 3)){
return [0, 0]
}
}
}
}
</script>
<style scoped>
</style>
以上就是我对Element表格的理解,如果文章由于我学识浅薄,导致您发现有严重谬误的地方,请一定在评论中指出,我会在第一时间修正我的文章,以避免误人子弟。