thinkphp做的商城网站分销平台,河北城乡建设部网站首页,广州招聘网最新招聘,广州专业网站改版设计公司背景 前端统计列表#xff0c;数据乱序。按日期、产品、阶段、DD项#xff08;所有header名称乱写#xff09;排序#xff0c;列表如下。 示例  
日期产品阶段DDEEFFGG20240414产品1阶段1场景1A01场景2B01其他A0120240410产品1阶段1场景2B01其他A0120240402产品2阶段1场景3…背景 前端统计列表数据乱序。按日期、产品、阶段、DD项所有header名称乱写排序列表如下。 示例  
日期产品阶段DDEEFFGG20240414产品1阶段1场景1A01场景2B01其他A0120240410产品1阶段1场景2B01其他A0120240402产品2阶段1场景3B01场景4A01场景5B01场景6A01产品1阶段2场景7B01场景9A01场景8B01阶段1场景10A01场景11B01场景12A01阶段1B01场景2A01其他B01A01B01A01B01A01B01A01B01A0120240401产品1阶段2场景7B01阶段1场景1A01场景11B01场景12A01场景2B01其他A01B01A01B01A01 el-table项目合并方法 :span-method “objectSpanMethods” row行数据         column列数据         rowIndex 行下标         columnIndex 列下标  objectSpanMethods({ row, column, rowIndex, columnIndex }) { // 列num_ 行num let key  columnIndex  _  rowIndex; if (this.tableMergeIndex[key]) { return this.tableMergeIndex[key]; } }, 
合并原理 
0,02,11,01,11,11,10,25,11,23,11,52,1 以行为例不合并列相当一个二维表格 (yx)  (0,2) 第一列 第三行  5,1 代表5行一列 其他 比如上表中 0,1  为  0,1   代表行的高度0列为1个高度。 有个初步概念如果我们要达到示例中的效果我们应该怎么做。 
featch到的数据处理后然后按 属性dt,p1,p2,p3 排序 当然如果 有其他这种中文自己考虑特殊处理 dt(日期好比较大小)p1 值固定 [1,2]p2 值固定 [1,2]p3 汉字排序特殊 其他放在最后 把特殊的位置处理后其他做填充 我们特殊数组A   tableMergeIndex [] const key columnIndex  _  rowIndex; tableMergeIndex[key]  [ 行数,1]   比如 tableMergeIndex[0_2]  [5,1]    ableMergeIndex[1_2] [3,1]  有了这些特殊的处理 如果是前4列有合并 后面不需要合并 我们需要生成一个数组 B 前四列 所有值 [0,1] 其他所有[1,1] 在把上面合并数组A 合并到 数组B就是我们的目标数组 for (let i  0; i  this.tableData.length; i) {for (let j  0; j  this.mergeCols.length; j) {const key  j  _  i;if (j  4) {if (tableMergeIndex[key]) {newList[key]  tableMergeIndex[key];} else {newList[key]  [0, 1];}} else {newList[key]  [1, 1];}}}  
0,02-11,01-11,11-10,25-11,23-11,52-1 
思路 基于第2点考虑怎么得到0,2[5,1]                                               (1,2)  [3,1]其实从我们数据层面就能很好划分从示例就很好看出来日期 -》产品-》阶段-》DD 当前 20240414日中最大的行数 是3行 产品、阶段、DD都不能超过3。所以有层级关系。 我的思路 :         1获取数据按属性升序或降序排序 如dt-》 desc       p1 -》asc         2按第1点中属性排序方式获取每种属性出现的所有的值和具体次数得到一个数组proptyNumList用于合并项赋值用数组格式如下  [     { 20240401: 10,        20240402: 22,        20240410: 2,        20240414: 2,        20240415: 1     },     {         1: 4,  2: 33     },     { 1: 4, 2: 33     },     {1: 18,  2: 19     },     {  “场景7”:1,  “场景2”:1,其他: 19,     } ]         3  遍历每种属性 生成合并项的数据 
这是第一项数据合并代码。我本来想写递归的没想好。。。上线后优化吧。 let yNum0  0;for (let index0  0;index0  propertyValuesNew[0].length;index0) {let yNum1  yNum0;const name0  propertyValuesNew[0][index0];let key0  0_  yNum0;yNum0  propertyValues[0][name0];list[key0]  [propertyValues[0][name0], 1];}return list; 写在一个循环里面的。不敢展示代码嵌套了4层。我写得真丑         注意     let yNum0  0;                         let yNum1  yNum0;                         let yNum2  yNum1;           的位置 和list push的时候和内层循环的顺序。 propertyListDg(propertyValues, propertyValuesNew) {const list  [];let yNum0  0;for (let index0  0;index0  propertyValuesNew[0].length;index0) {let yNum1  yNum0;const name0  propertyValuesNew[0][index0];// const p0  propertyValues[0][name0];for (let index1  0;index1  propertyValuesNew[1].length;index1) {let yNum2  yNum1;const name1  propertyValuesNew[1][index1];const num  this.getObjectsWithSameValues(this.tableData,[dt, productType],[name0, name1]).length;if (num  0) {let key1  1_  yNum1;yNum1  num;list[key1]  [num, 1];}}// console.log(name0);// console.log(data1);let key0  0_  yNum0;yNum0  propertyValues[0][name0];list[key0]  [propertyValues[0][name0], 1];}return list;}, 
最后得到 合并数组 A,  再执行  el-table项目合并方法 中第二点 就可以了。 监听这个数据的变化 刷新table就行了  this.$refs.market.refresh(); 方法汇总 其中几个用到的几个方法 
按属性排序 
//属性排序数组               sortData: [[dt, desc],[p1, asc],[p2, asc],[p3, asc],[p4, asc],], 调用      this.sortByProperties(list, ...this.sortData); sortByProperties(arr, ...props) {return arr.sort((a, b)  {for (let i  0; i  props.length; i) {const prop  props[i];const [key, order]  Array.isArray(prop)? prop: [prop, asc];// 获取属性值const valueA  a[key];const valueB  b[key];// 比较值考虑升序和降序if (valueA  valueB) {return order  asc ? -1 : 1;}if (valueA  valueB) {return order  asc ? 1 : -1;}// 如果相等比较下一个属性}// 所有属性都相等return 0;});}, 
获取属性出现的次数 getPropertyValues(array, propertys) {const list  [];for (let i  0; i  propertys.length; i) {const prop  propertys[i];const propertyValues  {};array.reduce((acc, item)  {const value  item[prop];if (value in acc) {acc[value];} else {acc[value]  1;}return acc;}, propertyValues);list.push(propertyValues);}return list;}, 
调用 const propertyValues  this.getPropertyValues(this.tableData,this.sortData.map((item)  {return item[0];}));console.log(propertyValues); 
获取对象列表属性具体值出现的次数 getObjectsWithSameValues(arr, properties, vals) {const list  arr.filter((item)  {let isRight  true;for (let index  0; index  properties.length; index) {const element  properties[index];if (item[element] ! vals[index]) {isRight  false;}}return isRight;});// console.log(451, properties, vals, list.length);return list;}, 
调用 
const name3  propertyValuesNew4[index3];            const num  this.getObjectsWithSameValues(this.tableData,[dt,productType,stageType,scenarioNameNew,],[name0, name1, name2, name3]).length; 
注意里面的name0 name1 name2 name3 都是通过获取每个属性值出现的次数的方法拿到再通过遍历每个属性的值数组 拿到。 
另外种方式 思路 判断上一个和下一个是否相同。相同就1然后递归。取到特殊值再合并数组。 
但是会出现bug 自己试试。 
templatediv classpageHandleListv-modelpageData.versionCode:inputShowfalse:search-showfalse:export-showtrue:add-showfalsesearchPlaceholder版本号input-title导出:exportDisabled!tableData.lengthel-date-pickerstylewidth: 260pxclassml10v-modelchatDatetypedaterangealignrightsizesmallunlink-panels:start-placeholderinsertStr(startDay, 4|6, -):end-placeholderinsertStr(endDay, 4|6, -)value-formatyyyyMMddchangechangeDate:picker-optionspickerOptions/el-date-picker/HandleListdiv classtableel-tablev-loadingloadingidstationTableclasstableheight100%tooltip-effectlight:datatableData:span-methodobjectSpanMethodsborderstylewidth: 100%template v-forcols in colConfigs!-- 无需合并的列 --el-table-columnv-ifcols.type  label  !cols.children:keycols.prop:propcols.prop:labelcols.label/el-table-column!-- 需要合并的列 --template v-else-ifcols.type  label  cols.childrenel-table-columnv-forchildren in cols.children:keychildren.prop:propchildren.prop:labelchildren.label//template/template/el-table/div/div
/templatescript
import HandleList from /components/HandleList;
import { getDateForNum } from /utils/formatDate.js;
export default {name: Table,components: { HandleList },data() {return {maxChatQueryDay: 7,chatDate: null,startDay: null,endDay: null,pageData: {startDay: 20231101,endDay: 20231120,versionCode: ,activityType: 首贷长尾,复贷有余额,复贷无余额,授信,productType: 1,},pickerOptions: {shortcuts: [{text: 最近一周,onClick(picker) {const end  new Date();const start  new Date();start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);picker.$emit(pick, [start, end]);},},{text: 最近一个月,onClick(picker) {const end  new Date();const start  new Date();start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);picker.$emit(pick, [start, end]);},},{text: 最近三个月,onClick(picker) {const end  new Date();const start  new Date();start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);picker.$emit(pick, [start, end]);},},],},loading: false,tableData: [{time: 2020-08-10,grade: 三年二班,name: 小明,subjects: 类型一,score: 80,score1: 1120,},{time: 2020-08-10,grade: 三年二班,name: 小明,subjects: 类型二,score: 80,score1: 1120,},{time: 2020-08-10,grade: 三年二班,name: 总成绩,subjects: 总成绩,score: 150,score1: 1120,},{time: 2020-08-10,grade: 三年二4班,name: 小明1,subjects: 类型一,score: 80,score1: 1120,},{time: 2020-08-10,grade: 三年二4班,name: 小明12,subjects: 类型二,score: 80,score1: 1120,},{time: 2020-08-10,grade: 三年二4班,name: 总成绩,subjects: 总成绩,score: 150,score1: 1120,},{time: 2020-08-10,grade: 三年一班,name: 小雷,subjects: 类型二,score: 70,score1: 1120,},{time: 2020-08-10,grade: 三年一班,name: 小雷,subjects: 类型一,score: 80,score1: 1120,},{time: 2020-08-10,grade: 三年一班,name: 总成绩,subjects: 总成绩,score: 150,score1: 1120,},{time: 2020-08-11,grade: 三年三班,name: 小花,subjects: 类型二,score: 60,score1: 1120,},{time: 2020-08-11,grade: 三年三班,name: 小花,subjects: 类型一,score: 601,score1: 1120,},{time: 2020-08-11,grade: 三年三班,name: 小花1,subjects: 类型一,score: 190,score1: 11201,},{time: 2020-08-11,grade: 三年三班,name: 小花1,subjects: 类型二,score: 190,score1: 11201,},{time: 2020-08-11,grade: 三年三班,name: 总成绩,subjects: 总成绩,score: 120,score1: 11201,},{time: 2020-09-11,grade: 三年三班,name: 小花1,subjects: 类型一,score: 190,score1: 1120,},{time: 2020-09-11,grade: 三年三班,name: 小花1,subjects: 类型二,score: 190,score1: 11201,},{time: 2020-09-11,grade: 三年三班,name: 总成绩,subjects: 总成绩,score: 120,score1: 11201,},],// 表格的信息 需要合并的需要放在 children 中colConfigs: [{type: label,children: [{ prop: time, label: 时间 },{ prop: grade, label: 年级 },{ prop: name, label: 姓名 },{ prop: subjects, label: 科目 },{ prop: score, label: 成绩 },{ prop: score1, label: 成绩1 },],},// { type: label, prop: age, label: 年龄 }],// 需要合并的行列信息 index必须是table表格对应的下标 不能随意修改mergeCols: [{ index: 0, name: time },{ index: 1, name: grade },{ index: 2, name: name },{ index: 3, name: subjects },{ index: 4, name: score },{ index: 5, name: score1 },// { index: 5, name: age }],// 用来记录每一个单元格的下标tableMergeIndex: [],};},methods: {// 获取当前时间getCurrentTime() {const startDay  getDateForNum(-this.maxChatQueryDay).replace(/-/g, );this.startDay  startDay;const endDay  getDateForNum(0).replace(/-/g, );this.endDay  endDay;this.$set(this, chatDate, [startDay, endDay]);this.pageData.startDay  startDay;this.pageData.endDay  endDay;},// 当前时间修改changeDate(val) {if (val) {this.pageData.startDay  val[0];this.pageData.endDay  val[1];} else {this.pageData.startDay  this.startDay;this.pageData.endDay  this.endDay;}this.fetch();},/**** param {*} source  原数据* param {*} start   下标位置用|隔开* param {*} newStr  添加的符号*/// 日期格式修改:后台返回:20240101  insertStr(startDay, 4|6, -)insertStr(source, start, newStr) {if (!source) {return ;}const list  start.split(|);list.forEach((num, index)  {const i  Number(num)  index;source  source.slice(0, i)  newStr  source.slice(i);});return source;},objectSpanMethods({ row, column, rowIndex, columnIndex }) {let key  columnIndex  _  rowIndex;if (this.tableMergeIndex[key]) {return this.tableMergeIndex[key];}},newTableMergeData() {for (let i  0; i  this.tableData.length; i) {for (let j  0; j  this.mergeCols.length; j) {// 初始化行、列坐标信息let rowIndex  1;let columnIndex  1;// 比较横坐标左方的第一个元素if (j  0 this.tableData[i][this.mergeCols[j][name]] this.tableData[i][this.mergeCols[j - 1][name]]) {columnIndex  0;}// 比较纵坐标上方的第一个元素if (i  0 this.tableData[i][this.mergeCols[j][name]] this.tableData[i - 1][this.mergeCols[j][name]] [time, grade, name].includes(this.mergeCols[j][name])) {rowIndex  0;}// 比较横坐标右方元素if (columnIndex  0) {columnIndex  this.onColIndex(this.tableData[i],j,j  1,1,this.mergeCols.length);}// 比较纵坐标下方元素if (rowIndex  0//  [time, grade, name].includes(this.mergeCols[j][name])// [time, grade, name].includes(this.mergeCols[j][name])) {// console.log(i, i  1, 1, this.mergeCols[j][name]);rowIndex  this.onRowIndex(this.tableData,i,i  1,1,this.mergeCols[j][name]);}let key  this.mergeCols[j][index]  _  i;this.tableMergeIndex[key]  [rowIndex, columnIndex];}}},/*** 计算列坐标信息* data 单元格所在行数据* index 当前下标* nextIndex 下一个元素坐标* count 相同内容的数量* maxLength 当前行的列总数*/onColIndex(data, index, nextIndex, count, maxLength) {// 比较当前单元格中的数据与同一行之后的单元格是否相同if (nextIndex  maxLength data[this.mergeCols[index][name]] data[this.mergeCols[nextIndex][name]]) {return this.onColIndex(data, index, nextIndex, count, maxLength);}return count;},/*** 计算行坐标信息* data 表格总数据* index 当前下标* nextIndex 下一个元素坐标* count 相同内容的数量* name 数据的key*/onRowIndex(data, index, nextIndex, count, name) {const nameIndex  this.mergeCols.findIndex((i)  {return i.name  name;});const tIndx  nameIndex || 1;const tName  this.mergeCols[tIndx].name;// 比较当前单元格中的数据与同一列之后的单元格是否相同if (nextIndex  data.length data[index][name]  data[nextIndex][name] // data[index][tName]  data[nextIndex][tName] [time, grade, name].includes(name)) {return this.onRowIndex(data, index, nextIndex, count, name);}return count;},},mounted() {if (this.mergeCols.length  0) {this.newTableMergeData();}this.getCurrentTime()},
};
/scriptstyle langscss scoped/style总结 我使用了一种笨方法实现了需求。主要是理解思路很重要。后面所有类型应该都能理解。         如果能解决问题麻烦给我点个赞非常感谢。 文章转载自: http://www.morning.khyqt.cn.gov.cn.khyqt.cn http://www.morning.kdlzz.cn.gov.cn.kdlzz.cn http://www.morning.fylsz.cn.gov.cn.fylsz.cn http://www.morning.gqcd.cn.gov.cn.gqcd.cn http://www.morning.zbkwj.cn.gov.cn.zbkwj.cn http://www.morning.xnqwk.cn.gov.cn.xnqwk.cn http://www.morning.jnrry.cn.gov.cn.jnrry.cn http://www.morning.tbknh.cn.gov.cn.tbknh.cn http://www.morning.ldfcb.cn.gov.cn.ldfcb.cn http://www.morning.jgncd.cn.gov.cn.jgncd.cn http://www.morning.lfsmf.cn.gov.cn.lfsmf.cn http://www.morning.srkqs.cn.gov.cn.srkqs.cn http://www.morning.hmpxn.cn.gov.cn.hmpxn.cn http://www.morning.xtkw.cn.gov.cn.xtkw.cn http://www.morning.yfphk.cn.gov.cn.yfphk.cn http://www.morning.nlcw.cn.gov.cn.nlcw.cn http://www.morning.cwnqd.cn.gov.cn.cwnqd.cn http://www.morning.bmjfp.cn.gov.cn.bmjfp.cn http://www.morning.yjmlg.cn.gov.cn.yjmlg.cn http://www.morning.gfprf.cn.gov.cn.gfprf.cn http://www.morning.gwjnm.cn.gov.cn.gwjnm.cn http://www.morning.smsjx.cn.gov.cn.smsjx.cn http://www.morning.rkqzx.cn.gov.cn.rkqzx.cn http://www.morning.jhrqn.cn.gov.cn.jhrqn.cn http://www.morning.ctswj.cn.gov.cn.ctswj.cn http://www.morning.kldtf.cn.gov.cn.kldtf.cn http://www.morning.bby45.cn.gov.cn.bby45.cn http://www.morning.jkzq.cn.gov.cn.jkzq.cn http://www.morning.gsksm.cn.gov.cn.gsksm.cn http://www.morning.wwxg.cn.gov.cn.wwxg.cn http://www.morning.ykrkq.cn.gov.cn.ykrkq.cn http://www.morning.pjrgb.cn.gov.cn.pjrgb.cn http://www.morning.cgntj.cn.gov.cn.cgntj.cn http://www.morning.jhtrb.cn.gov.cn.jhtrb.cn http://www.morning.hxcuvg.cn.gov.cn.hxcuvg.cn http://www.morning.mxdhy.cn.gov.cn.mxdhy.cn http://www.morning.c7625.cn.gov.cn.c7625.cn http://www.morning.zpqlf.cn.gov.cn.zpqlf.cn http://www.morning.dkbgg.cn.gov.cn.dkbgg.cn http://www.morning.kchwr.cn.gov.cn.kchwr.cn http://www.morning.hsrch.cn.gov.cn.hsrch.cn http://www.morning.qjsxf.cn.gov.cn.qjsxf.cn http://www.morning.rscrj.cn.gov.cn.rscrj.cn http://www.morning.rxydr.cn.gov.cn.rxydr.cn http://www.morning.bxrqf.cn.gov.cn.bxrqf.cn http://www.morning.brwei.com.gov.cn.brwei.com http://www.morning.dysgr.cn.gov.cn.dysgr.cn http://www.morning.whothehellami.com.gov.cn.whothehellami.com http://www.morning.zfyfy.cn.gov.cn.zfyfy.cn http://www.morning.dytqf.cn.gov.cn.dytqf.cn http://www.morning.nkjnr.cn.gov.cn.nkjnr.cn http://www.morning.tqlhn.cn.gov.cn.tqlhn.cn http://www.morning.nfnxp.cn.gov.cn.nfnxp.cn http://www.morning.npkrm.cn.gov.cn.npkrm.cn http://www.morning.qtqjx.cn.gov.cn.qtqjx.cn http://www.morning.tfznk.cn.gov.cn.tfznk.cn http://www.morning.dybth.cn.gov.cn.dybth.cn http://www.morning.drgmr.cn.gov.cn.drgmr.cn http://www.morning.wsyq.cn.gov.cn.wsyq.cn http://www.morning.xnqjs.cn.gov.cn.xnqjs.cn http://www.morning.zrdhd.cn.gov.cn.zrdhd.cn http://www.morning.zcqtr.cn.gov.cn.zcqtr.cn http://www.morning.nbfkk.cn.gov.cn.nbfkk.cn http://www.morning.sknbb.cn.gov.cn.sknbb.cn http://www.morning.kaakyy.com.gov.cn.kaakyy.com http://www.morning.rzdpd.cn.gov.cn.rzdpd.cn http://www.morning.yqqgp.cn.gov.cn.yqqgp.cn http://www.morning.jfbbq.cn.gov.cn.jfbbq.cn http://www.morning.dgpxp.cn.gov.cn.dgpxp.cn http://www.morning.bbgr.cn.gov.cn.bbgr.cn http://www.morning.zmwzg.cn.gov.cn.zmwzg.cn http://www.morning.rckmz.cn.gov.cn.rckmz.cn http://www.morning.sskkf.cn.gov.cn.sskkf.cn http://www.morning.lcqrf.cn.gov.cn.lcqrf.cn http://www.morning.thzgd.cn.gov.cn.thzgd.cn http://www.morning.dgwrz.cn.gov.cn.dgwrz.cn http://www.morning.pqndg.cn.gov.cn.pqndg.cn http://www.morning.bpmz.cn.gov.cn.bpmz.cn http://www.morning.npmx.cn.gov.cn.npmx.cn http://www.morning.wwkft.cn.gov.cn.wwkft.cn