开发预览 更新于 2026-05-10

QueryBuilder 查询构造器

可视化过滤条件构造器:字段 + 操作符 + 值。导出可序列化的 AND/OR 组合 AST,业务侧自由转换成 SQL / API query / GraphQL 过滤参数。

基础用法

fields 定义可查询字段;modelValue 是当前 query 树。每个 condition 形如 { id, field, operator, value };operator 依字段类型动态切换(string 给 contains / startsWith,number 给 >= 等)。当前版本是单层 AND/OR 组(无嵌套子组)。

背景 视口
src/App.vue
<script setup lang="ts">
import { ref } from 'vue';
import { CfQueryBuilder, type QueryField, type QueryGroup } from '@chufix-design/vue';

const fields: QueryField[] = [
  { key: 'name', label: '姓名', type: 'string' },
  { key: 'age', label: '年龄', type: 'number' },
  { key: 'created_at', label: '创建时间', type: 'date' },
  { key: 'active', label: '激活', type: 'boolean' },
  {
    key: 'role',
    label: '角色',
    type: 'enum',
    options: [
      { value: 'admin', label: '管理员' },
      { value: 'editor', label: '编辑' },
      { value: 'viewer', label: '只读' },
    ],
  },
];

const query = ref<QueryGroup>({
  combinator: 'AND',
  conditions: [
    { id: 'c1', field: 'name', operator: 'contains', value: 'ali' },
    { id: 'c2', field: 'age', operator: 'gte', value: 18 },
  ],
});
</script>
<template>
  <div class="qb-demo">
    <CfQueryBuilder
      :fields="fields"
      :model-value="query"
      @update:model-value="query = $event"
    />
    <pre class="qb-demo__json">{{ JSON.stringify(query, null, 2) }}</pre>
  </div>
</template>
<style scoped>
.qb-demo {
  display: grid;
  gap: 10px;
}
.qb-demo__json {
  margin: 0;
  padding: 10px 12px;
  background: var(--bg-inset);
  border-radius: var(--r-2);
  font-size: var(--t-12);
  color: var(--fg-2);
  overflow: auto;
}
</style>
<script setup>
import { ref } from 'vue';
import { CfQueryBuilder } from '@chufix-design/vue';

const fields= [
  { key: 'name', label: '姓名', type: 'string' },
  { key: 'age', label: '年龄', type: 'number' },
  { key: 'created_at', label: '创建时间', type: 'date' },
  { key: 'active', label: '激活', type: 'boolean' },
  {
    key: 'role',
    label: '角色',
    type: 'enum',
    options: [
      { value: 'admin', label: '管理员' },
      { value: 'editor', label: '编辑' },
      { value: 'viewer', label: '只读' },
    ],
  },
];

const query = ref<QueryGroup>({
  combinator: 'AND',
  conditions: [
    { id: 'c1', field: 'name', operator: 'contains', value: 'ali' },
    { id: 'c2', field: 'age', operator: 'gte', value: 18 },
  ],
});
</script>
<template>
  <div class="qb-demo">
    <CfQueryBuilder
      :fields="fields"
      :model-value="query"
      @update:model-value="query = $event"
    />
    <pre class="qb-demo__json">{{ JSON.stringify(query, null, 2) }}</pre>
  </div>
</template>
<style scoped>
.qb-demo {
  display: grid;
  gap: 10px;
}
.qb-demo__json {
  margin: 0;
  padding: 10px 12px;
  background: var(--bg-inset);
  border-radius: var(--r-2);
  font-size: var(--t-12);
  color: var(--fg-2);
  overflow: auto;
}
</style>
import { useState } from 'react';
import { CfQueryBuilder } from '@chufix-design/react';

export default function Demo() {
  const fields: QueryField[] = [
    { key: 'name', label: '姓名', type: 'string' },
    { key: 'age', label: '年龄', type: 'number' },
    { key: 'created_at', label: '创建时间', type: 'date' },
    { key: 'active', label: '激活', type: 'boolean' },
    {
      key: 'role',
      label: '角色',
      type: 'enum',
      options: [
        { value: 'admin', label: '管理员' },
        { value: 'editor', label: '编辑' },
        { value: 'viewer', label: '只读' },
      ],
    },
  ];

  const [query, setQuery] = useState<QueryGroup>({
    combinator: 'AND',
    conditions: [
      { id: 'c1', field: 'name', operator: 'contains', value: 'ali' },
      { id: 'c2', field: 'age', operator: 'gte', value: 18 },
    ],
  });
  return (
    <>
      <div className="qb-demo">
          <CfQueryBuilder fields={fields} modelValue={query} onModelValueChange={() => setQuery($event)}
          />
          <pre className="qb-demo__json">{JSON.stringify(query, null, 2)}</pre>
        </div>
    </>
  );
}
import { useState } from 'react';
import { CfQueryBuilder } from '@chufix-design/react';

export default function Demo() {
  const fields= [
    { key: 'name', label: '姓名', type: 'string' },
    { key: 'age', label: '年龄', type: 'number' },
    { key: 'created_at', label: '创建时间', type: 'date' },
    { key: 'active', label: '激活', type: 'boolean' },
    {
      key: 'role',
      label: '角色',
      type: 'enum',
      options: [
        { value: 'admin', label: '管理员' },
        { value: 'editor', label: '编辑' },
        { value: 'viewer', label: '只读' },
      ],
    },
  ];

  const [query, setQuery] = useState<QueryGroup>({
    combinator: 'AND',
    conditions: [
      { id: 'c1', field: 'name', operator: 'contains', value: 'ali' },
      { id: 'c2', field: 'age', operator: 'gte', value: 18 },
    ],
  });
  return (
    <>
      <div className="qb-demo">
          <CfQueryBuilder fields={fields} modelValue={query} onModelValueChange={() => setQuery($event)}
          />
          <pre className="qb-demo__json">{JSON.stringify(query, null, 2)}</pre>
        </div>
    </>
  );
}

API

Props (Vue)

属性类型默认说明
fieldsQueryField[]可查询字段
modelValueQueryGroup当前 query(用 v-model

Props (React)

属性类型默认说明
fieldsQueryField[]
valueQueryGroup
onChange(value) => void

Types

type QueryFieldType = 'string' | 'number' | 'date' | 'boolean' | 'enum';
type QueryOperator =
  | 'eq' | 'neq' | 'gt' | 'gte' | 'lt' | 'lte'
  | 'contains' | 'startsWith' | 'endsWith' | 'in'
  | 'isnull' | 'notnull';

interface QueryField {
  key: string;
  label: string;
  type: QueryFieldType;
  options?: { value: string | number; label: string }[];
}
interface QueryCondition {
  id: string;
  field: string;
  operator: QueryOperator;
  value?: unknown;
}
interface QueryGroup {
  combinator: 'AND' | 'OR';
  conditions: QueryCondition[];
}

反馈与讨论

QueryBuilder 查询构造器 的讨论

0
0 / 600
正在加载评论...