JS 多发票多金额分配

原来的需求是这样的,用户生成了400元订单,需要400元的发票去抵消,发票数和订单数不受限制,

将问题拟物化,订单可以想象成杯子,发票可以想象成水,现在要把水分配到每个杯子中去
我们先记录每个杯子的起始值和结束值,还有当前值,起始值(start)=当前杯子的起始值加上上一个杯子的结束值,结束值(end)即起始值加上杯子的容量,当前值(index)即当前杯子中的水,如果大于杯子的容量则倒下一个杯子,依次循环,所以其实整个倒水可以看做一个大杯子,按阶段倒水,每次记录倒水的index(即当前(或者当次)杯子中的水即可)

现在假设a杯50L, b杯20L
假如第一次倒, a[0, 50]杯子倒满,剩余20;index = 50 , start = 0 , end = 50;
第二次倒b杯[50, 70], 首先拿上一下剩余的20L, 刚好倒满,index = 20; start = 50 ,end = 70
依次类推

话不多说,上代码

export function getItemDistribution(a, b, waterKey, cupKey, policyId) {

    class ItemDistribution { 
        cupList = [];
        result = [];

        constructor(list, maps) {
            this.waterKey = waterKey;
            this.cupKey = cupKey;
            this.policyId = policyId;
            this.sort(list, maps);
            this.init(list);
        }

        sort(list, maps) {
            let {waterKey, cupKey} = this;
            if (waterKey) {
                list = list.sort((a, b) => a[waterKey] - b[waterKey]);
            } else {
                list = list.sort((a, b) => a - b);
            }
            if (cupKey) {
                maps = maps.sort((a, b) => a[cupKey] - b[cupKey]);
            } else {
                maps = maps.sort((a, b) => a - b);
            }
            this.list = list;
            this.maps = maps;
            return {list, maps}
        }

        init(list) {
            if (list == null || list.length <= 0) {
                return;
            }
            let start = 0, end = 0, index = 0;
            let {waterKey} = this;
            list.forEach((item, id) => {
                if (!waterKey) {
                    this.result[id] = [];
                }
                let water = waterKey ? item[waterKey] : item;
                end = start + Number(water);
                this.entry({start, index, end});
                start = end;
            });
            this.dispatchMaps();
        }

        entry({start, index, end}) {
            index = start;
            this.cupList.push({start, end, index})
        }

        dispatchMaps() {
            function isEmpty(o) {
                switch (JSON.stringify(o)) {
                    case 'null':
                    case undefined:
                        return true;
                    case '[]':
                        return true;
                }
                return false;
            }

            let {maps = [], cupList, cupKey} = this;
            if (isEmpty(cupList) || isEmpty(maps)) return false;
            maps.forEach((item, id) => {
                let cup = cupKey ? item[cupKey] : item;
                this.dispatchCup({item: cup, id});
            });
        }

        getCup() {
            function isEqual(a, b) {
                return String(a.toFixed(2)) !== String(b.toFixed(2));
            }

            let {cupList} = this;
            for (let i = 0; i < cupList.length; i++) {
                let item = cupList[i];
                if (isEqual(item.end, item.index)) {
                    return {cup: item, cupIndex: i};
                }
            }
            return {};
        }

        dispatchCup({item, id}) {
            let {cup, cupIndex} = this.getCup();
            if (!cup) return false;
            let {index, end} = cup;
            let remain = end - index;
            let {waterKey, list, policyId, maps} = this;
            if (remain > item) {
                cup.index = cup.index + item;
                waterKey ? this.result.push({
                    ...list[cupIndex],
                    [waterKey]: item,
                    [policyId]: maps[id][policyId]
                }) : this.result[id].push(item);
                return false;
            } else {
                cup.index = cup.end;
                waterKey ? this.result.push({
                    ...list[cupIndex],
                    [waterKey]: remain,
                    [policyId]: maps[id][policyId]
                }) : this.result[id].push(remain);
                item -= remain;
                this.dispatchCup({item, id})
            }
        }
    }

    return new ItemDistribution(a, b);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值