连续票据号段,每次选择号段之后,根据已选号段和剩余号段,自动选择号段问题解决思路。

38 篇文章 0 订阅
15 篇文章 0 订阅

需求:

在本项目中,添加选择票据信息时,每条票据信息都有一个指定的号码段,有起始号码,终止号码,隐藏的属性还有校验位信息,号码长度。
要求用户每次选择号段时,会根据用户已选票据,和用户当前选择的票据信息对比,若属于同一种票据,则需要根据用户已选的票据,和该号段下剩余的票据,自动进行选择。


选择规则:

若剩余的票据号段是一整段连续号段,则自动选择剩余的全部号段为一条票据信息。若剩余的票据号段有多个号段,则自动选择其中起始号和终止号最小的号段,作为本次选择的票据信息。


票据号码的处理规则:

若校验位信息checkMark为1,则表示该票据有校验位,那么最后一位号码属于校验位,计算票据号码需要截断最后一位来看。号码长度则代表当前票据的号码长度。校验位的计算规则是,传入除校验位之外的票号,根据函数计算得出,最后补齐校验位,并将剩余长度在左侧通过补零来补齐。


选择完票据信息之后,用户还可以手动修改票据号码,

修改规则:

1、若该票据有校验位,则永远认为用户输入的最后一位是校验位,每次用户输入之后都需要重新计算验证校验位,并根据票据长度来补零。
2、起始号码和终止号码,必须在所选择的票据信息的起始号和终止号范围之内。
3、修改起始号码,若起始号码小于终止号码,则根据终止号码减去其实号码,计算出本数。若起始号码大于终止号码,则根据本数,计算出新的终止号码。
4、修改终止号码,终止号码必须大于起始号码,不满足时要弹出友好提示。终止号码大于或等于起始号码时,则根据新输入的终止号码减去起始号码,计算出新的本数。
5、修改本数时,起始号码不变,根据新输入的本数加上起始号码,计算出新的终止号码。

以上规则均需同时满足。


解决

将以上规则整理成流程图,如下。
在这里插入图片描述
如图所示,号码效验联动可以单独处理,因此本次文章主要处理选号流程。

第一步,选择号段。

为选择号段事件绑定处理函数:
在这里插入图片描述

// 选择票证种类信息
basBillInfoSelect(datas) {
  console.log('选择的数据是:', datas)
}

第二步,判断所选项目和已存在项目是否相同。

首先确定目标billid,即当前选择的行数据的billid,只要表格中存在billid相同的项目,就可能是同一号段。为什么是可能呢?因为这里所选的号段,可能存在多个号段。
例如0000000001——000100000,可能分割成0000000001——0000500000和0000600000——000090000,这样就要以billid为基准,进一步判断起始号码和终止号码。若billid相同,且项目的起始号码大于或等于所选号段的起始号码,且项目的终止号码小于或等于所选号段的终止号码,则认为该项目从属于所选号段。由于对比号码还涉及到校验位的问题,所以这里多做了几个判断。

var targetBillId = datas.currentRow.billid
// 相同找到tabledata表格数组中相同billid的项目
var sameBillIdItemList = this.tableData.filter(item => {
  // return item.billid === targetBillId
  if (item.billid === targetBillId) {
    if (+item.checkmark === 0) {
      // 外面无校验位
      if (+datas.currentRow.checkmark === 0) {
        // 里面无校验位,外面无。
        return +item.startnumber >= +datas.currentRow.startnumber && +item.endnumber <= +datas.currentRow.endnumber
      } else {
        // 里面有校验位,外面无。表现形式不一致
        return false
      }
    } else {
      // 外面有校验位
      if (+datas.currentRow.checkmark === 0) {
        // 里面无校验位,外面有校验位。表现形式不一致
        return false
      } else {
        // 里面有校验位,外面也有校验位。
        return +item.startnumber.slice(0, -1) >= +datas.currentRow.startnumber.slice(0, -1) && +item.endnumber.slice(0, -1) <= +datas.currentRow.endnumber.slice(0, -1)
      }
    }
  } else {
    return false
  }
})

若项目中,与所选号段有所属关系的号段数组sameBillIdItemList 的长度为零,说明不存在已选择的号段,那么直接将该选择号段全部添加进去就行了。
在这里插入图片描述

