开发背景
由于开发页面的内容较多,包含两三个表格,这样展示效果有点不乐观,因此其中一个表格的内容采用表格嵌套及表格内容折叠的方式来呈现。
实现思路
- 表格嵌套
- 表格内容折叠
- 点击表格【人工成本】月份下内容区的金额与天数互换
实现过程
最开始拿到原型的时候,看了Element的官网的el-table的嵌套和折叠效果,发现并不适用我的这个场景。
- 表格嵌套
官网是采用了在el-table的el-table-column中再次嵌套el-table-column的方式实现的。由于我的需求是,嵌套了表格,但是该行的后半部分没有内容,所以,我采用通过构造数据结构,然后进行单元格的合并的方式来呈现表格嵌套的效果。- 通过
handleDetailData
方法将数据进行处理。将表格的内容分为【人工成本、其它福利补贴、其它成本、合计行】这四块。并分别设置这四块内容的tableType
来代表它属于哪个区块。然后将这四块数据进行整合,到表格。 - 通过
arraySpanMethod
方法对表格单元格合并,具体合并规则见element官网el-talbe的span-method
的实现方式 - 通过
tableCellClassName
方法对特殊单元格样式进行修改 - 这里要注意的是,当鼠标滑过表格的内容行的时候,该行的样式会发生变化,如背景色。这里,我要保证其它成本的表格头,在鼠标滑到该行时,样式不能发生变化。这时就需要修改鼠标滑过的样式
.other-header { background: #6c81cd; color: #fff; } //由于表格自带鼠标滑过表格体时,该行背景色会变化,所以,设置它的hover样式与它原来的样式保持一致 tbody tr:hover>td { background-color: unset !important; } tbody tr:hover { .other-header { background: #6c81cd !important; color: #fff !important; } .tatalRow-cursor{ background: #322323; cursor: pointer; } }
- 通过
- 表格折叠
这里并没有采用elment中el-table的折叠方法,不适用,它折叠的内容是父子关系。而我是同级关系。确切的说,我这里是对内容区的展示或影藏。- 通过
tableRowClassName
方法来修改某一行的样式。通过设置要折叠的行的样式display:none
来隐藏 - 通过
onTableCellClick
方法来做点击折叠,收起的效果。主要是对变量expand
的值的修改
- 通过
- 点击表格【人工成本】月份下内容区的金额与天数互换
- 通过
onTableCellClick
方法来做点击金额,与天数 做切换
- 通过
源代码
<template>
<div class="budget_income_info">
<el-table :data="tableData" style="width: 100%" size="mini" border
show-overflow-tooltip
:header-cell-style="{ background: '#6c81cd', color: '#fff' }"
:span-method="arraySpanMethod"
:cell-class-name="tableCellClassName"
:row-class-name="tableRowClassName"
@cell-click="onTableCellClick"
>
<el-table-column label="岗位条目" align="center">
<el-table-column label="岗位名称" prop="posiName" min-width="70">
<template slot-scope="scope">
{{ scope.row.posiName }}
<span v-if="!expand && scope.row.tableType === 'tatalRow'" style="color: #aaa;">(点击查看更多详情)</span>
<span v-if="expand && scope.row.tableType === 'tatalRow'" style="color: #aaa;">(点击收起)</span>
<i :class="!expand ? 'el-icon-caret-bottom' : 'el-icon-caret-top'"
v-if="scope.row.tableType === 'tatalRow'"></i>
</template>
</el-table-column>
<el-table-column label="职系" prop="posiGradeType" min-width="70"></el-table-column>
<el-table-column label="月付费额" prop="monthlyPayAmount" min-width="60"></el-table-column>
<el-table-column label="数量" prop="posiCount" min-width="35"></el-table-column>
<el-table-column label="语言" prop="langName" min-width="40"></el-table-column>
<el-table-column label="级别" prop="posiRank" min-width="40"></el-table-column>
<el-table-column label="业务类型" prop="positionName" min-width="75"></el-table-column>
<el-table-column label="等级" prop="posiLevel" min-width="40"></el-table-column>
<el-table-column label="地城" prop="cityName" min-width="60"></el-table-column>
<el-table-column label="人天成本" prop="budgetCostAmount" min-width="65"></el-table-column>
</el-table-column>
<el-table-column v-for="(item, index) in allYearMonth" :label="item" align="center" :key="item" min-width="60"
>
<template slot-scope="scope" v-show="scope.row.budgetValues && scope.row.budgetdays">
{{
isValToDays && scope.row.tableType === 'laborCost' ?
scope.row.budgetdays && scope.row.budgetdays[index] && scope.row.budgetdays[index] :
scope.row.budgetValues && scope.row.budgetValues[index] && ThousandFormat(scope.row.budgetValues[index])
}}
</template>
</el-table-column>
</el-table>
</div>
</template>
<script>
import { queryQuotaType } from '@/api/api';
export default {
props: {
detailData: {
type: Object,
default: function () {
return {};
}
},
allYearMonth: {
type: Array,
default: function () {
return [];
}
}
},
data() {
return {
tableData: [],
detailDataObj: {},
expand: false, //展开:false
isValToDays:false, //是否由金额转天
detailCodesObj:{},
}
},
mounted() {
this.queryQuotaType();
this.detailDataObj = this.detailData;
},
methods: {
//某个单元格的样式
tableCellClassName({ row, rowIndex, column, columnIndex }) {
if (row.tableType == 'otherHeader' && (columnIndex === 0 || columnIndex === 5)) {
return 'other-header';
}
if (row.tableType === 'tatalRow' && (columnIndex === 0)){
return 'tatalRow-cursor'
}
return '';
},
//查看预算填报类型
queryQuotaType() {
let params = {
quotaType: 'cost', //预算收入 income, 预算成本 cost
}
queryQuotaType(params).then(res => {
if (res.success) {
this.detailCodesObj = res.entity;
this.handleDetailData();
}
})
},
//处理详情数据
handleDetailData() {
let { costList, otherList, totals } = this.detailDataObj;
//人工成本
costList.forEach(item => {
if (item.detailCode === this.detailCodesObj.otherCode) { //其它福利补贴
item.tableType = 'otherWelfareSubsidies';
item.posiName = '其它福利补贴'
}else{
item.tableType = 'laborCost';
}
})
//其它成本
let temp = {};
if (otherList.length > 0) {
temp.tableType = 'otherHeader';
temp.budgetValues = new Array(this.allYearMonth.length).fill('');
temp.posiName = '预算条目大类';
temp.posiRank = '预算条目小类';
otherList.forEach(item => {
item.tableType = 'other';
item.posiName = item.expenseTypeOneDesc;
item.posiRank = item.expenseTypeTwoDesc;
})
}
//合计行
let totalRow = {
tableType: 'tatalRow',
posiName: '成本合计',
budgetValues: totals
}
if(Object.keys(temp).length > 0){
this.tableData = [...costList, temp, ...otherList, totalRow];
}else{
this.tableData = [...costList, ...otherList, totalRow];
}
},
//合并单元格
arraySpanMethod({ row, column, rowIndex, columnIndex }) {
//其它福利补贴
if (row.detailCode === this.detailCodesObj.otherCode) {
if (columnIndex === 0) {
return [1, 10]
} else if (columnIndex >= 1 && columnIndex <= 9) {
return [0, 0]
}
}
// 其它成本表头
if (row.tableType === 'otherHeader') {
if (columnIndex === 0) {
return [1, 5];
} else if (columnIndex === 5) {
return [1, 5];
} else if (columnIndex === 10) {
return [1, this.allYearMonth.length];
} else if ((columnIndex >= 1 && columnIndex <= 4) || (columnIndex >= 6 && columnIndex <= 9) || columnIndex > 10) {
return [0, 0]
}
}
//其它成本表体
if (row.tableType === 'other') {
if (columnIndex === 0) {
return [1, 5];
} else if (columnIndex === 5) {
return [1, 5];
} else if ((columnIndex >= 1 && columnIndex <= 4) || (columnIndex >= 6 && columnIndex <= 9)) {
return [0, 0]
}
}
//合计行
if (row.tableType === 'tatalRow') {
if (columnIndex === 0) {
return [1, 10]
} else if (columnIndex >= 1 && columnIndex <= 9) {
return [0, 0]
}
}
},
//某一行的样式
tableRowClassName({ row, rowIndex }) {
//折叠展开 隐藏表格内容,只展示最后一行
if (rowIndex !== this.tableData.length - 1 && !this.expand) {
return 'row-none'
}
// if(this.expand && rowIndex !== this.tableData.length - 1){
// return 'row-block'
// }
//成本合计行,文字加粗
if (rowIndex === this.tableData.length - 1) {
return 'font-weigth'
}
},
//单击某个单元格
onTableCellClick(row, column, cell, event) {
//点击成本合计行,折叠、展开表体内容
if (row.tableType === 'tatalRow' && column.property === 'posiName') {
this.expand = !this.expand; //折叠 、展开
}
//点击金额,与天数 做切换
if(row.tableType === 'laborCost' && this.allYearMonth.includes(column.label)){
this.isValToDays = !this.isValToDays;
}
}
}
}
</script>
<style lang="less" scoped>
.budget_income_info {
margin: 10px 0px;
/deep/ .el-table {
.cell {
padding: 0px 0px !important;
border: none;
text-align: center !important;
}
.other-header {
background: #6c81cd;
color: #fff;
}
//由于表格自带鼠标滑过表格体时,该行背景色会变化,所以,设置它的hover样式与它原来的样式保持一致
tbody tr:hover>td {
background-color: unset !important;
}
tbody tr:hover {
.other-header {
background: #6c81cd !important;
color: #fff !important;
}
.tatalRow-cursor{
background: #322323;
cursor: pointer;
}
}
.row-none {
display: none;
// position: absolute;
// top: 0;
// left: 0;
// opacity: 0;
// z-index: 0;
// visibility: hidden;
// transition: all ease-in .5s;
}
// .row-block{
// opacity: 1;
// visibility: visible;
// z-index: 999;
// }
.font-weigth {
font-weight: bold;
i {
font-size: 16px;
font-weight: bold;
}
}
}
}
</style>
主要数据
处理后要渲染的数据如下:
[
{
"id": null,
"applicationId": "xg20cd30d843bac4c208da92c041285c6ad",
"detailCode": "1201",
"budgetDate": null,
"budgetValues": [33609,43494,43494,43494,43494,43494,43494,43494,43494,43494,43494,43494,11862],
"itemType": null,
"expenseTypeOneCode": null,
"expenseTypeTwoCode": null,
"beginDate": null,
"endDate": null,
"quotaType": "cost",
"budgetValue": null,
"itemTypeName": null,
"item": null,
"note": null,
"rowIndex": 1,
"total": 523905,
"posiName": "测试岗位",
"posiGradeType": "技术职系",
"monthlyPayAmount": "10000.00",
"posiCount": "3.00",
"langName": "中文",
"posiRank": "高级",
"positionName": "数据分析",
"posiLevel": "I",
"cityName": "北京1",
"budgetCostAmount": "659.00",
"expenseTypeOneDesc": null,
"expenseTypeTwoDesc": null,
"budgetdays": [17, 22,22,22,22,22,22, 22,22,22,22,22, 6],
"tableType": "laborCost"
},
{
"id": null,
"applicationId": "xg20cd30d843bac4c208da92c041285c6ad",
"detailCode": "1201",
"budgetDate": null,
"budgetValues": [22406,28996,28996,28996,28996,28996,28996,28996,28996,28996,28996,28996,7908],
"itemType": null,
"expenseTypeOneCode": null,
"expenseTypeTwoCode": null,
"beginDate": null,
"endDate": null,
"quotaType": "cost",
"budgetValue": null,
"itemTypeName": null,
"item": null,
"note": null,
"rowIndex": 2,
"total": 349270,
"posiName": "岗位2",
"posiGradeType": "技术职系",
"monthlyPayAmount": "10000.00",
"posiCount": "2.00",
"langName": "中文",
"posiRank": "高级",
"positionName": "数据分析",
"posiLevel": "I",
"cityName": "北京1",
"budgetCostAmount": "659.00",
"expenseTypeOneDesc": null,
"expenseTypeTwoDesc": null,
"budgetdays": [17,22,22,22,22,22,22,22,22,22,22,22,6],
"tableType": "laborCost"
},
{
"id": null,
"applicationId": "xg20cd30d843bac4c208da92c041285c6ad",
"detailCode": "1202",
"budgetDate": null,
"budgetValues": [23,34,23,0,0,0,0,0,0,0,0,0,0],
"itemType": null,
"expenseTypeOneCode": null,
"expenseTypeTwoCode": null,
"beginDate": null,
"endDate": null,
"quotaType": "cost",
"budgetValue": null,
"itemTypeName": null,
"item": null,
"note": null,
"rowIndex": 3,
"total": null,
"posiName": "其它福利补贴",
"posiGradeType": null,
"monthlyPayAmount": null,
"posiCount": null,
"langName": null,
"posiRank": null,
"positionName": null,
"posiLevel": null,
"cityName": null,
"budgetCostAmount": null,
"expenseTypeOneDesc": null,
"expenseTypeTwoDesc": null,
"budgetdays": null,
"tableType": "otherWelfareSubsidies"
},
{
"tableType": "otherHeader",
"budgetValues": ["","","","","","","","","","","","",""],
"posiName": "预算条目大类",
"posiRank": "预算条目小类"
},
{
"id": null,
"applicationId": "xg20cd30d843bac4c208da92c041285c6ad",
"detailCode": "0101",
"budgetDate": null,
"budgetValues": [23, 34,23,12, 43, 0, 0, 0,0, 0, 0,0,0],
"itemType": null,
"expenseTypeOneCode": null,
"expenseTypeTwoCode": null,
"beginDate": null,
"endDate": null,
"quotaType": "other",
"budgetValue": null,
"itemTypeName": null,
"item": null,
"note": null,
"rowIndex": 1,
"total": 135,
"posiName": "交通费/差旅费",
"posiGradeType": null,
"monthlyPayAmount": null,
"posiCount": null,
"langName": null,
"posiRank": "市内交通费",
"positionName": null,
"posiLevel": null,
"cityName": null,
"budgetCostAmount": null,
"expenseTypeOneDesc": "交通费/差旅费",
"expenseTypeTwoDesc": "市内交通费",
"budgetdays": null,
"tableType": "other"
},
{
"id": null,
"applicationId": "xg20cd30d843bac4c208da92c041285c6ad",
"detailCode": "2001",
"budgetDate": null,
"budgetValues": [45,23,45,12,12,0, 0,0,0,0,0,0, 0],
"itemType": null,
"expenseTypeOneCode": null,
"expenseTypeTwoCode": null,
"beginDate": null,
"endDate": null,
"quotaType": "other",
"budgetValue": null,
"itemTypeName": null,
"item": null,
"note": null,
"rowIndex": 2,
"total": 137,
"posiName": "内部支出",
"posiGradeType": null,
"monthlyPayAmount": null,
"posiCount": null,
"langName": null,
"posiRank": "其他成本",
"positionName": null,
"posiLevel": null,
"cityName": null,
"budgetCostAmount": null,
"expenseTypeOneDesc": "内部支出",
"expenseTypeTwoDesc": "其他成本",
"budgetdays": null,
"tableType": "other"
},
{
"tableType": "tatalRow",
"posiName": "成本合计",
"budgetValues": [56106,72581,72581, 72514,72545, 72490,72490, 72490, 72490,72490,72490,72490, 19770]
}
]
效果图
- 收起效果
- 展开效果
- 点击这块内容区任何一处将所有金额和天数进行交替展示