正如我所怀疑的那样,我需要跟踪当前的争吵。由于我们可以向上移动一行或向下移动一行,因此每行中的每个机架都被赋予了两个索引,如果选择了通道中的每个货架,则这两个索引表示通过通道的最佳路线。“向下”索引与“向上”索引不是相反的。当向下移动一排时,第一个支架将在您的左侧。当向上移动一排时,第一个支架将在您的右侧。然后,向上移动行时按over/up/over分配索引,向下移动时按over/down/over分配索引。
我们提取我们的选择列表——一个订单中所有项目的数组,其中还包含可以找到产品的行和架——并提取出独特的通道。
以下是选择列表中的示例记录:
{
"idorder": 527261,
"orderIndex": 3,
"sku": "WZH76-4-W-YRS-PKP-XL",
"upc": "195041059206",
"quantity": 1,
"warehouse": 10,
"zone": 10,
"row": "20",
"rack": 20,
"tier": 1,
"shelf": 2,
"bin": 5,
"rowNorm": "000020",
"aisleNum": 1,
"rowIndex": 2,
"rowRackIndex": 2,
"rowRackIndexActual": 2,
"revRowRackIndexActual": -2,
"ecFactor": 0,
"aisleMaxRackIndex": 10,
"aisleRackIndex": 3,
"reverseAisleRackIndex": 16,
"rackCode": "10-10-20-20"
}
从整个选择列表中,我们可以获得独特的通道:
uniqueAisles = [...new Set(pickListArr.map((a) => a.aisleNum))].keySort({aisleNum: `asc`});
然后,我们在过道中循环,从挑选列表中选择与当前过道匹配的每一种产品:
sarr = [];
aisleRackArr = pickListArr.filter((r) => r.aisleNum === aa);
然后通过获得该通道的独特机架,再次完善我们的aisleRackArray:
aisleRackArr = [...new Map(aisleRackArr.map((item) => [item.aisleRackIndex, item])).values()];
然后我们弄清楚我们要往哪个方向走:向上还是向下。这与本次讨论无关,因此我们将跳过它。
一旦我们知道了我们的前进方向,我们就会根据订单选择列表中的向上或向下索引,对行中的每个选定机架进行粗略排序:
if (curDir === `up`) {
aisleRackArr.keySort({rowRackIndexActual: `asc`, rowindex: `desc`});
} else {
aisleRackArr.keySort({revRowRackIndexActual: `asc`, rowIndex: `asc`});
}
根据以上分类,我们知道我们的第一个机架,也知道我们要朝哪个方向发展。
const dirFactor = curDir === `up`?1 : -1;
curRack = aisleRackArr[0];
让我们取第一条记录,并将其推送到临时排序数组(sarr)中
sarr.push({rowIndex: curRack.rowIndex, rackIndex: curRack.rowRackIndexActual, aisleNum: curAisleNum, aisleSort: +(+(+curRack.rowRackIndex * 10)) * (+dirFactor), rackCode: curRack.rackCode});
然后将其从我们的过道机架阵列中移除:
aisleRackArr.splice(0, 1);
现在,我们将循环浏览通道机架阵列中的剩余记录,寻找我们应该移动到的下一个机架:
while (aisleRackArr.length > 0) {
curRack = getNextRack(aisleRackArr, dirFactor, curRack.rowIndex);
一旦我们知道我们的下一个机架,将其推入临时阵列,然后将其从机架阵列中移除:
sarr.push({rowIndex: curRack.rowIndex, rackIndex: curRack.rowRackIndexActual, aisleNum: curAisleNum, aisleSort: curRack.sorter, rackCode: curRack.rackCode});
const curIndex=aisleRackArr.indexOf(curRack);
aisleRackArr.splice(curIndex, 1);
并继续循环;
}
完成循环后,将整个临时数组推入主路由数组:
mapRouteArr.push(...sarr);
确定下一个机架的代码:
我们需要获得数组中的下三条记录,因为这些记录将包含我们下一步可以执行的每一步:向左移动、向右移动或向上移动。一旦我们有了这三条记录,我们就会根据机架索引(我们所在行的上下距离)以及其中一条或多条记录是否在我们当前所在的同一行(左或右)来分配新的排序顺序。我们将根据该标准对这三条记录进行排序。如果其中两个机架位于同一级别,请优先选择当前行中的机架。
然后返回该行,while循环将其存储在temp排序数组中,然后将其从混合中删除。
我们继续,直到机架阵列为空。
function getNextRack(rackArray, dirFactor, curRow) {
next3Arr = rackArray.slice(0, 4);
if (dirFactor === 1) { // going up!
next3Arr.forEach((a) => {
a.sorter = +(+(+a.rowRackIndexActual * 10) + (+curRow === +a.rowIndex ? 0 : 1));
a.currentRow = curRow;
});
return next3Arr.sort((a, b)=> a.sorter-b.sorter)[0];
} else { // going down!
next3Arr.forEach((a) => {
a.sorter = +((+a.rowRackIndexActual) * -10) - (+curRow === +a.rowIndex ? 1 : 0);
a.currentRow = curRow;
});
return next3Arr.sort((a, b) => a.sorter - b.sorter)[0];
}
}
我的测试用例使用了10个订单,导致47个不同的机架需要访问。排序结果如下所示。此数组考虑了所有可能的左/右、上/下和不同行长的情况,并且正是它应该的方式:
[
{
"rowIndex": 2,
"rackIndex": 2,
"aisleNum": 1,
"aisleSort": 20,
"rackCode": "10-10-20-20"
},
{
"rowIndex": 1,
"rackIndex": 6,
"aisleNum": 1,
"aisleSort": 61,
"rackCode": "10-10-10-70"
},
{
"rowIndex": 1,
"rackIndex": 8,
"aisleNum": 1,
"aisleSort": 80,
"rackCode": "10-10-10-90"
},
{
"rowIndex": 2,
"rackIndex": 9,
"aisleNum": 1,
"aisleSort": 91,
"rackCode": "10-10-20-90"
},
{
"rowIndex": 3,
"rackIndex": 9,
"aisleNum": 2,
"aisleSort": -100,
"rackCode": "10-10-30-90"
},
{
"rowIndex": 3,
"rackIndex": 8,
"aisleNum": 2,
"aisleSort": -81,
"rackCode": "10-10-30-80"
},
{
"rowIndex": 4,
"rackIndex": 8,
"aisleNum": 2,
"aisleSort": -80,
"rackCode": "10-10-40-80"
},
{
"rowIndex": 4,
"rackIndex": 7,
"aisleNum": 2,
"aisleSort": -71,
"rackCode": "10-10-40-70"
},
{
"rowIndex": 4,
"rackIndex": 4,
"aisleNum": 2,
"aisleSort": -41,
"rackCode": "10-10-40-40"
},
{
"rowIndex": 3,
"rackIndex": 0,
"aisleNum": 2,
"aisleSort": 0,
"rackCode": "10-10-e4-10"
},
{
"rowIndex": 5,
"rackIndex": 1,
"aisleNum": 3,
"aisleSort": 20,
"rackCode": "10-10-50-10"
},
{
"rowIndex": 5,
"rackIndex": 3,
"aisleNum": 3,
"aisleSort": 30,
"rackCode": "10-10-50-30"
},
{
"rowIndex": 5,
"rackIndex": 4,
"aisleNum": 3,
"aisleSort": 40,
"rackCode": "10-10-50-40"
},
{
"rowIndex": 6,
"rackIndex": 5,
"aisleNum": 3,
"aisleSort": 51,
"rackCode": "10-10-60-50"
},
{
"rowIndex": 6,
"rackIndex": 6,
"aisleNum": 3,
"aisleSort": 60,
"rackCode": "10-10-60-60"
},
{
"rowIndex": 5,
"rackIndex": 6,
"aisleNum": 3,
"aisleSort": 61,
"rackCode": "10-10-50-60"
},
{
"rowIndex": 5,
"rackIndex": 7,
"aisleNum": 3,
"aisleSort": 70,
"rackCode": "10-10-50-70"
},
{
"rowIndex": 5,
"rackIndex": 8,
"aisleNum": 3,
"aisleSort": 80,
"rackCode": "10-10-50-80"
},
{
"rowIndex": 6,
"rackIndex": 8,
"aisleNum": 3,
"aisleSort": 81,
"rackCode": "10-10-60-80"
},
{
"rowIndex": 6,
"rackIndex": 9,
"aisleNum": 3,
"aisleSort": 90,
"rackCode": "10-10-60-90"
},
{
"rowIndex": 7,
"rackIndex": 9,
"aisleNum": 4,
"aisleSort": -100,
"rackCode": "10-10-70-90"
},
{
"rowIndex": 8,
"rackIndex": 8,
"aisleNum": 4,
"aisleSort": -80,
"rackCode": "10-10-80-80"
},
{
"rowIndex": 7,
"rackIndex": 4,
"aisleNum": 4,
"aisleSort": -40,
"rackCode": "10-10-70-40"
},
{
"rowIndex": 9,
"rackIndex": 2,
"aisleNum": 5,
"aisleSort": 30,
"rackCode": "10-10-90-20"
},
{
"rowIndex": 10,
"rackIndex": 3,
"aisleNum": 5,
"aisleSort": 31,
"rackCode": "10-10-100-30"
},
{
"rowIndex": 10,
"rackIndex": 7,
"aisleNum": 5,
"aisleSort": 70,
"rackCode": "10-10-100-70"
},
{
"rowIndex": 11,
"rackIndex": 8,
"aisleNum": 6,
"aisleSort": -90,
"rackCode": "10-10-110-80"
},
{
"rowIndex": 11,
"rackIndex": 7,
"aisleNum": 6,
"aisleSort": -71,
"rackCode": "10-10-110-70"
},
{
"rowIndex": 12,
"rackIndex": 7,
"aisleNum": 6,
"aisleSort": -70,
"rackCode": "10-10-120-70"
},
{
"rowIndex": 12,
"rackIndex": 5,
"aisleNum": 6,
"aisleSort": -51,
"rackCode": "10-10-120-50"
},
{
"rowIndex": 11,
"rackIndex": 4,
"aisleNum": 6,
"aisleSort": -40,
"rackCode": "10-10-110-40"
},
{
"rowIndex": 12,
"rackIndex": 3,
"aisleNum": 6,
"aisleSort": -30,
"rackCode": "10-10-120-30"
},
{
"rowIndex": 11,
"rackIndex": 2,
"aisleNum": 6,
"aisleSort": -20,
"rackCode": "10-10-110-20"
},
{
"rowIndex": 11,
"rackIndex": 1,
"aisleNum": 6,
"aisleSort": -11,
"rackCode": "10-10-110-10"
},
{
"rowIndex": 12,
"rackIndex": 1,
"aisleNum": 6,
"aisleSort": -10,
"rackCode": "10-10-120-10"
},
{
"rowIndex": 13,
"rackIndex": 2,
"aisleNum": 7,
"aisleSort": 30,
"rackCode": "10-10-130-20"
},
{
"rowIndex": 13,
"rackIndex": 4,
"aisleNum": 7,
"aisleSort": 40,
"rackCode": "10-10-130-40"
},
{
"rowIndex": 13,
"rackIndex": 6,
"aisleNum": 7,
"aisleSort": 60,
"rackCode": "10-10-130-60"
},
{
"rowIndex": 15,
"rackIndex": 6,
"aisleNum": 8,
"aisleSort": -70,
"rackCode": "10-10-150-60"
},
{
"rowIndex": 16,
"rackIndex": 6,
"aisleNum": 8,
"aisleSort": -60,
"rackCode": "10-10-160-60"
},
{
"rowIndex": 15,
"rackIndex": 5,
"aisleNum": 8,
"aisleSort": -50,
"rackCode": "10-10-150-50"
},
{
"rowIndex": 15,
"rackIndex": 4,
"aisleNum": 8,
"aisleSort": -41,
"rackCode": "10-10-150-40"
},
{
"rowIndex": 15,
"rackIndex": 3,
"aisleNum": 8,
"aisleSort": -31,
"rackCode": "10-10-150-30"
},
{
"rowIndex": 16,
"rackIndex": 2,
"aisleNum": 8,
"aisleSort": -20,
"rackCode": "10-10-160-20"
},
{
"rowIndex": 15,
"rackIndex": 1,
"aisleNum": 8,
"aisleSort": -10,
"rackCode": "10-10-150-10"
},
{
"rowIndex": 17,
"rackIndex": 2,
"aisleNum": 9,
"aisleSort": 20,
"rackCode": "10-10-170-20"
},
{
"rowIndex": 17,
"rackIndex": 3,
"aisleNum": 9,
"aisleSort": 30,
"rackCode": "10-10-170-30"
}
]
EC机架是端盖,它们属于奇数排——从过道上看,右边的几排。整个排序中的第一个货架是红色的。使用这个起点并按照上面的数组,我们现在可以找到最短的路径来挑选一组订单。
注意:当我们完成一个通道时,有时下一个通道中最近的机架会在我们身后。以下是确定下一个过道中最近机架的计算,这是必须在当前通道中转身才能移动到下一个最近机架的因素:
if (curDir === `up`) {
x = reverseMinRack.reverseAisleRackIndex + previousReverseAisleRackIndex + curDir === `up` ? 0 : 1;// +1 accounts for having to turn around
y = minRack.aisleRackIndex + previousAisleRackIndex + curDir === `down` ? 0 : 1; // +1 accounts for having to turn around
}
if (x === y) {
curDir = curDir === `up` ? `down` : `up`;
}
if (x < y) {
curDir = `down`;
}
if (x > y) {
curDir = `up`;
}