用Echarts实现前端表格引用从属关系可视化

echarts,实现,前端,表格,引用,从属关系,可视化 · 浏览次数 : 9224

小编点评

## 代码解析 这篇文章使用纯前端表格和Echarts将审计审查过程可视化。以下是代码解析的步骤: **1. 引入库** * 使用`spreadSource`存储原始数据。 * 使用`trackCellInfo`存储从属关系的标识。 **2. 创建树状图** * 使用`buildNodeTreeAndPaint`函数递归构建树状图。 * `createNode`函数根据 sheet、row、col、deep、trackType创建每个节点。 **3. 获取引用和从属关系** * 使用`getNodeChild`函数根据trackType获取对应关系的节点。 **4. 渲染Echarts图表** * 创建一个`option`对象,指定tooltip、series等配置项。 * 使用`myChart.setOption`将图表配置到页面中。 **5. 代码逻辑** * `buildNodeTreeAndPaint`函数递归创建树状图,并使用`getNodeChild`获取对应关系的节点。 * `option`对象定义 chart 配置,包括tooltip、series等。 * `myChart.setOption`将图表配置到页面中。 **总结** 这篇文章展示了如何使用纯前端表格和Echarts将审计审查过程可视化。代码逻辑清晰易懂,使用合理的设计,可以实现高效的报表构建。

正文

本文由葡萄城技术团队于博客园原创并首发
转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具、解决方案和服务,赋能开发者。

在金融行业,我们经常会有审计审查的需求,对某个计算结果进行审查,但是这个计算结果可能依赖多个单元格,而且会有会有多级依赖的情况,如果让我们的从业人员靠眼睛找,工作量巨大,而且准确性存疑,基本上死路一条,因此让整个审查过程可视化,迫在眉睫,现在我们利用纯前端表格和Echarts将审计审查过程可视化

