示例详情

每个组件的真实字段配置、前端代码与后端适配器示例——代码区块由 npm run build:website 从真实源文件(playground.html / examples/demo)构建期抽取,非手抄

智能选项 FilterSmartOptionsmart_option

可枚举字段的选择组件:选项来自配置或数据库去重扫描,本地字面匹配过滤,自动区分精确/模糊。 在线体验 → · props 详情 →

字段配置(真实:Playground 运行配置)

{
            field: 'department', label: '部门', componentType: 'smart_option',
            options: ['研究院'],
            optionSource: { type: 'distinct_scan' },
            componentProps: { multiple: true },
          }

前端代码(真实:examples/demo/src/App.vue)

{
    field: 'dept',
    label: '部门',
    componentType: 'smart_option',
    // distinct_scan:选项来自 mockApi.getFieldOptions,配置项去重补充(灰色)
    optionSource: { type: 'distinct_scan' },
    options: ['总经办'],
    componentProps: { multiple: true },
    placeholder: '输入或选择部门',
  }

// 模板(全部组件统一用法):
<FilterField
            :field="f"
            v-model="values[f.field]"
            @criteria-change="onCriteriaChange(f.field, $event)"
            @ai-loading="aiLoadingField = $event ? f.field : ''"
            @ai-error="(e) => console.error(f.field, e)"
          />

后端适配器示例(真实:examples/demo/src/mockApi.js)

distinct_scan 选项集。真实 REST 后端用 SELECT DISTINCT 返回 { options: string[] } 即可。

/**
   * 智能选项的选项集(挂载时一次性加载):返回该字段的 distinct 值
   */
  async getFieldOptions(field) {
    const options = [...new Set(EMPLOYEES.map((e) => String(e[field] ?? '')).filter(Boolean))]
    return delay({ options })
  }

Criteria 输出示例

// 多选 · 全部选项内值
{ field: 'department', componentType: 'smart_option', operator: 'in', value: ['研发部', '市场部'] }

// 多选 · 混合(点选 + 回车自定义)
{ field: 'department', componentType: 'smart_option', operator: 'mixed',
  value: { exact: ['研发部'], fuzzy: ['总部'] } }

单选智能选项 FilterSmartOptionSinglesmart_option_single

smart_option 的单选独立类型:单值互斥(下拉点选精确 / 输入文本 LIKE),后端协议与适配器和 smart_option 完全一致。 在线体验 → · props 详情 →

字段配置(真实:Playground 运行配置)

{
            field: 'leader', label: '直属上级', componentType: 'smart_option_single',
            options: ['待定'],
            optionSource: { type: 'distinct_scan' },
          }

前端代码(真实:examples/demo/src/App.vue)

{
    // smart_option_single:单值互斥(下拉点选精确 / 输入文本 LIKE),与 smart_option 同协议
    field: 'leader',
    label: '直属上级',
    componentType: 'smart_option_single',
    options: ['王芳', '李强', '陈静', '刘洋'],
    optionSource: { type: 'static' },
    placeholder: '选择或输入上级姓名',
  }

// 模板(全部组件统一用法):
<FilterField
            :field="f"
            v-model="values[f.field]"
            @criteria-change="onCriteriaChange(f.field, $event)"
            @ai-loading="aiLoadingField = $event ? f.field : ''"
            @ai-error="(e) => console.error(f.field, e)"
          />

后端适配器示例(真实:examples/demo/src/mockApi.js)

选项来源与 smart_option 完全相同(static / distinct_scan / api)。真实 REST 后端用 SELECT DISTINCT 返回 { options: string[] } 即可。

/**
   * 智能选项的选项集(挂载时一次性加载):返回该字段的 distinct 值
   */
  async getFieldOptions(field) {
    const options = [...new Set(EMPLOYEES.map((e) => String(e[field] ?? '')).filter(Boolean))]
    return delay({ options })
  }

Criteria 输出示例

// 下拉点选 → 精确
{ field: 'leader', componentType: 'smart_option_single', operator: 'eq', value: '王芳' }

