Files
ruoyi-java/doc/自动识别列位置-优化说明.md
2025-11-06 12:40:16 +08:00

11 KiB
Raw Permalink Blame History

自动识别列位置 - 优化说明

🎯 优化目标

修改前:列位置可以由前端传递,也可以自动识别
修改后:所有列位置都由后端自动从表头识别,前端不再需要传递


优化原因

1. 降低前端复杂度

修改前,前端需要知道列的位置:

{
  "accessToken": "...",
  "fileId": "...",
  "sheetId": "...",
  "headerRow": 2,
  "orderNoColumn": 2,        // ❌ 前端需要传递
  "logisticsLinkColumn": 12  // ❌ 前端需要传递
}

修改后,前端只需要提供基本信息:

{
  "accessToken": "...",
  "fileId": "...",
  "sheetId": "...",
  "headerRow": 2            // ✅ 只需要表头行号可选默认为1
}

2. 增强灵活性

表格结构变化时,不需要修改前端代码:

场景 修改前 修改后
列的顺序改变 需要更新前端参数 自动识别,无需改动
添加新列 需要重新计算索引 自动识别,无需改动
列名称不变 无需改动 无需改动

3. 减少出错概率

常见错误

  • 前端传递的列索引不正确(数错了列)
  • 前端传递的索引是从1开始但后端期望从0开始
  • 表格结构变化后,前端忘记更新参数

修改后

  • 后端自动识别,避免手动数列
  • 统一使用从0开始的索引前端无需关心
  • 表格结构变化后,只要列名不变,自动适配

🔧 代码修改

修改 1删除前端参数接收

修改前

// 可选参数:指定列位置
Integer orderNoColumn = params.get("orderNoColumn") != null ? 
    Integer.valueOf(params.get("orderNoColumn").toString()) : null;
Integer logisticsLinkColumn = params.get("logisticsLinkColumn") != null ? 
    Integer.valueOf(params.get("logisticsLinkColumn").toString()) : null;
Integer headerRow = params.get("headerRow") != null ? 
    Integer.valueOf(params.get("headerRow").toString()) : 1;

修改后

// 可选参数:表头行号
Integer headerRow = params.get("headerRow") != null ? 
    Integer.valueOf(params.get("headerRow").toString()) : 1;

修改 2始终自动识别列位置

修改前(条件识别):

// 自动识别列位置(如果未指定)
if (orderNoColumn == null || logisticsLinkColumn == null) {
    // 查找所有相关列
    ...
}

修改后(始终识别):

// 自动识别列位置(从表头中识别)
Integer orderNoColumn = null;       // "单号"列
Integer logisticsLinkColumn = null; // "物流单号"列
Integer arrangedColumn = null;      // "是否安排"列
Integer markColumn = null;          // "标记"列

// 查找所有相关列
for (int i = 0; i < headerRowData.size(); i++) {
    String cellValue = headerRowData.getString(i);
    if (cellValue != null) {
        String cellValueTrim = cellValue.trim();
        
        // 识别"单号"列
        if (orderNoColumn == null && cellValueTrim.contains("单号")) {
            orderNoColumn = i;
            log.info("✓ 识别到 '单号' 列:第 {} 列(索引{}", i + 1, i);
        }
        
        // 识别"物流单号"或"物流链接"列
        if (logisticsLinkColumn == null && (cellValueTrim.contains("物流单号") || cellValueTrim.contains("物流链接"))) {
            logisticsLinkColumn = i;
            log.info("✓ 识别到 '物流单号' 列:第 {} 列(索引{}", i + 1, i);
        }
        
        // 识别"是否安排"列(可选)
        if (arrangedColumn == null && cellValueTrim.contains("是否安排")) {
            arrangedColumn = i;
            log.info("✓ 识别到 '是否安排' 列:第 {} 列(索引{}", i + 1, i);
        }
        
        // 识别"标记"列(可选)
        if (markColumn == null && cellValueTrim.contains("标记")) {
            markColumn = i;
            log.info("✓ 识别到 '标记' 列:第 {} 列(索引{}", i + 1, i);
        }
    }
}

修改 3增强错误提示

修改后的错误提示更加友好

// 检查必需的列是否都已识别
if (orderNoColumn == null) {
    return AjaxResult.error("无法找到'单号'列,请检查表头是否包含'单号'字段");
}
if (logisticsLinkColumn == null) {
    return AjaxResult.error("无法找到'物流单号'或'物流链接'列,请检查表头");
}

// 提示可选列的识别情况
if (arrangedColumn == null) {
    log.warn("未找到'是否安排'列,将跳过该字段的更新");
}
if (markColumn == null) {
    log.warn("未找到'标记'列,将跳过该字段的更新");
}

log.info("列位置识别完成 - 单号: {}, 物流单号: {}, 是否安排: {}, 标记: {}", 
    orderNoColumn, logisticsLinkColumn, arrangedColumn, markColumn);

📊 列识别规则

必需列

列名关键字 识别条件 必需 说明
"单号" cellValue.contains("单号") 用于匹配订单
"物流单号" 或 "物流链接" cellValue.contains("物流单号")
cellValue.contains("物流链接")
写入物流链接

可选列