一.首先我们先了解一下前端表格或Excel中引用和从属关系:
1.在单元格B1中设置公式 =SUM(A1)。 单元格A1是单元格B1的引用单元格(引用关系
2.在单元格B1中设置公式 =SUM(A1)。 单元格B1是单元格A1的从属单元格(从属关系

二.接下来我们看一下最终实现效果:

1.引用关系

2.从属关系

三.本次我们用的是Echarts的树图将引用和从属关系可视化,关于Echarts上手,大家去Echarts官网有完整上手教程,Echarts社区有很多开发者做的许多有趣又实用的demo,这里我们用的是树图

四.接下来我们要用纯前端表格控件的获取引用和从属关系的api将某个单元格的引用和从属关系顺藤摸瓜,刨根问题,刨到“祖坟”上,将这些关系,构造成Echarts树图的data结构,废话不说,直接上核心代码

// 递归构建追踪树
    buildNodeTreeAndPaint = (spreadSource, trackCellInfo) => {
        let info = this.getCellInfo(trackCellInfo);
        let sheetSource = spreadSource.getSheetFromName(info.sheetName);
        // 创建跟节点
        let rootNode = this.creatNode(info.row, info.col, sheetSource, 0, "");

        let name = rootNode.sheetName + "*" + rootNode.row + "*" + rootNode.col + "*" + Math.random().toString();
        let precedentsRootNode = '';
        let dependentsRootNode = '';
        if (this.state.trackType === "Precedents" || this.state.trackType === "Both") {
            this.getNodeChild(rootNode, sheetSource, "Precedents")
            debugger;
            console.log(rootNode)
            if (this.state.trackType === "Both") {
                let rootNodeChildren = JSON.parse(JSON.stringify(rootNode.children));
                rootNode.children = [];
                precedentsRootNode = JSON.parse(JSON.stringify(rootNode));
                precedentsRootNode.children.push({
                    name: "Precedents",
                    value: "Precedents",
                    children: rootNodeChildren
                })
                this.setState({
                    precedentsRootNode: JSON.parse(JSON.stringify(precedentsRootNode)),
                })
            }
        }
        if (this.state.trackType === "Dependents" || this.state.trackType === "Both") {
            this.getNodeChild(rootNode, sheetSource, "Dependents")
            console.log(rootNode)
            if (this.state.trackType === "Both") {
                let deepInfo = [1];
                let rootNodeChildren = JSON.parse(JSON.stringify(rootNode.children));
                rootNode.children = [];
                dependentsRootNode = JSON.parse(JSON.stringify(rootNode));
                dependentsRootNode.children.push({
                    name: "Dependents",
                    value: "Dependents",
                    children: rootNodeChildren
                })
                this.setState({
                    dependentsRootNode: JSON.parse(JSON.stringify(dependentsRootNode)),
                })
            }



        }
        if (this.state.trackType === "Both") {
            precedentsRootNode.children = precedentsRootNode.children.concat(dependentsRootNode.children);
            // let bothRootNode = precedentsRootNode.children[0].children.concat(dependentsRootNode.children[0].children)
            this.setState({
                rootNode1: JSON.parse(JSON.stringify(precedentsRootNode)),
            })
        } else {
            this.setState({
                rootNode1: JSON.parse(JSON.stringify(rootNode)),
            })
        }
    }
    creatNode = (row, col, sheet, deep, trackType) => {
        let node = {
            value: sheet.getValue(row, col),
            position: sheet.name() + "!" + GC.Spread.Sheets.CalcEngine.rangeToFormula(new GC.Spread.Sheets.Range(row, col, 1, 1)),
            deep: deep,
            name: `${sheet.name()}!${GC.Spread.Sheets.CalcEngine.rangeToFormula(new GC.Spread.Sheets.Range(row, col, 1, 1))}\nvalue:${sheet.getValue(row, col)}`,
            sheetName: sheet.name(),
            row: row,
            col: col,
            trackType: trackType
        };
        return node;
    }
    getNodeChild = (rootNode, sheet, trackType) => {
        let childNodeArray = [];
        let children = [];
        let row = rootNode.row, col = rootNode.col, deep = rootNode.deep;
        if (trackType == "Precedents") {
            children = sheet.getPrecedents(row, col);
        }
        else {
            children = sheet.getDependents(row, col);
        }
        // let self = this;
        if (children.length >= 1) {
            children.forEach((node) => {
                let row = node.row,
                    col = node.col,
                    rowCount = node.rowCount,
                    colCount = node.colCount,
                    _sheet = sheet.parent.getSheetFromName(node.sheetName);
                if (rowCount > 1 || colCount > 1) {
                    for (let r = row; r < row + rowCount; r++) {
                        for (let c = col; c < col + colCount; c++) {
                            let newNode = this.creatNode(r, c, _sheet, deep + 1, trackType)
                            // if (deep < self.maxDeep) {
                            this.getNodeChild(newNode, _sheet, trackType);
                            // }
                            childNodeArray.push(newNode);
                        }
                    }
                } else {
                    let newNode = this.creatNode(row, col, _sheet, deep + 1, trackType)
                    // if (deep < self.maxDeep) {
                    this.getNodeChild(newNode, _sheet, trackType);
                    // }
                    childNodeArray.push(newNode);
                }
            });
        }
        rootNode.children = childNodeArray;
    }

五.将构造好的引用和从属树rootNode在Echarts中渲染

myChart.setOption(
            (option = {
                tooltip: {
                    trigger: 'item',
                    triggerOn: 'mousemove'
                },
                series: [
                    {
                        type: 'tree',
                        data: [this.state.rootNode1],
                        top: '1%',
                        left: '15%',
                        bottom: '1%',
                        right: '7%',
                        symbolSize: 10,
                        orient: this.state.trackType === 'review'?'LR':'RL',
                        label: {
                            position: this.state.trackType === 'review'?'left':'right',
                            verticalAlign: 'middle',
                            align: this.state.trackType === 'review'?'right':'left',
                        },
                        leaves: {
                            label: {
                                position: this.state.trackType === 'review'?'right':'left',
                                verticalAlign: 'middle',
                                align: this.state.trackType === 'review'?'left':'right'
                            }
                        },
                        emphasis: {
                            focus: 'descendant'
                        },
                        // layout: 'radial',
                        expandAndCollapse: true,
                        animationDuration: 550,
                        animationDurationUpdate: 750
                    }
                ]
            })
        );

        option && myChart.setOption(option);

以上就是实现报表中公式引用从属关系Echarts可视化的核心实现逻辑,由于工程较大,需要完整内容可以留言。。

拓展阅读

React + Springboot + Quartz,从0实现Excel报表自动化

电子表格也能做购物车?简单三步就能实现

使用纯前端类Excel表格控件SpreadJS构建企业现金流量表

与用Echarts实现前端表格引用从属关系可视化相似的内容:

用Echarts实现前端表格引用从属关系可视化

本文由葡萄城技术团队于博客园原创并首发 转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具、解决方案和服务,赋能开发者。 在金融行业,我们经常会有审计审查的需求,对某个计算结果进行审查,但是这个计算结果可能依赖多个单元格,而且会有会有多级依赖的情况,如果让我们的从业人员靠眼睛找,工作量巨大

项目小结:使用Docker迁移服务到离线服务器

## 前言 最近遇到的这个场景,需要把之前开发的一套系统迁移到一个离线的服务器上,这个服务器有点麻烦,接入VPN后通过堡垒机才能访问,速度也很慢,遇到不少坑,本文记录一下迁移过程。 ## 基本信息 原本这套系统也挺简单的,Django 写的后端接口,搭配 `Vue+Echarts` 大屏,数据库用

用【游乐场】说清楚“硬件、操作系统、跨平台、应用软件、开发语言、代码”的关系

经常有小伙伴对一些计算机技术和概念不太清楚,产生很多误区,甚至张冠李戴,在一起聊天时又很难给对方解释清楚,经过苦思冥想,终于想到一些比喻,能够很好地阐述了“硬件、操作系统、跨平台、应用软件、开发语言、代码”之间的关系。 硬件 陆地(Intel)与海洋(AMD):硬件就像是一个广阔的自然环境,其中In

写了一个json小工具,希望大家体验(Mac平台)

用rust写了一个json小工具“JSON PICKER”,欢迎大家试用: https://github.com/davelet/json-picker/releases/tag/V0.2 动机是平常开发的时候,经常遇到大段json,里面的很多字段是不需要的。 我所在的项目组在接口对接上出现了rep

用StabilityMatrix一键安装Stable Diffusion

Stable Diffusion是2022年发布的深度学习文字到图像生成模型,它既能免费使用,又能部署在本地端,又有非常多的模型可以直接套用,在使用体验上比Midjourney和DALL-E更加强大。Stable Diffusion使用的模型有下列几大类,对照模型网站 https://civitai

用 KV 缓存量化解锁长文本生成

很高兴和大家分享 Hugging Face 的一项新功能: KV 缓存量化 ,它能够把你的语言模型的速度提升到一个新水平。 太长不看版: KV 缓存量化可在最小化对生成质量的影响的条件下,减少 LLM 在长文本生成场景下的内存使用量,从而在内存效率和生成速度之间提供可定制的权衡。 你是否曾尝试过用语

用 Sentence Transformers v3 训练和微调嵌入模型

Sentence Transformers 是一个 Python 库,用于使用和训练各种应用的嵌入模型,例如检索增强生成 (RAG)、语义搜索、语义文本相似度、释义挖掘 (paraphrase mining) 等等。其 3.0 版本的更新是该工程自创建以来最大的一次,引入了一种新的训练方法。在这篇博

用Python脚本迁移MongoDB数据到金仓-kingbase数据库

1、首先需要明确MongoDB与kingbase的对应关系,collection相当于table,filed相当于字段,根据这个对应关系创建表; 此次迁移的MongoDB里的数据字段是:_id(自动生成的objectid),image(转成二进制存储的文档) 所以在金仓里创建表 create tab

用.NET代码生成JSON Schema 验证器

问题 对于验证复杂JSON数据是否合法的需求,通常的解决方式是标准JSON Schema,.Net下有对应的JSON Schema实现库。应用程序通常需要将标准JSON schema传入实现库,来做后续的数据验证。这里有一种情况,就是如果使用者不太了解标准JSON Schema格式,但又希望能在自己

用python字典统计CSV数据

1.用python字典统计CSV数据的步骤和代码示例 为了使用Python字典来统计CSV数据,我们可以使用内置的csv模块来读取CSV文件,并使用字典来存储统计信息。以下是一个详细的步骤和完整的代码示例: 1.1步骤 (1)导入csv模块。 (2)打开CSV文件并读取数据。 (3)初始化一个空字典