跳转至

title: [ISSUE-0012] taskId + hasEmailOnly 同时启用时分页错乱 description: "taskId + 有邮箱 chip 时分页错乱(先分页再过滤数学不等价)" tags: [issue] created: 2026-05-26 updated: 2026-05-26 type: issue status: fixed severity: critical


[ISSUE-0012] taskId + hasEmailOnly 同时启用时分页错乱

相关源码src/api/search.ts 发现途径:v0.10.19 代码审查(agent)

用户感知的现象

筛选某个任务(按任务下拉)+ 点「有邮箱」chip: - 第 1 页看到的邮箱行不足 pageSize(如 20 条只显示几条) - 翻第 2 页几乎一定空 - 顶部「共 N 条」是错的

根因分析

v0.10.18 加的 hasEmailOnly 路径在 taskId 分支里实现错了:

if (taskId) {
  const data = await getListByTaskId(taskId, current, pageSize, sort, keyword);
  // data.list 已经是第 current 页的 pageSize 条
  if (hasEmailOnly && data?.list) {
    const filtered = data.list.filter(r => Array.isArray(r.emails) && r.emails.length > 0);
    const start = (current - 1) * pageSize;
    return { list: filtered.slice(start, start+pageSize), total: filtered.length, ... };
    //                                            ↑ 这是错的
  }
}

错在:getListByTaskId 已经分页(拿到第 current 页的 ~20 条),再 filter 后只剩几条,但又用 (current-1)*pageSize 当 slice 起点 → 第 2 页一定空。

修复方案

taskId 路径也跟全表路径一致 — 先全拉再 JS filter 再 slice

if (taskId) {
  if (hasEmailOnly) {
    const big = await getListByTaskId(taskId, 1, 50_000, sort, keyword);
    const filtered = (big?.list || []).filter(
      (r) => Array.isArray(r.emails) && r.emails.length > 0
    );
    const start = (current - 1) * pageSize;
    return {
      success: true,
      data: { list: filtered.slice(start, start + pageSize), total: filtered.length, current, pageSize },
    };
  }
  const data = await getListByTaskId(taskId, current, pageSize, sort, keyword);
  return { success: true, data };
}

改动文件

文件 改了什么
src/api/search.ts apiLocalDataList 的 taskId 分支重写,hasEmailOnly 走全拉 + JS filter + slice

验证方式

  1. 创建一个任务跑出数据
  2. 进入数据列表 → 「按任务筛选」选这个任务
  3. 点「有邮箱」chip
  4. 翻多页,验证:
  5. 每页都显示完整的 pageSize 条(除最后一页)
  6. 总条数等于该任务下有邮箱的商家数
  7. 切换任务 / 取消 chip 仍正常

如何避免再犯

  • 加了「旁路 / hack 路径」必须测分支组合:taskId + hasEmail 是两个独立参数,2×2 = 4 种组合都要过
  • 分页与过滤同时存在 → 必须「先过滤再分页」,不能「先分页再过滤」(数学上根本不等价)
  • 重要:v0.10.18 写 hasEmailOnly 时漏审了 taskId 分支 —— Code Review 必须看「同一函数所有分支」

相关问题