Vue動態(tài)擴展表頭的表格及數(shù)據(jù)方式(數(shù)組嵌套對象)
實現(xiàn)效果

需求描述
接收后端傳的json數(shù)據(jù),數(shù)據(jù)格式為數(shù)組對象嵌套數(shù)組對象再嵌套對象,需要將每個數(shù)組對象遍歷后取出想要的數(shù)據(jù),通過forEach()方法來實現(xiàn)遍歷、賦值。
數(shù)據(jù)結(jié)構(gòu)

業(yè)務(wù)代碼
<template>
<div class="app-container">
<!-- 表單區(qū)域 -->
<el-form :model="queryParams" ref="queryForm" :inline="true" label-width="68px">
<el-form-item label="店面" prop="storeId" label-width="40px">
<treeselect v-model="queryParams.storeId" :options="deptOptions" :normalizer="normalizerDept" size="small"
placeholder="請選擇" class="treeselect-main" />
</el-form-item>
<el-form-item label="品牌" prop="brandId" label-width="40px">
<el-select v-model="queryParams.brandId" filterable placeholder="請選擇" clearable size="medium">
<el-option v-for="dict in brandOptions" :key="dict.id" :label="dict.brand" :value="dict.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="區(qū)域" prop="areaId" label-width="80px">
<treeselect v-model="queryParams.areaId" :options="areaOptions" :normalizer="normalizer2" clearable size="small"
placeholder="請選擇" style="width:200px" />
</el-form-item>
<el-form-item label="日期" label-width="40px">
<el-date-picker v-model="dateRange" size="small" style="width: 240px" value-format="yyyy-MM-dd" type="daterange"
range-separator="-" start-placeholder="開始日期" end-placeholder="結(jié)束日期" :editable="false">
</el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
<el-button type="warning" plain icon="el-icon-download" size="mini" :loading="exportLoading"
@click="handleExport">導(dǎo)出</el-button>
</el-form-item>
</el-form>
<!-- 表單區(qū)域結(jié)束 -->
<!-- table表格區(qū)域 -->
<el-table v-loading="loading" :data="mileageList" @selection-change="handleSelectionChange" border>
<el-table-column label="試駕車" align="center" :show-overflow-tooltip="true">
<el-table-column label="店面" align="center" prop="storeName" :show-overflow-tooltip="true" width="180px" />
<el-table-column label="總行駛次數(shù)" align="center" class-name="small-padding fixed-width" width="130">
<template slot-scope="scope">
<el-button size="mini" type="text" @click="handleInfo(scope.row,1, scope.row.totalMount)">
{{ scope.row.totalMount }}
</el-button>
</template>
</el-table-column>
<el-table-column label="里程數(shù)(KM)" align="center" prop="totalMileage" width="130" :show-overflow-tooltip="true" />
<el-table-column label="總時長(分鐘)" align="center" prop="totalTime" width="130" :show-overflow-tooltip="true" />
<el-table-column label="GPS預(yù)估數(shù)" align="center" prop="predictMileage" width="130" :show-overflow-tooltip="true" />
<el-table-column label="里程占比" align="center" prop="mileageProportion" width="130" :show-overflow-tooltip="true" />
</el-table-column>
<el-table-column label="公務(wù)用車" align="center" :show-overflow-tooltip="true">
<!--用車數(shù)據(jù)-->
<el-table-column v-for="(planItem, index) in planList" :key="index" align="center" :label="planItem.dictLabel">
<el-table-column v-for="(stageItem, indexChild) in planItem.stageList" :key="index+'-'+indexChild" align="center"
:label="stageItem.stageLable" width="100">
<!-- <template slot-scope="scope">
<span>{{ scope.row.purposeTypeList[index].stageList[indexChild].value }}</span>
</template> -->
<template slot-scope="scope">
<span v-if="scope.row.purposeTypeList[index].stageList[indexChild].stageLable == '行駛次數(shù)'">
<el-button size="mini" type="text"
@click="handleInfo(scope.row,2, scope.row.month,planItem.stageList[indexChild].carType)">
{{ scope.row.purposeTypeList[index].stageList[indexChild].value }}
</el-button>
</span>
<span v-else>{{ scope.row.purposeTypeList[index].stageList[indexChild].value }}</span>
</template>
</el-table-column>
</el-table-column>
</el-table-column>
</el-table>
<!-- table表格區(qū)域結(jié)束 -->
<!-- 分頁區(qū)域 -->
<pagination v-show="total>0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize"
@pagination="getList" />
<!-- 分頁區(qū)域結(jié)束 -->
</div>
</template>
<script>
import {
selectMileageSumary,
exportMileageSumary,
exportDailyMileage
} from "@/api/amtestdriver/drivecar";
import Treeselect from "@riophae/vue-treeselect";
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
import {
selectDept
} from "@/api/system/dept";
import {
listArea,
} from "@/api/base/area/area";
import {
listData
} from "@/api/base/carBrand/carBrand";
export default {
name: "Mileagereport",
components: {
Treeselect
},
data() {
return {
brandOptions: [], //品牌查詢
areaOptions: [], //區(qū)域
deptOptions: [], //店面
planList: [],//公務(wù)車數(shù)據(jù)
dateRange: [],
// 遮罩層
loading: true,
// 導(dǎo)出遮罩層
exportLoading: false,
// 選中數(shù)組
ids: [],
// 非單個禁用
single: true,
// 非多個禁用
multiple: true,
// 顯示搜索條件
showSearch: false,
title: "",
open: false,
mileageList: [],
// 總條數(shù)
total: 0,
// 查詢參數(shù)
queryParams: {
pageNum: 1,
pageSize: 10,
storeId: null,
brandId: null,
areaId: null,
}
};
},
created() {
this.getList();
this.listDeptByType(2);
listData(this.queryParams).then(response => {
this.brandOptions = response.data;
});
listArea().then((response) => {
this.areaOptions = this.handleTree(response.data, "id", "parentId");
});
},
methods: {
normalizer2(node) {
if (node.children && !node.children.length) {
delete node.children;
}
return {
id: node.id,
label: node.name,
children: node.children,
};
},
//加載店面列表
listDeptByType(type) {
this.queryParams.type = type;
selectDept(this.queryParams).then(response => {
this.deptOptions = this.handleTree(response.data, "deptId");
if (response.data.length == 1) {
this.queryParams.storeId = response.data[0].deptId;
}
});
this.queryParams.type = null;
},
normalizerDept(node) {
if (node.children && !node.children.length) {
delete node.children;
}
return {
id: node.deptId,
label: node.deptName,
children: node.children
};
},
handleSelectionChange(selection) {
this.ids = selection.map(item => item.id)
this.single = selection.length !== 1
this.multiple = !selection.length
},
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
getList() {
this.loading = true;
if (null != this.dateRange && this.dateRange.length > 0) {
this.queryParams.startTime = this.dateRange[0];
this.queryParams.endTime = this.dateRange[1];
} else {
this.queryParams.startTime = null;
this.queryParams.endTime = null;
}
selectMileageSumary(this.queryParams).then(response => {
this.mileageList = response.rows;
console.log(response.rows);
this.mileageList.forEach((res, index) => {
this.mileageList[index].purposeTypeList.forEach((re, aaa) => {
this.stageList=[];
if(this.mileageList[index].purposeTypeList[aaa].driveCarMileageSumary!=null){
this.stageList.push({stageLable: '行駛次數(shù)',value: this.mileageList[index].purposeTypeList[aaa].driveCarMileageSumary.officialMount,
carType:this.mileageList[index].purposeTypeList[aaa].dictValue});
this.stageList.push({stageLable: '里程數(shù)(KM)',value: this.mileageList[index].purposeTypeList[aaa].driveCarMileageSumary.officialMileage});
this.stageList.push({stageLable: '時長(分鐘)',value: this.mileageList[index].purposeTypeList[aaa].driveCarMileageSumary.officialTime});
this.stageList.push({stageLable: 'GPS預(yù)估數(shù)',value: this.mileageList[index].purposeTypeList[aaa].driveCarMileageSumary.officialPredictMileage});
this.stageList.push({stageLable: '里程占比',value: this.mileageList[index].purposeTypeList[aaa].driveCarMileageSumary.officialMileageProportion});
}else{
this.stageList.push({stageLable: '行駛次數(shù)',value: null,carType: null});
this.stageList.push({stageLable: '里程數(shù)(KM)',value: null});
this.stageList.push({stageLable: '時長(分鐘)',value: null});
this.stageList.push({stageLable: 'GPS預(yù)估數(shù)',value: null});
this.stageList.push({stageLable: '里程占比',value: null});
}
this.mileageList[index].purposeTypeList[aaa].stageList = this.stageList;
})
})
this.planList = (this.mileageList[0] && this.mileageList[0]['purposeTypeList']) || [];
this.total = response.total;
this.loading = false;
});
},
// 詳情跳轉(zhuǎn)
handleInfo(row, type, val, carType) {
if (val != 0) {
let seaParams = {};
seaParams = this.queryParams;
seaParams.storeId = row.storeId;
seaParams.appType = String(type);
seaParams.dateRange = this.dateRange;
seaParams.type = carType,
this.$router.push({
path: '/mileage-report/details',
query: seaParams,
})
// console.log("this.queryParams",this.queryParams);
}
},
// 重置按鈕
resetQuery() {
this.queryParams.startTime = []
this.queryParams.endTime = []
this.dateRange = [];
this.resetForm("queryForm");
this.handleQuery();
},
/** 導(dǎo)出按鈕操作 */
handleExport() {
const queryParams = this.queryParams;
this.$confirm("是否導(dǎo)出里程報表數(shù)據(jù)?", "警告", {
confirmButtonText: "確定",
cancelButtonText: "取消",
type: "warning",
})
.then(() => {
this.exportLoading = true;
return exportMileageSumary(queryParams);
})
.then((response) => {
// console.log(response)
this.downloads(response);
this.exportLoading = false;
})
},
/**
* 導(dǎo)出下載
* @param {Object} response
*/
downloads(response) { // 拿到數(shù)據(jù)以后 通過 new Blob對象 創(chuàng)建excel
if (!response) {
return
}
let time = this.getNowTime();
let fileName = time + '里程報表數(shù)據(jù).xls'
const blob = new Blob([response], {
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8'
})
// const blob = new Blob(["\ufeff",response], {type: 'text/plain'});
const href = window.URL.createObjectURL(blob)
const downloadElement = document.createElement('a')
downloadElement.style.display = 'none'
downloadElement.href = href
downloadElement.download = fileName
document.body.appendChild(downloadElement)
downloadElement.click()
document.body.removeChild(downloadElement) // 下載完成移除元素
window.URL.revokeObjectURL(href) // 釋放掉blob對象
},
// 獲取當(dāng)前時間
getNowTime() {
var nowDate = new Date();
var year = nowDate.getFullYear();
var month = nowDate.getMonth() + 1 < 10 ? "0" + (nowDate.getMonth() + 1) : nowDate.getMonth() + 1;
var day = nowDate.getDate() < 10 ? "0" + nowDate.getDate() : nowDate.getDate();
var dateStr = year + "" + month + "" + day;
return dateStr;
},
}
};
</script>
<style>
.header {
padding: 20px;
margin-bottom: 10px;
border-bottom: 1px solid #e6ebf5;
}
</style>總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
基于Vue3實現(xiàn)鼠標(biāo)滑動和滾輪控制的輪播
在這篇文章主要為大家詳細介紹了如何一步步地實現(xiàn)一個基于?Vue?3?的輪播組件,這個組件的特點是可以通過鼠標(biāo)滑動和滾輪來控制輪播圖的切換,感興趣的可以了解下2024-02-02
Vue 列表頁帶參數(shù)進詳情頁的操作(router-link)
這篇文章主要介紹了Vue 列表頁帶參數(shù)進詳情頁的操作(router-link),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-11-11
Vue?Router嵌套路由(children)的用法小結(jié)
嵌套路由就是父路由里面嵌套他的子路由,父路由有自己的路由導(dǎo)航和路由容器(router-link、router-view),通過配置children可實現(xiàn)多層嵌套,這篇文章主要介紹了Vue--Router--嵌套路由(children)的用法,需要的朋友可以參考下2022-08-08
Vue使用openlayers實現(xiàn)繪制圓形和多邊形
這篇文章主要為大家詳細介紹了Vue如何使用openlayers實現(xiàn)繪制圓形和多邊形,文中的示例代碼講解詳細,感興趣的小伙伴快跟隨小編一起動手嘗試一下2022-06-06
使用vue-cli創(chuàng)建項目并webpack打包的操作方法
本文給大家分享使用vue-cli創(chuàng)建項目基于webpack模板打包的配置方法,本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧2021-07-07
Vue 實現(xiàn)高級穿梭框 Transfer 封裝過程
本文介紹了基于Vue2和Element-UI實現(xiàn)的高級穿梭框組件Transfer的設(shè)計與技術(shù)方案,組件支持多項選擇,并能實時同步已選擇項,包含豎版和橫版設(shè)計稿,并提供了組件的使用方法和源碼,此組件具備本地分頁和搜索功能,適用于需要在兩個列表間進行數(shù)據(jù)選擇和同步的場景2024-09-09
vue中報錯Duplicate?keys?detected:'1'.?This?may?c
我們在vue開發(fā)過程中常會遇到一些錯誤,這篇文章主要給大家介紹了關(guān)于vue中報錯Duplicate?keys?detected:‘1‘.?This?may?cause?an?update?error的解決方法,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下2023-03-03

