QueryBuilder 查询构造器
可视化过滤条件构造器:字段 + 操作符 + 值。导出可序列化的 AND/OR 组合 AST,业务侧自由转换成 SQL / API query / GraphQL 过滤参数。
English translation pending This page hasn't been translated yet — falling back to Chinese. PRs welcome on GitHub.
基础用法
fields 定义可查询字段;modelValue 是当前 query 树。每个 condition 形如 { id, field, operator, value };operator 依字段类型动态切换(string 给 contains / startsWith,number 给 >= 等)。当前版本是单层 AND/OR 组(无嵌套子组)。
背景 视口
<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)
| 属性 | 类型 | 默认 | 说明 |
|---|---|---|---|
fields | QueryField[] | — | 可查询字段 |
modelValue | QueryGroup | — | 当前 query(用 v-model) |
Props (React)
| 属性 | 类型 | 默认 | 说明 |
|---|---|---|---|
fields | QueryField[] | — | |
value | QueryGroup | — | |
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 查询构造器 · Discussion