板块管理页支持拖拽排序(group_reorder)
- 板块列表与网站列表同款的拖拽交互:按住行首手柄拖动,实时重排预览, 松手即保存(Ajax 动作 group_reorder,整组归一化为 index * SORT_STEP) - 板块没有分组维度,group_reorder 不带 group_id、不做归属校验 (apply_sort_order 不传 $groupId 时按给定 id 顺序整组重写) - admin.js 的拖拽排序从「只认网站列表」泛化为「所有带 data-sortable 的 tbody」:落库 action / group_id / 落库地址都改由 tbody 的 data-* 提供, 网站列表行为不变(仍从 #sites-tabs 读地址、带 group_id) - 新增板块仍排最后(MAX + SORT_STEP,上一轮已实现);板块上移/下移按钮 保留作无 JS 回退;页面顶部补说明文案 - 验证:HTTP e2e 新增 S12 系列 18 条(结构 / 拖拽落库 / 前台同步 / 新增排最后 / 上移回退),72/72;jsdom 新增板块页 19 项,26+19 全绿; 反向验证:函数层 4 变体 + HTTP 层 7 变体(新增 G:group_reorder 失效) + jsdom 4 变体全部精确报红、基准全绿;全量既有回归 193/193
This commit is contained in:
+17
-11
@@ -244,24 +244,30 @@
|
||||
|
||||
/**
|
||||
* 拖拽排序:按住某一行拖动即可改顺序,松手即保存。
|
||||
* 用于「网站列表」(每板块一个 tbody)与「板块列表」(整表一个 tbody)。
|
||||
*
|
||||
* 实现要点:
|
||||
* · 用**原生 HTML5 拖拽**(draggable=true + dragstart/dragover/drop),
|
||||
* 不引任何第三方库(本项目零依赖);
|
||||
* · 拖动过程中实时把被拖行**移动到光标位置**(真·所见即所得),
|
||||
* 而不是只画一条插入线 —— 个人导航站的列表不长,实时重排体验更直观;
|
||||
* · **只允许在本板块的 tbody 内拖动**:跨板块拖会被忽略(拖到别的板块前先改「板块」再排);
|
||||
* · 松手后收集该 tbody 的 id 顺序 → POST 给 site_reorder → 服务端整组归一化。
|
||||
* · 网站列表**只允许在本板块的 tbody 内拖动**:跨板块拖会被忽略(拖到别的板块前先改「板块」再排);
|
||||
* · 松手后收集该 tbody 的 id 顺序 → POST 给对应 action(tbody 上的 data-sort-action)
|
||||
* → 服务端整组归一化。
|
||||
*/
|
||||
function initDragSort() {
|
||||
var bodies = $$('tbody[data-group-id]');
|
||||
var bodies = $$('tbody[data-sortable]');
|
||||
if (!bodies.length) return;
|
||||
var wrap = $('#sites-tabs');
|
||||
var url = wrap ? wrap.getAttribute('data-reorder-url') : '';
|
||||
var csrf = (document.querySelector('input[name="csrf"]') || {}).value || '';
|
||||
|
||||
bodies.forEach(function (body) {
|
||||
var dragRow = null;
|
||||
var action = body.getAttribute('data-sort-action') || 'site_reorder';
|
||||
var gid = body.getAttribute('data-group-id') || '';
|
||||
// 落库地址:优先 tbody 自带;网站列表没有时回退到标签容器上的
|
||||
var url = body.getAttribute('data-reorder-url')
|
||||
|| (wrap ? wrap.getAttribute('data-reorder-url') : '');
|
||||
|
||||
body.addEventListener('dragstart', function (ev) {
|
||||
var row = ev.target.closest ? ev.target.closest('tr') : null;
|
||||
@@ -293,7 +299,7 @@
|
||||
if (!dragRow) return;
|
||||
dragRow.classList.remove('dragging');
|
||||
dragRow = null;
|
||||
saveOrder(body);
|
||||
saveOrder(body, action, gid, url);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -309,16 +315,16 @@
|
||||
return null;
|
||||
}
|
||||
|
||||
/** 收集顺序并提交;成功后更新状态提示 */
|
||||
function saveOrder(body) {
|
||||
/** 收集顺序并提交;成功后更新状态提示(action/gid/url 来自所属 tbody 的 data-*) */
|
||||
function saveOrder(body, action, gid, url) {
|
||||
if (!url) return;
|
||||
var gid = body.getAttribute('data-group-id');
|
||||
var ids = $$('tr', body).map(function (r) { return r.getAttribute('data-id'); }).filter(Boolean);
|
||||
var status = document.querySelector('.sort-status[data-group-id="' + gid + '"]');
|
||||
var scope = body.closest('.sites-panel') || body.closest('.card') || document;
|
||||
var status = $('.sort-status', scope);
|
||||
|
||||
var fd = new FormData();
|
||||
fd.append('action', 'site_reorder');
|
||||
fd.append('group_id', gid);
|
||||
fd.append('action', action);
|
||||
if (gid) { fd.append('group_id', gid); }
|
||||
fd.append('order', ids.join(','));
|
||||
fd.append('ajax', '1');
|
||||
fd.append('csrf', csrf);
|
||||
|
||||
Reference in New Issue
Block a user