复杂表格设计数据格式

简介: 复杂表格设计数据格式

1. 表头设计


原理:


和多叉树的原理类似,参考了它的展示形式。


微信图片_20220512125830.png


表头说明:


如果没有孩子节点就只返回如下一个字段:


  • name :名字


如果有孩子节点,就把数据加在children里面,层层嵌套,返回字段如下:


  • name :名字
  • children : 孩子节点


数据结构格式,参考如下代码:


headerData:[
            {
                name: '地区',
            },
            {
                name: '总数据',
                children: [
                    {
                        name: '数据1',
                        children: [
                            {
                                name: '数据11',
                                children: [
                                    {
                                        name: '数据111',
                                    },
                                    {
                                        name: '数据112',
                                    }
                                ]
                            },
                            {
                                name: '数据12',
                                children: [
                                    {
                                        name: '数据121',
                                    },
                                    {
                                        name: '数据122',
                                    }
                                ]
                            },
                            {
                                name: '数据13',
                                children: [
                                    {
                                        name: '数据131',
                                    },
                                    {
                                        name: '数据132',
                                    }
                                ]
                            },
                            {
                                name: '数据14',
                            },
                        ]
                    }
                ]
            }
        ];


表头的宽高方面,前端计算,后端不用管,按照如下格式返回数据即可。


2. 表格数据格式


每一项按照表头展示的顺序返回,通过数组的形式

返回一个参数:


  • bodyData:总数据


数据结构格式参考代码如下:


bodyData:[
        ["地区最先","数据111","数据112","数据121","数据122","数据131","数据132","数据14"],
        ["地区","数据111","数据112","数据121","数据122","数据131","数据132","数据14"],
        ["地区","数据111","数据112","数据121","数据122","数据131","数据132","数据14"],
        ["地区","数据111","数据112","数据121","数据122","数据131","数据132","数据14"],
        ["地区","数据111","数据112","数据121","数据122","数据131","数据132","数据14"],
        ["地区","数据111","数据112","数据121","数据122","数据131","数据132","数据14"],
        ["地区","数据111","数据112","数据121","数据122","数据131","数据132","数据14"],
        ["地区","数据111","数据112","数据121","数据122","数据131","数据132","数据14"], 
        ["地区","数据111","数据112","数据121","数据122","数据131","数据132","数据14"], 
        ["地区最后","数据111","数据112","数据121","数据122","数据131","数据132","数据14"], 
    ]


3. 效果


如上表头与表格数据代码生成的效果如图:


微信图片_20220512130025.png


4. 代码


语法高亮用到 codemirror 插件


/**
 * 递归遍历 格式化数组
 * @param { Array } paramArr 目标数组
 * @param { Number } level 层级
 */
export function formatArray(paramArr, level) {
  let levelFirst = Number(level)
  const arr = []
  let childArr = []
  for (let i = 0; i < paramArr.length; i++) {
      let obj = {}
      for (let j in paramArr[i]) {
          if (j != 'children') {
              obj[j] = paramArr[i][j]
          }
          obj['level'] = levelFirst
          obj['width'] = getLeafCountTree(paramArr[i])
          if (!paramArr[i].children) {
              obj['childrenNumber'] = 0
              // LeafNode: 叶子节点就是树中最底段的节点
              // obj['isLeafNode'] = true
          } else {
              // obj['isLeafNode'] = false
              obj['childrenNumber'] = paramArr[i].children.length
          }
      }
      arr.push(obj)
      if (paramArr[i].children) {
          let lev = Number(levelFirst) + 1
          childArr = childArr.concat(formatArray(paramArr[i].children, lev));
      }
  }
  let endArr = arr.concat(childArr)
  return endArr
}


/**
 * 获取 节点的所有叶子节点个数
 * @param {Object} json Object对象
 */
export function getLeafCountTree(json) {
  if(!json.children){
      return 1;
  }else{
      var leafCount = 0;
      for(var i = 0 ; i < json.children.length ; i++){
          leafCount = leafCount + getLeafCountTree(json.children[i]);
      }
      return leafCount;
  }
}