第三步,对已选择的票据进行排序

若存在相同号段票据,那么首先对sameBillIdItemList这个数组进行排序,根据起始号码来排序。
同样,由于涉及到校验位,这里多做一步判断。
在这里插入图片描述

第四步,根据已排序的票据号段,计算出剩余未选中的票据号段。

排序完成之后,需要根据排序完之后的数组,整个所选票据的起始号码,终止号码,校验位信息,来获取到剩余的没有被选择的数据组成的数组,并且按升序排列。
首先定义一个函数getRestNumberArray,将上面提到的4个信息全部作为参数传递进来。然后在函数内部定义一个空数组,准备接受待会传递进来的号段信息。

export function getRestNumberArray(ascTableDataArray, startNumber, endNumber, checkMark) {
  var restNumberArray = []
}

然后就需要考虑已选择的号段,可能出现的几种情况。
情况1:已选择的号段都是间断的,不连续的,且头尾都不靠近边界。
情况2:已选择的号段,起始号码是从票据号段头部开始,即头部靠近边界。
情况3:已选择的号段,终止号码正好是票据号段的尾部,即尾部靠近边界。
情况4:已选择的号段,中间的部分有连续,又有间隔,即中间部分可能连续也可能间断。

在这里插入图片描述

分析完以上4种情况后,应该可以得出这样的结论:
一、如果已选择号段的头部(左边第一个号段),它的起始号码大于整个号段的左边界,那么从左边界开始,到已选择号段的头部的号码 - 1 的号段,全部是未选中的号段,可以直接push到剩余号段中。(为了简单起见,这里暂时没有考虑校验位的情况。后面全部代码会写上)

  // 开头
    if (+ascTableDataArray[0].startnumber > +startNumber) {
      const newNumberItem = {}
      newNumberItem.startnumber = startNumber
      newNumberItem.endnumber = ascTableDataArray[0].startnumber - 1
      console.log('有一个大于左边界的号段被push进入', newNumberItem)
      restNumberArray.push(newNumberItem)
    }

二、如果已选择号段的尾部(右边最后一个号段),它的终止号码要小于整个号段的右边界,那么从右边界开始,往前一直到已选择号段的尾部的终止号码 - 1的号段,全部是未选中的号段,可以直接push到剩余号段中。

    // 结尾
    if (+ascTableDataArray[ascTableDataArray.length - 1].endnumber < +endNumber) {
      const newNumberItem = {}
      newNumberItem.startnumber = +ascTableDataArray[ascTableDataArray.length - 1].endnumber + 1
      newNumberItem.endnumber = endNumber
      console.log('有一个小于右边界的号段被push进入', newNumberItem)
      restNumberArray.push(newNumberItem)
    }

三、前面把头和尾的情况都处理了,接下来处理中间的情况。中间的情况主要有两种,连续和不连续。

这里判断连续的原理是:如果后面一段票据的起始号码减一,等于前面一段票据号码的终止号码,那么就认为这两段号码连续。

如果两段号码连续,那么两个号段中间无剩余票据,所以不做任何处理。
如果两段号码不连续,则说明两个号段中间有剩余票据。而剩余票据的起始号码,等于前面一段票据的终止号码加一;剩余票据的终止号码,等于后面一段票据的起始号码减一。
最后将该号码段push到剩余号段中。
这样,就获得了全部的剩余未选中号段!

// 中间
for (let i = 0; i < ascTableDataArray.length - 1; i++) {
  if (ascTableDataArray[i + 1].startnumber - 1 === +ascTableDataArray[i].endnumber) {
  // 说明连续。
  } else {
  // 说明中断了,区间数+1
    const newNumberItem = {}
    newNumberItem.startnumber = +ascTableDataArray[i].endnumber + 1
    newNumberItem.endnumber = ascTableDataArray[i + 1].startnumber - 1
    console.log('有一个中间号段被push进入', newNumberItem)
    restNumberArray.push(newNumberItem)
  }
}

全部代码如下,这是考虑了校验位的情况。cutoffCheckMark是另外一个函数,用来截掉校验位并返回除去校验位后的号码,其实就是slice(0,-1)的封装。

