最近在实现拖拽排序、置顶和置底逻辑时遇到了比较恶心的问题。以下为记录
背景
我们系统的排序是基于数据库中的 sort_num 字段进行的,sort_num 值越大,数据排位越靠前。新增数据时,其 sort_num 默认为其 id 值。假设当前有 10 条数据,最大 id 为 10,新增数据 id=11,sort_num 也为 11,因此新增的数据会排在最前面。
拖拽排序
最简单的拖拽排序方法是对当前页面的数据重新排序。假设当前页面有 5 条数据,排序顺序为:
1
2
3
4
5
当用户将 id=3 的数据拖动到第一位时,前端会传递新的排序顺序:
3
1
2
4
5
服务端会获取当前页面的最大 id 值(5),并减去排序项数量减 1(5-4=1),得到最小排序值(1),并重新分配排序号:
ID 排序号
3 5
1 4
2 3
4 2
5 1
这种方式可以实现拖拽排序。
置顶和置底逻辑
加入置顶和置底逻辑后,问题变得复杂。例如,假设 id=4 置顶,此时我们获取当前 id 最大的记录(假设 id=100, sort_num=100),并将 id=4 的 sort_num 更新为 100。但此时查询结果可能会有两个记录都显示在顶端:id=4 和 id=100。
为解决此问题,我们引入了多字段排序。即在 sort_num 相同的情况下,使用 update_time 作为第二排序字段。每次更新数据时,update_time 会更新为当前时间,因此可以通过 ORDER BY sort_num DESC, update_time DESC 实现正确排序。
置底逻辑
置底逻辑与置顶类似,不同之处在于我们会找到当前最小的排序值,并将其减 1 作为新的排序值。然而,由于 sort_num 字段是无符号类型,当最小排序值为 0 时,再减 1 仍然是 0。例如:
【id=4,sort_num=0,update_time=2024-07-09 17:00:00】
【id=5,sort_num=0,update_time=2024-07-09 17:01:00】
此时 id=4 在最底部,id=5 倒数第二,显然不符合预期。
解决方案
将 sort_num 字段改为有符号类型,使其支持负数。这样在置底逻辑中,当最小排序值为 0 时,我们可以继续向负数方向延伸,避免排序冲突。