// json对对象字符串的格式化,美化
export function  jsonFromat (text_value){
    if(text_value == ""){
       alert("不能为空");  
       return false;
    } else {
          var json=eval('(' + text_value + ')');
          text_value=JSON.stringify(json);
          var res="";
          for(var i=0,j=0,k=0,ii,ele;i<text_value.length;i++)
          {//k:缩进,j:""个数
              ele=text_value.charAt(i);
              if(j%2==0&&ele=="}")
              {
                  k--;                
                  for(ii=0;ii<k;ii++) ele="    "+ele;
                  ele="\n"+ele;
              }
              else if(j%2==0&&ele=="{")
              {
                  ele+="\n";
                  k++;     
                  for(ii=0;ii<k;ii++) ele+="    ";
              }
              else if(j%2==0&&ele==",")
              {
                  ele+="\n";
                  for(ii=0;ii<k;ii++) ele+="    ";
              }
              else if(ele=="\"") j++;
              res+=ele;        
          }
          return res
    }
  }


<template>
    <div class="pages-tables " id="pages-tables">
        <div class="textarea">
            <h1 class="title">复杂表头 json 数据格式验证:</h1>
            <p class="message">表头展示效果如下:</p>
            <div class="rolling-table auto-table" ref="tableBox" :style="{height: maxHeight + 'px'}">
                <table class="table" id="table" cellpadding="0" cellspacing="0" ref="rollingTable">
                    <thead ref="thead">
                        <tr v-for="(x,i) in headerList" :key="i">
                            <th class="rows " :class="{'cross': index == 0 && i == 0}" v-for="(l,index) in x" :key="index" :colspan="l.width" :rowspan="l.height">{{l.name}}</th>
                        </tr>
                    </thead>
                    <tbody>
                        <tr v-for="(b,i) in bodyList" :key="i + 'a'">
                            <template v-for="(x, index) in b">
                                <td :class="{'cols':  index == 0 }" :key="index + 'b'">
                                    {{ x | valueFromt }}
                                </td>
                            </template>
                        </tr>
                        <tr></tr>
                    </tbody>
                </table>
            </div>
            <p class="message">提示:输入 json 覆盖原来的即可,且有验证 json 格式是否正确的功能</p>
            <div class="control">
                <!-- <div class="content fl">
                    <p>select a theme:
                        <select @change="selectTheme" v-model="selected">
                            <option>default</option>
                            <option>night</option>
                            <option>monokai</option>
                            <option>neat</option>
                            <option>elegant</option>
                            <option>cobalt</option>
                            <option>eclipse</option>
                            <option>rubyblue</option>
                            <option>lesser-dark</option>
                            <option>xq-dark</option>
                        </select>
                    </p>
                </div>
                <div class="content fl ml20">
                    <p>select the editor language:
                        <select @change="selectMode" v-model="mode">
                            <option>javascript</option>
                            <option>php</option>
                            <option>python</option>
                            <option>vue</option>
                            <option>xml</option>
                            <option>sql</option>
                            <option>http</option>
                            <option>css</option>
                            <option>sass</option>
                            <option>jsx</option>
                            <option>django</option>
                        </select>
                    </p>
                </div>
                <div class="content fl ml20">
                    <p>select keyMap:
                        <select @change="selectKeyMap" v-model="keyMap">
                            <option>default</option>
                            <option>emacs</option>
                            <option>sublime</option>
                            <option>vim</option>
                        </select>
                    </p>
                </div> -->
                <div class="fl ml20 mt20 mb10 submit">
                    <mt-button type="primary"  size="small" @click.native="setInputValue">提交</mt-button>
                </div>
                <div class="clearfix"></div>
            </div>
            <textarea id="code" name="code">
                [
                    {
                        name: '地区',
                    },
                    {
                        name: '总数据',
                        children: [
                            {
                                name: '数据1',
                                children: [
                                    {
                                        name: '数据11',
                                        children: [{
                                            name: '数据111',
                                        },
                                        {
                                            name: '数据112',
                                        }
                                        ]
                                    },
                                    {
                                        name: '数据12',
                                        children: [{
                                            name: '数据121',
                                        },
                                        {
                                            name: '数据122',
                                        }
                                        ]
                                    },
                                    {
                                        name: '数据13',
                                        children: [{
                                            name: '数据131',
                                        },
                                        {
                                            name: '数据132',
                                        }
                                        ]
                                    },
                                    {
                                        name: '数据14',
                                    },
                                    {
                                        name: '数据15',
                                    },
                                    {
                                        name: '数据16数据16数据16数据16',
                                    },
                                    {
                                        name: '数据17',
                                    },
                                ]
                            }
                        ]
                    }
                ];
            </textarea>
        </div>
    </div>
