先上效果图
表头的时间首个是搜索项的endTime,后面的时间则是startTime到endTime-1的正序排列,折线图则是时间的正序排列
1、先实现月份表头,用的是项目封装后的el-table,但是跟直接在页面上实现没有啥区别
//数据结构
{"status":200,"message":"SUCCESS","data":{"records":
[{
"customerName":"客户A",
"applicationId":"11111111",
"statisticNum":
{"2024-01_stock":0,
"2023-09_incr":1,
"2023-10_stock":3,
"2023-09_stock":1,
"2023-12_stock":2,
"2024-02_incr":0,
"2023-12_incr":2,
"2023-11_incr":1,
"2023-11_stock":1,
"2024-01_incr":0,
"2024-02_stock":0,
"2023-10_incr":3}
},],"total":"xxx","size":"xxx","current":"xxx","searchCount":true,"pages":"xxxx"}}
//存量&增量下拉框值v-model="incrOrstock"
<el-option value="6" label="存量&增量"></el-option>
<el-option value="2" label="存量"></el-option>
<el-option value="3" label="增量"></el-option>
//methods
//在调取列表接口前调用获取头部方法getList(){const params = {aa:xxx,bb:xxx};this.generateCols();//调用表头方法tableApi(params).then((res)=>{//处理完下面的表头数据这的this.tableDefs里就有了cols属性,页面上展示的数据用的也是cols里的this.tableDefs.data = res.data.records; //给el-table赋值//从这是后面设置eacharts时用的if (res.data.records.length) {this.incrArr = [];//增量this.stockArr = [];//存量this.statisticNum = [];//总的数据res.data.records.forEach((ele) => {this.statisticNum.push(ele.statisticNum);});}//调用处理echartsthis.initData(); })},//处理时间数据,将endTime放在第一个,其余的正序排getMonthDifference(start_date, end_date) {const start = new Date(start_date);const end = new Date(end_date);const difference = [];difference.push(end_date);//先将endTime放进去while (start < end) {const currentMonth = `${start.getFullYear()}-${(start.getMonth() + 1).toString().padStart(2, "0")}`; //补零difference.push(currentMonth);//时间小于endTime-1时结束循环start.setMonth(start.getMonth() + 1);}//difference就是除endTime的其余时间正序排列return difference;},generateCols() {const months = this.getMonthDifference(this.dateRange[0],//搜索项的startTimethis.dateRange[1]//搜索项的endTime);const cols = [];//第一列表头this.$set(cols, cols.length, {name: "客户名称",field: "customerName",//field就是el-table-column上的propalign: "center",});const chartItem = {name: "统计图",align: "center",cols: [],};//将第一块的二级表头放在统计图下if (this.incrOrstock % 3 === 0) {//下拉框值能整除3就是增量this.$set(chartItem.cols, chartItem.cols.length, {name: "增量",field: "chartIncr",//图表插槽});}if (this.incrOrstock % 2 === 0) {//下拉框值能整除2就是存量this.$set(chartItem.cols, chartItem.cols.length, {name: "存量",field: "chartStock",});}this.$set(cols, cols.length, chartItem);//跟上面一样,将二级表头放在时间一级表头下months.forEach((month) => {const newItem = {name: month,field: "month",align: "center",cols: [],};if (this.incrOrstock % 3 === 0) {this.$set(newItem.cols, newItem.cols.length, {name: "增量",field: "statisticNum." + month + "_incr",align: "center",});}if (this.incrOrstock % 2 === 0) {this.$set(newItem.cols, newItem.cols.length, {name: "存量",field: "statisticNum." + month + "_stock",align: "center",});}this.$set(cols, cols.length, newItem);});this.tableDefs.cols = cols;//放到el-table-column上},
2、实现将charts放到el-table中(主要就是想办法给你要放图标的元素指定id,因为echarts需要获取到指定元素才能初始化)
//这是在el-table中,因为我这是公共table组件,需要加一些判断来防止影响到其他页面
//html<div v-if="item.hasOwnProperty('cols')"><el-table-columnv-for="(item2, index2) in item.cols" //item就是遍历的tableData:key="index2":type="item2.type":label="item2.name":prop="item2.field":align="item.align || 'center'"><template slot-scope="scope"><divv-if="item2.field == 'chartStock'"class="chart_box":id="item2.field == 'chartStock'//重要的就是给id这,想办法给到你要展示图表的元素唯一id值? 'chart_stock_' + scope.$index: ''"></div><divv-if="item2.field == 'chartIncr'"class="chart_box":id="item2.field == 'chartIncr'? 'chart_incr_' + scope.$index: ''"></div>//这下面的判断是为了防止切换单个存量or增量时数据展示错误<div v-if="item2.field.split('_')[1] == 'stock'">{{item.cols.length == 2? scope.row.statisticNum[item.cols[1].field.split(".")[1]]: scope.row.statisticNum[item.cols[0].field.split(".")[1]]}}</div><div v-if="item2.field.split('_')[1] == 'incr' && item.cols">{{ scope.row.statisticNum[item.cols[0].field.split(".")[1]] }}</div></template></el-table-column></div>//methodsinitData() {this.$nextTick(() => {//判断是否下拉选项带着存量if (this.incrOrstock == 6 || this.incrOrstock == 2) {//this.tableDefs.pages.size就是当前table展示几条数据,我这默认是一页十条for (let i = 0; i < this.tableDefs.pages.size; i++) {let stockArr = this.statisticNum[i];let sortArr = [];//归类数组并按时间排序for (let [key, value] of Object.entries(stockArr)) {if (key.split("_")[1] == "stock") {//截取判断一下是否是存量的数据//将存量数据归类按照时间前后排序sortArr.push({ key: key, value: value });}}sortArr.sort((a, b) => {const dateA = new Date(a.key.split("_")[0]);const dateB = new Date(b.key.split("_")[0]);return dateA - dateB;});let dataArr = [];//排序完不需要key值了sortArr.forEach((ele) => {dataArr.push(ele.value); //图标需要的数据});//在el-table-column中已经定义好的id直接获取初始图标就行let myChart = echarts.init(document.getElementById("chart_stock_" + i));// 绘制图表myChart.setOption({xAxis: {type: "category",boundaryGap: false,data: [],},yAxis: {type: "value",axisLabel: {show: false, // 不显示坐标轴上的文字},splitLine: {show: false, // 不显示网格线},axisTick: {show: false, // 不显示坐标轴刻度线},},series: [{data: dataArr,type: "line",areaStyle: {},},],});//监听容器大小发生变化重绘图表const element = document.getElementById("chart_stock_" + i);const resizeObserver = new ResizeObserver((entries) => {myChart.resize();});resizeObserver.observe(element);}}//增量处理方式相同if (this.incrOrstock == 6 || this.incrOrstock == 3) {........}});},