Files
workspace/code/jsp/js/feegrid-manager.js
T
2026-05-11 21:45:04 +08:00

938 lines
26 KiB
JavaScript

/**
* DataGrid 公共管理模块
*
* 核心设计原则:
* 1. 草稿态维护最终状态,而非操作过程
* 2. delete 是临时挂起状态,保留 backup 用于恢复
* 3. 本地数据不参与条件搜索,搜索完全依赖远程接口
* 4. 搜索与展示分离:搜索=远程,展示=本地状态覆盖
* 5. baseSearchCondition 作为永久根条件
*
* 使用方式:
* var gridManager = createDataGridManager({
* gridId: 'feegrid',
* keyField: 'subid',
* viewName: 'v_cwzd_orderfee_s',
* baseSearchCondition: "mx_zdorderid='xxx'",
* onLoadSuccess: function(rows) { ... },
* onAfterEdit: function(rowIndex, row, changes) { ... },
* onSelectionChange: function() { ... }
* });
*/
(function (window) {
"use strict";
// ==================== DraftStateManager(内部模块)====================
function createDraftStateManager(config) {
var keyField = (config && config.keyField) || "id";
var defaultPageSize = (config && config.pageSize) || 50;
var draftStateMap = {};
var isAllChecked = false;
var pagination = {
pageSize: defaultPageSize,
pageNumber: 1,
remoteTotal: 0,
};
function initOrUpdateDraftState(rowId) {
if (!draftStateMap[rowId]) {
draftStateMap[rowId] = {
state: null,
data: null,
backup: null,
selected: false,
excluded: false,
};
}
return draftStateMap[rowId];
}
function setDraftState(rowId, state, data, backup) {
var draftState = initOrUpdateDraftState(rowId);
draftState.state = state;
draftState.data = data;
draftState.backup = backup;
}
function getDraftState(rowId) {
return draftStateMap[rowId];
}
function removeDraftState(rowId) {
delete draftStateMap[rowId];
}
function hasDraftState(rowId) {
return draftStateMap.hasOwnProperty(rowId);
}
function setRowSelected(rowId, selected) {
var draftState = initOrUpdateDraftState(rowId);
draftState.selected = selected;
}
function setRowExcluded(rowId, excluded) {
var draftState = initOrUpdateDraftState(rowId);
draftState.excluded = excluded;
}
function addInsertRow(row) {
if (!row._rowState) row._rowState = "insert";
var key = getRowKey(row);
setDraftState(key, "insert", row, null);
}
function removeInsertRow(row) {
var key = getRowKey(row);
removeDraftState(key);
}
function addUpdateRow(row) {
var key = getRowKey(row);
var existingState = getDraftState(key);
if (existingState && existingState.state === "delete") {
return;
}
row._rowState = "update";
setDraftState(key, "update", row, null);
}
function addDeleteRow(row) {
var key = getRowKey(row);
var existingState = getDraftState(key);
var backupData = existingState ? existingState.data : row;
row._rowState = "delete";
setDraftState(key, "delete", row, backupData);
setRowSelected(key, false);
}
function recoverRow(row) {
var key = getRowKey(row);
var state = getDraftState(key);
if (state && state.state === "delete") {
if (state.backup) {
var backupState = state.backup._rowState || "";
setDraftState(key, backupState, state.backup, null);
row._rowState = backupState;
} else {
removeDraftState(key);
row._rowState = "";
}
}
}
function addSelectedRow(row) {
var key = getRowKey(row);
setRowSelected(key, true);
}
function removeSelectedRow(row) {
var key = getRowKey(row);
setRowSelected(key, false);
}
function clearSelectedRows() {
for (var key in draftStateMap) {
draftStateMap[key].selected = false;
}
}
function addExcludedRow(row) {
var key = getRowKey(row);
setRowExcluded(key, true);
}
function removeExcludedRow(row) {
var key = getRowKey(row);
setRowExcluded(key, false);
}
function clearExcludedRows() {
for (var key in draftStateMap) {
draftStateMap[key].excluded = false;
}
}
function isRowExcluded(row) {
var key = getRowKey(row);
var state = getDraftState(key);
return state ? state.excluded : false;
}
function cloneRow(row) {
if (!row) return null;
return JSON.parse(JSON.stringify(row));
}
function applyDraftState(remoteRows) {
var displayRows = [];
for (var i = 0; i < remoteRows.length; i++) {
var row = remoteRows[i];
var key = getRowKey(row);
var draftState = getDraftState(key);
if (draftState) {
switch (draftState.state) {
case "delete":
continue;
case "update":
case "insert":
displayRows.push(cloneRow(draftState.data));
break;
default:
displayRows.push(cloneRow(row));
}
} else {
displayRows.push(cloneRow(row));
}
}
return displayRows;
}
function reset() {
draftStateMap = {};
isAllChecked = false;
pagination = {
pageSize: defaultPageSize,
pageNumber: 1,
remoteTotal: 0,
};
}
function getRowKey(row) {
return row[keyField];
}
function getRowIdsByState(stateFilter) {
var ids = [];
for (var key in draftStateMap) {
var state = draftStateMap[key];
if (state.state === stateFilter) {
ids.push(key);
}
}
return ids;
}
return {
keyField: keyField,
setDraftState: setDraftState,
getDraftState: getDraftState,
removeDraftState: removeDraftState,
hasDraftState: hasDraftState,
addInsertRow: addInsertRow,
removeInsertRow: removeInsertRow,
addUpdateRow: addUpdateRow,
addDeleteRow: addDeleteRow,
recoverRow: recoverRow,
getInsertRows: function () {
var inserts = [];
for (var key in draftStateMap) {
if (draftStateMap[key].state === "insert") {
inserts.push(draftStateMap[key].data);
}
}
return inserts;
},
getInsertRowIds: function () {
return getRowIdsByState("insert");
},
getUpdateRows: function () {
var updates = [];
for (var key in draftStateMap) {
if (draftStateMap[key].state === "update") {
updates.push(draftStateMap[key].data);
}
}
return updates;
},
getDeleteRows: function () {
var deletes = [];
for (var key in draftStateMap) {
if (draftStateMap[key].state === "delete") {
deletes.push(draftStateMap[key].data);
}
}
return deletes;
},
addSelectedRow: addSelectedRow,
removeSelectedRow: removeSelectedRow,
getSelectedRowIds: function () {
var ids = [];
for (var key in draftStateMap) {
if (
draftStateMap[key].selected &&
(!draftStateMap[key].state || draftStateMap[key].state !== "delete")
) {
ids.push(key);
}
}
return ids;
},
getSelectedRows: function () {
var rows = [];
for (var key in draftStateMap) {
var state = draftStateMap[key];
if (state.selected && state.data) {
rows.push(state.data);
}
}
return rows;
},
getValidSelectedRows: function () {
var rows = [];
for (var key in draftStateMap) {
var state = draftStateMap[key];
if (
state.selected &&
state.data &&
(!state.state || state.state !== "delete")
) {
rows.push(state.data);
}
}
return rows;
},
clearSelectedRows: clearSelectedRows,
isAllChecked: function () {
return isAllChecked;
},
setAllChecked: function (value) {
isAllChecked = value;
if (value) clearSelectedRows();
},
addExcludedRow: addExcludedRow,
removeExcludedRow: removeExcludedRow,
getExcludedRowIds: function () {
var ids = [];
for (var key in draftStateMap) {
if (draftStateMap[key].excluded) {
ids.push(key);
}
}
return ids;
},
getExcludedRows: function () {
var rows = [];
for (var key in draftStateMap) {
var state = draftStateMap[key];
if (state.excluded && state.data) {
rows.push(state.data);
}
}
return rows;
},
clearExcludedRows: clearExcludedRows,
isRowExcluded: isRowExcluded,
applyDraftState: applyDraftState,
pagination: {
get: function () {
return pagination;
},
setPageNumber: function (pageNumber) {
pagination.pageNumber = pageNumber;
},
setPageSize: function (pageSize) {
pagination.pageSize = pageSize;
},
setRemoteTotal: function (remoteTotal) {
pagination.remoteTotal = remoteTotal;
},
getPageSize: function () {
return pagination.pageSize;
},
getPageNumber: function () {
return pagination.pageNumber;
},
getRemoteTotal: function () {
return pagination.remoteTotal;
},
getTotalPages: function () {
return Math.ceil(pagination.remoteTotal / pagination.pageSize);
},
},
getRowKey: getRowKey,
reset: reset,
};
}
// ==================== createDataGridManager(导出)====================
function createDataGridManager(config) {
var $ = window.jQuery;
var DEFAULT_CONFIG = {
gridId: "feegrid",
keyField: "subid",
pageSize: 50,
viewName: "",
searchUrl: "jsp/searchdatapagenew.jsp",
orderField: "b_id",
baseSearchCondition: null,
searchCondition: null,
pageList: [50, 100, 200],
rowStateStyles: {
insert: "background-color: #f6ffed;",
update: "background-color: #fffbe6;",
delete: "background-color: #fff1f0;",
},
selectAllBtn: "#btn_select_all",
selectAllText: "全部选中",
unselectAllText: "全部反选",
userid: "",
customDatagridOptions: null,
ajaxTimeout: 30000,
onLoadError: null,
onLoadSuccess: null,
onAfterEdit: null,
onSelectionChange: null,
};
var options = $.extend(true, {}, DEFAULT_CONFIG, config);
var state = {
draftManager: null,
editIndex: undefined,
isLoading: false,
pagerId: null,
requestVersion: 0,
};
_initDraftManager();
_initGrid();
function _initDraftManager() {
state.draftManager = createDraftStateManager({
keyField: options.keyField,
pageSize: options.pageSize,
});
}
function _getPagerId() {
if (!state.pagerId) {
state.pagerId = options.gridId + "_pager";
}
return state.pagerId;
}
function _setLoading() {
state.isLoading = true;
$("#" + options.gridId).datagrid("loading");
$("#" + _getPagerId())
.css({
"pointer-events": "none",
opacity: "0.6",
})
.pagination("loading");
}
function _clearLoading() {
state.isLoading = false;
$("#" + options.gridId).datagrid("loaded");
$("#" + _getPagerId())
.css({
"pointer-events": "",
opacity: "",
})
.pagination("loaded");
}
function _syncGridChecks() {
var rows = $("#" + options.gridId).datagrid("getRows");
var selectedKeys = {};
var selectedRowIds = state.draftManager.getSelectedRowIds();
for (var s = 0; s < selectedRowIds.length; s++) {
selectedKeys[selectedRowIds[s]] = true;
}
var excludedKeys = {};
var excludedRowIds = state.draftManager.getExcludedRowIds();
for (var e = 0; e < excludedRowIds.length; e++) {
excludedKeys[excludedRowIds[e]] = true;
}
for (var i = 0; i < rows.length; i++) {
var row = rows[i];
var key = state.draftManager.getRowKey(row);
if (state.draftManager.isAllChecked()) {
if (excludedKeys[key]) {
$("#" + options.gridId).datagrid("uncheckRow", i);
} else {
$("#" + options.gridId).datagrid("checkRow", i);
}
} else {
if (selectedKeys[key]) {
$("#" + options.gridId).datagrid("checkRow", i);
} else {
$("#" + options.gridId).datagrid("uncheckRow", i);
}
}
}
}
function _handleRowStyles() {
$(".datagrid-body tr").each(function () {
var rowIndex = $(this).attr("datagrid-row-index");
if (rowIndex !== undefined) {
var row = $("#" + options.gridId).datagrid("getRows")[
parseInt(rowIndex)
];
if (row && row._rowState === "delete") {
$(this).addClass("datagrid-row-delete");
} else {
$(this).removeClass("datagrid-row-delete");
}
}
});
}
function buildFinalCondition() {
var parts = [];
if (options.baseSearchCondition) {
parts.push(options.baseSearchCondition);
}
if (options.searchCondition) {
parts.push(options.searchCondition);
}
return parts.join(" AND ");
}
function loadPage(pageNumber) {
_setLoading();
var pageSize = state.draftManager.pagination.getPageSize();
var searchCondition = buildFinalCondition();
var currentRequestVersion = ++state.requestVersion;
if (!searchCondition) {
var insertRows = state.draftManager.getInsertRows();
var pageData = [];
if (insertRows.length > 0) {
var startInInsert = (pageNumber - 1) * pageSize;
var endInInsert = startInInsert + pageSize;
pageData = insertRows.slice(startInInsert, endInInsert);
}
_renderPage(pageData, insertRows.length, pageNumber, pageSize);
_clearLoading();
return;
}
var searchParam = {
viewname: options.viewName,
searchcondition: searchCondition,
userid: options.userid,
orderfield: options.orderField,
keyfield: options.keyField,
page: pageNumber,
rows: pageSize,
};
$.ajax({
type: "post",
url: options.searchUrl,
cache: false,
data: searchParam,
dataType: "json",
timeout: options.ajaxTimeout,
success: function (result) {
if (currentRequestVersion !== state.requestVersion) {
return;
}
state.draftManager.pagination.setRemoteTotal(result.total);
var displayRows = state.draftManager.applyDraftState(result.rows);
_renderPage(displayRows, result.total, pageNumber, pageSize);
},
error: function (xhr, status, error) {
if (currentRequestVersion !== state.requestVersion) {
return;
}
if (typeof options.onLoadError === "function") {
options.onLoadError(xhr, status, error);
} else {
console.log("分页加载失败: " + status);
}
},
complete: function () {
if (currentRequestVersion === state.requestVersion) {
_clearLoading();
}
},
});
}
function _renderPage(pageData, total, pageNumber, pageSize) {
$("#" + options.gridId).datagrid("loadData", pageData);
$("#" + _getPagerId()).pagination("refresh", {
total: total,
pageNumber: pageNumber,
pageSize: pageSize,
});
}
function refreshCurrentPage() {
var currentPage = state.draftManager.pagination.getPageNumber();
loadPage(currentPage);
}
function refreshDisplay() {
var currentRows = $("#" + options.gridId).datagrid("getRows");
$("#" + options.gridId).datagrid("loadData", currentRows);
$("#" + options.gridId).datagrid("clearChecked");
_triggerCallback("onSelectionChange");
}
function refreshAfterDelete() {
var pageSize = state.draftManager.pagination.getPageSize();
var remoteTotal = state.draftManager.pagination.getRemoteTotal();
var totalPages = Math.ceil(remoteTotal / pageSize);
var currentPage = state.draftManager.pagination.getPageNumber();
if (currentPage > totalPages && totalPages > 0) {
state.draftManager.pagination.setPageNumber(totalPages);
$("#" + _getPagerId()).pagination("select", totalPages);
} else if (remoteTotal === 0) {
$("#" + options.gridId).datagrid("loadData", []);
$("#" + _getPagerId()).pagination("refresh", {
total: 0,
pageNumber: 1,
pageSize: pageSize,
});
} else {
loadPage(currentPage);
}
$("#" + options.gridId).datagrid("clearChecked");
_triggerCallback("onSelectionChange");
}
function refreshAfterUndo() {
var currentPage = state.draftManager.pagination.getPageNumber();
loadPage(currentPage);
}
function addInsertRows(rows) {
if (!$.isArray(rows)) rows = [rows];
for (var i = 0; i < rows.length; i++) {
state.draftManager.addInsertRow(rows[i]);
}
}
function removeInsertRow(row) {
state.draftManager.removeInsertRow(row);
}
function addDeleteRow(row) {
state.draftManager.addDeleteRow(row);
}
function removeDeleteRow(row) {
state.draftManager.recoverRow(row);
refreshAfterUndo();
}
function addUpdateRow(row) {
state.draftManager.addUpdateRow(row);
}
function toggleSelectAll() {
var btn = $(options.selectAllBtn);
if (state.draftManager.isAllChecked()) {
state.draftManager.setAllChecked(false);
state.draftManager.clearExcludedRows();
state.draftManager.clearSelectedRows();
$("#" + options.gridId).datagrid("clearChecked");
if (btn.length) btn.val(options.selectAllText);
} else {
state.draftManager.setAllChecked(true);
state.draftManager.clearExcludedRows();
var rows = $("#" + options.gridId).datagrid("getRows");
for (var i = 0; i < rows.length; i++) {
$("#" + options.gridId).datagrid("checkRow", i);
}
if (btn.length) btn.val(options.unselectAllText);
}
_triggerCallback("onSelectionChange");
}
function clearSelection() {
state.draftManager.setAllChecked(false);
state.draftManager.clearExcludedRows();
state.draftManager.clearSelectedRows();
$("#" + options.gridId).datagrid("clearChecked");
_triggerCallback("onSelectionChange");
}
function setAllChecked(value) {
state.draftManager.setAllChecked(value);
if (value) state.draftManager.clearExcludedRows();
_syncGridChecks();
_triggerCallback("onSelectionChange");
}
function setSearchCondition(condition) {
options.searchCondition = condition;
}
function clearSearch() {
options.searchCondition = null;
}
function reload(newSearchCondition) {
if (newSearchCondition !== undefined) {
options.searchCondition = newSearchCondition;
}
state.draftManager.pagination.setPageNumber(1);
loadPage(1);
}
function resetSearch() {
options.searchCondition = null;
reload();
}
function _triggerCallback(callbackName) {
var callback = options[callbackName];
if (typeof callback === "function") {
var args = Array.prototype.slice.call(arguments, 1);
callback.apply(null, args);
}
}
function handleAfterEdit(rowIndex, row, changes) {
if (Object.keys(changes).length === 0) return;
var key = state.draftManager.getRowKey(row);
var draftState = state.draftManager.getDraftState(key);
if (draftState && draftState.state === "delete") {
return;
}
if (draftState && draftState.state === "insert") {
row._rowState = "insert";
state.draftManager.setDraftState(key, "insert", row, null);
} else if (draftState && draftState.state === "update") {
row._rowState = "update";
state.draftManager.setDraftState(key, "update", row, null);
} else {
row._rowState = "update";
state.draftManager.addUpdateRow(row);
}
_triggerCallback("onAfterEdit", rowIndex, row, changes);
}
function handleRowCheck(index, row) {
if (state.draftManager.isAllChecked()) {
state.draftManager.removeExcludedRow(row);
} else {
state.draftManager.addSelectedRow(row);
}
_triggerCallback("onSelectionChange");
}
function handleRowUncheck(index, row) {
if (state.draftManager.isAllChecked()) {
state.draftManager.addExcludedRow(row);
} else {
state.draftManager.removeSelectedRow(row);
}
_triggerCallback("onSelectionChange");
}
function handleCheckAll() {
state.draftManager.setAllChecked(true);
state.draftManager.clearExcludedRows();
_triggerCallback("onSelectionChange");
}
function handleUncheckAll() {
state.draftManager.setAllChecked(false);
state.draftManager.clearExcludedRows();
state.draftManager.clearSelectedRows();
_triggerCallback("onSelectionChange");
}
function handleLoadSuccess() {
$.messager.progress("close");
_syncGridChecks();
_handleRowStyles();
var rows = $("#" + options.gridId).datagrid("getRows");
_triggerCallback("onLoadSuccess", rows);
}
function reset() {
state.editIndex = undefined;
state.isLoading = false;
if (state.draftManager) state.draftManager.reset();
}
function _initGrid() {
var baseDatagridOptions = {
idField: options.keyField,
pageSize: options.pageSize,
rowStyler: function (index, row) {
var stateStyle = options.rowStateStyles[row._rowState];
return stateStyle || "";
},
onLoadSuccess: handleLoadSuccess,
onAfterEdit: handleAfterEdit,
onCheckAll: handleCheckAll,
onUncheckAll: handleUncheckAll,
onCheck: handleRowCheck,
onUncheck: handleRowUncheck,
};
var datagridOptions = options.customDatagridOptions
? $.extend(true, {}, baseDatagridOptions, options.customDatagridOptions)
: baseDatagridOptions;
$("#" + options.gridId)
.datagrid(datagridOptions)
.datagrid("columnMoving");
$("#" + options.gridId)
.datagrid("getPanel")
.find(".datagrid-body")
.on("scroll.datagrid", function () {
if (state.editIndex !== undefined) {
$("#" + options.gridId).datagrid("endEdit", state.editIndex);
state.editIndex = undefined;
}
});
var pagerId = _getPagerId();
var pagerSelector = "#" + pagerId;
if ($(pagerSelector).length === 0) {
var gridPanel = $("#" + options.gridId).datagrid("getPanel");
var pagerDiv = $(
'<div id="' +
pagerId +
'" class="pagination" style="margin: 6px 0px;background:#efefef;border:1px solid #ccc;"></div>',
);
gridPanel.after(pagerDiv);
}
$(pagerSelector).pagination({
total: 0,
pageSize: options.pageSize,
pageNumber: 1,
pageList: options.pageList,
onSelectPage: function (pageNumber, pageSize) {
state.draftManager.pagination.setPageNumber(pageNumber);
state.draftManager.pagination.setPageSize(pageSize);
loadPage(pageNumber);
},
onChangePageSize: function (pageSize) {
state.draftManager.pagination.setPageNumber(1);
state.draftManager.pagination.setPageSize(pageSize);
if (!state.draftManager.isAllChecked()) {
$("#" + options.gridId).datagrid("clearChecked");
state.draftManager.clearSelectedRows();
}
_triggerCallback("onSelectionChange");
loadPage(1);
},
});
}
function setColumns(columns) {
$("#" + options.gridId).datagrid({
columns: [columns],
});
}
function isLoading() {
return state.isLoading;
}
function getPager() {
return $("#" + _getPagerId());
}
function getGrid() {
return $("#" + options.gridId);
}
return {
setColumns: setColumns,
loadPage: loadPage,
refreshCurrentPage: refreshCurrentPage,
refreshDisplay: refreshDisplay,
refreshAfterDelete: refreshAfterDelete,
refreshAfterUndo: refreshAfterUndo,
addInsertRows: addInsertRows,
removeInsertRow: removeInsertRow,
addDeleteRow: addDeleteRow,
removeDeleteRow: removeDeleteRow,
addUpdateRow: addUpdateRow,
getValidSelectedRows: function () {
return state.draftManager.getValidSelectedRows();
},
getSelectedRows: function () {
return state.draftManager.getSelectedRows();
},
toggleSelectAll: toggleSelectAll,
clearSelection: clearSelection,
setAllChecked: setAllChecked,
getInsertRows: function () {
return state.draftManager.getInsertRows();
},
getUpdateRows: function () {
return state.draftManager.getUpdateRows();
},
getDeleteRows: function () {
return state.draftManager.getDeleteRows();
},
getDraftManager: function () {
return state.draftManager;
},
setSearchCondition: setSearchCondition,
clearSearch: clearSearch,
reload: reload,
resetSearch: resetSearch,
isLoading: isLoading,
getPager: getPager,
getGrid: getGrid,
reset: reset,
};
}
window.createDataGridManager = createDataGridManager;
})(window);