</template>
<script>
// 说明这个 demo 是给 pc 端用的,单位要为 px
import { formatArray, getLeafCountTree, jsonFromat } from "libs/common/common";
import { Button, MessageBox } from 'mint-ui';
import * as CodeMirror from 'codemirror/lib/codemirror'
// 根据设置的主题,引入相应的主题包,主题包存储在theme下,使用其他主题包时设置option中theme为对应主题
import 'codemirror/lib/codemirror.css'
import 'codemirror/theme/monokai.css'
import 'codemirror/theme/neat.css'
import 'codemirror/theme/elegant.css'
import 'codemirror/theme/night.css'
import 'codemirror/theme/cobalt.css'
import 'codemirror/theme/eclipse.css'
import 'codemirror/theme/rubyblue.css'
import 'codemirror/theme/xq-dark.css'
// styleActiveLine: 设置光标所在行高亮true/false,需引入工具包:
import 'codemirror/addon/selection/active-line'
// 根据设置的编辑器语言,引入相应工具包,以下为常用语言包
import 'codemirror/mode/javascript/javascript'
import 'codemirror/mode/go/go'
import 'codemirror/mode/php/php'
import 'codemirror/mode/python/python'
import 'codemirror/mode/http/http'
import 'codemirror/mode/sql/sql'
import 'codemirror/mode/vue/vue'
import 'codemirror/mode/xml/xml'
import 'codemirror/mode/css/css'
import 'codemirror/mode/sass/sass'
import 'codemirror/mode/jsx/jsx'
import 'codemirror/mode/django/django'
// keyMap:快捷键,default使用默认快捷键,除此之外包括emacs,sublime,vim快捷键,使用需引入工具
import 'codemirror/keymap/sublime.js'
import 'codemirror/keymap/emacs.js'
import 'codemirror/keymap/vim.js'
// extraKeys 快捷键,例如 {“Ctrl-Q”: “autocomplete”}:自动补全使用需要引入工具
import 'codemirror/addon/hint/show-hint'
import 'codemirror/addon/hint/javascript-hint'
import 'codemirror/addon/hint/sql-hint'
import 'codemirror/addon/hint/html-hint'
import 'codemirror/addon/hint/xml-hint'
import 'codemirror/addon/hint/anyword-hint'
import 'codemirror/addon/hint/css-hint'
import 'codemirror/addon/hint/show-hint'
export default {
    data() {
        return {
            mapArray: [],
            keyMap: 'default',
            mode: 'javascript',
            editor: '',
            selected: 'monokai',
            header: '',
            maxHeight: '100%',
            theadHeight: '100%',
            offsetHeight: 0,
            scroll: {
                scroller: null
            },
            headerList: [],
            bodyList: [],
        }
    },
    filters: {
        valueFromt: function (value) {
            let realValue = ''
            if (!value) return ''
            value = value.toString()
            if (value.length > 20) {
                realValue = value.slice(0, 15) + '...'
            } else {
                realValue = value
            }
            return realValue
        },
    },
    methods: {
        selectKeyMap(){
            this.editor.addKeyMap(this.keyMap)  
        },
        selectMode(){
            this.editor.setOption("mode",this.mode)   
        },
        selectTheme() {
            this.editor.setOption("theme", this.selected);
        },
        setInputValue() {
            this.header = this.editor.getValue();
            if(this.header){
                this.change()
            }
        },
        change() {
            try {
                const newData = formatArray(eval(this.header), 0)
                let maxLevel = newData[newData.length - 1].level
                this.setHeight(newData, maxLevel + 1)
                this.arayLayered(newData, maxLevel)
                this.headerList = this.arayLayered(newData, maxLevel)
            } catch (e) {
                console.log('e:', e)
                MessageBox('提示', '请检查 json 格式是否正确!!!');
            }
        },
        setHeight(arr, maxLevel) {
            // console.log("setHeight maxLevel", maxLevel)
            for (let i = maxLevel; i >= 0; i--) {
                for (let j = 0; j < arr.length; j++) {
                    // 设置高
                    if (arr[j].childrenNumber) {
                        arr[j].height = 1
                    } else {
                        arr[j].height = maxLevel - arr[j].level
                    }
                }
            }
            return arr
        },
        arayLayered(arr, maxLevel) {
            let returnArr = []
            for (let i = 0; i <= maxLevel; i++) {
                let arrLevel = []
                for (let j = 0; j < arr.length; j++) {
                    if (arr[j].level == i) {
                        arrLevel.push(arr[j])
                    }
                }
                returnArr[i] = arrLevel
            }
            return returnArr
        }
    },
    mounted() {
        let bodyListA = [
            ["地区最先", "数据111", "数据112", "数据121", "数据122", "数据131", "数据132", "数据14"],
            ["地区", "数据111", "数据112", "数据121", "数据122", "数据131", "数据132", "数据14"],
            ["地区", "数据111", "数据112", "数据121", "数据122", "数据131", "数据132", "数据14"],
            ["地区", "数据111", "数据112", "数据121", "数据122", "数据131", "数据132", "数据14"],
            ["地区", "数据111", "数据112", "数据121", "数据122", "数据131", "数据132", "数据14"],
            ["地区", "数据111", "数据112", "数据121", "数据122", "数据131", "数据132", "数据14"],
            ["地区", "数据111", "数据112", "数据121", "数据122", "数据131", "数据132", "数据14"],
            ["地区", "数据111", "数据112", "数据121", "数据122", "数据131", "数据132", "数据14"],
            ["地区", "数据111", "数据112", "数据121", "数据122", "数据131", "数据132", "数据14"],
            ["地区最后", "数据111", "数据112", "数据121", "数据122", "数据131", "数据132", "数据14"],
        ]
        const data = [
            {
                name: '地区',
            },
            {
                name: '总数据',
                children: [
                    {
                        name: '数据1',
                        children: [
                            {
                                name: '数据11',
                                children: [{
                                    name: '数据111',
                                },
                                {
                                    name: '数据112',
                                }
                                ]
                            },
                            {
                                name: '数据12',
                                children: [{
                                    name: '数据121',
                                },
                                {
                                    name: '数据122',
                                }
                                ]
                            },
                            {
                                name: '数据13',
                                children: [{
                                    name: '数据131',
                                },
                                {
                                    name: '数据132',
                                }
                                ]
                            },
                            {
                                name: '数据14',
                            },
                            {
                                name: '数据15',
                            },
                            {
                                name: '数据16数据16数据16数据16',
                            },
                            {
                                name: '数据17',
                            },
                        ]
                    }
                ]
            }
        ];
        this.header = jsonFromat(JSON.stringify(data))
        const newData = formatArray(data, 0)
        let maxLevel = newData[newData.length - 1].level
        this.setHeight(newData, maxLevel + 1)
        this.arayLayered(newData, maxLevel)
        this.headerList = this.arayLayered(newData, maxLevel)
        this.editor = CodeMirror.fromTextArea(document.getElementById("code"), {
            // value : data,  // 文本域默认显示的文本
            lineNumbers: true, /* 定义是否显示行号 */
            mode: "javascript",  /* 定义语法的类型,如果是html则为:text/html */
            theme: "monokai", /* 定义主题 */
            smartIndent: true,  // 是否智能缩进
            styleActiveLine: true,
            keymap:"defaule"
        });
        // this.editor.on("changes",() =>{
        //     //编译器内容更改事件
        //     this.setInputValue();
        // });
        this.editor.setSize(1200,500)
    }
}
</script>
<style lang="less" >
.CodeMirror {
    border: 1px solid black;
    line-height: 16px;
    font-size: 16px;
    text-align: left;
}
</style>
<style lang="less" scoped>
.submit{
    margin-left: 580px;
    margin-top: 20px;
}
textarea{
    width: 1300px;
    height: 1300px;
}
.content{
    font-size: 16px;
}
.textarea{
    text-align: center;
    font-size: 20px;
    .title{
        margin-top: 20px;
        font-size: 30px;
        color: #333;
    }
    textarea{
        border: 1px solid #eee;
        font-size: 16px;
        resize: both;
        width: 800px;
        min-height: 900px;
    }
}
.message{
    color: red;
    font-size: 16px;
}
.waterMask {
    position: absolute;
    width: 100%;
    height: 100%;
    z-index: 4;
    pointer-events: none;
}
.pages-tables {
  -webkit-overflow-scrolling: touch; // ios滑动顺畅
  position: relative;
  margin-left: 5%;
  padding-bottom: 160px;
  margin: 0 auto;
  width: 1200px;
}
.rolling-table {
    height: 100%;
    font-size: 0.28rem;
    color: #86939a;
    background-color: #fff;
    width: 100%;
    -webkit-overflow-scrolling: touch;
    position: relative;
    top: 0;
    // overflow: hidden;
  }
