使用DFS实现表格统计

759 阅读2分钟

今天接到需求,要开发一个二维表格的统计功能,统计项是嵌套的,看来还是得思考下

具体需求如下

  • 统计a.1项的值是由a.1.1, a.1.2,a.1.3的值求和得到
  • a.1.2 的值由 a.1.2.1, a.1.2.2, a.1.2.3 求和得到
  • 统计项的值只读,被统计项可输入,统计项随被统计项联动展示

效果如下 ;

有的同学说你这个循环就搞定了,求个值搞个类,每个计算格子的地方来个函数,此时的我:

开个玩笑了,哈哈哈。

由于后面还有四个类似的表格,肯定不能硬编码到实现里了,后面表格变了代码也会废掉; 其实这个东西有点像浏览器里事件的冒泡,输入变了后,一次将变动向上传递给依赖,传递的过程中再去累加,但是考虑到样式和布局以及渲染的方便,这个实现方式没有继续深入;最终定的数据格式如下,渲染中去查找依赖并设置total

// 一个list 直接循环渲染出来,list 成员结构
 {
    "label": "金额1",
    "code": "1",
    "dependency": ['1.1','1.2', '1.3', '1.4', '1.5'], // 求和依赖
    "attr": 0,
    "value": [
        {
            "type": 1,
            "dictCode": "1110001",
            "doubleValue": "", // 每一列的值
        },
        {
            "type": 1,
            "dictCode": "1110002",
            "doubleValue": ""
        },
        {
            "type": 1,
            "dictCode": "1110003",
            "doubleValue": ""
        },
        {
            "type": 1,
            "dictCode": "1110004",
            "doubleValue": ""
        }
    ] 
}

list 渲染组件

<template>
<div class="line">
          <div class="label min middle-center padding-h">
              {{desc.label}}
          </div>
          <div class="value">
              <div class="line" v-for="(line) in desc.list" :key="line.label">
                  <div class="label reset padding-h">{{desc.label}}</div>
                  <template v-if="!line.dependency.length">
                    <div class="value" v-for="col in line.value" :key="col.dictCode">
                        <el-input v-model.number="col.doubleValue"></el-input>
                    </div>
                  </template>
                  <render-cell :origin-data="desc.list" :desc="line" v-else></render-cell>
              </div>
          </div>
      </div>
</template>

render-cell 组件

<template>
export default {
    name: 'renderCell',
    props: {
        originData: {
            type: Array,
            default () {
                return []
            }
        },
        desc: {
            type: Object,
            default () {
                return {}
            }
        }
    },
    render (h) {
        let getValue = (desc, originData) => {
            let dependency = desc.dependency;
            let dependencyObj = this.originData.filter(item => {
                return dependency.some(dependencyId => item.code === dependencyId)
            });
            let initValue = JSON.parse(JSON.stringify(desc.value)).map(item => {
                item.doubleValue = 0;
                return item;
            });
            let value = dependencyObj.reduce((asum, item, idx) => {
                let Ivalue = item.value;
                if (item.dependency.length) {
                    Ivalue = getValue(item) // DFS
                }
                asum.forEach((elem, idx) => {
                    elem.doubleValue += Number(Ivalue[idx].doubleValue);
                });
                
                return asum;
            }, initValue)
            return value;
        }
        const value = getValue(this.desc);
        return (
            <fragment>
                {
                    value.map(item => {
                        return (
                            <div class="value bg">
                                <el-input value={item.doubleValue} readonly={true}/>
                            </div>
                        )
                    })
                }
            </fragment>
        )
    }
}
</template>

为啥要用DFS呢?其实是因为金额 = 金额1 + 金额2 + 金额3的时候,这些的值可能是旧的;大家有好的方法希望可以在底下评论;抱拳。