找回密码
 立即注册

QQ登录

只需一步,快速开始

爱迪生

超级版主

55

主题

65

帖子

1394

积分

超级版主

Rank: 8Rank: 8

积分
1394
爱迪生
超级版主   /  发表于:2022-3-2 12:02  /   查看:2576  /  回复:2
本帖最后由 爱迪生 于 2022-3-2 13:52 编辑

在金融行业,我们经常会有审计审查的需求,对某个计算结果进行审查,但是这个计算结果可能依赖多个单元格,而且会有会有多级依赖的情况,如果让我们的从业人员靠眼睛找,工作量巨大,而且准确性存疑,基本上死路一条,因此让整个审查过程可视化,迫在眉睫,本章我们利用SpreadJS和Echarts将审计审查过程可视化
一.首先我们先了解一下SpreadJS或Excel中引用和从属关系
   1.在单元格B1中设置公式 =SUM(A1)。 单元格A1是单元格B1的引用单元格(引用关系
   2.在单元格B1中设置公式 =SUM(A1)。 单元格B1是单元格A1的从属单元格(从属关系
二.接下来我们看一下最终实现效果
   1.引用关系
    2022-03-02 11.14.12.gif
   2.从属关系
2022-03-02 11.33.44.gif
三.本次我们用的是Echarts的树图将引用和从属关系可视化,关于Echarts上手,大家去Echarts官网有完整上手教程,Echarts社区有很多开发者做的许多有趣又实用的demo,这里我们用的是树图
image.png477385863.png
我们看一下它的data的数据结构:
image.png802108764.png
四.接下来我们要用SpreadJS的获取引用和从属关系的api将某个单元格的引用和从属关系顺藤摸瓜,刨根问题,刨到“祖坟”上,将这些关系,构造成Echarts树图的data结构,废话不说,直接上核心代码

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

  7.         let name = rootNode.sheetName + "*" + rootNode.row + "*" + rootNode.col + "*" + Math.random().toString();
  8.         let precedentsRootNode = '';
  9.         let dependentsRootNode = '';
  10.         if (this.state.trackType === "Precedents" || this.state.trackType === "Both") {
  11.             this.getNodeChild(rootNode, sheetSource, "Precedents")
  12.             debugger;
  13.             console.log(rootNode)
  14.             if (this.state.trackType === "Both") {
  15.                 let rootNodeChildren = JSON.parse(JSON.stringify(rootNode.children));
  16.                 rootNode.children = [];
  17.                 precedentsRootNode = JSON.parse(JSON.stringify(rootNode));
  18.                 precedentsRootNode.children.push({
  19.                     name: "Precedents",
  20.                     value: "Precedents",
  21.                     children: rootNodeChildren
  22.                 })
  23.                 this.setState({
  24.                     precedentsRootNode: JSON.parse(JSON.stringify(precedentsRootNode)),
  25.                 })
  26.             }
  27.         }
  28.         if (this.state.trackType === "Dependents" || this.state.trackType === "Both") {
  29.             this.getNodeChild(rootNode, sheetSource, "Dependents")
  30.             console.log(rootNode)
  31.             if (this.state.trackType === "Both") {
  32.                 let deepInfo = [1];
  33.                 let rootNodeChildren = JSON.parse(JSON.stringify(rootNode.children));
  34.                 rootNode.children = [];
  35.                 dependentsRootNode = JSON.parse(JSON.stringify(rootNode));
  36.                 dependentsRootNode.children.push({
  37.                     name: "Dependents",
  38.                     value: "Dependents",
  39.                     children: rootNodeChildren
  40.                 })
  41.                 this.setState({
  42.                     dependentsRootNode: JSON.parse(JSON.stringify(dependentsRootNode)),
  43.                 })
  44.             }



  45.         }
  46.         if (this.state.trackType === "Both") {
  47.             precedentsRootNode.children = precedentsRootNode.children.concat(dependentsRootNode.children);
  48.             // let bothRootNode = precedentsRootNode.children[0].children.concat(dependentsRootNode.children[0].children)
  49.             this.setState({
  50.                 rootNode1: JSON.parse(JSON.stringify(precedentsRootNode)),
  51.             })
  52.         } else {
  53.             this.setState({
  54.                 rootNode1: JSON.parse(JSON.stringify(rootNode)),
  55.             })
  56.         }
  57.     }
  58.     creatNode = (row, col, sheet, deep, trackType) => {
  59.         let node = {
  60.             value: sheet.getValue(row, col),
  61.             position: sheet.name() + "!" + GC.Spread.Sheets.CalcEngine.rangeToFormula(new GC.Spread.Sheets.Range(row, col, 1, 1)),
  62.             deep: deep,
  63.             name: `${sheet.name()}!${GC.Spread.Sheets.CalcEngine.rangeToFormula(new GC.Spread.Sheets.Range(row, col, 1, 1))}\nvalue:${sheet.getValue(row, col)}`,
  64.             sheetName: sheet.name(),
  65.             row: row,
  66.             col: col,
  67.             trackType: trackType
  68.         };
  69.         return node;
  70.     }
  71.     getNodeChild = (rootNode, sheet, trackType) => {
  72.         let childNodeArray = [];
  73.         let children = [];
  74.         let row = rootNode.row, col = rootNode.col, deep = rootNode.deep;
  75.         if (trackType == "Precedents") {
  76.             children = sheet.getPrecedents(row, col);
  77.         }
  78.         else {
  79.             children = sheet.getDependents(row, col);
  80.         }
  81.         // let self = this;
  82.         if (children.length >= 1) {
  83.             children.forEach((node) => {
  84.                 let row = node.row,
  85.                     col = node.col,
  86.                     rowCount = node.rowCount,
  87.                     colCount = node.colCount,
  88.                     _sheet = sheet.parent.getSheetFromName(node.sheetName);
  89.                 if (rowCount > 1 || colCount > 1) {
  90.                     for (let r = row; r < row + rowCount; r++) {
  91.                         for (let c = col; c < col + colCount; c++) {
  92.                             let newNode = this.creatNode(r, c, _sheet, deep + 1, trackType)
  93.                             // if (deep < self.maxDeep) {
  94.                             this.getNodeChild(newNode, _sheet, trackType);
  95.                             // }
  96.                             childNodeArray.push(newNode);
  97.                         }
  98.                     }
  99.                 } else {
  100.                     let newNode = this.creatNode(row, col, _sheet, deep + 1, trackType)
  101.                     // if (deep < self.maxDeep) {
  102.                     this.getNodeChild(newNode, _sheet, trackType);
  103.                     // }
  104.                     childNodeArray.push(newNode);
  105.                 }
  106.             });
  107.         }
  108.         rootNode.children = childNodeArray;
  109.     }
复制代码
五.将构造好的引用和从属树rootNode在Echarts中渲染
  1. myChart.setOption(
  2.             (option = {
  3.                 tooltip: {
  4.                     trigger: 'item',
  5.                     triggerOn: 'mousemove'
  6.                 },
  7.                 series: [
  8.                     {
  9.                         type: 'tree',
  10.                         data: [this.state.rootNode1],
  11.                         top: '1%',
  12.                         left: '15%',
  13.                         bottom: '1%',
  14.                         right: '7%',
  15.                         symbolSize: 10,
  16.                         orient: this.state.trackType === 'review'?'LR':'RL',
  17.                         label: {
  18.                             position: this.state.trackType === 'review'?'left':'right',
  19.                             verticalAlign: 'middle',
  20.                             align: this.state.trackType === 'review'?'right':'left',
  21.                         },
  22.                         leaves: {
  23.                             label: {
  24.                                 position: this.state.trackType === 'review'?'right':'left',
  25.                                 verticalAlign: 'middle',
  26.                                 align: this.state.trackType === 'review'?'left':'right'
  27.                             }
  28.                         },
  29.                         emphasis: {
  30.                             focus: 'descendant'
  31.                         },
  32.                         // layout: 'radial',
  33.                         expandAndCollapse: true,
  34.                         animationDuration: 550,
  35.                         animationDurationUpdate: 750
  36.                     }
  37.                 ]
  38.             })
  39.         );

  40.         option && myChart.setOption(option);
复制代码
以上就是实现报表中公式引用从属关系Echarts可视化的核心实现逻辑,由于工程较大,如需获取源码,可找我获取


2 个回复

倒序浏览
FzcSuiY
注册会员   /  发表于:2022-12-16 09:30:25
沙发
你好  源码怎么获取
回复 使用道具 举报
爱迪生
超级版主   /  发表于:2022-12-16 09:36:10
板凳
FzcSuiY 发表于 2022-12-16 09:30
你好  源码怎么获取

你好,私信我一下你的微信,我让商务同事发你
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 立即注册
返回顶部