feat(公共): 筛选面板组件调整

This commit is contained in:
xinxin.wu 2023-09-28 12:30:52 +08:00 committed by fit2-zhao
parent 4ee10e11dc
commit 7a191e2c40
6 changed files with 143 additions and 60 deletions

View File

@ -1,4 +1,5 @@
import { OPERATORS } from './operator';
import type { SearchKeyType } from './type';
// eslint-disable-next-line no-shadow
export enum CaseKeyEnum {
@ -17,7 +18,7 @@ export enum CaseKeyEnum {
}
// 名称
export const NAME = {
export const NAME: SearchKeyType = {
key: CaseKeyEnum.NAME, // 对应字段key
type: 'a-input', // Vue控件名称
label: '显示名称', // 显示名称
@ -28,7 +29,7 @@ export const NAME = {
};
// 标签
export const TAGS = {
export const TAGS: SearchKeyType = {
key: CaseKeyEnum.TAGS,
type: 'a-input',
label: '标签',
@ -39,7 +40,7 @@ export const TAGS = {
};
// 所属模块
export const MODULE = {
export const MODULE: SearchKeyType = {
key: 'module',
type: 'a-tree-select',
label: '所属模块',
@ -50,23 +51,27 @@ export const MODULE = {
};
// 创建时间
export const CREATE_TIME = {
export const CREATE_TIME: SearchKeyType = {
key: CaseKeyEnum.CREATE_TIME,
type: 'time-select', // 时间选择器
label: '创建时间',
rules: [{ required: true, message: '请选择创建时间!' }],
props: {},
operator: {
value: '',
options: [OPERATORS.BETWEEN, OPERATORS.GT, OPERATORS.LT],
},
};
// 更新时间
export const UPDATE_TIME = {
export const UPDATE_TIME: SearchKeyType = {
key: CaseKeyEnum.UPDATE_TIME,
type: 'time-select',
label: '更新时间',
rules: [{ required: true, message: '请选择更新时间!' }],
props: {},
operator: {
value: '',
options: [OPERATORS.BETWEEN, OPERATORS.GT, OPERATORS.LT],
},
};

View File

@ -6,11 +6,11 @@
:is="form.searchKey.type"
v-bind="form.searchKey.props"
v-model="form.searchKey.value"
@change="cate1ChangeHandler"
@change="searchKeyChange"
>
<a-optgroup
v-for="(group, index) of props.selectGroupList"
:key="`${group.label as string + index}`"
v-for="(group, i) of props.selectGroupList"
:key="`${group.label as string}-${i}`"
:label="group.label"
>
<a-option
@ -36,35 +36,46 @@
</component>
</div>
<div class="flex flex-1">
<TimerSelect
v-if="getQueryContentType('time-select')"
:model-value="form.queryContent.value"
v-bind="form.queryContent.props"
:operation-type="form.operatorCondition.value"
@update-time="updateTimeValue"
/>
<component
:is="form.queryContent.type"
v-else
v-bind="form.queryContent.props"
v-model="form.queryContent.value"
@change="filterKeyChange"
>
<template v-if="form.queryContent.type === 'a-select'">
<a-option v-for="opt of form.queryContent.options" :key="opt.value" :value="opt.value">{{
opt.label
}}</a-option>
</template>
<template v-else-if="form.queryContent.type === 'a-select-group'">
<a-select v-model="form.queryContent.value" v-bind="form.queryContent.props">
<a-optgroup v-for="group of form.searchKey.options" :key="group.id" :label="group.label">
<a-option v-for="groupOptions of group.options" :key="groupOptions.id" :value="groupOptions.id">{{
groupOptions.label
<a-form ref="queryContentFormRef" :model="form.queryContent">
<a-form-item
required
field="value"
:rules="form.queryContent.rules || [{ required: true, message: '请输入筛选内容' }]"
hide-label
hide-asterisk
class="mb-0"
>
<TimerSelect
v-if="form.queryContent.type === 'time-select'"
:model-value="form.queryContent.value"
v-bind="form.queryContent.props"
:operation-type="form.operatorCondition.value"
@update-time="updateTimeValue"
/>
<component
:is="form.queryContent.type"
v-else
v-bind="form.queryContent.props"
v-model="form.queryContent.value"
@change="filterKeyChange"
>
<template v-if="form.queryContent.type === 'a-select'">
<a-option v-for="opt of form.queryContent.options" :key="opt.value" :value="opt.value">{{
opt.label
}}</a-option>
</a-optgroup>
</a-select>
</template>
</component>
</template>
<template v-else-if="form.queryContent.type === 'a-select-group'">
<a-select v-model="form.queryContent.value" v-bind="form.queryContent.props">
<a-optgroup v-for="group of form.searchKey.options" :key="group.id" :label="group.label">
<a-option v-for="groupOptions of group.options" :key="groupOptions.id" :value="groupOptions.id">{{
groupOptions.label
}}</a-option>
</a-optgroup>
</a-select>
</template>
</component>
</a-form-item>
</a-form>
<div class="minus"> <slot></slot></div>
</div>
</div>
@ -78,6 +89,8 @@
import { TEST_PLAN_TEST_CASE } from './caseUtils';
import TimerSelect from './time-select.vue';
import { SelectOptionData } from '@arco-design/web-vue';
import type { FormInstance } from '@arco-design/web-vue';
import type { SearchKeyType } from './type';
const { t } = useI18n();
@ -93,20 +106,24 @@
const form = ref({ ...cloneDeep(props.formItem) });
watchEffect(() => {
form.value.queryContent.value = props.formItem.queryContent.value;
form.value = { ...cloneDeep(props.formItem) };
});
//
const cate1ChangeHandler = (value: string) => {
const searchKeyChange = (value: string) => {
const { operatorCondition, queryContent } = form.value;
operatorCondition.value = '';
operatorCondition.options = [];
queryContent.value = '';
// Key
const currentKeysConfig = TEST_PLAN_TEST_CASE.find((item) => item.key === value);
const currentKeysConfig = TEST_PLAN_TEST_CASE.find((item: any) => item.key === value);
if (currentKeysConfig) {
operatorCondition.options = currentKeysConfig.operator.options;
operatorCondition.value = currentKeysConfig.operator.options[0].value;
queryContent.type = currentKeysConfig.type;
if (currentKeysConfig.rules) {
queryContent.rules = currentKeysConfig.rules;
}
}
emits('dataUpdated', form.value, props.index);
};
@ -132,17 +149,22 @@
form.value.queryContent.value = time;
emits('dataUpdated', form.value, props.index);
};
const queryContentFormRef = ref<FormInstance>();
//
const getQueryContentType = (type: string) => {
switch (type) {
//
case 'time-select':
return true;
default:
return false;
}
//
const validateQueryContent = (callBack: (isSuccess: string) => void) => {
queryContentFormRef.value?.validate((errors) => {
if (!errors) {
callBack('ok');
} else {
callBack('no');
}
});
};
defineExpose({
validateQueryContent,
});
</script>
<style scoped></style>

View File

@ -15,6 +15,7 @@
<div v-for="(formItem, index) in formModels" :key="index" class="mb-[8px]">
<a-scrollbar class="overflow-y-auto" :style="{ 'max-height': props.maxHeight || '300px' }">
<QueryFromItem
ref="queryFromRef"
:form-item="formItem"
:form-list="formModels"
:select-group-list="selectGroupList"
@ -162,6 +163,11 @@
type: 'a-input',
value: '',
field: 'condition',
props: {
'max-length': 60,
'show-word-limit': true,
'allow-clear': true,
},
},
};
@ -169,17 +175,37 @@
//
const removeField = (index: number) => {
debugger;
formModels.value.splice(index, 1);
};
//
const allValidateResult = ref<string[]>([]);
const queryFromRef = ref();
//
const addField = () => {
const addField = async () => {
allValidateResult.value = [];
//
await Promise.all(
queryFromRef.value.map((item: any) => {
return new Promise<void>((resolve) => {
item.validateQueryContent(async (isValidated: string) => {
allValidateResult.value.push(isValidated);
resolve();
});
});
})
);
const isValidateSuccess = allValidateResult.value.every((item: string) => item === 'ok');
const ishasCondition = formModels.value.some((item) => !item.searchKey.value);
if (ishasCondition) {
Message.warning(t('searchPanel.selectTip'));
return;
}
formModels.value.push(deaultTemplate);
if (isValidateSuccess && !ishasCondition) {
formModels.value.push(deaultTemplate);
}
};
//
@ -223,4 +249,7 @@
background: rgb(var(--primary-9));
}
}
:deep(.arco-scrollbar-track-direction-vertical .arco-scrollbar-thumb-bar) {
margin: 7px;
}
</style>

View File

@ -4,7 +4,6 @@
v-model:model-value="timeValue"
class="w-[100%]"
show-time
allow-clear
:time-picker-props="{ defaultValue: '00:00:00' }"
format="YYYY-MM-DD HH:mm:ss"
position="br"
@ -15,6 +14,7 @@
v-model:model-value="timeRangeValue"
position="br"
show-time
:allow-clear="false"
class="w-[100%]"
format="YYYY-MM-DD HH:mm"
:time-picker-props="{
@ -26,12 +26,12 @@
<script setup lang="ts">
import { CalendarValue } from '@arco-design/web-vue/es/date-picker/interface';
import { ref, watch } from 'vue';
import { ref, watch, watchEffect } from 'vue';
type PickerType = 'between' | 'gt' | 'lt'; // | |
const props = defineProps<{
modelValue: [] | string; //
modelValue: string[] | string; //
operationType: PickerType; //
}>();
@ -39,12 +39,19 @@
const timeValue = ref<string>('');
const timeRangeValue = ref([]);
const timeRangeValue = ref<string[]>([]);
const changeHandler = (value: Date | string | number | undefined | (CalendarValue | undefined)[] | undefined) => {
emits('updateTime', value);
};
watchEffect(() => {
if (props.operationType === 'between') {
timeRangeValue.value = props.modelValue as string[];
}
timeValue.value = props.modelValue as string;
});
watch(
() => props.modelValue,
(val) => {

View File

@ -1,4 +1,4 @@
import { SelectOptionData } from '@arco-design/web-vue';
import { SelectOptionData, FieldRule } from '@arco-design/web-vue';
export interface ConditionOptions {
id: string;
@ -17,8 +17,8 @@ export interface QueryField {
type: 'a-select' | 'a-input' | 'a-input-number' | 'time-select' | 'a-tree-select';
value: string;
field: string;
rules?: FieldRule[];
props?: {
placeholder: string;
[key: string]: string | number | boolean;
};
options?: SelectOptionData[];
@ -29,3 +29,23 @@ export interface QueryTemplate {
operatorCondition: QueryField;
queryContent: QueryField;
}
export interface OptionsType {
label: string;
value: string;
}
export interface OperatorValue {
value: string; // 如果未设置value初始值则value初始值为options[0]
options: OptionsType[]; // 运算符选项
}
export interface SearchKeyType {
key: string; // 对应字段key
type: string; // Vue控件名称
label: string; // 显示名称
rules?: FieldRule[];
props?: {
[key: string]: string | number | boolean;
};
operator: OperatorValue;
}

View File

@ -2,9 +2,9 @@
<div class="page-header h-[34px]">
<div class="text-[var(--color-text-1)]"
>{{ t('featureTest.featureCase.allCase') }}
<span class="text-[var(--color-text-4)]"> ({{ allCaseCount }}</span></div
<span class="text-[var(--color-text-4)]"> ({{ allCaseCount }})</span></div
>
<div>
<div class="flex w-[80%] items-center justify-end">
<a-select class="w-[240px]" :placeholder="t('featureTest.featureCase.versionPlaceholder')">
<a-option v-for="version of versionOptions" :key="version.id" :value="version.id">{{ version.name }}</a-option>
</a-select>
@ -28,7 +28,7 @@
</MsTag>
<a-radio-group v-model:model-value="showType" type="button" class="file-show-type ml-[4px]">
<a-radio value="list" class="show-type-icon p-[2px]"><MsIcon type="icon-icon_view-list_outlined" /></a-radio>
<a-radio value="xmind" class="show-type-icon p-[2px]"><icon-mind-mapping /></a-radio>
<a-radio value="xmind" class="show-type-icon p-[2px]"><MsIcon type="icon-icon_mindnote_outlined" /></a-radio>
</a-radio-group>
</div>
</div>