Skip to content

dashboard: 一个既非预设名也非 ISO 日期的 date filter 值会静默降级成永不命中的等值比较 #3151

Description

@os-zhuang

Found while fixing objectstack#4475 (Setup 系统概览 KPI 全为 0)。#4475 的修复覆盖了预设名这一类;这一条是它旁边没被覆盖的姐妹情形,单独立项以免扩大那个 PR 的范围。

现象

date / dateRange 型的 dashboard filter 拿到一个既不是已知预设名、也不是合法 ISO 日期的字符串值时,会被静默降级成一个永远命中不了任何行的等值比较。请求返回 200 OK,widget 正常渲染,数字是 0——和"这个区间确实没有数据"完全无法区分。

复现

任意 dashboard 声明一个拼错的 date filter 默认值:

globalFilters: [
  { field: 'created_at', type: 'date', label: 'Date Range', defaultValue: 'last_7_dayz' },
  //                                                                              ^ 拼错
]

@object-ui/core 的 buildFilterCondition 走到这一支:

if (def.type === 'dateRange' || def.type === 'date') {
  const v = value as DateRangeValue;
  if (typeof v === 'object') { /* 预设 / from-to → 区间 */ }
  // A bare string date means equality on that day.
  return value;                         // ← 'last_7_dayz' 原样成为比较值
}

于是 widget 发出 runtimeFilter: { created_at: 'last_7_dayz' },后端如实编译:

SELECT COUNT(*) AS "user_count" FROM "sys_user" WHERE created_at = $1

零行。同一条路径上,'last_7_days'(拼对)在 objectstack#4475 修好后会被提升成
{ $gte: '{7_days_ago}', $lte: '{today}' },得到正确的计数。

{ preset: 'last_7_dayz' } 这种对象形式也一样:PRESET_RANGES[v.preset] 查不到 → from/to 都是 undefined → buildFilterCondition 返回 undefined → 该 filter 被整个丢弃。这一支至少是放宽(不过滤)而不是归零,但同样是静默的。

为什么值得修

和 objectstack#4475 是同一类失败模式,而且是其中更隐蔽的方向:0 看起来像一个合法答案。没有 4xx、没有 console 警告、没有任何 UI 信号,作者拿到的是"这个筛选条件下没有数据"这个完全合理的结论。objectstack#4475 花了一整轮 RC 验证才被抓到,靠的是有人去读响应里的 sql 字段。

对比一下同一模块里已有的严格度:buildWidgetScopedFilter 在 knownFields 可用时,对默认绑定到不存在字段的 filter 会跳过并打 console.warn,理由正是"不要发一个后端只会空匹配或直接拒绝的查询"。字段名走了这条路,字段值没有。

期望

date/dateRange filter 的字符串值应当在三条里择一,而不是无声落到等值:

  1. 是已知预设名 → 提升为区间(objectstack#4475 已实现);
  2. 是可解析的 ISO 日期 → 当天等值(现有的文档化行为,保留);
  3. 两者都不是 → 拒绝或跳过,并打 console.warn 指名该 filter 与那个值,与 buildWidgetScopedFilter 对未知字段名的处理保持同一种严格度。

第 3 条是当前缺失的那条。至于是"跳过 + 警告"(与未知字段名一致,倾向放宽)还是在作者时就拒绝,需要定夺——GlobalFilterSchema.defaultValue 是 string | number | boolean,所以校验能不能上移到 spec/lint 层也是同一个决策的一部分。

关联

Activity

  1. self-assigned this
    on Aug 2, 2026
  2. os-zhuang commented on Aug 2, 2026

    @os-zhuang
    ContributorAuthor

    认领:PM 循环第 1 轮(分片:objectui 整仓)
    会话:session_01PRJtkgUAaVG11FsJQbvZWA
    分支:claude/issue-3151-date-filter-unknown-value
    Worktree:objectui-issue-3151

    分诊裁决(PM 可决,依据仓内既有规范,维护者可否决):按期望第 3 条实现「跳过该 filter + console.warn 点名 filter 与值」,与 buildWidgetScopedFilter 对未知字段名的处理保持同一严格度;{ preset: 未知 } 对象形式一并补警告。spec/lint 层(GlobalFilterSchema.defaultValue)的作者时校验属 objectstack 侧收紧,不在本分片扩大范围——如实现中确认必要,按越界发现另立 issue,不进本 PR。


    Generated by Claude Code

  3. os-zhuang commented on Aug 2, 2026

    @os-zhuang
    ContributorAuthor

    验收:ACCEPT → PR #3196(draft,CI 全绿后进合并流程)。

    交付内容:① buildFilterCondition 把 date/dateRange 值收口到三种合法写法(预设名→区间 / ISO 或宏 token→当天等值 / 其余跳过 + console.warn 点名 filter、值与正确拼法);② { preset: 未知 } 静默丢弃改为有声,显式 from/to 仍生效并说明;③ 宏识别直接问 resolveDateMacros,不造第二方言;④ 8 个新测试(含 #3150 回归与端到端);⑤ 文档补齐 defaultValue 的合法写法;⑥ changeset @object-ui/core: minor。

    spec 层作者时校验按分诊裁决未在本 PR 扩大范围,已按越界发现立 objectstack#4614(A/B/C 选项 + 倾向 A),已补 needs-user-decision 标签进维护者决策收件箱。


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions