我们有一个电子商务网站,现在已经销售了几天的商品。我们有一个可以订购产品的系统,因此“特色”产品位于顶部,销售情况不佳的产品位于折扣底部。
我们最近推出的产品运行了几天而不是一天,但这会对我们的排序算法造成严重破坏。
以前我们每天都会设置产品订单,所以如果我们在一天内销售了5件产品,我们会在数据库中将其设置为:
Position | Product
----------------------
1 | Product # 1
5 | Product # 2
4 | Product # 3
2 | Product # 4
3 | Product # 5
然后,我们可以将产品列表拉出一天,按位置和显示进行排序。但是现在我们必须补偿多天运行的产品,因此可以在多天内拥有多个仓位。我们认为我们可以轻松调整算法以在整个产品表中运行,如下所示:
Position | Product
----------------------
51 | Product # 1
75 | Product # 2
69 | Product # 3
62 | Product # 4
66 | Product # 5
这些产品的订单仍与原先相同,但该位置基于表中的每个产品,而不仅仅是当天。这给了我们一个我们期望的日历(数字是产品表中的当前位置):
当我们想要重新订购产品时,问题就出现了。如果我们的产品#6运行了3天,那么它的位置可能是64,当时它位于#4和#3以上,但是当我们重新订购这些产品时,它会移动并获得jQuery UI数据列表中与任何事物无关的位置,虽然我们知道产品与其他日子的关系,但我们不知道那些日子是如何联系在一起的。
我们目前在每次下降后都会触发回调,因此我们只需要处理一次移动的产品。这减少了我们需要做的计算,但我们宁愿一次性设置顺序并从那里处理它。这也为用户提供了中止的机会。
这是我们当前的排序算法,它将产品插入到其他两个之间:
public function setPosition($after, $before)
{
// Get products which this product is after and before
$after = $this->find($after);
$before = $this->find($before);
// Move all items down to clear a space for the product
$this->where('position', '>', $before->position)->update(array('position', DB::raw('position + 1')));
$this->position = $after->position + 1;
$this->updateUniques();
}
我们确信我们不是唯一遇到过此问题的人,并认为必须有办法解决这个问题。
答案 0 :(得分:0)
我认为当你展示它们时,条目的“位置”真的很重要。唯一重要的是显示的条目的相对位置。因此,你可以交换他们的整体头寸。所以在你的第二个例子中,
Position | Product
----------------------
51 | Product # 1
75 | Product # 2
69 | Product # 3
62 | Product # 4
66 | Product # 5
如果要交换产品2和3,只需将#2位置设置为69,将#3位置设置为75.
Position | Product
----------------------
51 | Product # 1
75 | Product # 3
69 | Product # 2
62 | Product # 4
66 | Product # 5
如果我理解正确,我认为这不会影响其他日子。
为了实现这一点,我将在HTML元素上使用data
属性,类似data-position
,并将其设置为从数据库返回的值。然后在jQuery中,当您交换行时,您可以通过AJAX轻松地将两个data-position
发送到您的SQL查询中以交换位置。
如果您决定重新排序所有条目并发送一个回调,这也应该有效。在您关闭回调时,只需对每个元素使用data-position
。
希望这是有道理的。
答案 1 :(得分:0)
这不是完美的,但是我没有移动产品本身,而是最终移动了受影响的产品并且似乎有效。
数据作为数组从jQueryUI可排序传递。
控制器具有此更新功能:
/**
* Update the schedule order
*
* @return object
*/
public function update()
{
// Find product before and after
foreach (Input::get('order') as $key => $product)
{
if ($product['id'] != Input::get('id')) continue;
// Find the products before or after this product
$before = Input::get('order.' . ($key - 1) . '.id') ?: 0;
$after = Input::get('order.' . ($key + 1) . '.id') ?: 0;
break;
}
// Find product
$product = Product::find(Input::get('id'));
$product->updatePosition($before, $after);
return $this->get();
}
该模型具有此updatePosition函数:
/**
* Move/reorder a product into another position
*
* @param int $before [= 0]
* @param int $after [= 0]
* @return void
*/
public function updatePosition($before = 0, $after = 0)
{
// Get products which are before or after this product
$before = $this->find($before);
$after = $this->find($after);
// Determine which direction we've moved this product
if ( ! $before) $direction = -1;
elseif ( ! $after) $direction = 1;
elseif ($before->position < $this->position && $after->position < $this->position) $direction = -1;
else $direction = 1;
// Determine how much we've moved
if ($direction == 1)
{
// We've moved this product down
$difference = $this->position - $before->position - 1;
$this->whereNull('parent_id')->where('position', '<=', $before->position)->where('id', '!=', $this->id)->update(array('position' => DB::raw('position + ' . $difference)));
}
else
{
$difference = $this->position - $after->position + 1;
$this->whereNull('parent_id')->where('position', '>=', $after->position)->where('id', '!=', $this->id)->update(array('position' => DB::raw('position + ' . $difference)));
}
}
这样做的缺点是我仍然需要在每次下降之后保存,而不是重新排序一堆产品并计算出他们的新职位但是它有效......