mirror of
https://gitee.com/fit2cloud-feizhiyun/MeterSphere.git
synced 2024-11-30 11:08:38 +08:00
feat: 高级搜索-样式(除视图)
This commit is contained in:
parent
86581e4580
commit
e755c9de4d
@ -248,6 +248,8 @@
|
||||
.btn-outline-sec-hover();
|
||||
.btn-outline-sec-active();
|
||||
.btn-outline-sec-disabled();
|
||||
|
||||
border-color: var(--color-text-n8) !important;
|
||||
}
|
||||
.arco-btn-outline--danger {
|
||||
.btn-outline-danger-default();
|
||||
|
@ -1,415 +0,0 @@
|
||||
<template>
|
||||
<a-form ref="formRef" :model="formModel" layout="vertical">
|
||||
<div class="w-full overflow-y-auto bg-[var(--color-text-n9)] px-[12px] py-[12px]">
|
||||
<header class="flex flex-row items-center justify-between">
|
||||
<div class="text-[var(--color-text-2)]">{{ t('advanceFilter.setFilterCondition') }}</div>
|
||||
<div class="flex flex-row items-center text-[var(--color-text-2)]">
|
||||
<div class="text-[var(--color-text-2)]">{{ t('advanceFilter.accordBelow') }}</div>
|
||||
<div class="ml-[16px]">
|
||||
<a-select v-model:model-value="accordBelow" size="small">
|
||||
<a-option value="AND">{{ t('advanceFilter.all') }}</a-option>
|
||||
<a-option value="OR">{{ t('advanceFilter.any') }}</a-option>
|
||||
</a-select>
|
||||
</div>
|
||||
<div class="ml-[8px] text-[var(--color-text-2)]">{{ t('advanceFilter.condition') }}</div>
|
||||
</div>
|
||||
</header>
|
||||
<a-scrollbar :style="{ 'max-height': '300px', 'overflow': 'auto' }">
|
||||
<article class="mt-[12px] flex max-h-[300px] flex-col gap-[8px]">
|
||||
<section
|
||||
v-for="(item, idx) in formModel.list"
|
||||
:key="item.dataIndex || `filter_item_${idx}`"
|
||||
class="flex flex-row items-center gap-[8px]"
|
||||
>
|
||||
<div class="flex-1 grow">
|
||||
<a-form-item
|
||||
:field="`list[${idx}].dataIndex`"
|
||||
hide-asterisk
|
||||
class="hidden-item"
|
||||
:rules="[{ required: true, message: t('advanceFilter.plaseSelectFilterDataIndex') }]"
|
||||
>
|
||||
<a-select v-model="item.dataIndex" allow-search @change="(v) => dataIndexChange(v, idx)">
|
||||
<div v-for="(option, i) in currentOptionArr" :key="option.dataIndex">
|
||||
<a-option :value="option.dataIndex" :disabled="option.disabled">
|
||||
{{ t(option.title as string) }}
|
||||
</a-option>
|
||||
<a-divider
|
||||
v-if="
|
||||
props?.customList &&
|
||||
(props.customList || []).length &&
|
||||
(props.configList || []).length - 1 === i
|
||||
"
|
||||
class="!my-1"
|
||||
/>
|
||||
</div>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</div>
|
||||
<div class="grow-0">
|
||||
<a-form-item
|
||||
:field="`list[${idx}].operator`"
|
||||
hide-asterisk
|
||||
class="hidden-item"
|
||||
:rules="[{ required: true, message: t('advanceFilter.plaseSelectOperator') }]"
|
||||
>
|
||||
<a-select
|
||||
v-model="item.operator"
|
||||
class="w-[120px]"
|
||||
:disabled="!item.dataIndex"
|
||||
@change="(v) => operationChange(v, item.dataIndex as string, idx)"
|
||||
>
|
||||
<a-option
|
||||
v-for="option in getOperationOption(item.type as FilterType, item.dataIndex as string)"
|
||||
:key="option.value"
|
||||
:value="option.value"
|
||||
>
|
||||
{{ t(option.label as string) }}
|
||||
</a-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
</div>
|
||||
<div class="flex-1 grow">
|
||||
<a-form-item
|
||||
:field="`list[${idx}].value`"
|
||||
:rules="[{ required: true, message: t('advanceFilter.plaseInputFilterContent') }]"
|
||||
hide-asterisk
|
||||
class="hidden-item"
|
||||
>
|
||||
<a-input
|
||||
v-if="item.type === FilterType.INPUT && !isMutipleOperator(item.operator as string)"
|
||||
v-model:model-value="item.value"
|
||||
class="w-full"
|
||||
allow-clear
|
||||
:disabled="!item.dataIndex"
|
||||
:max-length="255"
|
||||
/>
|
||||
<MsTagsInput
|
||||
v-else-if="isMutipleOperator(item.operator as string)"
|
||||
v-model:model-value="item.value"
|
||||
:disabled="!item.dataIndex"
|
||||
allow-clear
|
||||
unique-value
|
||||
retain-input-value
|
||||
/>
|
||||
<a-input-number
|
||||
v-else-if="item.type === FilterType.NUMBER"
|
||||
v-model:model-value="item.value"
|
||||
class="w-full"
|
||||
allow-clear
|
||||
:disabled="!item.dataIndex"
|
||||
:max-length="255"
|
||||
/>
|
||||
<MsSelect
|
||||
v-else-if="item.type === FilterType.SELECT"
|
||||
v-model:model-value="item.value"
|
||||
class="w-full"
|
||||
allow-clear
|
||||
allow-search
|
||||
:placeholder="t('common.pleaseSelect')"
|
||||
:disabled="!item.dataIndex"
|
||||
:options="item.selectProps?.options || []"
|
||||
v-bind="item.selectProps"
|
||||
/>
|
||||
<a-tree-select
|
||||
v-else-if="item.type === FilterType.TREE_SELECT"
|
||||
v-model:model-value="item.value"
|
||||
:data="item.treeSelectData"
|
||||
:disabled="!item.dataIndex"
|
||||
v-bind="(item.treeSelectProps as any)"
|
||||
/>
|
||||
<a-date-picker
|
||||
v-else-if="item.type === FilterType.DATE_PICKER && item.operator !== 'between'"
|
||||
v-model:model-value="item.value"
|
||||
class="w-full"
|
||||
show-time
|
||||
format="YYYY-MM-DD hh:mm"
|
||||
:disabled="!item.dataIndex"
|
||||
/>
|
||||
<a-range-picker
|
||||
v-else-if="item.type === FilterType.DATE_PICKER && item.operator === 'between'"
|
||||
v-model:model-value="item.value"
|
||||
class="w-full"
|
||||
show-time
|
||||
format="YYYY-MM-DD HH:mm"
|
||||
:separator="t('common.to')"
|
||||
:disabled="!item.dataIndex"
|
||||
/>
|
||||
<MsCascader
|
||||
v-else-if="item.type === FilterType.CASCADER"
|
||||
v-model:model-value="item.value"
|
||||
:options="item.cascaderOptions || []"
|
||||
:disabled="!item.dataIndex"
|
||||
v-bind="item.cascaderProps"
|
||||
/>
|
||||
<a-textarea
|
||||
v-else-if="item.type === FilterType.TEXTAREA"
|
||||
v-model:model-value="item.value"
|
||||
class="w-full"
|
||||
allow-clear
|
||||
:disabled="!item.dataIndex"
|
||||
:auto-size="{
|
||||
minRows: 1,
|
||||
maxRows: 1,
|
||||
}"
|
||||
:max-length="1000"
|
||||
/>
|
||||
<a-radio-group v-else-if="item.type === FilterType.RADIO" v-model:model-value="item.value">
|
||||
<a-radio
|
||||
v-for="it of item.radioProps?.options || []"
|
||||
:key="it[item.radioProps?.valueKey || 'value']"
|
||||
:value="it[item.radioProps?.valueKey || 'value']"
|
||||
>{{ it[item.radioProps?.labelKey || 'label'] }}</a-radio
|
||||
>
|
||||
</a-radio-group>
|
||||
<a-checkbox-group v-else-if="item.type === FilterType.CHECKBOX" v-model:model-value="item.value">
|
||||
<a-checkbox
|
||||
v-for="it of item.checkProps?.options || []"
|
||||
:key="it[item.checkProps?.valueKey || 'value']"
|
||||
:value="it[item.checkProps?.valueKey || 'value']"
|
||||
>{{ it[item.checkProps?.labelKey || 'label'] }}</a-checkbox
|
||||
>
|
||||
</a-checkbox-group>
|
||||
</a-form-item>
|
||||
</div>
|
||||
<div
|
||||
v-if="formModel.list.length > 1"
|
||||
class="delete-btn"
|
||||
:class="{ 'delete-btn:disabled': idx === 0 }"
|
||||
@click="handleDeleteItem(idx)"
|
||||
>
|
||||
<icon-minus-circle />
|
||||
</div>
|
||||
</section>
|
||||
</article>
|
||||
</a-scrollbar>
|
||||
<footer
|
||||
class="mt-[12px] flex flex-row items-center justify-between"
|
||||
:class="{ '!justify-end': !showAddCondition }"
|
||||
>
|
||||
<div
|
||||
v-if="showAddCondition"
|
||||
class="flex cursor-pointer items-center gap-[4px] text-[rgb(var(--primary-7))]"
|
||||
@click="handleAddItem"
|
||||
>
|
||||
<icon-plus />
|
||||
<span>{{ t('advanceFilter.addCondition') }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<a-button class="mr-[8px]" @click="handleReset">{{ t('advanceFilter.reset') }}</a-button>
|
||||
<a-button type="primary" @click="handleFilter">{{ t('advanceFilter.filter') }}</a-button>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
</a-form>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { FormInstance } from '@arco-design/web-vue';
|
||||
|
||||
import MsTagsInput from '@/components/pure/ms-tags-input/index.vue';
|
||||
import MsCascader from '@/components/business/ms-cascader/index.vue';
|
||||
import MsSelect from '@/components/business/ms-select';
|
||||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
|
||||
import { SelectValue } from '@/models/projectManagement/menuManagement';
|
||||
|
||||
import { isMutipleOperator, OPERATOR_MAP } from './index';
|
||||
import { AccordBelowType, BackEndEnum, CombineItem, FilterFormItem, FilterResult, FilterType } from './type';
|
||||
|
||||
const { t } = useI18n();
|
||||
const accordBelow = ref<AccordBelowType>('AND');
|
||||
const formRef = ref<FormInstance | null>(null);
|
||||
const formModel = reactive<{ list: FilterFormItem[] }>({
|
||||
list: [],
|
||||
});
|
||||
const props = defineProps<{
|
||||
configList: FilterFormItem[]; // 系统字段
|
||||
customList?: FilterFormItem[]; // 自定义字段
|
||||
visible: boolean;
|
||||
count: number;
|
||||
rowCount: number;
|
||||
}>();
|
||||
const emit = defineEmits<{
|
||||
(e: 'onSearch', value: FilterResult): void;
|
||||
(e: 'dataIndexChange', value: string): void;
|
||||
(e: 'update:count', value: number): void; // 用于展示 FilterIcon 的数量
|
||||
(e: 'update:rowCount', value: number): void; // 用于展示 MsBaseTable 的总行数
|
||||
(e: 'reset'): void;
|
||||
}>();
|
||||
|
||||
const isMultipleSelect = (dataIndex: string) => {
|
||||
const tmpObj = [...props.configList, ...(props.customList || [])].find((item) => item.dataIndex === dataIndex);
|
||||
if (tmpObj) {
|
||||
return tmpObj.selectProps?.multiple || tmpObj.type === FilterType.TAGS_INPUT;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
const getOperationOption = (type: FilterType, dataIndex: string) => {
|
||||
let result: { label: string; value: string }[] = [];
|
||||
switch (type) {
|
||||
case FilterType.NUMBER:
|
||||
result = OPERATOR_MAP.number;
|
||||
break;
|
||||
case FilterType.DATE_PICKER:
|
||||
result = OPERATOR_MAP.date;
|
||||
break;
|
||||
case FilterType.SELECT:
|
||||
result = isMultipleSelect(dataIndex) ? OPERATOR_MAP.array : OPERATOR_MAP.string;
|
||||
break;
|
||||
default:
|
||||
result = OPERATOR_MAP.string;
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
// 获取当前可选的选项
|
||||
const getCurrentOptionArr = () => {
|
||||
const arr1 = [...props.configList, ...(props?.customList || [])];
|
||||
const arr2 = formModel.list.map((item) => item.dataIndex);
|
||||
const intersection = arr1.map((item1) => ({
|
||||
...item1,
|
||||
disabled: arr2.includes(item1.dataIndex),
|
||||
}));
|
||||
return intersection;
|
||||
};
|
||||
|
||||
const currentOptionArr = computed(() => getCurrentOptionArr());
|
||||
|
||||
// 是否显示添加条件按钮
|
||||
const showAddCondition = computed(() => {
|
||||
return currentOptionArr.value.some((item) => !item.disabled);
|
||||
});
|
||||
|
||||
const getInitItem = () => {
|
||||
return {
|
||||
dataIndex: '',
|
||||
type: FilterType.INPUT,
|
||||
operator: '',
|
||||
value: '',
|
||||
backendType: BackEndEnum.STRING,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* @description 添加条件
|
||||
*/
|
||||
const handleAddItem = async () => {
|
||||
formRef.value?.validate((errors) => {
|
||||
if (!errors) {
|
||||
formModel.list.push(getInitItem());
|
||||
}
|
||||
});
|
||||
};
|
||||
/**
|
||||
* @description 删除条件
|
||||
*/
|
||||
const handleDeleteItem = (index: number) => {
|
||||
// if (index === 0) {
|
||||
// return;
|
||||
// }
|
||||
if (formModel.list.length === 1) {
|
||||
return;
|
||||
}
|
||||
formModel.list.splice(index, 1);
|
||||
};
|
||||
/**
|
||||
* @description 重置
|
||||
*/
|
||||
const handleReset = () => {
|
||||
formRef.value?.resetFields();
|
||||
formModel.list = [getInitItem()];
|
||||
emit('reset');
|
||||
};
|
||||
/**
|
||||
* @description 筛选
|
||||
*/
|
||||
const handleFilter = () => {
|
||||
formRef.value?.validate((errors) => {
|
||||
if (!errors) {
|
||||
const tmpObj: FilterResult = { accordBelow: 'AND', combine: {} };
|
||||
const combine: CombineItem = {};
|
||||
formModel.list.forEach((item) => {
|
||||
combine[item.dataIndex as string] = {
|
||||
operator: item.operator,
|
||||
value: item.value,
|
||||
backendType: Array.isArray(item.value) ? BackEndEnum.ARRAY : item.backendType,
|
||||
};
|
||||
});
|
||||
tmpObj.accordBelow = accordBelow.value;
|
||||
tmpObj.combine = combine;
|
||||
emit('onSearch', tmpObj);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const getAttributeByDataIndex = (dataIndex: string) => {
|
||||
return [...props.configList, ...(props.customList || [])].find((item) => item.dataIndex === dataIndex);
|
||||
};
|
||||
|
||||
/**
|
||||
* @description 筛选项变化
|
||||
*/
|
||||
const dataIndexChange = (dataIndex: SelectValue, idx: number) => {
|
||||
if (!dataIndex) {
|
||||
return;
|
||||
}
|
||||
const tmpObj = getAttributeByDataIndex(dataIndex as string);
|
||||
if (!tmpObj) {
|
||||
return;
|
||||
}
|
||||
formModel.list[idx] = { ...tmpObj };
|
||||
formModel.list[idx].value = isMultipleSelect(dataIndex as string) ? [] : '';
|
||||
|
||||
emit('dataIndexChange', dataIndex as string);
|
||||
};
|
||||
|
||||
const operationChange = (v: SelectValue, dataIndex: string, idx: number) => {
|
||||
if (isMutipleOperator(v as string)) {
|
||||
formModel.list[idx].value = [];
|
||||
} else {
|
||||
formModel.list[idx].value = isMultipleSelect(dataIndex) ? [] : '';
|
||||
}
|
||||
};
|
||||
|
||||
onBeforeMount(() => {
|
||||
formModel.list = [getInitItem()];
|
||||
});
|
||||
watch(
|
||||
() => props.visible,
|
||||
(val) => {
|
||||
if (!val) {
|
||||
emit('update:count', formModel.list.filter((item) => !!item.dataIndex).length);
|
||||
}
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.delete-btn {
|
||||
padding: 8px;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 4px;
|
||||
color: var(--color-text-4);
|
||||
cursor: pointer;
|
||||
}
|
||||
.delete-btn:hover {
|
||||
color: rgb(var(--primary-5));
|
||||
background-color: rgb(var(--primary-9));
|
||||
}
|
||||
.delete-btn:disabled {
|
||||
@apply cursor-not-allowed hover:bg-transparent hover:text-[var(--color-text-4)];
|
||||
}
|
||||
:deep(.arco-form-item-layout-vertical > .arco-form-item-label-col) {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
:deep(.arco-form-item.arco-form-item-error, .arco-form-item.arco-form-item-has-help) {
|
||||
position: relative;
|
||||
top: 10px;
|
||||
}
|
||||
:deep(.arco-scrollbar-track-direction-vertical .arco-scrollbar-thumb-bar) {
|
||||
margin-left: 8px;
|
||||
}
|
||||
</style>
|
315
frontend/src/components/pure/ms-advance-filter/filterDrawer.vue
Normal file
315
frontend/src/components/pure/ms-advance-filter/filterDrawer.vue
Normal file
@ -0,0 +1,315 @@
|
||||
<template>
|
||||
<MsDrawer v-model:visible="visible" :width="800">
|
||||
<template #title>
|
||||
<a-input
|
||||
v-show="isShowNameInput"
|
||||
ref="nameInputRef"
|
||||
v-model:model-value="formModel.name"
|
||||
class="flex-1"
|
||||
:max-length="255"
|
||||
show-word-limit
|
||||
@blur="isShowNameInput = false"
|
||||
/>
|
||||
<div v-show="!isShowNameInput" class="flex flex-1 items-center gap-[8px] overflow-hidden">
|
||||
<a-tooltip :content="formModel.name">
|
||||
<div class="one-line-text"> {{ formModel.name }}</div>
|
||||
</a-tooltip>
|
||||
<MsIcon
|
||||
type="icon-icon_edit_outlined"
|
||||
class="min-w-[16px] cursor-pointer hover:text-[rgb(var(--primary-5))]"
|
||||
@click="showNameInput"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<a-form ref="formRef" :model="formModel" layout="vertical">
|
||||
<a-select v-model="formModel.andOrType" :options="andOrTypeOptions" class="w-[170px]">
|
||||
<template #prefix> {{ t('advanceFilter.meetTheFollowingConditions') }} </template>
|
||||
</a-select>
|
||||
<div
|
||||
v-for="(item, listIndex) in formModel.list"
|
||||
:key="item.dataIndex || `filter_item_${listIndex}`"
|
||||
class="flex items-center gap-[8px]"
|
||||
>
|
||||
<a-form-item class="flex-1 overflow-hidden" :field="`list[${listIndex}].dataIndex`" hide-asterisk>
|
||||
<a-select
|
||||
v-model="item.dataIndex"
|
||||
allow-search
|
||||
@change="(val: SelectValue) => dataIndexChange(val, listIndex)"
|
||||
>
|
||||
<div
|
||||
v-for="(option, currentOptionsIndex) in currentOptions(item.dataIndex as string)"
|
||||
:key="option.dataIndex"
|
||||
>
|
||||
<a-option :value="option.dataIndex">
|
||||
{{ t(option.title as string) }}
|
||||
</a-option>
|
||||
<a-divider
|
||||
v-if="(props?.customList || [])?.length && (props.configList || []).length - 1 === currentOptionsIndex"
|
||||
class="!my-1"
|
||||
/>
|
||||
</div>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item :field="`list[${listIndex}].operator`" class="w-[120px]" hide-asterisk>
|
||||
<a-select v-model="item.operator" :disabled="!item.dataIndex" @change="operatorChange(item, listIndex)">
|
||||
<a-option v-for="option in operatorOptionsMap[item.type]" :key="option.value" :value="option.value">
|
||||
{{ t(option.label as string) }}
|
||||
</a-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item class="flex-1 overflow-hidden" :field="`list[${listIndex}].value`" hide-asterisk>
|
||||
<a-input
|
||||
v-if="item.type === FilterType.INPUT"
|
||||
v-model:model-value="item.value"
|
||||
allow-clear
|
||||
:disabled="isValueDisabled(item)"
|
||||
:max-length="255"
|
||||
:placeholder="t('advanceFilter.inputPlaceholder')"
|
||||
/>
|
||||
<a-textarea
|
||||
v-else-if="item.type === FilterType.TEXTAREA"
|
||||
v-model:model-value="item.value"
|
||||
allow-clear
|
||||
:disabled="isValueDisabled(item)"
|
||||
:auto-size="{
|
||||
minRows: 1,
|
||||
maxRows: 1,
|
||||
}"
|
||||
:placeholder="t('advanceFilter.inputPlaceholder')"
|
||||
:max-length="1000"
|
||||
/>
|
||||
<MsTagsInput
|
||||
v-else-if="item.type === FilterType.TAGS_INPUT"
|
||||
v-model:model-value="item.value"
|
||||
:disabled="isValueDisabled(item)"
|
||||
allow-clear
|
||||
unique-value
|
||||
retain-input-value
|
||||
/>
|
||||
<a-input-number
|
||||
v-else-if="item.type === FilterType.NUMBER"
|
||||
v-model:model-value="item.value"
|
||||
allow-clear
|
||||
:disabled="isValueDisabled(item)"
|
||||
:max-length="255"
|
||||
:placeholder="t('common.pleaseInput')"
|
||||
/>
|
||||
<MsSelect
|
||||
v-else-if="item.type === FilterType.SELECT"
|
||||
v-model:model-value="item.value"
|
||||
allow-clear
|
||||
allow-search
|
||||
:placeholder="t('common.pleaseSelect')"
|
||||
:disabled="isValueDisabled(item)"
|
||||
:options="item.selectProps?.options || []"
|
||||
v-bind="item.selectProps"
|
||||
/>
|
||||
<a-tree-select
|
||||
v-else-if="item.type === FilterType.TREE_SELECT"
|
||||
v-model:model-value="item.value"
|
||||
:data="item.treeSelectData"
|
||||
:disabled="isValueDisabled(item)"
|
||||
v-bind="item.treeSelectProps"
|
||||
/>
|
||||
<a-date-picker
|
||||
v-else-if="item.type === FilterType.DATE_PICKER && item.operator !== 'between'"
|
||||
v-model:model-value="item.value"
|
||||
show-time
|
||||
format="YYYY-MM-DD hh:mm"
|
||||
:disabled="isValueDisabled(item)"
|
||||
/>
|
||||
<a-range-picker
|
||||
v-else-if="item.type === FilterType.DATE_PICKER && item.operator === 'between'"
|
||||
v-model:model-value="item.value"
|
||||
show-time
|
||||
format="YYYY-MM-DD HH:mm"
|
||||
:separator="t('common.to')"
|
||||
:disabled="isValueDisabled(item)"
|
||||
/>
|
||||
<a-radio-group
|
||||
v-else-if="item.type === FilterType.RADIO"
|
||||
v-model:model-value="item.value"
|
||||
:disabled="isValueDisabled(item)"
|
||||
>
|
||||
<a-radio
|
||||
v-for="it of item.radioProps?.options || []"
|
||||
:key="it[item.radioProps?.valueKey || 'value']"
|
||||
:value="it[item.radioProps?.valueKey || 'value']"
|
||||
>
|
||||
{{ it[item.radioProps?.labelKey || 'label'] }}
|
||||
</a-radio>
|
||||
</a-radio-group>
|
||||
<a-checkbox-group
|
||||
v-else-if="item.type === FilterType.CHECKBOX"
|
||||
v-model:model-value="item.value"
|
||||
:disabled="isValueDisabled(item)"
|
||||
>
|
||||
<a-checkbox
|
||||
v-for="it of item.checkProps?.options || []"
|
||||
:key="it[item.checkProps?.valueKey || 'value']"
|
||||
:value="it[item.checkProps?.valueKey || 'value']"
|
||||
>
|
||||
{{ it[item.checkProps?.labelKey || 'label'] }}
|
||||
</a-checkbox>
|
||||
</a-checkbox-group>
|
||||
</a-form-item>
|
||||
<a-button
|
||||
v-if="formModel.list.length > 1"
|
||||
type="outline"
|
||||
class="arco-btn-outline--secondary"
|
||||
@click="handleDeleteItem(listIndex)"
|
||||
>
|
||||
<template #icon> <MsIcon type="icon-icon_block_outlined" class="text-[var(--color-text-4)]" /> </template>
|
||||
</a-button>
|
||||
</div>
|
||||
</a-form>
|
||||
<MsButton type="text" class="mt-[5px]" @click="handleAddItem">
|
||||
<MsIcon type="icon-icon_add_outlined" class="mr-[3px]" />
|
||||
{{ t('advanceFilter.addCondition') }}
|
||||
</MsButton>
|
||||
<template #footer>
|
||||
<div v-show="!isSaveAsView" class="flex items-center gap-[8px]">
|
||||
<a-button type="primary" @click="handleFilter">{{ t('common.filter') }}</a-button>
|
||||
<a-button class="mr-[16px]">{{ t('common.reset') }}</a-button>
|
||||
<MsButton type="text" class="!text-[var(--color-text-1)]"> {{ t('common.save') }}</MsButton>
|
||||
<MsButton type="text" class="!text-[var(--color-text-1)]" @click="isSaveAsView = true">
|
||||
{{ t('advanceFilter.saveAsView') }}
|
||||
</MsButton>
|
||||
</div>
|
||||
<div v-show="isSaveAsView" class="flex items-center gap-[8px]">
|
||||
<a-input
|
||||
v-model:model-value="saveAsViewName"
|
||||
:placeholder="t('advanceFilter.viewNamePlaceholder')"
|
||||
class="w-[240px]"
|
||||
:max-length="255"
|
||||
show-word-limit
|
||||
/>
|
||||
<a-button type="primary">{{ t('common.save') }}</a-button>
|
||||
<a-button @click="handleCancelSaveAsView">{{ t('common.cancel') }}</a-button>
|
||||
</div>
|
||||
</template>
|
||||
</MsDrawer>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { FormInstance, InputInstance } from '@arco-design/web-vue';
|
||||
|
||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||
import MsDrawer from '@/components/pure/ms-drawer/index.vue';
|
||||
import MsTagsInput from '@/components/pure/ms-tags-input/index.vue';
|
||||
import MsSelect from '@/components/business/ms-select';
|
||||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
|
||||
import { SelectValue } from '@/models/projectManagement/menuManagement';
|
||||
|
||||
import { defaultFormModelList, operatorOptionsMap } from './index';
|
||||
import { AccordBelowType, BackEndEnum, FilterFormItem, FilterResult, FilterType } from './type';
|
||||
|
||||
const props = defineProps<{
|
||||
configList: FilterFormItem[]; // 系统字段
|
||||
customList?: FilterFormItem[]; // 自定义字段
|
||||
}>();
|
||||
const emit = defineEmits<{
|
||||
(e: 'handleFilter', value: FilterResult): void;
|
||||
}>();
|
||||
const visible = defineModel<boolean>('visible', { required: true });
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
// TODO lmy 联调
|
||||
const formModel = ref<{ name: string; andOrType: AccordBelowType; list: FilterFormItem[] }>({
|
||||
name: '111',
|
||||
andOrType: 'AND',
|
||||
list: [...defaultFormModelList],
|
||||
});
|
||||
|
||||
const isShowNameInput = ref(false);
|
||||
const nameInputRef = ref<InputInstance>();
|
||||
function showNameInput() {
|
||||
isShowNameInput.value = true;
|
||||
nextTick(() => {
|
||||
nameInputRef.value?.focus();
|
||||
});
|
||||
}
|
||||
|
||||
const andOrTypeOptions = [
|
||||
{ value: 'AND', label: t('advanceFilter.and') },
|
||||
{ value: 'OR', label: t('advanceFilter.or') },
|
||||
];
|
||||
|
||||
function getListItemByDataIndex(dataIndex: string) {
|
||||
return [...props.configList, ...(props.customList || [])].find((item) => item.dataIndex === dataIndex);
|
||||
}
|
||||
// 第三列值是数组类型的
|
||||
function valueIsArray(listItem: FilterFormItem) {
|
||||
return (
|
||||
listItem.selectProps?.multiple ||
|
||||
[FilterType.CHECKBOX, FilterType.TAGS_INPUT].includes(listItem.type) ||
|
||||
(listItem.type === FilterType.DATE_PICKER && listItem.operator === 'between')
|
||||
);
|
||||
}
|
||||
// 第一列下拉数据
|
||||
const currentOptions = computed(() => {
|
||||
return (currentDataIndex: string) => {
|
||||
const otherDataIndices = formModel.value.list
|
||||
.filter((listItem) => listItem.dataIndex !== currentDataIndex)
|
||||
.map((item: FilterFormItem) => item.dataIndex);
|
||||
return [...props.configList, ...(props.customList || [])]
|
||||
.filter(({ dataIndex }) => !otherDataIndices.includes(dataIndex))
|
||||
.map((item) => ({ ...item, label: t(item.title as string) }));
|
||||
};
|
||||
});
|
||||
// 改变第一列值
|
||||
function dataIndexChange(dataIndex: SelectValue, index: number) {
|
||||
const listItem = getListItemByDataIndex(dataIndex as string);
|
||||
if (!listItem) return;
|
||||
formModel.value.list[index] = { ...listItem };
|
||||
formModel.value.list[index].value = valueIsArray(listItem) ? [] : '';
|
||||
}
|
||||
// 改变第二列值
|
||||
function operatorChange(item: FilterFormItem, index: number) {
|
||||
formModel.value.list[index].value = valueIsArray(item) ? [] : '';
|
||||
}
|
||||
function isValueDisabled(item: FilterFormItem) {
|
||||
return !item.dataIndex || ['EMPTY', 'NOT_EMPTY'].includes(item.operator as string);
|
||||
}
|
||||
|
||||
function handleDeleteItem(index: number) {
|
||||
if (formModel.value.list.length === 1) return;
|
||||
formModel.value.list.splice(index, 1);
|
||||
}
|
||||
function handleAddItem() {
|
||||
const item = {
|
||||
dataIndex: '',
|
||||
type: FilterType.INPUT,
|
||||
operator: '',
|
||||
value: '',
|
||||
backendType: BackEndEnum.STRING,
|
||||
};
|
||||
formModel.value.list.push(item);
|
||||
}
|
||||
|
||||
const formRef = ref<FormInstance>();
|
||||
function handleFilter() {
|
||||
formRef.value?.validate((errors) => {
|
||||
if (!errors) {
|
||||
// TODO lmy 联调
|
||||
emit('handleFilter', { accordBelow: 'AND', combine: {} });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const isSaveAsView = ref(false);
|
||||
const saveAsViewName = ref('');
|
||||
function handleCancelSaveAsView() {
|
||||
isSaveAsView.value = false;
|
||||
saveAsViewName.value = '';
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
:deep(.arco-form-item) {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
</style>
|
@ -1,35 +1,43 @@
|
||||
export { default as FilterForm } from './FilterForm.vue';
|
||||
import { BackEndEnum, FilterType } from './type';
|
||||
|
||||
export { default as MsAdvanceFilter } from './index.vue';
|
||||
|
||||
// const IN = { label: 'advanceFilter.operator.in', value: 'in' };
|
||||
// const NOT_IN = { label: 'advanceFilter.operator.not_in', value: 'not_in' };
|
||||
export const LIKE = { label: 'advanceFilter.operator.like', value: 'like' };
|
||||
export const NOT_LIKE = { label: 'advanceFilter.operator.not_like', value: 'not_like' };
|
||||
export const GT = { label: 'advanceFilter.operator.gt', value: 'GT' };
|
||||
export const GE = { label: 'advanceFilter.operator.ge', value: 'GT_OR_EQUALS' };
|
||||
export const LT = { label: 'advanceFilter.operator.lt', value: 'LT' };
|
||||
export const LE = { label: 'advanceFilter.operator.le', value: 'LT_OR_EQUALS' };
|
||||
export const EQUAL = { label: 'advanceFilter.operator.equal', value: 'EQUALS' };
|
||||
export const NOT_EQUAL = { label: 'advanceFilter.operator.notEqual', value: 'NOT_EQUALS' };
|
||||
export const BETWEEN = { label: 'advanceFilter.operator.between', value: 'between' };
|
||||
export const NO_CHECK = { label: 'advanceFilter.operator.no_check', value: 'UNCHECK' };
|
||||
export const CONTAINS = { label: 'advanceFilter.operator.contains', value: 'CONTAINS' };
|
||||
export const NO_CONTAINS = { label: 'advanceFilter.operator.not_contains', value: 'NOT_CONTAINS' };
|
||||
export const START_WITH = { label: 'advanceFilter.operator.start_with', value: 'START_WITH' };
|
||||
export const END_WITH = { label: 'advanceFilter.operator.end_with', value: 'END_WITH' };
|
||||
export const EMPTY = { label: 'advanceFilter.operator.empty', value: 'EMPTY' };
|
||||
export const NOT_EMPTY = { label: 'advanceFilter.operator.not_empty', value: 'NOT_EMPTY' };
|
||||
export const REGEX = { label: 'advanceFilter.operator.regexp', value: 'REGEX' };
|
||||
export const LENGTH_EQUAL = { label: 'advanceFilter.operator.length.equal', value: 'LENGTH_EQUALS' };
|
||||
export const LENGTH_GT = { label: 'advanceFilter.operator.length.gt', value: 'LENGTH_GT' };
|
||||
export const LENGTH_GE = { label: 'advanceFilter.operator.length.ge', value: 'LENGTH_GT_OR_EQUALS' };
|
||||
export const LENGTH_LT = { label: 'advanceFilter.operator.length.lt', value: 'LENGTH_LT' };
|
||||
export const LENGTH_LE = { label: 'advanceFilter.operator.length.le', value: 'LENGTH_LT_OR_EQUALS' };
|
||||
export const OPERATOR_MAP = {
|
||||
string: [LIKE, NOT_LIKE, EQUAL, NOT_EQUAL],
|
||||
number: [GT, GE, LT, LE, EQUAL, NOT_EQUAL, BETWEEN],
|
||||
date: [GT, GE, LT, LE, EQUAL, NOT_EQUAL, BETWEEN],
|
||||
array: [BETWEEN],
|
||||
export const LIKE = { label: 'advanceFilter.operator.contains', value: 'like' }; // 包含
|
||||
export const NOT_LIKE = { label: 'advanceFilter.operator.not_contains', value: 'not_like' }; // 不包含
|
||||
export const GT = { label: 'advanceFilter.operator.gt', value: 'GT' }; // 大于
|
||||
export const GE = { label: 'advanceFilter.operator.ge', value: 'GT_OR_EQUALS' }; // 大于等于
|
||||
export const LT = { label: 'advanceFilter.operator.lt', value: 'LT' }; // 小于
|
||||
export const LE = { label: 'advanceFilter.operator.le', value: 'LT_OR_EQUALS' }; // 小于等于
|
||||
export const EQUAL = { label: 'advanceFilter.operator.equal', value: 'EQUALS' }; // 等于
|
||||
export const NOT_EQUAL = { label: 'advanceFilter.operator.notEqual', value: 'NOT_EQUALS' }; // 不等于
|
||||
export const BETWEEN = { label: 'advanceFilter.operator.between', value: 'between' }; // 介于
|
||||
export const NO_CHECK = { label: 'advanceFilter.operator.no_check', value: 'UNCHECK' }; // 不校验
|
||||
export const CONTAINS = { label: 'advanceFilter.operator.contains', value: 'CONTAINS' }; // 包含
|
||||
export const NO_CONTAINS = { label: 'advanceFilter.operator.not_contains', value: 'NOT_CONTAINS' }; // 不包含
|
||||
export const START_WITH = { label: 'advanceFilter.operator.start_with', value: 'START_WITH' }; // 以...开始
|
||||
export const END_WITH = { label: 'advanceFilter.operator.end_with', value: 'END_WITH' }; // 以...结束
|
||||
export const EMPTY = { label: 'advanceFilter.operator.empty', value: 'EMPTY' }; // 为空
|
||||
export const NOT_EMPTY = { label: 'advanceFilter.operator.not_empty', value: 'NOT_EMPTY' }; // 不为空
|
||||
export const REGEX = { label: 'advanceFilter.operator.regexp', value: 'REGEX' }; // 正则匹配
|
||||
export const LENGTH_EQUAL = { label: 'advanceFilter.operator.length.equal', value: 'LENGTH_EQUALS' }; // 长度等于
|
||||
export const LENGTH_GT = { label: 'advanceFilter.operator.length.gt', value: 'LENGTH_GT' }; // 长度大于
|
||||
export const LENGTH_GE = { label: 'advanceFilter.operator.length.ge', value: 'LENGTH_GT_OR_EQUALS' }; // 长度大于等于
|
||||
export const LENGTH_LT = { label: 'advanceFilter.operator.length.lt', value: 'LENGTH_LT' }; // 长度小于
|
||||
export const LENGTH_LE = { label: 'advanceFilter.operator.length.le', value: 'LENGTH_LT_OR_EQUALS' }; // 长度小于等于
|
||||
|
||||
const COMMON_TEXT_OPERATORS = [LIKE, NOT_LIKE, EMPTY, NOT_EMPTY, EQUAL, NOT_EQUAL];
|
||||
const COMMON_SELECTION_OPERATORS = [LIKE, NOT_LIKE, EMPTY, NOT_EMPTY];
|
||||
|
||||
export const operatorOptionsMap: Record<string, { value: string; label: string }[]> = {
|
||||
[FilterType.INPUT]: COMMON_TEXT_OPERATORS,
|
||||
[FilterType.TEXTAREA]: COMMON_TEXT_OPERATORS,
|
||||
[FilterType.NUMBER]: [GT, LT, EQUAL, EMPTY, NOT_EMPTY],
|
||||
[FilterType.RADIO]: COMMON_SELECTION_OPERATORS,
|
||||
[FilterType.CHECKBOX]: COMMON_SELECTION_OPERATORS,
|
||||
[FilterType.SELECT]: COMMON_SELECTION_OPERATORS,
|
||||
[FilterType.TAGS_INPUT]: [EMPTY, LIKE, NOT_LIKE, LENGTH_LT, LENGTH_GT],
|
||||
[FilterType.TREE_SELECT]: [LIKE, NOT_LIKE],
|
||||
[FilterType.DATE_PICKER]: [BETWEEN, EQUAL, EMPTY, NOT_EMPTY],
|
||||
};
|
||||
|
||||
export const timeSelectOptions = [GE, LE];
|
||||
@ -155,8 +163,29 @@ export const CustomTypeMaps: Record<string, any> = {
|
||||
},
|
||||
};
|
||||
|
||||
export const MULTIPLE_OPERATOR_LIST = ['between'];
|
||||
|
||||
export function isMutipleOperator(operator: string) {
|
||||
return MULTIPLE_OPERATOR_LIST.includes(operator);
|
||||
}
|
||||
export const defaultFormModelList = [
|
||||
{
|
||||
dataIndex: 'id',
|
||||
title: 'caseManagement.featureCase.tableColumnID',
|
||||
type: FilterType.INPUT,
|
||||
operator: '',
|
||||
value: '',
|
||||
backendType: BackEndEnum.STRING,
|
||||
},
|
||||
{
|
||||
dataIndex: 'name',
|
||||
label: 'common.name',
|
||||
type: FilterType.INPUT,
|
||||
operator: '',
|
||||
value: '',
|
||||
backendType: BackEndEnum.STRING,
|
||||
},
|
||||
{
|
||||
dataIndex: 'moduleId',
|
||||
label: 'common.belongModule',
|
||||
type: FilterType.TREE_SELECT,
|
||||
operator: '',
|
||||
value: '',
|
||||
backendType: BackEndEnum.STRING,
|
||||
},
|
||||
];
|
||||
|
@ -31,22 +31,20 @@
|
||||
@search="emit('keywordSearch', keyword, filterResult)"
|
||||
@clear="handleClear"
|
||||
></a-input-search>
|
||||
<!-- <MsTag
|
||||
:type="visible ? 'primary' : 'default'"
|
||||
:theme="visible ? 'lightOutLine' : 'outline'"
|
||||
size="large"
|
||||
class="min-w-[64px] cursor-pointer"
|
||||
no-margin
|
||||
<a-button
|
||||
v-if="props.showFilter"
|
||||
type="outline"
|
||||
:class="`${visible ? '' : 'arco-btn-outline--secondary'} p-[0_8px]`"
|
||||
@click="handleOpenFilter"
|
||||
>
|
||||
<span :class="!visible ? 'text-[var(--color-text-4)]' : ''">
|
||||
<icon-filter class="text-[16px]" />
|
||||
<span class="ml-[4px]">
|
||||
<span v-if="filterCount">{{ filterCount }}</span>
|
||||
{{ t('common.filter') }}
|
||||
</span>
|
||||
</span>
|
||||
</MsTag> -->
|
||||
<template #icon>
|
||||
<MsIcon
|
||||
type="icon-icon_copy_outlined"
|
||||
:class="`${visible ? 'text-[rgb(var(--primary-5))]' : 'text-[var(--color-text-4)]'}`"
|
||||
/>
|
||||
</template>
|
||||
{{ t('common.filter') }}
|
||||
</a-button>
|
||||
|
||||
<slot name="right"></slot>
|
||||
<MsTag
|
||||
@ -61,24 +59,20 @@
|
||||
</MsTag>
|
||||
</div>
|
||||
</div>
|
||||
<FilterForm
|
||||
v-show="visible"
|
||||
v-model:count="filterCount"
|
||||
:row-count="props.rowCount"
|
||||
:visible="visible"
|
||||
<FilterDrawer
|
||||
v-model:visible="visible"
|
||||
:config-list="props.filterConfigList"
|
||||
:custom-list="props.customFieldsConfigList"
|
||||
class="mt-[8px]"
|
||||
@on-search="handleFilter"
|
||||
@data-index-change="dataIndexChange"
|
||||
@reset="handleResetFilter"
|
||||
@handle-filter="handleFilter"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import MsIcon from '@/components/pure/ms-icon-font/index.vue';
|
||||
import MsTag from '../ms-tag/ms-tag.vue';
|
||||
import FilterForm from './FilterForm.vue';
|
||||
import FilterDrawer from './filterDrawer.vue';
|
||||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
|
||||
import { FilterFormItem, FilterResult } from './type';
|
||||
|
||||
@ -90,6 +84,7 @@
|
||||
name?: string;
|
||||
count?: number;
|
||||
notShowInputSearch?: boolean;
|
||||
showFilter?: boolean; // 展示高级搜索按钮
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
@ -99,17 +94,13 @@
|
||||
(e: 'refresh', value: FilterResult): void;
|
||||
}>();
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const keyword = defineModel<string>('keyword', { default: '' });
|
||||
const visible = ref(false);
|
||||
const filterCount = ref(0);
|
||||
const defaultFilterResult: FilterResult = { accordBelow: 'AND', combine: {} };
|
||||
const filterResult = ref<FilterResult>({ ...defaultFilterResult });
|
||||
|
||||
const handleResetFilter = () => {
|
||||
filterResult.value = { ...defaultFilterResult };
|
||||
emit('advSearch', { ...defaultFilterResult });
|
||||
};
|
||||
|
||||
const handleFilter = (filter: FilterResult) => {
|
||||
filterResult.value = filter;
|
||||
emit('advSearch', filter);
|
||||
@ -119,10 +110,6 @@
|
||||
emit('refresh', filterResult.value);
|
||||
};
|
||||
|
||||
const dataIndexChange = (dataIndex: string) => {
|
||||
emit('dataIndexChange', dataIndex);
|
||||
};
|
||||
|
||||
const handleClear = () => {
|
||||
keyword.value = '';
|
||||
emit('keywordSearch', '', filterResult.value);
|
||||
|
@ -1,8 +1,4 @@
|
||||
export default {
|
||||
'advanceFilter.operator.like': 'like',
|
||||
'advanceFilter.operator.not_like': 'not like',
|
||||
'advanceFilter.operator.in': 'in',
|
||||
'advanceFilter.operator.not_in': 'not in',
|
||||
'advanceFilter.operator.gt': 'gt',
|
||||
'advanceFilter.operator.ge': 'ge',
|
||||
'advanceFilter.operator.lt': 'lt',
|
||||
@ -18,21 +14,16 @@ export default {
|
||||
'advanceFilter.operator.not_empty': 'not empty',
|
||||
'advanceFilter.operator.regexp': 'Regular',
|
||||
'advanceFilter.operator.between': 'between',
|
||||
'advanceFilter.setFilterCondition': 'Set Filter Condition',
|
||||
'advanceFilter.accordBelow': 'Accord below',
|
||||
'advanceFilter.all': 'All',
|
||||
'advanceFilter.any': 'Any',
|
||||
'advanceFilter.condition': 'Condition',
|
||||
'advanceFilter.addCondition': 'Add Condition',
|
||||
'advanceFilter.reset': 'Reset',
|
||||
'advanceFilter.filter': 'Filter',
|
||||
'advanceFilter.plaseSelectFilterDataIndex': 'Please select a filter conditions',
|
||||
'advanceFilter.plaseInputFilterContent': 'Please input filter content',
|
||||
'advanceFilter.plaseSelectOperator': 'Please select an operator',
|
||||
'advanceFilter.operator.length.equal': 'Length equal to',
|
||||
'advanceFilter.operator.length.not_equal': 'Not equal in length',
|
||||
'advanceFilter.operator.length.gt': 'Length greater than',
|
||||
'advanceFilter.operator.length.ge': 'Length greater than or equal to',
|
||||
'advanceFilter.operator.length.lt': 'Less than',
|
||||
'advanceFilter.operator.length.le': 'Length less than or equal to',
|
||||
'advanceFilter.saveAsView': 'Save as view',
|
||||
'advanceFilter.viewNamePlaceholder': 'Please enter the view name',
|
||||
'advanceFilter.meetTheFollowingConditions': 'Meet the following conditions',
|
||||
'advanceFilter.and': 'And',
|
||||
'advanceFilter.or': 'Or',
|
||||
'advanceFilter.inputPlaceholder': 'Separate keywords with spaces',
|
||||
'advanceFilter.addCondition': 'Add conditions',
|
||||
};
|
||||
|
@ -1,15 +1,11 @@
|
||||
export default {
|
||||
'advanceFilter.operator.like': '包含',
|
||||
'advanceFilter.operator.not_like': '不包含',
|
||||
'advanceFilter.operator.in': '在列表中',
|
||||
'advanceFilter.operator.not_in': '不在列表中',
|
||||
'advanceFilter.operator.gt': '大于',
|
||||
'advanceFilter.operator.ge': '大于等于',
|
||||
'advanceFilter.operator.lt': '小于',
|
||||
'advanceFilter.operator.le': '小于等于',
|
||||
'advanceFilter.operator.equal': '等于',
|
||||
'advanceFilter.operator.notEqual': '不等于',
|
||||
'advanceFilter.operator.between': '介于',
|
||||
'advanceFilter.operator.between': '区间',
|
||||
'advanceFilter.operator.no_check': '不校验',
|
||||
'advanceFilter.operator.contains': '包含',
|
||||
'advanceFilter.operator.not_contains': '不包含',
|
||||
@ -18,21 +14,17 @@ export default {
|
||||
'advanceFilter.operator.empty': '为空',
|
||||
'advanceFilter.operator.not_empty': '不为空',
|
||||
'advanceFilter.operator.regexp': '正则匹配',
|
||||
'advanceFilter.setFilterCondition': '设置筛选条件',
|
||||
'advanceFilter.accordBelow': '满足以下',
|
||||
'advanceFilter.all': '所有',
|
||||
'advanceFilter.any': '任意',
|
||||
'advanceFilter.condition': '条件',
|
||||
'advanceFilter.addCondition': '添加条件',
|
||||
'advanceFilter.reset': '重置',
|
||||
'advanceFilter.filter': '过滤',
|
||||
'advanceFilter.plaseSelectFilterDataIndex': '请选择过滤条件',
|
||||
'advanceFilter.plaseInputFilterContent': '请输入筛选内容',
|
||||
'advanceFilter.plaseSelectOperator': '请选择运算符',
|
||||
'advanceFilter.operator.length.equal': '长度等于',
|
||||
'advanceFilter.operator.length.not_equal': '长度不等于',
|
||||
'advanceFilter.operator.length.gt': '长度大于',
|
||||
'advanceFilter.operator.length.ge': '长度大于等于',
|
||||
'advanceFilter.operator.length.lt': '长度小于',
|
||||
'advanceFilter.operator.length.le': '长度小于等于',
|
||||
|
||||
'advanceFilter.saveAsView': '另存为视图',
|
||||
'advanceFilter.viewNamePlaceholder': '请输入视图名称',
|
||||
'advanceFilter.meetTheFollowingConditions': '符合以下条件',
|
||||
'advanceFilter.and': '所有',
|
||||
'advanceFilter.or': '任一',
|
||||
'advanceFilter.inputPlaceholder': '关键字之间以空格进行分隔',
|
||||
'advanceFilter.addCondition': '添加条件',
|
||||
};
|
||||
|
@ -38,21 +38,21 @@ export enum FilterType {
|
||||
NUMBER = 'Number',
|
||||
SELECT = 'Select',
|
||||
DATE_PICKER = 'DatePicker',
|
||||
CASCADER = 'Cascader',
|
||||
TAGS_INPUT = 'TagsInput',
|
||||
TREE_SELECT = 'TreeSelect',
|
||||
TEXTAREA = 'textArea',
|
||||
RADIO = 'radio',
|
||||
CHECKBOX = 'checkbox',
|
||||
CASCADER = 'Cascader',
|
||||
JIRAKEY = 'JIRAKEY',
|
||||
}
|
||||
|
||||
export interface FilterFormItem {
|
||||
dataIndex?: string; // 对应的row的数据key
|
||||
title?: string; // 显示的label 国际化字符串定义在前端
|
||||
type: FilterType; // 类型:Input,Select,DatePicker,RangePicker
|
||||
value?: any; // 值 字符串 和 数组
|
||||
operator?: string; // 运算符号
|
||||
dataIndex?: string; // 第一列下拉的value
|
||||
title?: string; // 第一列下拉显示的label
|
||||
operator?: string; // 第二列的值
|
||||
type: FilterType; // 类型:判断第二列下拉数据和第三列显示形式
|
||||
value?: any; // 第三列的值
|
||||
cascaderOptions?: CascaderOption[]; // 级联选择的选项
|
||||
backendType?: BackEndEnum; // 后端类型 string array time
|
||||
selectProps?: Partial<MsSearchSelectProps>; // select的props, 参考 MsSelect
|
||||
|
@ -5,6 +5,7 @@
|
||||
<template v-if="showType === 'list'">
|
||||
<MsAdvanceFilter
|
||||
v-model:keyword="keyword"
|
||||
show-filter
|
||||
:filter-config-list="filterConfigList"
|
||||
:custom-fields-config-list="searchCustomFields"
|
||||
:search-placeholder="t('caseManagement.featureCase.searchPlaceholder')"
|
||||
@ -976,7 +977,6 @@
|
||||
selectAll: batchParams.value.selectAll,
|
||||
selectIds: batchParams.value.selectedIds || [],
|
||||
keyword: keyword.value,
|
||||
combine: batchParams.value.condition,
|
||||
};
|
||||
}
|
||||
// 获取父组件模块数量
|
||||
@ -1604,24 +1604,10 @@
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
const filterResult = ref<FilterResult>({ accordBelow: 'AND', combine: {} });
|
||||
// 当前选择的条数
|
||||
const currentSelectParams = ref<BatchActionQueryParams>({ selectAll: false, currentSelectCount: 0 });
|
||||
// 高级检索
|
||||
const handleAdvSearch = (filter: FilterResult) => {
|
||||
filterResult.value = filter;
|
||||
const { accordBelow, combine } = filter;
|
||||
const handleAdvSearch = async (filter: FilterResult) => {
|
||||
setAdvanceFilter(filter);
|
||||
currentSelectParams.value = {
|
||||
...currentSelectParams.value,
|
||||
condition: {
|
||||
keyword: keyword.value,
|
||||
searchMode: accordBelow,
|
||||
filter: propsRes.value.filter,
|
||||
combine,
|
||||
},
|
||||
};
|
||||
initData();
|
||||
loadList();
|
||||
};
|
||||
// 更新用例等级
|
||||
async function handleStatusChange(record: any) {
|
||||
|
Loading…
Reference in New Issue
Block a user