refactor: 高级筛选-重构视图下拉
This commit is contained in:
parent
b39aa92da0
commit
bf74d8d882
|
@ -77,22 +77,25 @@
|
|||
: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-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"
|
||||
allow-clear
|
||||
:disabled="isValueDisabled(item)"
|
||||
:max-length="255"
|
||||
: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
|
||||
v-else-if="item.type === FilterType.MEMBER"
|
||||
v-model:model-value="item.value"
|
||||
|
@ -343,7 +346,9 @@
|
|||
function valueIsArray(listItem: FilterFormItem) {
|
||||
return (
|
||||
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)
|
||||
);
|
||||
}
|
||||
|
@ -376,6 +381,8 @@
|
|||
formModel.value.list[index].operator = OperatorEnum.BELONG_TO;
|
||||
} else if (optionsValueList.includes(OperatorEnum.EQUAL)) {
|
||||
formModel.value.list[index].operator = OperatorEnum.EQUAL;
|
||||
} else {
|
||||
formModel.value.list[index].operator = OperatorEnum.BETWEEN; // 时间
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -401,22 +408,25 @@
|
|||
}
|
||||
|
||||
function getParams() {
|
||||
const conditions = formModel.value.list.map(({ type, value, operator, customField, dataIndex }) => {
|
||||
let timeValue;
|
||||
// 转换成时间戳
|
||||
if (type === FilterType.DATE_PICKER && value?.[0] && value?.[1]) {
|
||||
timeValue =
|
||||
operator === OperatorEnum.BETWEEN
|
||||
? [new Date(value[0]).getTime(), new Date(value[1]).getTime()]
|
||||
: new Date(value).getTime();
|
||||
const conditions = formModel.value.list.map(
|
||||
({ customFieldType, type, value, operator, customField, dataIndex }) => {
|
||||
let timeValue;
|
||||
// 转换成时间戳
|
||||
if (type === FilterType.DATE_PICKER && value?.[0] && value?.[1]) {
|
||||
timeValue =
|
||||
operator === OperatorEnum.BETWEEN
|
||||
? [new Date(value[0]).getTime(), new Date(value[1]).getTime()]
|
||||
: new Date(value).getTime();
|
||||
}
|
||||
return {
|
||||
value: timeValue ?? value,
|
||||
operator,
|
||||
customField: customField ?? false,
|
||||
name: dataIndex,
|
||||
customFieldType: customFieldType ?? '',
|
||||
};
|
||||
}
|
||||
return {
|
||||
value: timeValue ?? value,
|
||||
operator,
|
||||
customField: customField ?? false,
|
||||
name: dataIndex,
|
||||
};
|
||||
});
|
||||
);
|
||||
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 NOT_EQUAL = { label: 'advanceFilter.operator.notEqual', value: OperatorEnum.NOT_EQUAL }; // 不等于
|
||||
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_LT = { label: 'advanceFilter.operator.length.lt', value: OperatorEnum.COUNT_LT }; // 数量小于
|
||||
export const COUNT_GT = { label: 'advanceFilter.operator.count.gt', value: OperatorEnum.COUNT_GT }; // 数量大下
|
||||
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 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.TAGS_INPUT]: [EMPTY, CONTAINS, NO_CONTAINS, COUNT_LT, COUNT_GT],
|
||||
[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];
|
||||
|
|
|
@ -31,57 +31,81 @@
|
|||
@search="emit('keywordSearch', keyword)"
|
||||
@clear="handleClear"
|
||||
></a-input-search>
|
||||
<a-select
|
||||
v-if="props.viewType"
|
||||
v-model:model-value="currentView"
|
||||
:loading="viewListLoading"
|
||||
:trigger-props="{ contentClass: 'view-select-trigger' }"
|
||||
class="w-[180px]"
|
||||
show-footer-on-empty
|
||||
<!-- 在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"
|
||||
>
|
||||
<template #prefix> {{ t('advanceFilter.view') }} </template>
|
||||
<a-optgroup :label="t('advanceFilter.systemView')">
|
||||
<a-option v-for="item in internalViews" :key="item.id" :value="item.id">
|
||||
{{ item.name }}
|
||||
</a-option>
|
||||
</a-optgroup>
|
||||
<a-optgroup :label="t('advanceFilter.myView')">
|
||||
<template v-for="item in customViews" :key="item.id">
|
||||
<a-option v-show="!item.isShowNameInput" :value="item.id">
|
||||
<div>{{ item.name }}</div>
|
||||
<div class="select-extra flex">
|
||||
<a-tooltip :content="t('common.rename')">
|
||||
<MsButton type="text" status="secondary" class="!mr-[4px]" @click="handleToRenameView(item)">
|
||||
<MsIcon type="icon-icon_edit_outlined" class="hover:text-[rgb(var(--primary-4))]" size="12" />
|
||||
</MsButton>
|
||||
</a-tooltip>
|
||||
<a-tooltip :content="t('advanceFilter.deleteView')">
|
||||
<MsButton type="text" :disabled="deleteLoading" status="secondary" @click="handleDeleteView(item)">
|
||||
<MsIcon
|
||||
type="icon-icon_delete-trash_outlined1"
|
||||
class="hover:text-[rgb(var(--primary-4))]"
|
||||
size="12"
|
||||
/>
|
||||
</MsButton>
|
||||
</a-tooltip>
|
||||
<a-select
|
||||
v-if="props.viewType"
|
||||
v-model:model-value="currentView"
|
||||
:loading="viewListLoading"
|
||||
:options="[...internalViews, ...customViews].map((item) => ({ value: item.id, label: item.name }))"
|
||||
:trigger-props="{ contentClass: 'view-select-trigger' }"
|
||||
class="w-[180px]"
|
||||
show-footer-on-empty
|
||||
>
|
||||
<template #prefix> {{ t('advanceFilter.view') }} </template>
|
||||
</a-select>
|
||||
<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 }}
|
||||
</div>
|
||||
<div class="view-option-title">
|
||||
<span>{{ t('advanceFilter.myView') }}</span>
|
||||
<a-divider></a-divider>
|
||||
</div>
|
||||
<template v-for="item in customViews" :key="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 class="select-extra flex">
|
||||
<a-tooltip :content="t('common.rename')">
|
||||
<MsButton type="text" status="secondary" class="!mr-[4px]" @click="handleToRenameView(item)">
|
||||
<MsIcon type="icon-icon_edit_outlined" class="hover:text-[rgb(var(--primary-4))]" size="12" />
|
||||
</MsButton>
|
||||
</a-tooltip>
|
||||
<a-tooltip :content="t('advanceFilter.deleteView')">
|
||||
<MsButton type="text" :disabled="deleteLoading" status="secondary" @click="handleDeleteView(item)">
|
||||
<MsIcon
|
||||
type="icon-icon_delete-trash_outlined1"
|
||||
class="hover:text-[rgb(var(--primary-4))]"
|
||||
size="12"
|
||||
/>
|
||||
</MsButton>
|
||||
</a-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
</a-option>
|
||||
<ViewNameInput
|
||||
v-if="item.isShowNameInput"
|
||||
:ref="(el:refItem) => setNameInputRefMap(el, item)"
|
||||
v-model:form="formModel"
|
||||
:all-names="allViewNames.filter((name) => name !== item.name)"
|
||||
@handle-submit="handleRenameView"
|
||||
/>
|
||||
</template>
|
||||
</a-optgroup>
|
||||
<template #footer>
|
||||
<div class="flex cursor-pointer items-center gap-[8px]" @click="toNewView">
|
||||
<MsIcon type="icon-icon_add_outlined" />
|
||||
{{ t('advanceFilter.newView') }}
|
||||
</div>
|
||||
<ViewNameInput
|
||||
v-if="item.isShowNameInput"
|
||||
:ref="(el:refItem) => setNameInputRefMap(el, item)"
|
||||
v-model:form="formModel"
|
||||
:all-names="allViewNames.filter((name) => name !== item.name)"
|
||||
@handle-submit="handleRenameView"
|
||||
/>
|
||||
</template>
|
||||
<div class="flex cursor-pointer items-center gap-[8px] px-[8px] py-[3px]" @click="toNewView">
|
||||
<MsIcon type="icon-icon_add_outlined" />
|
||||
{{ t('advanceFilter.newView') }}
|
||||
</div>
|
||||
</a-spin>
|
||||
</template>
|
||||
</a-select>
|
||||
</a-trigger>
|
||||
<a-button
|
||||
v-if="props.viewType"
|
||||
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>>();
|
||||
function toNewView() {
|
||||
if (canNotAddView.value) {
|
||||
|
@ -301,40 +336,59 @@
|
|||
}
|
||||
}
|
||||
|
||||
async function changeViewToFirstCustom() {
|
||||
await getUserViewList();
|
||||
currentView.value = customViews.value[0].id;
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
isAdvancedSearchMode,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.view-select-trigger .arco-select-dropdown {
|
||||
.arco-select-option-content {
|
||||
@apply flex w-full items-center justify-between;
|
||||
.view-select-trigger {
|
||||
display: none;
|
||||
}
|
||||
.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 {
|
||||
visibility: hidden;
|
||||
}
|
||||
.arco-select-option:hover {
|
||||
.select-extra {
|
||||
visibility: visible;
|
||||
.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 {
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
&-active {
|
||||
color: rgb(var(--primary-5)) !important;
|
||||
background-color: rgb(var(--primary-1)) !important;
|
||||
}
|
||||
}
|
||||
.arco-select-dropdown-list-wrapper {
|
||||
max-height: 255px;
|
||||
.arco-form-item-content,
|
||||
.arco-input-wrapper {
|
||||
height: 28px;
|
||||
}
|
||||
.arco-select-group-title {
|
||||
margin: 0 2px;
|
||||
padding: 0 8px;
|
||||
color: var(--color-text-brand);
|
||||
}
|
||||
.arco-select-dropdown-footer {
|
||||
padding: 3px 8px;
|
||||
border: none;
|
||||
.arco-form-item-message {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -21,6 +21,8 @@ export default {
|
|||
'advanceFilter.operator.length.ge': 'Length greater than or equal to',
|
||||
'advanceFilter.operator.length.lt': 'Length less than',
|
||||
'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.unnamedView': 'Unnamed View',
|
||||
|
|
|
@ -21,6 +21,8 @@ export default {
|
|||
'advanceFilter.operator.length.ge': '长度大于等于',
|
||||
'advanceFilter.operator.length.lt': '长度小于',
|
||||
'advanceFilter.operator.length.le': '长度小于等于',
|
||||
'advanceFilter.operator.count.lt': '数量小于',
|
||||
'advanceFilter.operator.count.gt': '数量大于',
|
||||
|
||||
'advanceFilter.view': '视图',
|
||||
'advanceFilter.unnamedView': '未命名视图',
|
||||
|
|
|
@ -34,6 +34,7 @@ export interface FilterFormItem {
|
|||
type: FilterType; // 类型:判断第二列下拉数据和第三列显示形式
|
||||
value?: any; // 第三列的值
|
||||
customField?: boolean; // 是否是自定义字段
|
||||
customFieldType?: string; // 自定义字段的类型
|
||||
cascaderOptions?: CascaderOption[]; // 级联选择的选项
|
||||
selectProps?: Partial<MsSearchSelectProps>; // select的props, 参考 MsSelect
|
||||
cascaderProps?: Partial<MsCascaderProps>; // cascader的props, 参考 MsCascader
|
||||
|
|
|
@ -1108,12 +1108,14 @@
|
|||
dataIndex: item.id,
|
||||
type: formType,
|
||||
customField: true,
|
||||
customFieldType: item.type,
|
||||
};
|
||||
|
||||
if (formObject.propsKey && formProps.options) {
|
||||
formProps.options = item.options;
|
||||
currentItem[formObject.propsKey] = {
|
||||
...formProps,
|
||||
customFieldType: item.type,
|
||||
};
|
||||
}
|
||||
return currentItem;
|
||||
|
|
Loading…
Reference in New Issue