|
@@ -0,0 +1,307 @@
|
|
|
+<script setup lang="ts">
|
|
|
+import { onMounted, ref } from 'vue'
|
|
|
+import FilterInput from './FilterInput.vue'
|
|
|
+import FilterSelectLabel from './FilterSelectLabel.vue'
|
|
|
+import FilterSelect from './FilterSelect.vue'
|
|
|
+import { FilterType, type QueryInfo } from '@/types/table'
|
|
|
+import { Filter } from '@element-plus/icons-vue'
|
|
|
+import { useCustomFilter } from '@/hooks/useCustomFilter'
|
|
|
+import CustomFilter from '../CustomFilter.vue'
|
|
|
+import { throttleFunc } from '@/utils/common'
|
|
|
+type CustomFilterRef = InstanceType<typeof CustomFilter>
|
|
|
+
|
|
|
+interface TableFilterFormData {
|
|
|
+ [key: string]: any
|
|
|
+}
|
|
|
+
|
|
|
+interface TableFilterFormProps {
|
|
|
+ queryInfo: Array<QueryInfo>
|
|
|
+}
|
|
|
+
|
|
|
+interface TableFilterItems {
|
|
|
+ [key: string]: QueryInfo[]
|
|
|
+ input: QueryInfo[]
|
|
|
+ select: QueryInfo[]
|
|
|
+ date: QueryInfo[]
|
|
|
+ custom: QueryInfo[]
|
|
|
+}
|
|
|
+
|
|
|
+const customFilterRef = ref<CustomFilterRef>()
|
|
|
+
|
|
|
+const {
|
|
|
+ customFilterDialog,
|
|
|
+ customFilterInfo,
|
|
|
+ customFilterList,
|
|
|
+ activeCustomFilterKey,
|
|
|
+ initCustomFilterInfo,
|
|
|
+ resetCustomFilterList,
|
|
|
+ openCustomFilter,
|
|
|
+ openedInit,
|
|
|
+ confirmCustomFilter
|
|
|
+} = useCustomFilter(customFilterRef)
|
|
|
+
|
|
|
+const props = defineProps<TableFilterFormProps>()
|
|
|
+
|
|
|
+const emits = defineEmits(['query'])
|
|
|
+
|
|
|
+// 节流时间
|
|
|
+const throttleTime = 1000
|
|
|
+
|
|
|
+// 各类型的查询选项集合
|
|
|
+const filterItems = ref<TableFilterItems>({
|
|
|
+ input: [],
|
|
|
+ select: [],
|
|
|
+ date: [],
|
|
|
+ custom: []
|
|
|
+})
|
|
|
+
|
|
|
+// 双向绑定一下
|
|
|
+const queryFormData = defineModel<TableFilterFormData>('queryFormData', {
|
|
|
+ required: true
|
|
|
+})
|
|
|
+
|
|
|
+// 备份表单的默认值信息
|
|
|
+const backupFormDefault: TableFilterFormData = {}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 初始化查询选项集合
|
|
|
+ *
|
|
|
+ * 根据type值直接跟filterItems的键对应
|
|
|
+ *
|
|
|
+ */
|
|
|
+const initFilterItems = () => {
|
|
|
+ props.queryInfo.forEach((item) => {
|
|
|
+ let key = item.type
|
|
|
+ // 多选和单选公用select值
|
|
|
+ if (item.type === FilterType.MULTI_SELECT) {
|
|
|
+ key = FilterType.SELECT
|
|
|
+ }
|
|
|
+ filterItems.value[key].push(item)
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 初始化查询框的数据,同时备份默认值信息,用于重置表单
|
|
|
+ *
|
|
|
+ */
|
|
|
+const initFormData = () => {
|
|
|
+ props.queryInfo?.map((item: QueryInfo) => {
|
|
|
+ queryFormData.value[item.name] = item.default
|
|
|
+ backupFormDefault[item.name] = item.default
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 查询数据,触发事件,交由外部处理
|
|
|
+ *
|
|
|
+ */
|
|
|
+const queryData = () => {
|
|
|
+ emits('query')
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 节流包装查询功能
|
|
|
+ */
|
|
|
+const throttleQuery = throttleFunc(queryData, throttleTime)
|
|
|
+
|
|
|
+/**
|
|
|
+ * 重置自定义表单数据
|
|
|
+ */
|
|
|
+const resetCustomFilterInfo = () => {
|
|
|
+ initCustomFilterInfo(filterItems.value.custom) // 重置自定义表单数据
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 重置查询表单数据
|
|
|
+ */
|
|
|
+const resetFormData = () => {
|
|
|
+ for (const [k, v] of Object.entries(backupFormDefault)) {
|
|
|
+ // 需要对undefined情况处理一下,否则会报错
|
|
|
+ // JSON.stringify()第二个参数可以用来处理undefined的情况,第一个参数设置为_可以避免ts检查
|
|
|
+ queryFormData.value[k] = JSON.parse(
|
|
|
+ JSON.stringify(v, (_, val) => (typeof val === 'undefined' ? '' : val))
|
|
|
+ )
|
|
|
+ }
|
|
|
+ resetCustomFilterInfo()
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 重置查询参数且查询
|
|
|
+ *
|
|
|
+ */
|
|
|
+const resetQuery = () => {
|
|
|
+ resetFormData() // 重置查询参数
|
|
|
+ queryData() // 重新查询数据
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 包装重置查询功能
|
|
|
+ */
|
|
|
+const throttleResetQuery = throttleFunc(resetQuery, throttleTime)
|
|
|
+
|
|
|
+/**
|
|
|
+ * 接收重置表单命令
|
|
|
+ */
|
|
|
+const resetCustomFilterData = () => {
|
|
|
+ resetCustomFilterList(queryFormData)
|
|
|
+}
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ initFilterItems()
|
|
|
+ initFormData()
|
|
|
+ resetCustomFilterInfo()
|
|
|
+})
|
|
|
+
|
|
|
+defineExpose({
|
|
|
+ throttleResetQuery,
|
|
|
+ resetFormData
|
|
|
+})
|
|
|
+</script>
|
|
|
+
|
|
|
+<template>
|
|
|
+ <div class="tableFilterFormContainer">
|
|
|
+ <el-form
|
|
|
+ :inline="true"
|
|
|
+ ref="queryFormRef"
|
|
|
+ :model="queryFormData"
|
|
|
+ class="queryForm"
|
|
|
+ :label-position="'right'"
|
|
|
+ >
|
|
|
+ <template v-for="item in filterItems.input" :key="item.name">
|
|
|
+ <!-- 所有的input查询框 -->
|
|
|
+
|
|
|
+ <FilterInput
|
|
|
+ :item-info="item"
|
|
|
+ :label="item.label"
|
|
|
+ v-model="queryFormData[item.name]"
|
|
|
+ @input-enter-query="throttleQuery"
|
|
|
+ ></FilterInput>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <!-- 所有选择框 -->
|
|
|
+ <el-form-item
|
|
|
+ :label="item.label"
|
|
|
+ v-for="item in filterItems.select"
|
|
|
+ :key="item.name"
|
|
|
+ class="filterItem"
|
|
|
+ >
|
|
|
+ <template #label="{ label }">
|
|
|
+ <FilterSelectLabel :label="label" :supplement="item.supplementInfo"></FilterSelectLabel>
|
|
|
+ </template>
|
|
|
+ <FilterSelect :item="item" v-model="queryFormData[item.name]"></FilterSelect>
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <!-- 所有日期选择框 -->
|
|
|
+ <el-form-item
|
|
|
+ :label="item.label"
|
|
|
+ v-for="item in filterItems.date"
|
|
|
+ :key="item.name"
|
|
|
+ class="filterItem"
|
|
|
+ >
|
|
|
+ <el-date-picker
|
|
|
+ v-model="queryFormData[item.name]"
|
|
|
+ type="date"
|
|
|
+ :value-format="item.otherOption.valueFormat"
|
|
|
+ :placeholder="item.placeholder"
|
|
|
+ clearable
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+
|
|
|
+ <!-- 所有自定义筛选条件 -->
|
|
|
+ <el-form-item
|
|
|
+ :label="item.label"
|
|
|
+ v-for="item in filterItems.custom"
|
|
|
+ :key="item.name"
|
|
|
+ class="filterItem"
|
|
|
+ >
|
|
|
+ <el-button plain size="default" :icon="Filter" @click="openCustomFilter(item)"
|
|
|
+ >筛选
|
|
|
+ </el-button>
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ <!-- 分割线 -->
|
|
|
+ <div class="queryBox">
|
|
|
+ <el-divider class="queryPartition" content-position="center" direction="vertical" />
|
|
|
+ <div class="queryBtnBox">
|
|
|
+ <el-button class="queryBtn" color="#165dff" @click="throttleQuery">
|
|
|
+ <el-icon>
|
|
|
+ <Search />
|
|
|
+ </el-icon>
|
|
|
+ 查询
|
|
|
+ </el-button>
|
|
|
+ <el-button class="refreshBtn" color="#f2f3f5" @click="throttleResetQuery">
|
|
|
+ <el-icon>
|
|
|
+ <RefreshRight />
|
|
|
+ </el-icon>
|
|
|
+ 重置
|
|
|
+ </el-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <el-dialog v-model="customFilterDialog" title="自定义筛选条件" width="800" @open="openedInit">
|
|
|
+ <CustomFilter
|
|
|
+ :custom-filter-list="customFilterList[activeCustomFilterKey]"
|
|
|
+ :filter="customFilterInfo[activeCustomFilterKey]"
|
|
|
+ @reset-filter-list="resetCustomFilterData"
|
|
|
+ ref="customFilterRef"
|
|
|
+ ></CustomFilter>
|
|
|
+ <template #footer>
|
|
|
+ <div class="dialog-footer">
|
|
|
+ <el-button
|
|
|
+ type="primary"
|
|
|
+ @click="confirmCustomFilter(queryFormData)"
|
|
|
+ style="margin-right: 20px"
|
|
|
+ >
|
|
|
+ 确定
|
|
|
+ </el-button>
|
|
|
+ <el-button @click="customFilterDialog = false">取消</el-button>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </el-dialog>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<style scoped>
|
|
|
+.tableFilterFormContainer {
|
|
|
+ width: 98%;
|
|
|
+ box-sizing: border-box;
|
|
|
+
|
|
|
+ margin: 10px auto;
|
|
|
+ display: flex;
|
|
|
+ padding: 0 24px;
|
|
|
+}
|
|
|
+
|
|
|
+.queryForm {
|
|
|
+ width: 90%;
|
|
|
+ display: flex;
|
|
|
+ flex-wrap: wrap;
|
|
|
+}
|
|
|
+
|
|
|
+.filterItem {
|
|
|
+ width: 20%;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+
|
|
|
+.queryBox {
|
|
|
+ width: 10%;
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-around;
|
|
|
+}
|
|
|
+
|
|
|
+.queryPartition {
|
|
|
+ height: 90%;
|
|
|
+}
|
|
|
+
|
|
|
+.queryBtnBox {
|
|
|
+ width: 100%;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+}
|
|
|
+
|
|
|
+.refreshBtn {
|
|
|
+ margin-top: 10%;
|
|
|
+ margin-bottom: 10%;
|
|
|
+}
|
|
|
+</style>
|