修复号码管理显示条数

This commit is contained in:
root
2026-07-05 23:40:13 +08:00
parent ef4c8153c2
commit 2e621bf970
4 changed files with 1016 additions and 0 deletions
@@ -25,6 +25,11 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
fixedColumns: true,
fixedRightNumber: 1,
searchFormVisible: true,
pageSize: 10,
pageList: Controller.api.streamLoad.PAGE_LIST,
queryParams: function (params) {
return Controller.api.streamLoad.wrapQueryParams(table, params);
},
columns: [
[
{checkbox: true},
@@ -122,6 +127,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
});
Table.api.bindevent(table);
Controller.api.streamLoad.bind(table);
Controller.api.bindDeferredFilter(table);
Controller.api.bindDeferredCleanup(table);
},
@@ -167,6 +173,504 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin
}
},
/**
* 分页选「全部」时改为分块滚动加载,避免一次渲染过多 DOM 导致卡顿
*/
streamLoad: {
CHUNK: 50,
SCROLL_THRESHOLD: 80,
LOAD_DELAY: 1500,
PAGE_LIST: [10, 30, 50, 100, 200, 300, 500, 'All'],
createState: function () {
return {
enabled: false,
loading: false,
pendingLoad: false,
loadTimer: null,
loaded: 0,
total: 0,
chunk: 50,
pendingReset: false,
pendingAllSelect: false,
appendQuery: false
};
},
getState: function (table) {
var state = table.data('splitStreamLoad');
if (!state) {
state = Controller.api.streamLoad.createState();
table.data('splitStreamLoad', state);
}
return state;
},
getAllLabel: function () {
var localeKey = (typeof Config !== 'undefined' && Config.language === 'zh-cn') ? 'zh-CN' : 'en-US';
var locale = $.fn.bootstrapTable.locales && $.fn.bootstrapTable.locales[localeKey];
if (locale && typeof locale.formatAllRows === 'function') {
return locale.formatAllRows();
}
if ($.fn.bootstrapTable.defaults && typeof $.fn.bootstrapTable.defaults.formatAllRows === 'function') {
return $.fn.bootstrapTable.defaults.formatAllRows();
}
return 'All';
},
/**
* initServer 首次请求时实例尚未写入 data('bootstrap.table')getOptions 会退回 jQuery 对象
*/
safeGetOptions: function (table) {
if (!table || !table.length) {
return null;
}
var opts = table.bootstrapTable('getOptions');
if (opts && typeof opts.formatAllRows === 'function') {
return opts;
}
var instance = table.data('bootstrap.table');
if (instance && instance.options && typeof instance.options.formatAllRows === 'function') {
return instance.options;
}
return null;
},
getDefaultPageList: function () {
return Controller.api.streamLoad.PAGE_LIST;
},
getMaxNormalPageSize: function (pageList) {
var api = Controller.api.streamLoad;
var maxNormal = 0;
$.each(pageList || api.getDefaultPageList(), function (i, value) {
if (api.isAllPageSize(value)) {
return;
}
var num = parseInt(value, 10);
if (!isNaN(num) && num > maxNormal) {
maxNormal = num;
}
});
return maxNormal;
},
isAllPageSize: function (pageSize) {
if (pageSize === undefined || pageSize === null || pageSize === '') {
return false;
}
return String(pageSize).toUpperCase() === String(Controller.api.streamLoad.getAllLabel()).toUpperCase();
},
isLargeStoredPageSize: function (table, params) {
var api = Controller.api.streamLoad;
var options = api.safeGetOptions(table);
var pageSize = options ? options.pageSize : null;
var limit = params ? (parseInt(params.limit, 10) || 0) : 0;
if (pageSize !== null && api.isAllPageSize(pageSize)) {
return true;
}
var maxNormal = api.getMaxNormalPageSize(options ? options.pageList : null);
if (typeof pageSize === 'number' && pageSize > maxNormal) {
return true;
}
if (!options && limit > maxNormal) {
return true;
}
return false;
},
shouldEnable: function (table, params) {
var api = Controller.api.streamLoad;
var state = api.getState(table);
if (state.pendingAllSelect || state.enabled) {
return true;
}
var options = api.safeGetOptions(table);
var limit = parseInt(params.limit, 10) || 0;
if (options) {
var totalRows = parseInt(options.totalRows, 10) || 0;
if (api.isAllPageSize(options.pageSize)) {
return true;
}
if (api.isLargeStoredPageSize(table, params)) {
return true;
}
return totalRows > 0 && limit >= totalRows;
}
// 表格构造阶段:All 模式 totalRows 尚未就绪时 limit 可能为 0
if (limit === 0) {
var stored = localStorage.getItem('pagesize');
if (stored && api.isAllPageSize(stored)) {
return true;
}
}
return api.isLargeStoredPageSize(table, params);
},
enable: function (table) {
var state = Controller.api.streamLoad.getState(table);
state.enabled = true;
state.loaded = 0;
state.loading = false;
state.pendingReset = true;
},
disable: function (table) {
var api = Controller.api.streamLoad;
var state = api.getState(table);
api.cancelPendingLoad(table);
state.enabled = false;
state.loaded = 0;
state.total = 0;
state.loading = false;
state.pendingReset = false;
state.pendingAllSelect = false;
api.updateHint(table);
api.togglePaginationNav(table, false);
api.showBottomLoading(table, false);
},
wrapQueryParams: function (table, params) {
var api = Controller.api.streamLoad;
var state = api.getState(table);
if (api.shouldEnable(table, params)) {
state.enabled = true;
state.pendingAllSelect = false;
}
if (!state.enabled) {
return params;
}
params.limit = state.chunk;
if (state.appendQuery) {
params.offset = parseInt(params.offset, 10) || 0;
} else {
params.offset = 0;
state.pendingReset = true;
}
state.appendQuery = false;
return params;
},
bind: function (table) {
var api = Controller.api.streamLoad;
var $wrapper = table.closest('.bootstrap-table');
$wrapper.on('click.splitStream', '.page-list .dropdown-menu li a', function () {
api.cancelPendingLoad(table);
var label = $.trim($(this).text());
if (api.isAllPageSize(label)) {
api.getState(table).pendingAllSelect = true;
api.enable(table);
}
});
table.on('page-change.bs.table', function (e, pageNumber, pageSize) {
var options = api.safeGetOptions(table);
if (!options) {
return;
}
if (api.isAllPageSize(pageSize)
|| (typeof pageSize === 'number' && pageSize === options.totalRows && options.totalRows > 0)) {
api.enable(table);
return;
}
if (typeof pageSize === 'number' && pageSize < options.totalRows) {
api.disable(table);
}
});
table.on('refresh.bs.table search.bs.table common-search.bs.table', function () {
var state = api.getState(table);
api.cancelPendingLoad(table);
if (!state.enabled) {
return;
}
state.loaded = 0;
state.pendingReset = true;
});
table.on('sort.bs.table', function () {
var state = api.getState(table);
api.cancelPendingLoad(table);
if (!state.enabled) {
return;
}
state.loaded = 0;
state.pendingReset = true;
});
table.on('load-success.bs.table', function (e, data) {
var state = api.getState(table);
if (!state.enabled || !data || typeof data.total === 'undefined') {
return;
}
state.total = parseInt(data.total, 10) || 0;
if (state.pendingReset) {
state.loaded = $.isArray(data.rows) ? data.rows.length : 0;
state.pendingReset = false;
}
api.updateHint(table);
api.togglePaginationNav(table, true);
api.bindScrollContainer(table);
api.autoFillViewport(table);
var tableOptions = api.safeGetOptions(table);
if (tableOptions && tableOptions.fixedColumns) {
table.bootstrapTable('resetView');
}
});
table.on('post-body.bs.table', function () {
if (!api.getState(table).enabled) {
return;
}
api.updateHint(table);
});
},
bindScrollContainer: function (table) {
var api = Controller.api.streamLoad;
var $body = table.closest('.bootstrap-table').find('.fixed-table-body');
if (!$body.length || $body.data('splitStreamBound')) {
return;
}
$body.data('splitStreamBound', true);
$body.on('scroll.splitStream', function () {
api.onScroll(table, this);
});
},
onScroll: function (table, el) {
var api = Controller.api.streamLoad;
var state = api.getState(table);
if (!state.enabled || state.loading || state.loaded >= state.total) {
return;
}
var atBottom = el.scrollTop + el.clientHeight >= el.scrollHeight - api.SCROLL_THRESHOLD;
if (!atBottom) {
api.cancelPendingLoad(table);
return;
}
if (state.pendingLoad) {
return;
}
api.scheduleLoadMore(table);
},
isNearBottom: function (table) {
var api = Controller.api.streamLoad;
var $body = table.closest('.bootstrap-table').find('.fixed-table-body');
if (!$body.length) {
return false;
}
var el = $body[0];
return el.scrollTop + el.clientHeight >= el.scrollHeight - api.SCROLL_THRESHOLD;
},
scheduleLoadMore: function (table) {
var api = Controller.api.streamLoad;
var state = api.getState(table);
if (state.loading || state.pendingLoad || !state.enabled || state.loaded >= state.total) {
return;
}
state.pendingLoad = true;
api.showBottomLoading(table, true);
api.updateHint(table, false, true);
state.loadTimer = setTimeout(function () {
state.pendingLoad = false;
state.loadTimer = null;
if (!state.enabled) {
api.showBottomLoading(table, false);
api.updateHint(table);
return;
}
if (!api.isNearBottom(table)) {
api.showBottomLoading(table, false);
api.updateHint(table);
return;
}
api.loadMore(table);
}, api.LOAD_DELAY);
},
cancelPendingLoad: function (table) {
var api = Controller.api.streamLoad;
var state = api.getState(table);
if (state.loadTimer) {
clearTimeout(state.loadTimer);
state.loadTimer = null;
}
state.pendingLoad = false;
if (!state.loading) {
api.showBottomLoading(table, false);
api.updateHint(table);
}
},
showBottomLoading: function (table, show) {
var $body = table.closest('.bootstrap-table').find('.fixed-table-body');
if (!$body.length) {
return;
}
var $bar = $body.children('.split-stream-loading-bar');
if (show) {
if (!$bar.length) {
var loadingText = __('Stream loading bottom');
if (!loadingText || loadingText === 'Stream loading bottom') {
loadingText = '加载中...';
}
$bar = $('<div class="split-stream-loading-bar text-center" style="padding:14px 0;color:#999;border-top:1px solid #f0f0f0;background:#fafafa;">'
+ '<i class="fa fa-spinner fa-spin"></i> ' + Fast.api.escape(loadingText)
+ '</div>');
$body.append($bar);
}
$bar.show();
} else if ($bar.length) {
$bar.hide();
}
},
buildRequestParams: function (table, offset, limit) {
var options = Controller.api.streamLoad.safeGetOptions(table);
if (!options) {
return {offset: offset, limit: limit};
}
var state = Controller.api.streamLoad.getState(table);
state.appendQuery = true;
return options.queryParams({
search: options.searchText,
sort: options.sortName,
order: options.sortOrder,
offset: offset,
limit: limit
});
},
loadMore: function (table) {
var api = Controller.api.streamLoad;
var state = api.getState(table);
if (state.loading || !state.enabled || state.loaded >= state.total) {
return;
}
state.loading = true;
api.updateHint(table, true);
var options = api.safeGetOptions(table);
if (!options) {
state.loading = false;
return;
}
$.ajax({
url: options.url,
type: options.method,
data: api.buildRequestParams(table, state.loaded, state.chunk),
dataType: 'json'
}).done(function (res) {
state.loading = false;
api.showBottomLoading(table, false);
if (!res || typeof res.rows === 'undefined') {
Toastr.error(__('Unknown data format'));
api.updateHint(table);
return;
}
var rows = res.rows || [];
if (rows.length === 0) {
state.loaded = state.total;
api.updateHint(table);
return;
}
table.bootstrapTable('append', rows);
state.loaded += rows.length;
api.updateHint(table);
api.autoFillViewport(table);
if (options.fixedColumns) {
table.bootstrapTable('resetView');
}
}).fail(function () {
state.loading = false;
api.showBottomLoading(table, false);
api.updateHint(table);
Toastr.error(__('Unknown data format'));
});
},
autoFillViewport: function (table) {
var api = Controller.api.streamLoad;
var state = api.getState(table);
if (!state.enabled || state.loading || state.pendingLoad || state.loaded >= state.total) {
return;
}
var $body = table.closest('.bootstrap-table').find('.fixed-table-body');
if (!$body.length) {
return;
}
var el = $body[0];
if (el.scrollHeight <= el.clientHeight + api.SCROLL_THRESHOLD) {
api.scheduleLoadMore(table);
}
},
togglePaginationNav: function (table, hide) {
table.closest('.bootstrap-table').find('.fixed-table-pagination .pagination').toggle(!hide);
},
getHintText: function (loaded, total, loading, pending) {
if (pending) {
var pendingText = __('Stream loading pending');
if (!pendingText || pendingText === 'Stream loading pending') {
pendingText = '即将加载更多,可切换显示条数取消...';
}
return pendingText;
}
if (loading) {
var loadingText = __('Stream loading');
return loadingText && loadingText !== 'Stream loading' ? loadingText : '加载中...';
}
var template = __('Stream loaded');
if (!template || template === 'Stream loaded') {
template = '已加载 %loaded% / %total%,继续滚动加载更多';
}
return template
.replace('%loaded%', String(loaded))
.replace('%total%', String(total));
},
updateHint: function (table, loading, pending) {
var api = Controller.api.streamLoad;
var state = api.getState(table);
var $wrapper = table.closest('.bootstrap-table');
var $detail = $wrapper.find('.pagination-detail');
if (!state.enabled) {
$wrapper.find('.split-stream-hint').remove();
return;
}
var $hint = $wrapper.find('.split-stream-hint');
if (!$hint.length) {
$hint = $('<span class="split-stream-hint text-muted" style="margin-left:10px;font-size:12px;"></span>');
$detail.append($hint);
}
var isPending = pending !== undefined ? pending : state.pendingLoad;
var isLoading = loading !== undefined ? loading : state.loading;
$hint.text(api.getHintText(state.loaded, state.total, isLoading, isPending));
}
},
formatter: {
platformStatus: function (value, row) {
var text = row.platform_status_text != null && row.platform_status_text !== ''