feat(table): 支持 controlled 受控模式(灰度开关)

This commit is contained in:
augushong
2026-09-10 19:32:38 +00:00
parent 6c5be1a15a
commit 305632199b

View File

@@ -25,6 +25,57 @@
return originalTableReloadData.apply(this, arguments);
};
// 受控表渲染接线(加载期执行一次):store 的 fetch/reload 只负责取数与状态、
// 不触发渲染,这里在唯一的数据到达点(store.reload 的成功回调)注入引擎
// 纯渲染——首屏/搜索/排序/switch 回滚/删除刷新全部经 shim 汇入 reload。
// 渲染必须走备份的原引擎引用:走 table.reloadData 会被上方 shim 路由回
// store 造成请求循环。initSort 透传保持表头排序箭头(与引擎 url 模式的
// listenTableSort 行为一致)。受控表分页条由 render() 内的
// syncControlledPager 自管:store 的 pager.jump 在内部直呼 fetch,外部
// 注入不了渲染回调,故 register 时不传 pagerElem 使 store 分页静默跳过,
// laypage 的 jump 经 shim(table.reloadData)回 store.reload 形成闭环。
var syncControlledPager = function (tableId) {
var state = window.UA_TABLE_STORE.dataProvider.getState(tableId);
if (!state) {
return;
}
layui.laypage.render({
elem: 'ua-store-pager-' + tableId,
count: state.count,
curr: state.page.curr,
limit: state.page.limit,
limits: state.limits,
layout: ['count', 'prev', 'page', 'next', 'limit', 'skip'],
jump: function (obj, first) {
if (!first) {
table.reloadData(tableId, {
page: {curr: obj.curr, limit: obj.limit}
});
}
}
});
};
if (window.UA_TABLE_STORE) {
var storeReload = window.UA_TABLE_STORE.reload;
window.UA_TABLE_STORE.reload = function (tableId, opts) {
opts = opts || {};
var userDone = opts.done;
opts.done = function (res) {
originalTableReloadData.call(table, tableId, {
data: res.data,
totalRow: res.totalRow,
initSort: opts.initSort
});
syncControlledPager(tableId);
if (typeof userDone === 'function') {
userDone(res);
}
};
return storeReload(tableId, opts);
};
}
ua.table = {
// 受控/非受控分发入口(后续任务直呼改造的定义点):非受控路径走备份的
// 原引擎引用,不经过上方已包装的 table.reloadData,避免递归
@@ -165,39 +216,52 @@
parseData = options.parseData;
}
options.parseData = function (res) {
if (options.controlled === true) {
// 受控灰度模式:数据请求与分页职责移交 UA_TABLE_STORE,引擎只做
// 纯渲染(空数据起步、关闭引擎分页,由 store 的 laypage 自绘)。
// 选择态注入(rowDisableCallback / URL selectedIds / LAY_CHECKED
// 跨页回显)由 store.fetch 的 injectSelectionMarks 承接,故不装
// 引擎 parseData。默认关闭——未显式 controlled:true 的页面保持
// 引擎 url 模式,行为与历史版本完全一致。
delete options.url;
delete options.parseData;
options.data = [];
options.page = false;
} else {
options.parseData = function (res) {
// 初始化已经选择的值
if (selectMode == 'checkbox' || selectMode == 'radio') {
if (typeof options.rowDisableCallback == 'function') {
for (let index = 0; index < res.data.length; index++) {
const dataItem = res.data[index];
// 初始化已经选择的值
if (selectMode == 'checkbox' || selectMode == 'radio') {
if (typeof options.rowDisableCallback == 'function') {
for (let index = 0; index < res.data.length; index++) {
const dataItem = res.data[index];
var rowDisableResult = options.rowDisableCallback(dataItem);
if (rowDisableResult === false || rowDisableResult === true) {
res.data[index].LAY_DISABLED = rowDisableResult;
var rowDisableResult = options.rowDisableCallback(dataItem);
if (rowDisableResult === false || rowDisableResult === true) {
res.data[index].LAY_DISABLED = rowDisableResult;
}
}
}
var selectedIds = ua.getQueryVariable('selectedIds', '');
if (selectedIds.length > 0) {
var selectedIdArr = selectedIds.split(',');
for (let index = 0; index < res.data.length; index++) {
const dataItem = res.data[index];
if (selectedIdArr.indexOf(dataItem.id.toString()) > -1) {
res.data[index].LAY_DISABLED = true;
}
}
}
}
var selectedIds = ua.getQueryVariable('selectedIds', '');
if (selectedIds.length > 0) {
var selectedIdArr = selectedIds.split(',');
for (let index = 0; index < res.data.length; index++) {
const dataItem = res.data[index];
if (selectedIdArr.indexOf(dataItem.id.toString()) > -1) {
res.data[index].LAY_DISABLED = true;
}
}
}
}
res = parseData(res);
return res;
};
res = parseData(res);
return res;
};
}
// 初始化表格
@@ -221,6 +285,50 @@
// 监听表格选择器
ua.table.listenTableSelectConfirm(options);
// 受控模式接线(在共享监听挂载之后):注册 store、自建分页容器、
// 同步勾选事件、首屏取数。搜索/排序/switch/编辑等既有监听的
// table.reloadData 调用经 shim 自动分流到 store.reload(渲染由顶部
// 接线层注入的 done 承接),此处无需逐点改造。
if (options.controlled === true) {
// 分页容器挂在引擎视图容器之后(表格容器外),不与引擎分页共存。
// 注意 layui render 后原 table 元素被移出视图(成为 view 的兄弟
// 节点),不能用 closest 向上找 view
var pagerId = 'ua-store-pager-' + options.id;
$('#' + pagerId).remove();
$(options.elem).siblings('.layui-table-view').first().after(
'<div id="' + pagerId + '" class="ua-store-pager"></div>'
);
window.UA_TABLE_STORE.register(options.id, {
indexUrl: options.init.indexUrl,
where: options.where,
page: {curr: 1, limit: options.limit},
limits: options.limits,
selectMode: selectMode,
rowDisableCallback: options.rowDisableCallback
// 不传 pagerElem:store 的 pager.jump 内部直呼 fetch 无法
// 触发引擎渲染,分页条由接线层 syncControlledPager 自管
});
// 引擎勾选事件 → store 选中集合:跨页勾选回显(LAY_CHECKED 注入)
// 的数据源。layui 2.10 事件回调 obj.data 是当次操作的单行对象
// (type=all 时不含可用行数据),全选场景以 store 的当页数据为准
//(selection.checkAll 缺省即当页数据,禁用行由其内部跳过)
table.on('checkbox(' + options.layFilter + ')', function (obj) {
if (obj.type === 'all') {
window.UA_TABLE_STORE.selection.checkAll(options.id, undefined, obj.checked);
} else {
window.UA_TABLE_STORE.selection.set(options.id, obj.data);
}
});
table.on('radio(' + options.layFilter + ')', function (obj) {
window.UA_TABLE_STORE.selection.set(options.id, obj.data);
});
// 首屏取数:经接线后的 store.reload 触发 fetch + 引擎纯渲染
window.UA_TABLE_STORE.reload(options.id);
}
return newTable;
},
renderToolbar: function (data, elem, tableId, init) {