export function getRestNumberArray(ascTableDataArray, startNumber, endNumber, checkMark) {
  var restNumberArray = []
  console.log('收到的排序后的数组为:', ascTableDataArray)
  if (+checkMark === 0) {
  // 无校验位时
  // 开头
    if (+ascTableDataArray[0].startnumber > +startNumber) {
      const newNumberItem = {}
      newNumberItem.startnumber = startNumber
      newNumberItem.endnumber = ascTableDataArray[0].startnumber - 1
      console.log('有一个大于左边界的号段被push进入', newNumberItem)
      restNumberArray.push(newNumberItem)
    }
    // 中间
    for (let i = 0; i < ascTableDataArray.length - 1; i++) {
      if (ascTableDataArray[i + 1].startnumber - 1 === +ascTableDataArray[i].endnumber) {
      // 说明连续。
      } else {
      // 说明中断了,区间数+1
        const newNumberItem = {}
        newNumberItem.startnumber = +ascTableDataArray[i].endnumber + 1
        newNumberItem.endnumber = ascTableDataArray[i + 1].startnumber - 1
        console.log('有一个中间号段被push进入', newNumberItem)
        restNumberArray.push(newNumberItem)
      }
    }
    // 结尾
    if (+ascTableDataArray[ascTableDataArray.length - 1].endnumber < +endNumber) {
      const newNumberItem = {}
      newNumberItem.startnumber = +ascTableDataArray[ascTableDataArray.length - 1].endnumber + 1
      newNumberItem.endnumber = endNumber
      console.log('有一个小于右边界的号段被push进入', newNumberItem)
      restNumberArray.push(newNumberItem)
    }
  } else {
    // 有校验位时
    // 开头
    if (+cutoffCheckMark(ascTableDataArray[0].startnumber) > +cutoffCheckMark(startNumber)) {
      console.log(+cutoffCheckMark(ascTableDataArray[0].startnumber))
      console.log(+cutoffCheckMark(startNumber))
      const newNumberItem = {}
      newNumberItem.startnumber = cutoffCheckMark(startNumber)
      newNumberItem.endnumber = cutoffCheckMark(ascTableDataArray[0].startnumber) - 1
      console.log('有一个大于左边界的号段被push进入', newNumberItem)
      restNumberArray.push(newNumberItem)
    }
    // 中间
    for (let i = 0; i < ascTableDataArray.length - 1; i++) {
      if (cutoffCheckMark(ascTableDataArray[i + 1].startnumber) - 1 === +cutoffCheckMark(ascTableDataArray[i].endnumber)) {
      // 说明连续。
      } else {
      // 说明中断了,区间数+1
        const newNumberItem = {}
        newNumberItem.startnumber = +cutoffCheckMark(ascTableDataArray[i].endnumber) + 1
        newNumberItem.endnumber = cutoffCheckMark(ascTableDataArray[i + 1].startnumber) - 1
        console.log('有一个中间号段被push进入', newNumberItem)
        restNumberArray.push(newNumberItem)
      }
    }
    // 结尾
    if (+cutoffCheckMark(ascTableDataArray[ascTableDataArray.length - 1].endnumber) < +cutoffCheckMark(endNumber)) {
      const newNumberItem = {}
      newNumberItem.startnumber = +cutoffCheckMark(ascTableDataArray[ascTableDataArray.length - 1].endnumber) + 1
      newNumberItem.endnumber = cutoffCheckMark(endNumber)
      console.log('有一个小于右边界的号段被push进入', newNumberItem)
      restNumberArray.push(newNumberItem)
    }
  }
  return restNumberArray
}

这样,就获取到了按升序排列,且没有被选中的所有号段,所组成的数组。

第五步,取剩余号段中,最左的那条号段作为本次选择结果,并将该数据从剩余号段数组中剔除。

这里添加选择结果之前,还需要判断一下,如果剩余票据号段长度为零,说明该票种下面的全部号段已经添加完毕,给个友好提示即可。
如果不为零,则每次取剩余号段中的第一个,取完之后记得使用shift方法删除剩余号段中的第一条数据。
在这里插入图片描述

这样,票据选择时,根据票据分段自动选择数据的功能就基本实现了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值