近期在处理数据报表项目过程中频繁面临表格合并的挑战。产品经理希望能将表格中重复内容并合至同一行显示。尽管通过查阅众多博文了解相关方法与实践,但实际操作却无法解决相关问题。例如,提及ant design版本不适配或添加相关代码仍未成功;更为糟糕的是,即使成功合并,数据仍然仅可水平居中,无法实现垂直居中。作为技术支持者,必须满足产品需求,力求保持99%的原型匹配度。虽然工作压力较大,但我坚信这些困难并非无法克服。所以,我也将这些经验分享出来,供大家共同探讨学习。
一、开发页面、获取表格数据
在使用ant design组件时需要进行提前安转,这个具体安装步骤在ant design官网中有,不会的小伙伴可以去查看一下,但是版本尽量和vue匹配,不然后续在写代码时就会发现有很多都无法使用的问题。安装完组件后就可以正常使用了,下面是具体详细代码:
(1)<template>部分
<template>
<!-- 表格部分 -->
<div class="content">
<div class="table-body">
<a-table
:columns="columns"
:dataSource="tableData"
:pagination="false"
bordered
:scroll="{ y: 'calc(100vh - 520px)' }"
/>
</div>
<!-- 分页 -->
<div class="pagination">
<a-pagination
:current="current"
:size="size"
:total="pageData.total"
@change="onChange"
show-less-items
show-quick-jumper
show-size-changer
:show-total="(total, range) => `共 ${pageData.total || 0} 条`"
/>
</div>
</div>
</template>
(2)<script>部分
<script setup>
import { getRoadManageTotal} from '../api/index'
// 分页信息
const pageData = ref({})
// 当前页
const current = ref(1)
// 多少页入参
const size = ref('')
const tableData = ref([])
const columns = ref([
{
title: '日期',
dataIndex: 'tabdate',
key: 'tabdate',
align: 'center'
},
{
title: '路线',
dataIndex: 'tabroad',
key: 'road',
align: 'center',
},
{
title: '路段',
dataIndex: 'tabhighway',
key: 'highway',
align: 'center'
},
{
title: '断面流量(万辆)',
dataIndex: 'tabdmflow',
key: 'dmflow',
align: 'center'
},
{
title: '清障统计',
// dataIndex: 'tabwrecker',
// key: 'wrecker',
// align: 'center',
children: [
{
title: '合计(起)',
dataIndex: 'wreckertotal',
align: 'center',
key: 'total',
width: 100,
sorter: true
},
{
title: '放空(起)',
dataIndex: 'wreckvent',
align: 'center',
key: 'vent'
}
]
},
{
title: '交通事故(起)',
dataIndex: 'tabtrafficacci',
key: 'trafficacci',
align: 'center'
}
])
// 获取表格数据
const getTabData = ()=> {
return new Promise((resolve, reject) => {
getRoadManageTotal()
.then(res => {
tableData.value = []
if (res.code === 200 && res.data) {
const dataList = res.data.list
dataList.forEach((item, index) => {
console.log(item, 'ieieiei')
if (item.hj === 'null' && item.fk === 'null' && item.jtsg === 'null') {
tableData.value.push({
tabdate: item.createDate,
tabroad: item.road,
tabhighway: item.sectionName,
tabdmflow: item.dmll,
wreckertotal: 0,
wreckvent: 0,
// tabwrecker: item.qzzy,
tabtrafficacci: 0
})
} else {
tableData.value.push({
tabdate: item.createDate,
tabroad: item.road,
tabhighway: item.sectionName,
tabdmflow: item.dmll,
wreckertotal: item.hj,
wreckvent: item.fk,
// tabwrecker: item.qzzy,
tabtrafficacci: item.jtsg
})
}
})
// console.log(res.data, '数据是:')
pageData.value = {
...pageData.value,
total: res.data.total,
showTotal: () => `共 ${res.data.total || 0} 条`
// current: res.data.page.currentPage
}
} else {
tableData.value = []
}
resolve(res.data)
})
.catch(error => {
reject(error)
})
})
}
onMounted(() => {
getTabData()
})
</script>
二、合并行
在需要合并行的表格头部添加customCell,并写入以下代码:
customCell: (record, rowIndex, column) => {
return {
rowSpan: rowSpanArr.value[rowIndex],
style: {
'text-align': 'center', // 单元格文本居中
'vertical-align': 'middle' // 单元格内容垂直居中
}
}
}
在操作完以上步骤之后,重新再定义一个合并行的函数,名为getRowspan,具体代码如下:
//合并行
const getRowspan = (dataScroce, filed) => {
// console.log(dataScroce, 'dataScrocedataScroce')
console.log(filed, 'filedfiledfiled')
let spanArr = []
let position = 0
dataScroce.forEach((item, index) => {
if (index === 0) {
spanArr.push(1)
// spanArr.splice(2, 0, 1)
position = 0
} else {
//需要合并的地方判断
if (dataScroce[index][filed] === dataScroce[index - 1][filed]) {
spanArr[position] += 1
spanArr.push(0)
// spanArr.splice(2, 0, 0)
} else {
spanArr.push(1)
position = index
console.log(position, ' position position')
}
}
})
return spanArr
}
我这里需要合并的是时期和路线,所以需要再重新定义两个变量,
//定义合并的时期变量
const rowSpanArr = ref([])
const roadSpanArr = ref([])
操作完以上步骤后,对于定义的这些如何使用呢,这里需要将合并的两个字段进行处理,所以我们在获取表格数据的地方进行操作,
rowSpanArr.value = getRowspan(tableData.value, 'tabdate')
roadSpanArr.value = getRowspan(tableData.value, 'tabroad')
这样就完成了相应的合并啦。
三、结果展示、完整代码
可能看完以上代码有些小伙伴还是有些迷糊,下面将完整代码分享给大家吧!
<template>
<!-- 表格部分 -->
<div class="content">
<div class="table-body">
<a-table
:columns="columns"
:dataSource="tableData"
:pagination="false"
bordered
:scroll="{ y: 'calc(100vh - 520px)' }"
/>
</div>
<!-- 分页 -->
<div class="pagination">
<a-pagination
:current="current"
:size="size"
:total="pageData.total"
@change="onChange"
show-less-items
show-quick-jumper
show-size-changer
:show-total="(total, range) => `共 ${pageData.total || 0} 条`"
/>
</div>
</div>
</template>
<script setup>
import { getRoadManageTotal} from '../api/index'
// 分页信息
const pageData = ref({})
// 当前页
const current = ref(1)
// 多少页入参
const size = ref('')
const tableData = ref([])
//合并行
const getRowspan = (dataScroce, filed) => {
// console.log(dataScroce, 'dataScrocedataScroce')
console.log(filed, 'filedfiledfiled')
let spanArr = []
let position = 0
dataScroce.forEach((item, index) => {
if (index === 0) {
spanArr.push(1)
// spanArr.splice(2, 0, 1)
position = 0
} else {
//需要合并的地方判断
if (dataScroce[index][filed] === dataScroce[index - 1][filed]) {
spanArr[position] += 1
spanArr.push(0)
// spanArr.splice(2, 0, 0)
} else {
spanArr.push(1)
position = index
console.log(position, ' position position')
}
}
})
return spanArr
}
//定义合并的时期变量
const rowSpanArr = ref([])
const roadSpanArr = ref([])
const columns = ref([
{
title: '日期',
dataIndex: 'tabdate',
key: 'tabdate',
align: 'center',
customCell: (record, rowIndex, column) => {
return {
rowSpan: rowSpanArr.value[rowIndex],
style: {
'text-align': 'center', // 单元格文本居中
'vertical-align': 'middle' // 单元格内容垂直居中
}
}
}
},
{
title: '路线',
dataIndex: 'tabroad',
key: 'road',
align: 'center',
customCell: (record, rowIndex, column) => {
return {
rowSpan: roadSpanArr.value[rowIndex],
style: {
'text-align': 'center', // 单元格文本居中
'vertical-align': 'middle' // 单元格内容垂直居中
}
}
}
},
{
title: '路段',
dataIndex: 'tabhighway',
key: 'highway',
align: 'center'
},
{
title: '断面流量(万辆)',
dataIndex: 'tabdmflow',
key: 'dmflow',
align: 'center'
},
{
title: '清障统计',
// dataIndex: 'tabwrecker',
// key: 'wrecker',
// align: 'center',
children: [
{
title: '合计(起)',
dataIndex: 'wreckertotal',
align: 'center',
key: 'total',
width: 100,
sorter: true
},
{
title: '放空(起)',
dataIndex: 'wreckvent',
align: 'center',
key: 'vent'
}
]
},
{
title: '交通事故(起)',
dataIndex: 'tabtrafficacci',
key: 'trafficacci',
align: 'center'
}
])
// 获取表格数据
const getTabData = () => {
return new Promise((resolve, reject) => {
getRoadManageTotal()
.then(res => {
tableData.value = []
if (res.code === 200 && res.data) {
const dataList = res.data.list
dataList.forEach((item, index) => {
console.log(item, 'ieieiei')
if (item.hj === 'null' && item.fk === 'null' && item.jtsg === 'null') {
tableData.value.push({
tabdate: item.createDate,
tabroad: item.road,
tabhighway: item.sectionName,
tabdmflow: item.dmll,
wreckertotal: 0,
wreckvent: 0,
// tabwrecker: item.qzzy,
tabtrafficacci: 0
})
} else {
tableData.value.push({
tabdate: item.createDate,
tabroad: item.road,
tabhighway: item.sectionName,
tabdmflow: item.dmll,
wreckertotal: item.hj,
wreckvent: item.fk,
// tabwrecker: item.qzzy,
tabtrafficacci: item.jtsg
})
}
rowSpanArr.value = getRowspan(tableData.value, 'tabdate')
roadSpanArr.value = getRowspan(tableData.value, 'tabroad')
})
// console.log(res.data, '数据是:')
pageData.value = {
...pageData.value,
total: res.data.total,
showTotal: () => `共 ${res.data.total || 0} 条`
// current: res.data.page.currentPage
}
} else {
tableData.value = []
}
resolve(res.data)
})
.catch(error => {
reject(error)
})
})
}
onMounted(() => {
getTabData()
})
</script>
<style lang="less" scoped>
.search-accident {
width: 100%;
height: 12%;
display: flex;
align-items: center;
background-color: #fff;
.accident-date {
padding: 0 10px 0 30px;
font-size: 18px;
// color: #929292;
}
.btn-list {
display: flex;
align-items: center;
::v-deep .ant-btn {
line-height: 1.4vw;
height: 2vw;
}
}
}
.content {
width: 100%;
height: 85%;
margin-top: 30px;
background-color: #fff;
.content-top {
display: flex;
justify-content: flex-end;
padding-top: 30px;
padding-right: 30px;
::v-deep .ant-btn {
line-height: 1.4vw;
height: 2vw;
}
}
.table-body {
// width: 100%;
height: 70%;
margin-top: 2%;
padding: 0 20px;
box-sizing: border-box;
background-color: #fff;
}
.pagination {
// width: 100%;
height: 10%;
margin-top: 2%;
background-color: #fff;
display: flex;
justify-content: flex-end;
align-items: center;
padding-right: 30px;
}
}
</style>