// 输入文本 → 模糊
{ field: 'leader', componentType: 'smart_option_single', operator: 'like', value: '张' }

智能文本 FilterTextInputtext_input

文本 LIKE 模糊搜索:数据库联想返回候选文本,前端截取上下文片段并高亮关键词,点击上屏。 在线体验 → · props 详情 →

字段配置(真实:Playground 运行配置)

{
            field: 'name', label: '姓名', componentType: 'text_input',
            placeholder: '输入姓名关键词,如:张伟',
          }

前端代码(真实:examples/demo/src/App.vue)

{
    field: 'name',
    label: '姓名',
    componentType: 'text_input',
    placeholder: '输入姓名(数据库联想)',
    componentProps: { selectable: true, suggestLimit: 5 },
  }

// 模板(全部组件统一用法):
<FilterField
            :field="f"
            v-model="values[f.field]"
            @criteria-change="onCriteriaChange(f.field, $event)"
            @ai-loading="aiLoadingField = $event ? f.field : ''"
            @ai-error="(e) => console.error(f.field, e)"
          />

后端适配器示例(真实:examples/demo/src/mockApi.js)

数据库 LIKE 联想。真实 REST 后端按 LIKE '%keyword%' 查询并返回 { suggestions: string[] };片段截取与关键词高亮在前端完成,后端返回完整文本即可。