.rows {
    position: relative;
    z-index: 3;
}
.cross {
    position: relative;
    z-index: 5;
}
table td {
  border: 0px solid #000;
  font-size: 25px;
  background: #fff;
}
::-webkit-scrollbar {
    display: none;
}
.table {
  border-collapse: collapse; //去掉重复的border
  color: #86939e;
  font-size: 25px;
  border: 0px solid #000;
  min-height: 100%;
  text-align: center;
  td {
    border-bottom: 1px solid #eee;
    height: 30px;
    line-height: 30px;
    padding: 0 0.2rem;
    // white-space: nowrap;
    white-space: inherit;
    max-width: 500px;
    min-width: 50px;
    // overflow:hidden; 
    // text-overflow:ellipsis;
    // -webkit-line-clamp:2; 
  }
  th {
    color: #43484d;
    white-space: pre-wrap;
    height: 36px;
    line-height: 36px;
    padding: 5px 6px;
    background-color: #f3f4f6;
    font-weight: normal;
    padding-bottom: 0;
    padding-top: 0;
    max-width: 200px;
    border: 1px solid red;
    &:last-child{
        // border-right: 0rem solid #e4e8f5;
    }
  }
}
tr{
    position: relative;
    background-color: #fff;
    &:nth-of-type(odd){
        td{
            background-color: #ebf9fc;
        }
    }
}
</style>


