Files
workspace/code/jsp/.trae/documents/search_local_data_plan.md
T
2026-05-11 21:45:04 +08:00

6.4 KiB
Raw Blame History

搜索场景下本地数据处理方案

场景分析

场景一:新增数据后的搜索

问题:用户新增了10条数据(仅在本地,未保存到数据库),执行 LIKE 搜索时,这些本地数据无法被搜索到。

期望:搜索结果应包含本地新增的行,且支持 LIKE 模糊匹配。

场景二:更新数据后的搜索

问题:用户更新了10条数据(本地已修改),执行搜索时,远程返回的是旧数据,本地修改的数据可能不符合搜索条件。

期望:搜索结果应使用本地更新后的数据进行匹配,而不是远程的旧数据。


解决方案

方案核心思路

  1. 本地数据也参与搜索过滤:在搜索时,对本地的 insertRows 和 updateRows 也应用搜索条件过滤
  2. 合并展示:将远程搜索结果与本地过滤后的结果合并展示
  3. 保持状态:保留本地数据的 _rowState 标记

修改内容

1. JS 文件修改 (js/feegrid-manager.js)

新增方法:

  • _filterLocalRows(condition) - 根据搜索条件过滤本地数据

  • 修改 loadPage() - 在加载远程数据后,合并本地过滤后的数据

搜索条件解析:

  • 支持 LIKE '%xxx%' 模糊匹配

  • 支持 =, !=, <, >, <=, >= 比较

  • 支持 AND, OR 逻辑(简化版)

2. 修改 loadPage() 方法

function loadPage(pageNumber) {
    _setLoading();
    
    var pagination = state.draftManager.getPagination();
    var pageSize = pagination.pageSize;
    var remoteTotal = pagination.remoteTotal;
    var insertRows = state.draftManager.getInsertRows();
    var updateRows = state.draftManager.getUpdateRows();
    
    // 获取搜索条件
    var searchCondition = options.searchCondition ||
        options.keyField.replace('subid', 'mx_') + "='" + state.masterId + "'";
    
    // 过滤本地数据
    var filteredInserts = _filterLocalRows(insertRows, searchCondition);
    var filteredUpdates = _filterLocalRows(updateRows, searchCondition);
    
    // ... 原有远程加载逻辑 ...
    
    // 合并结果时,使用本地过滤后的数据
}

3. 新增条件解析工具函数

function _filterLocalRows(rows, condition) {
    if (!condition || condition.trim() === '') {
        return rows;
    }
    
    var filtered = [];
    var conditions = _parseCondition(condition);
    
    for (var i = 0; i < rows.length; i++) {
        var row = rows[i];
        if (_matchesConditions(row, conditions)) {
            filtered.push(row);
        }
    }
    
    return filtered;
}

function _parseCondition(condition) {
    var result = [];
    
    var parts = condition.split(/\s+(AND|OR)\s+/i);
    for (var i = 0; i < parts.length; i += 2) {
        var expr = parts[i].trim();
        var operator = parts[i + 1] ? parts[i + 1].toUpperCase() : 'AND';
        
        var match;
        
        // LIKE 匹配
        if ((match = expr.match(/^\s*(\w+)\s+LIKE\s+['"](.*)['"]\s*$/i))) {
            result.push({
                field: match[1],
                operator: 'LIKE',
                value: match[2],
                logic: operator
            });
        }
        // 等于匹配
        else if ((match = expr.match(/^\s*(\w+)\s*=\s*['"](.*)['"]\s*$/))) {
            result.push({
                field: match[1],
                operator: '=',
                value: match[2],
                logic: operator
            });
        }
        // 不等于匹配
        else if ((match = expr.match(/^\s*(\w+)\s*(!=|<>)=\s*['"](.*)['"]\s*$/))) {
            result.push({
                field: match[1],
                operator: '!=',
                value: match[2],
                logic: operator
            });
        }
    }
    
    return result;
}

function _matchesConditions(row, conditions) {
    if (conditions.length === 0) return true;
    
    var result = true;
    
    for (var i = 0; i < conditions.length; i++) {
        var cond = conditions[i];
        var fieldValue = row[cond.field];
        
        if (fieldValue === undefined || fieldValue === null) {
            fieldValue = '';
        }
        
        var fieldStr = String(fieldValue).toLowerCase();
        var valueStr = String(cond.value).toLowerCase();
        var matches = false;
        
        switch (cond.operator) {
            case 'LIKE':
                var pattern = valueStr
                    .replace(/%/g, '.*')
                    .replace(/_/g, '.');
                matches = new RegExp('^' + pattern + '$').test(fieldStr);
                break;
                
            case '=':
                matches = fieldStr === valueStr;
                break;
                
            case '!=':
                matches = fieldStr !== valueStr;
                break;
        }
        
        if (cond.logic === 'AND') {
            result = result && matches;
        } else {
            result = result || matches;
        }
        
        if (!result && cond.logic === 'AND') {
            break;
        }
    }
    
    return result;
}

实施步骤

  1. 修改 js/feegrid-manager.js:

    • 新增 _filterLocalRows() 函数

    • 新增 _parseCondition() 函数

    • 新增 _matchesConditions() 函数

    • 修改 loadPage() 方法,在加载时过滤本地数据

  2. 修改 reload() 方法:

    • 确保 reload() 时也应用本地数据过滤
  3. 测试验证:

    • 测试新增数据后的 LIKE 搜索

    • 测试更新数据后的搜索匹配


预期效果

场景 操作 预期结果
场景一 新增10条数据 → 搜索 LIKE '%xxx%' 本地新增且匹配的行会显示在搜索结果中
场景二 更新10条数据 → 搜索更新后的字段 使用本地更新后的数据进行匹配
场景三 删除数据后搜索 已标记删除的行仍然出现在搜索结果中,但是status显示删除即可

风险与注意事项

  1. 条件解析复杂度:只支持简单的 LIKE、=、!= 操作符,复杂条件可能解析失败
  2. 性能考虑:本地数据量大时,过滤可能有性能问题(建议限制本地数据量)
  3. 日期格式:日期字段的比较需要注意格式统一
  4. 多表关联:不支持跨表字段的搜索条件