ProSearch 高级筛选表单
基于 plus-pro-components / Search 的 dh-design-pc 二次封装,用于业务列表页的筛选栏、报表条件区、弹窗内查询表单。
ts
import { createApp } from 'vue'
import { ProSearch } from '@szhn/dh-design-pc'
const app = createApp({})
app.use(ProSearch)基础用法
<template>
<dh-pro-search
v-model="state"
:columns="assetColumns.slice(0, 4)"
@search="handleSearch"
@reset="handleReset"
>
<template #toolbar>
<el-button type="primary">添加成员</el-button>
<el-button>导入</el-button>
<el-button>导出花名册</el-button>
<el-button disabled>批量删除</el-button>
<el-input placeholder="请输入文字" style="width: 220px" />
</template>
</dh-pro-search>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import { assetColumns, assetState } from './layout-shared'
const state = ref<Record<string, any>>({ ...assetState })
const handleSearch = (values: Record<string, any>) => console.log(values, 'search')
const handleReset = (values: Record<string, any>) => console.log(values, 'reset')
</script>1 项筛选
<template>
<dh-pro-search
v-model="state"
:columns="createMetricColumns(1)"
@search="handleSearch"
@reset="handleReset"
>
<template #toolbar>
<el-button type="primary">新增分组</el-button>
<el-button>导入</el-button>
<el-button>导出</el-button>
</template>
</dh-pro-search>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import { createMetricColumns, metricState } from './layout-shared'
const state = ref<Record<string, any>>({ ...metricState })
const handleSearch = (values: Record<string, any>) => console.log(values, 'search')
const handleReset = (values: Record<string, any>) => console.log(values, 'reset')
</script>2 项筛选
<template>
<dh-pro-search
v-model="state"
:columns="createMetricColumns(2)"
@search="handleSearch"
@reset="handleReset"
>
<template #toolbar>
<el-button type="primary">新增分组</el-button>
<el-button>导入</el-button>
<el-button>导出</el-button>
</template>
</dh-pro-search>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import { createMetricColumns, metricState } from './layout-shared'
const state = ref<Record<string, any>>({ ...metricState })
const handleSearch = (values: Record<string, any>) => console.log(values, 'search')
const handleReset = (values: Record<string, any>) => console.log(values, 'reset')
</script>3 项筛选
<template>
<dh-pro-search
v-model="state"
:columns="createMetricColumns(3)"
@search="handleSearch"
@reset="handleReset"
>
<template #toolbar>
<el-button type="primary">新增分组</el-button>
<el-button>导入</el-button>
<el-button>导出</el-button>
</template>
</dh-pro-search>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import { createMetricColumns, metricState } from './layout-shared'
const state = ref<Record<string, any>>({ ...metricState })
const handleSearch = (values: Record<string, any>) => console.log(values, 'search')
const handleReset = (values: Record<string, any>) => console.log(values, 'reset')
</script>4 项筛选
<template>
<dh-pro-search
v-model="state"
:columns="assetColumns.slice(0, 4)"
@search="handleSearch"
@reset="handleReset"
>
<template #toolbar>
<el-button type="primary">添加成员</el-button>
<el-button>导入</el-button>
<el-button>导出花名册</el-button>
<el-button disabled>批量删除</el-button>
<el-input placeholder="请输入文字" style="width: 220px" />
</template>
</dh-pro-search>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import { assetColumns, assetState } from './layout-shared'
const state = ref<Record<string, any>>({ ...assetState })
const handleSearch = (values: Record<string, any>) => console.log(values, 'search')
const handleReset = (values: Record<string, any>) => console.log(values, 'reset')
</script>4-8 项筛选
<template>
<dh-pro-search
v-model="state"
:columns="assetColumns.slice(0, 8)"
@search="handleSearch"
@reset="handleReset"
>
<template #toolbar>
<el-button type="primary">添加成员</el-button>
<el-button>导入</el-button>
<el-button>导出花名册</el-button>
<el-button disabled>批量删除</el-button>
<el-input placeholder="请输入文字" style="width: 220px" />
</template>
</dh-pro-search>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import { assetColumns, assetState } from './layout-shared'
const state = ref<Record<string, any>>({ ...assetState })
const handleSearch = (values: Record<string, any>) => console.log(values, 'search')
const handleReset = (values: Record<string, any>) => console.log(values, 'reset')
</script>8 项以上筛选
<template>
<dh-pro-search
v-model="state"
:columns="assetColumns"
@search="handleSearch"
@reset="handleReset"
>
<template #toolbar>
<el-button type="primary">添加成员</el-button>
<el-button>导入</el-button>
<el-button>导出花名册</el-button>
<el-button disabled>批量删除</el-button>
<el-input placeholder="请输入文字" style="width: 220px" />
</template>
</dh-pro-search>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import { assetColumns, assetState } from './layout-shared'
const state = ref<Record<string, any>>({ ...assetState })
const handleSearch = (values: Record<string, any>) => console.log(values, 'search')
const handleReset = (values: Record<string, any>) => console.log(values, 'reset')
</script>已选更多筛选
<template>
<dh-pro-search
v-model="state"
:columns="assetColumns"
layout="horizontal"
@search="handleSearch"
@reset="handleReset"
@advanced-apply="handleSearch"
>
<template #toolbar>
<el-button type="primary">添加成员</el-button>
<el-button>导入</el-button>
<el-button>导出花名册</el-button>
<el-button disabled>批量删除</el-button>
<el-input placeholder="请输入文字" style="width: 220px" />
</template>
</dh-pro-search>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import { Button as ElButton, Input as ElInput } from '@szhn/dh-design-pc'
import { assetColumns } from './layout-shared'
const state = ref<Record<string, any>>({})
const handleSearch = (values: Record<string, any>) => console.log('search', values)
const handleReset = (values: Record<string, any>) => console.log('reset', values)
</script>显示个数
<template>
<el-card>
<dh-pro-search
v-model="state"
:columns="searchColumns"
:show-number="3"
@search="handleSearch"
/>
</el-card>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import { searchColumns } from './shared'
const state = ref<Record<string, any>>({})
const handleSearch = (values: Record<string, any>) => console.log(values, 'search')
</script>展开收缩隐藏
<template>
<el-card>
<dh-pro-search
v-model="state"
:columns="searchColumns"
:has-unfold="false"
:show-number="2"
/>
</el-card>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import { searchColumns } from './shared'
const state = ref<Record<string, any>>({})
</script>自定义搜索按钮
<template>
<el-card>
<dh-pro-search v-model="state" :columns="searchColumns" :show-number="2">
<template #footer="{ handleReset, handleSearch, handleUnfold, isShowUnfold }">
<div class="pro-search-footer">
<el-button type="primary" @click="handleSearch">搜索</el-button>
<el-button @click="handleReset">重置</el-button>
<el-button @click="handleUnfold">
{{ isShowUnfold ? '收起' : '展开' }}
</el-button>
</div>
</template>
</dh-pro-search>
</el-card>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import { searchColumns } from './shared'
const state = ref<Record<string, any>>({})
</script>
<style scoped>
.pro-search-footer {
display: flex;
gap: 12px;
}
</style>默认搜索参数
<template>
<el-card>
<dh-pro-search
v-model="state"
:columns="searchColumns"
:default-values="defaultValues"
:show-number="2"
/>
</el-card>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import { searchColumns } from './shared'
const defaultValues = {
status: '1',
place: '海口国贸',
}
const state = ref<Record<string, any>>({ ...defaultValues })
</script>隐藏 label
<template>
<el-card>
<dh-pro-search v-model="state" :columns="columns" :has-label="false" />
</el-card>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import type { PcProColumn } from '@szhn/dh-design-pc'
const state = ref<Record<string, any>>({})
const columns: PcProColumn[] = [
{
label: '名称',
prop: 'name',
fieldProps: {
placeholder: '请输入名称',
},
},
{
label: '状态',
prop: 'status',
valueType: 'select',
options: [
{ label: '未解决', value: '0' },
{ label: '已解决', value: '1' },
],
},
]
</script>异步数据用法
<template>
<el-card>
<dh-pro-search v-model="state" :columns="columns" :show-number="2" />
</el-card>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import type { PcProColumn } from '@szhn/dh-design-pc'
const state = ref<Record<string, any>>({})
const columns: PcProColumn[] = [
{
label: '状态',
prop: 'status',
valueType: 'select',
options: async () => {
await new Promise(resolve => setTimeout(resolve, 150))
return [
{ label: '未解决', value: '0', color: 'red' },
{ label: '已解决', value: '1', color: 'blue' },
{ label: '解决中', value: '2', color: 'yellow' },
]
},
},
{
label: '负责人',
prop: 'owner',
fieldProps: async () => {
await new Promise(resolve => setTimeout(resolve, 150))
return {
clearable: true,
placeholder: '异步加载 placeholder',
}
},
},
]
</script>高级筛选入口
<template>
<dh-pro-search
v-model="form"
:columns="columns"
:col="4"
layout="horizontal"
advanced-panel
show-more-filter
v-model:advanced-visible="advancedOpen"
advanced-title="高级筛选"
advanced-description="补充更多业务条件后,再点击确定执行查询。"
more-filter-text="更多筛选"
@search="onSearch"
@advanced-apply="onApplyAdvanced"
>
<template #advanced-nav>
<div class="advanced-nav">
<button
v-for="item in sections"
:key="item.value"
type="button"
class="advanced-nav__item"
:class="{ 'is-active': activeSection === item.value }"
@click="activeSection = item.value"
>
{{ item.label }}
</button>
</div>
</template>
<template #advanced>
<el-form label-width="90px" label-position="right" class="advanced-form">
<template v-if="activeSection === 'business'">
<el-form-item label="付款类型">
<el-select v-model="form.payType" placeholder="请选择">
<el-option label="申请人" value="applicant" />
<el-option label="审批人" value="approver" />
<el-option label="未联系人员" value="uncontacted" />
<el-option label="付款申请" value="payRequest" />
<el-option label="付款凭据" value="payReceipt" />
<el-option label="未联系名单" value="uncontactedList" />
</el-select>
</el-form-item>
<el-form-item label="付款时间">
<el-date-picker
v-model="form.payAt"
type="daterange"
range-separator="—"
/>
</el-form-item>
</template>
<template v-else>
<el-form-item label="创建人">
<el-input v-model="form.creator" placeholder="请输入创建人" />
</el-form-item>
<el-form-item label="审批状态">
<el-select v-model="form.approvalStatus" placeholder="请选择">
<el-option label="待审批" value="pending" />
<el-option label="审批中" value="processing" />
<el-option label="已完成" value="done" />
</el-select>
</el-form-item>
</template>
</el-form>
</template>
</dh-pro-search>
<pre class="pro-demo-result">{{ form }}</pre>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import type { PcProColumn } from '@szhn/dh-design-pc'
const form = ref<Record<string, any>>({})
const advancedOpen = ref(false)
const activeSection = ref<'business' | 'flow'>('business')
const sections = [
{ label: '业务条件', value: 'business' },
{ label: '流程条件', value: 'flow' },
] as const
const columns: PcProColumn[] = [
{ label: '资产名称/编号', prop: 'name', valueType: 'input' },
{ label: '资产类型', prop: 'type', valueType: 'input' },
{ label: '所属地', prop: 'region', valueType: 'input' },
{ label: '商圈/门牌', prop: 'code', valueType: 'input' },
]
const onSearch = (val: Record<string, any>) => console.log('search', val)
const onApplyAdvanced = (val: Record<string, any>) => console.log('advanced', val)
</script>
<style scoped>
.advanced-nav {
display: grid;
gap: 8px;
}
.advanced-nav__item {
appearance: none;
background: var(--el-fill-color-blank);
border: 1px solid var(--el-border-color-light);
border-radius: 6px;
color: var(--el-text-color-regular);
cursor: pointer;
padding: 8px 12px;
text-align: left;
}
.advanced-nav__item.is-active {
background: var(--el-fill-color-light);
border-color: var(--el-color-primary-light-5);
color: var(--el-color-primary);
}
.advanced-form {
max-width: 560px;
}
.pro-demo-result {
background-color: var(--el-fill-color-lighter);
border-radius: 4px;
margin-top: 16px;
padding: 12px;
}
</style>ProSearch API
Props
| 属性名 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| model-value / v-model | 搜索表单绑定值 | Record | {} |
| columns | 搜索配置数组 | PcProColumn[] | [] |
| layout | auto(按筛选项数量自动切换)/ horizontal / vertical | string | auto |
| col | 每行展示的筛选项数量,支持 1~8 或响应式对象 | number / object | 自动推导 |
| show-number | 折叠前默认展示几个筛选项;启用内建更多筛选时,也作为常用条件和更多条件的分界 | number | ≤8 全展示,>8 默认 8 项 |
| label-width | label 宽度(vertical 布局生效) | string / number | 100px |
| show-more-filter | 是否展示“更多筛选”入口 | boolean | false |
| more-filter-text | “更多筛选”文案 | string | 更多筛选 |
| saved-schemes | 已保存的筛选方案列表 | Array | [] |
| advanced-panel | 是否启用内建高级筛选面板 | boolean | false |
| advanced-visible / v-model:advanced-visible | 内建高级筛选面板显示状态 | boolean | false |
| advanced-title | 内建高级筛选面板标题 | string | 高级筛选 |
| advanced-description | 内建高级筛选面板描述文案 | string | '' |
| advanced-apply-text | 内建高级筛选面板确认按钮文案 | string | 确定 |
| advanced-reset-text | 内建高级筛选面板重置按钮文案 | string | 重置 |
其余 Search 官方属性(如 default-values、has-footer、has-reset、has-unfold、search-loading、has-label、default-unfold 等)可直接透传。若只想复用“更多筛选”入口,也可以只监听 open-advanced,由业务方自行接对话框、抽屉或路由侧栏。
Events
| 事件名 | 说明 | 回调参数 |
|---|---|---|
| update:model-value | 表单值变化 | (val: Record) |
| update:advanced-visible | 内建高级筛选面板开关变化 | (visible: boolean) |
| search | 点击查询 | (val: Record) |
| reset | 点击重置 | (val: Record) |
| open-advanced | 点击“更多筛选” | — |
| advanced-apply | 点击内建高级筛选面板“确定” | (val: Record) |
| advanced-reset | 点击内建高级筛选面板“重置” | (val: Record) |
| scheme-change | 筛选方案切换 | (scheme) |
Slots
| 插槽名 | 说明 |
|---|---|
| footer | 自定义搜索按钮区域 |
| toolbar | footer 左侧业务操作区 |
| buttonAfter | footer 右侧扩展按钮区域,位于“更多筛选”之后 |
| advanced | 内建高级筛选面板主体内容 |
| advanced-nav | 内建高级筛选面板左侧导航区 |
| advanced-footer | 内建高级筛选面板底部按钮区 |
| tooltip-icon | 自定义 tooltip 图标 |
| plus-field-* | 自定义表单项 |
| plus-label-* | 自定义表单项 label |
| plus-extra-* | 自定义表单项额外说明区域 |
Expose
| 方法名 | 说明 | 类型 |
|---|---|---|
| getFormRef | 获取底层 PlusSearch 实例 | () => PlusSearch |
| closeAdvancedPanel | 主动关闭内建高级筛选面板 | () => void |