/**
   * 智能文本参考结果(数据库 LIKE 实时搜索片段)
   * 对员工数据中对应字段做包含匹配,截取 前 contextBefore 字 + 匹配词 + 后 contextAfter 字
   */
  async suggestFieldValues(field, keyword, { limit = 5, contextBefore = 3, contextAfter = 8 }

Criteria 输出示例

{ field: 'name', componentType: 'text_input', operator: 'like', value: '张' }

智能时间计算 FilterTimeCalctime_calc

把"年龄 ≥ 35"这类虚拟字段条件换算成真实日期列区间;AI 对话 / 规则 / 直接三模式,三精度(year / month / date)。 在线体验 → · props 详情 → · 内部运作专题 →

字段配置(真实:Playground 三精度运行配置)

// 年精度(dateType: year)
{
            field: 'age', label: '年龄', componentType: 'time_calc',
            operator: 'gte',
            targetField: 'birth_date', targetFieldLabel: '出生年份',
            componentProps: { dateType: 'year', inputMode: 'ai_dialog' },
          }

// 年月精度(dateType: month,默认)
{
            field: 'age', label: '年龄', componentType: 'time_calc',
            operator: 'gte',
            targetField: 'birth_date', targetFieldLabel: '出生年月',
            componentProps: { dateType: 'month', inputMode: 'ai_dialog' },
          }

// 年月日精度(dateType: date)
{
            field: 'age', label: '年龄', componentType: 'time_calc',
            operator: 'gte',
            targetField: 'birth_date', targetFieldLabel: '出生日期',
            componentProps: { dateType: 'date', inputMode: 'ai_dialog' },
          }

前端代码(真实:examples/demo/src/App.vue)

{
    // time_calc 双标签字段:虚拟字段"年龄" ⇄ 真实字段"出生日期"
    field: 'age',
    label: '年龄',
    componentType: 'time_calc',
    targetField: 'birth_date',
    targetFieldLabel: '出生日期',
    placeholder: '如:30岁以上',
    componentProps: { dateType: 'year', inputMode: 'ai_dialog' },
  }

// 模板(全部组件统一用法):
<FilterField
            :field="f"
            v-model="values[f.field]"
            @criteria-change="onCriteriaChange(f.field, $event)"
            @ai-loading="aiLoadingField = $event ? f.field : ''"
            @ai-error="(e) => console.error(f.field, e)"
          />

后端适配器示例(真实:examples/demo/src/mockApi.js)

模糊自然语言 → 日期范围。真实后端转发 LLM,按 dateType 精度返回 { start, end, description };注意:简单表达式组件本地解析,不会调到这个函数,"规则 → 对话"回填也是本地确定性转换,无需反向接口。

/**
   * 时间计算 AI 正向解析:自然语言 → 日期范围
   * 支持:"30岁以上" / "大于30岁" / "30岁以下" / "20到30岁" / "30岁"
   * fieldLabel 为虚拟字段(如"年龄"),返回真实日期字段的边界
   */
  async timeParse(text, fieldLabel, dateType = 'month') {
    const label = fieldLabel || '数值'
    let m

    // 区间:20到30岁 / 20~30 / 20-30岁
    m = text.match(/(\d+)\s*(?:到|至|~|-|—)\s*(\d+)/)
    if (m) {
      const [, low, high] = m
      return delay({
        start: fmt(yearsAgo(+high), dateType),
        end: fmt(yearsAgo(+low), dateType),
        description: `${label} ${low} ~ ${high}`,
      })
    }

    // 大于等于:30岁以上 / 大于等于30 / 不小于30 / 超过30
    m = text.match(/(\d+)\s*岁?\s*(?:以上|及以上)/) ||
        text.match(/(?:大于等于|不小于|至少|超过)\s*(\d+)/) ||
        text.match(/大于\s*(\d+)/)
    if (m) {
      const n = +m[1]
      return delay({
        start: null,
        end: fmt(yearsAgo(n), dateType),
        description: `${label} ≥ ${n}`,
      })
    }

    // 小于等于:30岁以下 / 小于等于30 / 不超过30 / 不足30
    m = text.match(/(\d+)\s*岁?\s*(?:以下|及以下|以内)/) ||
        text.match(/(?:小于等于|不超过|至多|不足)\s*(\d+)/) ||
        text.match(/小于\s*(\d+)/)
    if (m) {
      const n = +m[1]
      return delay({
        start: fmt(yearsAgo(n), dateType),
        end: null,
        description: `${label} ≤ ${n}`,
      })
    }

    // 等于:30岁 / 等于30
    m = text.match(/(\d+)/)
    if (m) {
      const n = +m[1]
      return delay({
        start: fmt(yearsAgo(n + 1), dateType),
        end: fmt(yearsAgo(n), dateType),
        description: `${label} = ${n}`,
      })
    }

    return delay(null)
  }

Criteria 输出示例

// 年龄 ≥ 35(节点恒为 V 侧语义;resolved 附带 D 侧日期区间)
{ field: 'age', componentType: 'time_calc', operator: 'gte', value: 35,
  targetField: 'birth_date', fieldLabel: '年龄',
  resolved: { field: 'birth_date', start: null, end: '1991-07' } }

智能数值计算 FilterNumberCalcnumber_calc

数值比较筛选:规则模式(算符 + 数值)与 AI 对话模式一键切换;面板算符可点击循环、数值可编辑。 在线体验 → · props 详情 →

字段配置(真实:Playground 运行配置)

{
            field: 'perf_score', label: '绩效分', componentType: 'number_calc',
            operator: 'gte',
            componentProps: { inputMode: 'expression' },
          }

前端代码(真实:examples/demo/src/App.vue)

{
    field: 'perf_score',
    label: '绩效分',
    componentType: 'number_calc',
    placeholder: '如:大于80',
    componentProps: { inputMode: 'ai_dialog' },
  }

// 模板(全部组件统一用法):
<FilterField
            :field="f"
            v-model="values[f.field]"
            @criteria-change="onCriteriaChange(f.field, $event)"
            @ai-loading="aiLoadingField = $event ? f.field : ''"
            @ai-error="(e) => console.error(f.field, e)"
          />

后端适配器示例(真实:examples/demo/src/mockApi.js)

模糊自然语言 → 算符 + 数值。真实后端转发 LLM,返回 { operator, value, value2? }(value2 仅 between);简单表达式同样由组件本地解析,不调此函数。

/**
   * 数值计算 AI 解析:自然语言 → 算符 + 数值
   * 支持:"大于30" / "大于等于30" / "小于30" / "20到40" / "等于30"
   */
  async numberParse(text, field, fieldLabel) {
    let m

    m = text.match(/(\d+(?:\.\d+)?)\s*(?:到|至|~|-|—)\s*(\d+(?:\.\d+)?)/)
    if (m) {
      return delay({ operator: 'between', value: +m[1], value2: +m[2] })
    }
    m = text.match(/(?:大于等于|不小于|至少)\s*(\d+(?:\.\d+)?)/) || text.match(/(\d+(?:\.\d+)?)\s*(?:以上|及以上)/)
    if (m) {
      return delay({ operator: 'gte', value: +m[1] })
    }
    m = text.match(/(?:小于等于|不超过|至多)\s*(\d+(?:\.\d+)?)/) || text.match(/(\d+(?:\.\d+)?)\s*(?:以下|及以下|以内)/)
    if (m) {
      return delay({ operator: 'lte', value: +m[1] })
    }
    m = text.match(/(?:大于|超过)\s*(\d+(?:\.\d+)?)/)
    if (m) {
      return delay({ operator: 'gt', value: +m[1] })
    }
    m = text.match(/(?:小于|不足)\s*(\d+(?:\.\d+)?)/)
    if (m) {
      return delay({ operator: 'lt', value: +m[1] })
    }
    m = text.match(/(\d+(?:\.\d+)?)/)
    if (m) {
      return delay({ operator: 'eq', value: +m[1] })
    }
    return delay(null)
  }

Criteria 输出示例

// 非区间
{ field: 'perf_score', componentType: 'number_calc', operator: 'gte', value: 80 }

// 区间
{ field: 'perf_score', componentType: 'number_calc', operator: 'between',
  value: { start: 60, end: 80 } }

布尔开关 FilterBooleanSwitchboolean_switch

二值字段的三态开关:开 / 关 / 未设置(不参与筛选),标签可自定义。 在线体验 → · props 详情 →

字段配置(真实:Playground 运行配置)

{
            field: 'status', label: '在职状态', componentType: 'boolean_switch',
            componentProps: { trueLabel: '在职', falseLabel: '离职' },
          }

前端代码(真实:examples/demo/src/App.vue)

{
    field: 'status',
    label: '在职状态',
    componentType: 'boolean_switch',
    componentProps: { trueLabel: '在职', falseLabel: '离职' },
  }

// 模板(全部组件统一用法):
<FilterField
            :field="f"
            v-model="values[f.field]"
            @criteria-change="onCriteriaChange(f.field, $event)"
            @ai-loading="aiLoadingField = $event ? f.field : ''"
            @ai-error="(e) => console.error(f.field, e)"
          />

后端适配器示例

本组件为纯前端交互(开关切换直接产出 eq 节点),不需要任何适配器函数。后端按 Criteria 节点的 eq + 标签字符串生成查询条件即可。

Criteria 输出示例

{ field: 'status', componentType: 'boolean_switch', operator: 'eq', value: '在职' }

精确ID输入 FilterIdInputid_input

单个标识码精确查询:一个可清空的输入框,固定 eq。 在线体验 → · props 详情 →

字段配置(真实:Playground 运行配置)

{
            field: 'emp_no', label: '工号', componentType: 'id_input',
            placeholder: '输入工号,如:E100231',
          }

前端代码(真实:examples/demo/src/App.vue)

{
    field: 'emp_no',
    label: '工号',
    componentType: 'id_input',
    placeholder: '输入工号(精确匹配,如 EMP-1001)',
  }

// 模板(全部组件统一用法):
<FilterField
            :field="f"
            v-model="values[f.field]"
            @criteria-change="onCriteriaChange(f.field, $event)"
            @ai-loading="aiLoadingField = $event ? f.field : ''"
            @ai-error="(e) => console.error(f.field, e)"
          />

后端适配器示例

本组件为纯前端交互(输入即产出 eq 节点),不需要任何适配器函数

Criteria 输出示例

{ field: 'emp_no', componentType: 'id_input', operator: 'eq', value: 'E100231' }