JS 多發票多金額分配

原來的需求是這樣的,用戶生成了400元訂單,須要400元的發票去抵消,發票數和訂單數不受限制,this

將問題擬物化,訂單能夠想象成杯子,發票能夠想象成水,如今要把水分配到每一個杯子中去
咱們先記錄每一個杯子的起始值和結束值,還有當前值,起始值(start)=當前杯子的起始值加上上一個杯子的結束值,結束值(end)即起始值加上杯子的容量,當前值(index)即當前杯子中的水,若是大於杯子的容量則倒下一個杯子,依次循環,因此其實整個倒水能夠看作一個大杯子,按階段倒水,每次記錄倒水的index(即當前(或者當次)杯子中的水便可)spa

如今假設a杯50L, b杯20L
假如第一次倒, a[0, 50]杯子倒滿,剩餘20;index = 50 , start = 0 , end = 50;
第二次倒b杯[50, 70], 首先拿上一下剩餘的20L, 恰好倒滿,index = 20; start = 50 ,end = 70
依次類推code

話很少說,上代碼rem

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);
}
相關文章
相關標籤/搜索