列名关键字 识别条件 必需 说明
"是否安排" cellValue.contains("是否安排") 写入 "2"
"标记" cellValue.contains("标记") 写入日期(yyMMdd

识别规则

  • 只要列名包含关键字即可(不需要完全匹配)
  • 自动去除前后空格
  • 区分大小写
  • 从左到右查找,找到第一个匹配的列

🔍 日志输出示例

成功识别

✓ 识别到 '单号' 列:第 3 列索引2
✓ 识别到 '物流单号' 列:第 13 列索引12
✓ 识别到 '是否安排' 列:第 12 列索引11
✓ 识别到 '标记' 列:第 15 列索引14
列位置识别完成 - 单号: 2, 物流单号: 12, 是否安排: 11, 标记: 14

部分列缺失(可选列)

✓ 识别到 '单号' 列:第 3 列索引2
✓ 识别到 '物流单号' 列:第 13 列索引12
WARN 未找到'是否安排'列,将跳过该字段的更新
WARN 未找到'标记'列,将跳过该字段的更新
列位置识别完成 - 单号: 2, 物流单号: 12, 是否安排: null, 标记: null

必需列缺失(错误)

ERROR 无法找到'单号'列,请检查表头是否包含'单号'字段

ERROR 无法找到'物流单号'或'物流链接'列,请检查表头

🧪 测试场景

场景 1标准表格

表头 | 日期 | 公司 | 单号 | 型号 | ... | 物流单号 | 是否安排 | 标记 |

结果

  • 所有列都识别成功
  • 同时更新4个字段

场景 2列名有变化

表头 | 日期 | 公司 | 订单单号 | 型号 | ... | 物流链接 | 安排状态 | 备注标记 |

结果

  • "订单单号" → 识别为"单号"列(包含"单号"
  • "物流链接" → 识别为"物流单号"列(包含"物流链接"
  • "安排状态" → 无法识别(不包含"是否安排"
  • "备注标记" → 识别为"标记"列(包含"标记"

场景 3列顺序改变

原表头 | 单号 | 公司 | 日期 | ... | 物流单号 | 是否安排 | 标记 |

新表头(顺序改变): | 日期 | 单号 | 公司 | ... | 是否安排 | 标记 | 物流单号 |

结果

  • 仍然能正确识别所有列
  • 前端代码无需任何修改

场景 4最小必需列

表头 | 日期 | 公司 | 单号 | 型号 | ... | 物流单号 |

结果

  • 必需列识别成功
  • ⚠️ "是否安排"列不存在,跳过更新
  • ⚠️ "标记"列不存在,跳过更新
  • 只更新物流单号

📋 前端调用示例

修改前(需要传递列位置)

// ❌ 需要手动指定列位置
const data = {
  accessToken: "...",
  fileId: "DUW50RUprWXh2TGJK",
  sheetId: "BB08J2",
  headerRow: 2,
  orderNoColumn: 2,        // 需要前端知道列位置
  logisticsLinkColumn: 12  // 需要前端知道列位置
};

axios.post('/jarvis/tencentDoc/fillLogisticsByOrderNo', data);

修改后(自动识别)

// ✅ 只需要基本信息
const data = {
  accessToken: "...",
  fileId: "DUW50RUprWXh2TGJK",
  sheetId: "BB08J2",
  headerRow: 2  // 可选默认为1
};

axios.post('/jarvis/tencentDoc/fillLogisticsByOrderNo', data);

📝 API 参数说明

请求参数

参数名 类型 必需 默认值 说明
accessToken String - 腾讯文档访问令牌
fileId String - 文件ID
sheetId String - 工作表ID
headerRow Integer 1 表头所在行号从1开始
forceStart Boolean false 是否强制从指定行开始
forceStartRow Integer null 强制起始行号

已移除的参数

  • orderNoColumn - 不再需要,自动识别
  • logisticsLinkColumn - 不再需要,自动识别

响应示例

{
  "msg": "填充物流链接完成",
  "code": 200,
  "data": {
    "startRow": 3,
    "endRow": 52,
    "filledCount": 45,
    "skippedCount": 3,
    "errorCount": 0,
    "orderNoColumn": 2,        // 自动识别的列位置
    "logisticsLinkColumn": 12, // 自动识别的列位置
    "message": "处理完成:成功填充 45 条,跳过 3 条,错误 0 条"
  }
}

⚠️ 注意事项

1. 列名要求

必需列必须包含特定关键字:

  • "单号"、"订单单号"、"第三方单号" → 都能识别
  • "编号"、"ID" → 无法识别

建议:保持列名包含明确的关键字,如"单号"、"物流单号"、"是否安排"、"标记"。


2. 列名唯一性

如果表格中有多个包含相同关键字的列,只会识别第一个:

示例 | 采购单号 | 销售单号 | 物流单号 |

识别结果

  • "单号"列 → 第1列采购单号
  • "物流单号"列 → 第3列

建议:如果有多个"单号"列,确保目标列是第一个出现的。


3. 向后兼容

虽然前端不再需要传递 orderNoColumnlogisticsLinkColumn,但如果传递了这些参数,后端会忽略它们,不会报错。


总结

优化效果

方面 优化前 优化后
前端参数 5个参数 3个参数
前端复杂度 需要知道列位置 只需要基本信息
灵活性 表格结构变化需要修改前端 自动适配
出错概率 容易传错列索引 自动识别,减少错误
可维护性 前后端都需要维护列信息 只有后端识别逻辑

关键改进

  1. 前端简化:不再需要传递列位置
  2. 自动适配:表格结构变化时自动识别
  3. 错误提示:更友好的错误信息
  4. 日志完善:详细的识别过程日志

文档版本1.0
修改日期2025-11-05
状态 已完成