5. 效果链接:


效果链接如下:


复杂表格设计数据格式


动态效果:


微信图片_20220512130404.gif

相关文章
|
8天前
|
数据采集 JSON 数据可视化
JSON数据解析实战:从嵌套结构到结构化表格
在信息爆炸的时代,从杂乱数据中提取精准知识图谱是数据侦探的挑战。本文以Google Scholar为例,解析嵌套JSON数据,提取文献信息并转换为结构化表格,通过Graphviz制作技术关系图谱,揭示文献间的隐秘联系。代码涵盖代理IP、请求头设置、JSON解析及可视化,提供完整实战案例。
JSON数据解析实战:从嵌套结构到结构化表格
|
Android开发
安卓中显示表格并将表格数据以excel格式导出
安卓中显示表格并将表格数据以excel格式导出
474 0
|
10月前
|
存储 NoSQL 关系型数据库
表格结构
表格结构
147 1
|
Rust 自然语言处理 算法
【算法】2194. Excel 表中某个范围内的单元格(多语言实现)
Excel 表中的一个单元格 (r, c) 会以字符串 "<col><row>" 的形式进行表示,其中: <col> 即单元格的列号 c 。用英文字母表中的 字母 标识。 例如,第 1 列用 'A' 表示,第 2 列用 'B' 表示,第 3 列用 'C' 表示,以此类推。 <row> 即单元格的行号 r 。第 r 行就用 整数 r 标识。 给你一个格式为 "<col1><row1>:<col2><row2>" 的字符串 s ,其中 <col1> 表示 c1 列,<row1> 表示 r1 行,<col2> 表示 c2 列,<row2> 表示 r2 行,并满足
【算法】2194. Excel 表中某个范围内的单元格(多语言实现)
|
关系型数据库 RDS 监控
日志服务数据加工最佳实践: 构建字典与表格做数据富化
本篇介绍日志服务数据加工最佳实践: 构建字典与表格做数据富化, 覆盖多种方式: 直接, 任务配置, 字典表格函数, RDS-MySQL, 其他Logstore等
1715 0
|
开发工具
规则引擎到表格储存
1.规则引擎只需要配置主键列 2.table表格属性列会自动添加 3.预定义列的测试
238 0
规则引擎到表格储存
|
10月前
|
自然语言处理 中间件 测试技术
中间件数据格式结构化数据与非结构化数据之间的转换
中间件数据格式结构化数据与非结构化数据之间的转换
146 3