refactor: 高级筛选-重构视图下拉
This commit is contained in:
parent
b39aa92da0
commit
bf74d8d882
|
@ -77,22 +77,25 @@
|
||||||
:placeholder="t('advanceFilter.inputPlaceholder')"
|
:placeholder="t('advanceFilter.inputPlaceholder')"
|
||||||
:max-length="1000"
|
: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
|
<a-input-number
|
||||||
v-else-if="item.type === FilterType.NUMBER"
|
v-else-if="
|
||||||
|
item.type === FilterType.NUMBER ||
|
||||||
|
(item.type === FilterType.TAGS_INPUT && [OperatorEnum.COUNT_LT, OperatorEnum.COUNT_GT].includes(item.operator as OperatorEnum))
|
||||||
|
"
|
||||||
v-model:model-value="item.value"
|
v-model:model-value="item.value"
|
||||||
allow-clear
|
allow-clear
|
||||||
:disabled="isValueDisabled(item)"
|
:disabled="isValueDisabled(item)"
|
||||||
:max-length="255"
|
:max-length="255"
|
||||||
:placeholder="t('common.pleaseInput')"
|
:placeholder="t('common.pleaseInput')"
|
||||||
/>
|
/>
|
||||||
|
<MsTagsInput
|
||||||
|
v-else-if="item.type === FilterType.TAGS_INPUT&& ![OperatorEnum.COUNT_LT, OperatorEnum.COUNT_GT].includes(item.operator as OperatorEnum)"
|
||||||
|
v-model:model-value="item.value"
|
||||||
|
:disabled="isValueDisabled(item)"
|
||||||
|
allow-clear
|
||||||
|
unique-value
|
||||||
|
retain-input-value
|
||||||
|
/>
|
||||||
<MsSelect
|
<MsSelect
|
||||||
v-else-if="item.type === FilterType.MEMBER"
|
v-else-if="item.type === FilterType.MEMBER"
|
||||||
v-model:model-value="item.value"
|
v-model:model-value="item.value"
|
||||||
|
@ -343,7 +346,9 @@
|
||||||
function valueIsArray(listItem: FilterFormItem) {
|
function valueIsArray(listItem: FilterFormItem) {
|
||||||
return (
|
return (
|
||||||
listItem.selectProps?.multiple ||
|
listItem.selectProps?.multiple ||
|
||||||
[FilterType.CHECKBOX, FilterType.TAGS_INPUT].includes(listItem.type) ||
|
[FilterType.CHECKBOX].includes(listItem.type) ||
|
||||||
|
(listItem.type === FilterType.TAGS_INPUT &&
|
||||||
|
![OperatorEnum.COUNT_LT, OperatorEnum.COUNT_GT].includes(listItem.operator as OperatorEnum)) ||
|
||||||
(listItem.type === FilterType.DATE_PICKER && listItem.operator === OperatorEnum.BETWEEN)
|
(listItem.type === FilterType.DATE_PICKER && listItem.operator === OperatorEnum.BETWEEN)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -376,6 +381,8 @@
|
||||||
formModel.value.list[index].operator = OperatorEnum.BELONG_TO;
|
formModel.value.list[index].operator = OperatorEnum.BELONG_TO;
|
||||||
} else if (optionsValueList.includes(OperatorEnum.EQUAL)) {
|
} else if (optionsValueList.includes(OperatorEnum.EQUAL)) {
|
||||||
formModel.value.list[index].operator = OperatorEnum.EQUAL;
|
formModel.value.list[index].operator = OperatorEnum.EQUAL;
|
||||||
|
} else {
|
||||||
|
formModel.value.list[index].operator = OperatorEnum.BETWEEN; // 时间
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -401,7 +408,8 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function getParams() {
|
function getParams() {
|
||||||
const conditions = formModel.value.list.map(({ type, value, operator, customField, dataIndex }) => {
|
const conditions = formModel.value.list.map(
|
||||||
|
({ customFieldType, type, value, operator, customField, dataIndex }) => {
|
||||||
let timeValue;
|
let timeValue;
|
||||||
// 转换成时间戳
|
// 转换成时间戳
|
||||||
if (type === FilterType.DATE_PICKER && value?.[0] && value?.[1]) {
|
if (type === FilterType.DATE_PICKER && value?.[0] && value?.[1]) {
|
||||||
|
@ -415,8 +423,10 @@
|
||||||
operator,
|
operator,
|
||||||
customField: customField ?? false,
|
customField: customField ?? false,
|
||||||
name: dataIndex,
|
name: dataIndex,
|
||||||
|
customFieldType: customFieldType ?? '',
|
||||||
};
|
};
|
||||||
});
|
}
|
||||||
|
);
|
||||||
return { searchMode: formModel.value.searchMode, conditions };
|
return { searchMode: formModel.value.searchMode, conditions };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,8 +11,8 @@ export const LE = { label: 'advanceFilter.operator.le', value: 'LT_OR_EQUALS' };
|
||||||
export const EQUAL = { label: 'advanceFilter.operator.equal', value: OperatorEnum.EQUAL }; // 等于
|
export const EQUAL = { label: 'advanceFilter.operator.equal', value: OperatorEnum.EQUAL }; // 等于
|
||||||
export const NOT_EQUAL = { label: 'advanceFilter.operator.notEqual', value: OperatorEnum.NOT_EQUAL }; // 不等于
|
export const NOT_EQUAL = { label: 'advanceFilter.operator.notEqual', value: OperatorEnum.NOT_EQUAL }; // 不等于
|
||||||
export const BETWEEN = { label: 'advanceFilter.operator.between', value: OperatorEnum.BETWEEN }; // 介于
|
export const BETWEEN = { label: 'advanceFilter.operator.between', value: OperatorEnum.BETWEEN }; // 介于
|
||||||
export const COUNT_GT = { label: 'advanceFilter.operator.length.gt', value: OperatorEnum.COUNT_GT }; // 数量大下
|
export const COUNT_GT = { label: 'advanceFilter.operator.count.gt', value: OperatorEnum.COUNT_GT }; // 数量大下
|
||||||
export const COUNT_LT = { label: 'advanceFilter.operator.length.lt', value: OperatorEnum.COUNT_LT }; // 数量小于
|
export const COUNT_LT = { label: 'advanceFilter.operator.count.lt', value: OperatorEnum.COUNT_LT }; // 数量小于
|
||||||
|
|
||||||
export const EMPTY = { label: 'advanceFilter.operator.empty', value: OperatorEnum.EMPTY }; // 为空
|
export const EMPTY = { label: 'advanceFilter.operator.empty', value: OperatorEnum.EMPTY }; // 为空
|
||||||
export const NOT_EMPTY = { label: 'advanceFilter.operator.not_empty', value: OperatorEnum.NOT_EMPTY }; // 不为空
|
export const NOT_EMPTY = { label: 'advanceFilter.operator.not_empty', value: OperatorEnum.NOT_EMPTY }; // 不为空
|
||||||
|
@ -41,7 +41,7 @@ export const operatorOptionsMap: Record<string, { value: string; label: string }
|
||||||
[FilterType.MEMBER]: COMMON_SELECTION_OPERATORS,
|
[FilterType.MEMBER]: COMMON_SELECTION_OPERATORS,
|
||||||
[FilterType.TAGS_INPUT]: [EMPTY, CONTAINS, NO_CONTAINS, COUNT_LT, COUNT_GT],
|
[FilterType.TAGS_INPUT]: [EMPTY, CONTAINS, NO_CONTAINS, COUNT_LT, COUNT_GT],
|
||||||
[FilterType.TREE_SELECT]: [BELONG_TO, NOT_BELONG_TO],
|
[FilterType.TREE_SELECT]: [BELONG_TO, NOT_BELONG_TO],
|
||||||
[FilterType.DATE_PICKER]: [BETWEEN, EQUAL, EMPTY, NOT_EMPTY],
|
[FilterType.DATE_PICKER]: [BETWEEN, GT, LT, EMPTY, NOT_EMPTY],
|
||||||
};
|
};
|
||||||
|
|
||||||
export const timeSelectOptions = [GE, LE];
|
export const timeSelectOptions = [GE, LE];
|
||||||
|
|
|
@ -31,23 +31,48 @@
|
||||||
@search="emit('keywordSearch', keyword)"
|
@search="emit('keywordSearch', keyword)"
|
||||||
@clear="handleClear"
|
@clear="handleClear"
|
||||||
></a-input-search>
|
></a-input-search>
|
||||||
|
<!-- 在select的option里写input,鼠标点击和失焦不好使,故单独写了一个下拉trigger -->
|
||||||
|
<a-trigger
|
||||||
|
v-model:popup-visible="viewSelectOptionVisible"
|
||||||
|
trigger="click"
|
||||||
|
:popup-translate="[0, 4]"
|
||||||
|
content-class="arco-trigger-menu view-custom-trigger-content"
|
||||||
|
>
|
||||||
<a-select
|
<a-select
|
||||||
v-if="props.viewType"
|
v-if="props.viewType"
|
||||||
v-model:model-value="currentView"
|
v-model:model-value="currentView"
|
||||||
:loading="viewListLoading"
|
:loading="viewListLoading"
|
||||||
|
:options="[...internalViews, ...customViews].map((item) => ({ value: item.id, label: item.name }))"
|
||||||
:trigger-props="{ contentClass: 'view-select-trigger' }"
|
:trigger-props="{ contentClass: 'view-select-trigger' }"
|
||||||
class="w-[180px]"
|
class="w-[180px]"
|
||||||
show-footer-on-empty
|
show-footer-on-empty
|
||||||
>
|
>
|
||||||
<template #prefix> {{ t('advanceFilter.view') }} </template>
|
<template #prefix> {{ t('advanceFilter.view') }} </template>
|
||||||
<a-optgroup :label="t('advanceFilter.systemView')">
|
</a-select>
|
||||||
<a-option v-for="item in internalViews" :key="item.id" :value="item.id">
|
<template #content>
|
||||||
|
<a-spin class="w-full" :loading="viewListLoading">
|
||||||
|
<div class="view-option-title">
|
||||||
|
<span>{{ t('advanceFilter.systemView') }}</span>
|
||||||
|
<a-divider></a-divider>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-for="item in internalViews"
|
||||||
|
:key="item.id"
|
||||||
|
:class="[`view-option-item ${item.id === currentView ? 'view-option-item-active' : ''}`]"
|
||||||
|
@click="changeView(item)"
|
||||||
|
>
|
||||||
{{ item.name }}
|
{{ item.name }}
|
||||||
</a-option>
|
</div>
|
||||||
</a-optgroup>
|
<div class="view-option-title">
|
||||||
<a-optgroup :label="t('advanceFilter.myView')">
|
<span>{{ t('advanceFilter.myView') }}</span>
|
||||||
|
<a-divider></a-divider>
|
||||||
|
</div>
|
||||||
<template v-for="item in customViews" :key="item.id">
|
<template v-for="item in customViews" :key="item.id">
|
||||||
<a-option v-show="!item.isShowNameInput" :value="item.id">
|
<div
|
||||||
|
v-show="!item.isShowNameInput"
|
||||||
|
:class="[`view-option-item ${item.id === currentView ? 'view-option-item-active' : ''}`]"
|
||||||
|
@click="changeView(item)"
|
||||||
|
>
|
||||||
<div>{{ item.name }}</div>
|
<div>{{ item.name }}</div>
|
||||||
<div class="select-extra flex">
|
<div class="select-extra flex">
|
||||||
<a-tooltip :content="t('common.rename')">
|
<a-tooltip :content="t('common.rename')">
|
||||||
|
@ -65,7 +90,7 @@
|
||||||
</MsButton>
|
</MsButton>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
</div>
|
</div>
|
||||||
</a-option>
|
</div>
|
||||||
<ViewNameInput
|
<ViewNameInput
|
||||||
v-if="item.isShowNameInput"
|
v-if="item.isShowNameInput"
|
||||||
:ref="(el:refItem) => setNameInputRefMap(el, item)"
|
:ref="(el:refItem) => setNameInputRefMap(el, item)"
|
||||||
|
@ -74,14 +99,13 @@
|
||||||
@handle-submit="handleRenameView"
|
@handle-submit="handleRenameView"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</a-optgroup>
|
<div class="flex cursor-pointer items-center gap-[8px] px-[8px] py-[3px]" @click="toNewView">
|
||||||
<template #footer>
|
|
||||||
<div class="flex cursor-pointer items-center gap-[8px]" @click="toNewView">
|
|
||||||
<MsIcon type="icon-icon_add_outlined" />
|
<MsIcon type="icon-icon_add_outlined" />
|
||||||
{{ t('advanceFilter.newView') }}
|
{{ t('advanceFilter.newView') }}
|
||||||
</div>
|
</div>
|
||||||
|
</a-spin>
|
||||||
</template>
|
</template>
|
||||||
</a-select>
|
</a-trigger>
|
||||||
<a-button
|
<a-button
|
||||||
v-if="props.viewType"
|
v-if="props.viewType"
|
||||||
type="outline"
|
type="outline"
|
||||||
|
@ -207,6 +231,17 @@
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const viewSelectOptionVisible = ref(false);
|
||||||
|
function changeView(item: ViewItem) {
|
||||||
|
currentView.value = item.id;
|
||||||
|
viewSelectOptionVisible.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function changeViewToFirstCustom() {
|
||||||
|
await getUserViewList();
|
||||||
|
currentView.value = customViews.value[0].id;
|
||||||
|
}
|
||||||
|
|
||||||
const filterDrawerRef = ref<InstanceType<typeof FilterDrawer>>();
|
const filterDrawerRef = ref<InstanceType<typeof FilterDrawer>>();
|
||||||
function toNewView() {
|
function toNewView() {
|
||||||
if (canNotAddView.value) {
|
if (canNotAddView.value) {
|
||||||
|
@ -301,40 +336,59 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function changeViewToFirstCustom() {
|
|
||||||
await getUserViewList();
|
|
||||||
currentView.value = customViews.value[0].id;
|
|
||||||
}
|
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
isAdvancedSearchMode,
|
isAdvancedSearchMode,
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
.view-select-trigger .arco-select-dropdown {
|
.view-select-trigger {
|
||||||
.arco-select-option-content {
|
display: none;
|
||||||
@apply flex w-full items-center justify-between;
|
}
|
||||||
|
.view-custom-trigger-content {
|
||||||
|
width: 180px;
|
||||||
|
max-height: 300px;
|
||||||
|
.ms-scroll-bar();
|
||||||
|
.view-option-title {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin: 0 2px;
|
||||||
|
padding: 0 8px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--color-text-brand);
|
||||||
|
line-height: 20px;
|
||||||
|
.arco-divider-horizontal {
|
||||||
|
margin: 4px 0 4px 8px;
|
||||||
|
min-width: 0;
|
||||||
|
border-bottom-color: var(--color-text-n8);
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.select-extra {
|
.select-extra {
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
}
|
}
|
||||||
.arco-select-option:hover {
|
.view-option-item {
|
||||||
|
padding: 3px 8px;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
@apply flex w-full items-center justify-between;
|
||||||
|
&:hover {
|
||||||
|
background-color: rgb(var(--primary-1));
|
||||||
.select-extra {
|
.select-extra {
|
||||||
visibility: visible;
|
visibility: visible;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.arco-select-dropdown-list-wrapper {
|
&-active {
|
||||||
max-height: 255px;
|
color: rgb(var(--primary-5)) !important;
|
||||||
|
background-color: rgb(var(--primary-1)) !important;
|
||||||
}
|
}
|
||||||
.arco-select-group-title {
|
|
||||||
margin: 0 2px;
|
|
||||||
padding: 0 8px;
|
|
||||||
color: var(--color-text-brand);
|
|
||||||
}
|
}
|
||||||
.arco-select-dropdown-footer {
|
.arco-form-item-content,
|
||||||
padding: 3px 8px;
|
.arco-input-wrapper {
|
||||||
border: none;
|
height: 28px;
|
||||||
|
}
|
||||||
|
.arco-form-item-message {
|
||||||
|
margin: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -21,6 +21,8 @@ export default {
|
||||||
'advanceFilter.operator.length.ge': 'Length greater than or equal to',
|
'advanceFilter.operator.length.ge': 'Length greater than or equal to',
|
||||||
'advanceFilter.operator.length.lt': 'Length less than',
|
'advanceFilter.operator.length.lt': 'Length less than',
|
||||||
'advanceFilter.operator.length.le': 'Length less than or equal to',
|
'advanceFilter.operator.length.le': 'Length less than or equal to',
|
||||||
|
'advanceFilter.operator.count.lt': 'Quantity less than',
|
||||||
|
'advanceFilter.operator.count.gt': 'Quantity greater than',
|
||||||
|
|
||||||
'advanceFilter.view': 'View',
|
'advanceFilter.view': 'View',
|
||||||
'advanceFilter.unnamedView': 'Unnamed View',
|
'advanceFilter.unnamedView': 'Unnamed View',
|
||||||
|
|
|
@ -21,6 +21,8 @@ export default {
|
||||||
'advanceFilter.operator.length.ge': '长度大于等于',
|
'advanceFilter.operator.length.ge': '长度大于等于',
|
||||||
'advanceFilter.operator.length.lt': '长度小于',
|
'advanceFilter.operator.length.lt': '长度小于',
|
||||||
'advanceFilter.operator.length.le': '长度小于等于',
|
'advanceFilter.operator.length.le': '长度小于等于',
|
||||||
|
'advanceFilter.operator.count.lt': '数量小于',
|
||||||
|
'advanceFilter.operator.count.gt': '数量大于',
|
||||||
|
|
||||||
'advanceFilter.view': '视图',
|
'advanceFilter.view': '视图',
|
||||||
'advanceFilter.unnamedView': '未命名视图',
|
'advanceFilter.unnamedView': '未命名视图',
|
||||||
|
|
|
@ -34,6 +34,7 @@ export interface FilterFormItem {
|
||||||
type: FilterType; // 类型:判断第二列下拉数据和第三列显示形式
|
type: FilterType; // 类型:判断第二列下拉数据和第三列显示形式
|
||||||
value?: any; // 第三列的值
|
value?: any; // 第三列的值
|
||||||
customField?: boolean; // 是否是自定义字段
|
customField?: boolean; // 是否是自定义字段
|
||||||
|
customFieldType?: string; // 自定义字段的类型
|
||||||
cascaderOptions?: CascaderOption[]; // 级联选择的选项
|
cascaderOptions?: CascaderOption[]; // 级联选择的选项
|
||||||
selectProps?: Partial<MsSearchSelectProps>; // select的props, 参考 MsSelect
|
selectProps?: Partial<MsSearchSelectProps>; // select的props, 参考 MsSelect
|
||||||
cascaderProps?: Partial<MsCascaderProps>; // cascader的props, 参考 MsCascader
|
cascaderProps?: Partial<MsCascaderProps>; // cascader的props, 参考 MsCascader
|
||||||
|
|
|
@ -1108,12 +1108,14 @@
|
||||||
dataIndex: item.id,
|
dataIndex: item.id,
|
||||||
type: formType,
|
type: formType,
|
||||||
customField: true,
|
customField: true,
|
||||||
|
customFieldType: item.type,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (formObject.propsKey && formProps.options) {
|
if (formObject.propsKey && formProps.options) {
|
||||||
formProps.options = item.options;
|
formProps.options = item.options;
|
||||||
currentItem[formObject.propsKey] = {
|
currentItem[formObject.propsKey] = {
|
||||||
...formProps,
|
...formProps,
|
||||||
|
customFieldType: item.type,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return currentItem;
|
return currentItem;
|
||||||
|
|
Loading…
Reference in New Issue