mirror of
https://gitee.com/fit2cloud-feizhiyun/MeterSphere.git
synced 2024-12-04 13:09:28 +08:00
feat(测试用例): 测试用例支持高级搜索&修改高级搜索交互
This commit is contained in:
parent
73a011985c
commit
543909c358
@ -245,7 +245,7 @@ export function getDefaultLocale() {
|
|||||||
|
|
||||||
// 视图列表
|
// 视图列表
|
||||||
export function getViewList(viewType: string, scopeId: string) {
|
export function getViewList(viewType: string, scopeId: string) {
|
||||||
return MSR.get<ViewList>({ url: `/user-view/${viewType}/grouped/list`, params: scopeId });
|
return MSR.get<ViewList>({ url: `/user-view/${viewType}/grouped/list`, params: { scopeId } });
|
||||||
}
|
}
|
||||||
// 视图详情
|
// 视图详情
|
||||||
export function getViewDetail(viewType: string, id: string) {
|
export function getViewDetail(viewType: string, id: string) {
|
||||||
@ -261,5 +261,5 @@ export function addView(viewType: string, data: ViewParams) {
|
|||||||
}
|
}
|
||||||
// 删除视图
|
// 删除视图
|
||||||
export function deleteView(viewType: string, id: string) {
|
export function deleteView(viewType: string, id: string) {
|
||||||
return MSR.post({ url: `/user-view/${viewType}/delete/${id}` });
|
return MSR.get({ url: `/user-view/${viewType}/delete/${id}` });
|
||||||
}
|
}
|
||||||
|
@ -302,7 +302,8 @@
|
|||||||
.arco-input-tag-disabled,
|
.arco-input-tag-disabled,
|
||||||
.arco-input-disabled,
|
.arco-input-disabled,
|
||||||
.arco-textarea-disabled,
|
.arco-textarea-disabled,
|
||||||
.arco-select-view-disabled
|
.arco-select-view-disabled,
|
||||||
|
.arco-picker-disabled
|
||||||
):hover {
|
):hover {
|
||||||
border-color: rgb(var(--primary-5)) !important;
|
border-color: rgb(var(--primary-5)) !important;
|
||||||
background-color: white;
|
background-color: white;
|
||||||
@ -314,7 +315,8 @@
|
|||||||
.arco-input-tag-disabled,
|
.arco-input-tag-disabled,
|
||||||
.arco-select-view-disabled,
|
.arco-select-view-disabled,
|
||||||
.arco-textarea-disabled,
|
.arco-textarea-disabled,
|
||||||
.arco-input-disabled {
|
.arco-input-disabled,
|
||||||
|
.arco-picker-disabled {
|
||||||
border-color: var(--color-text-n9) !important;
|
border-color: var(--color-text-n9) !important;
|
||||||
background-color: var(--color-text-n9) !important;
|
background-color: var(--color-text-n9) !important;
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
class="hidden-item"
|
class="hidden-item"
|
||||||
hide-asterisk
|
hide-asterisk
|
||||||
field="name"
|
field="name"
|
||||||
:validate-trigger="['blur', 'input']"
|
:validate-trigger="['change', 'input']"
|
||||||
:rules="[{ required: true, message: t('advanceFilter.viewNameRequired') }, { validator: validateName }]"
|
:rules="[{ required: true, message: t('advanceFilter.viewNameRequired') }, { validator: validateName }]"
|
||||||
>
|
>
|
||||||
<a-input
|
<a-input
|
||||||
@ -60,7 +60,16 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function validateForm(cb: () => void) {
|
||||||
|
formRef.value?.validate(async (errors) => {
|
||||||
|
if (!errors) {
|
||||||
|
cb();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
inputFocus,
|
inputFocus,
|
||||||
|
validateForm,
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -2,17 +2,18 @@
|
|||||||
<MsDrawer v-model:visible="visible" :mask="false" :width="600">
|
<MsDrawer v-model:visible="visible" :mask="false" :width="600">
|
||||||
<template #title>
|
<template #title>
|
||||||
<ViewNameInput
|
<ViewNameInput
|
||||||
v-show="isShowNameInput"
|
v-if="isShowNameInput"
|
||||||
ref="viewNameInputRef"
|
ref="viewNameInputRef"
|
||||||
v-model:form="formModel"
|
v-model:form="formModel"
|
||||||
:all-names="allViewNames"
|
:all-names="allViewNames.filter((name) => name !== savedFormModel.name)"
|
||||||
@handle-submit="isShowNameInput = false"
|
@handle-submit="isShowNameInput = false"
|
||||||
/>
|
/>
|
||||||
<div v-show="!isShowNameInput" class="flex flex-1 items-center gap-[8px] overflow-hidden">
|
<div v-else class="flex flex-1 items-center gap-[8px] overflow-hidden">
|
||||||
<a-tooltip :content="formModel.name">
|
<a-tooltip :content="formModel.name">
|
||||||
<div class="one-line-text"> {{ formModel.name }}</div>
|
<div class="one-line-text"> {{ formModel.name }}</div>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
<MsIcon
|
<MsIcon
|
||||||
|
v-if="formModel?.internalViewKey !== 'ALL_DATA'"
|
||||||
type="icon-icon_edit_outlined"
|
type="icon-icon_edit_outlined"
|
||||||
class="min-w-[16px] cursor-pointer hover:text-[rgb(var(--primary-5))]"
|
class="min-w-[16px] cursor-pointer hover:text-[rgb(var(--primary-5))]"
|
||||||
@click="showNameInput"
|
@click="showNameInput"
|
||||||
@ -92,6 +93,18 @@
|
|||||||
:max-length="255"
|
:max-length="255"
|
||||||
:placeholder="t('common.pleaseInput')"
|
:placeholder="t('common.pleaseInput')"
|
||||||
/>
|
/>
|
||||||
|
<MsSelect
|
||||||
|
v-else-if="item.type === FilterType.MEMBER"
|
||||||
|
v-model:model-value="item.value"
|
||||||
|
allow-clear
|
||||||
|
allow-search
|
||||||
|
:placeholder="t('common.pleaseSelect')"
|
||||||
|
:disabled="isValueDisabled(item)"
|
||||||
|
:options="props.memberOptions"
|
||||||
|
multiple
|
||||||
|
:search-keys="['label']"
|
||||||
|
:max-tag-count="1"
|
||||||
|
/>
|
||||||
<MsSelect
|
<MsSelect
|
||||||
v-else-if="item.type === FilterType.SELECT"
|
v-else-if="item.type === FilterType.SELECT"
|
||||||
v-model:model-value="item.value"
|
v-model:model-value="item.value"
|
||||||
@ -180,12 +193,13 @@
|
|||||||
{{ t('advanceFilter.addCondition') }}
|
{{ t('advanceFilter.addCondition') }}
|
||||||
</MsButton>
|
</MsButton>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<div v-show="!isSaveAsView" class="flex items-center gap-[8px]">
|
<div v-if="!isSaveAsView" class="flex items-center gap-[8px]">
|
||||||
<a-button type="primary" @click="handleFilter">{{ t('common.filter') }}</a-button>
|
<a-button type="primary" @click="handleFilter">{{ t('common.filter') }}</a-button>
|
||||||
<a-button class="mr-[16px]" @click="handleReset">{{ t('common.reset') }}</a-button>
|
<a-button class="mr-[16px]" @click="handleReset">{{ t('common.reset') }}</a-button>
|
||||||
<MsButton
|
<MsButton
|
||||||
v-if="formModel?.internalViewKey !== 'ALL_DATA'"
|
v-if="formModel?.internalViewKey !== 'ALL_DATA'"
|
||||||
type="text"
|
type="text"
|
||||||
|
:loading="saveLoading"
|
||||||
class="!text-[var(--color-text-1)]"
|
class="!text-[var(--color-text-1)]"
|
||||||
@click="handleSaveView"
|
@click="handleSaveView"
|
||||||
>
|
>
|
||||||
@ -195,14 +209,14 @@
|
|||||||
{{ t('advanceFilter.saveAsView') }}
|
{{ t('advanceFilter.saveAsView') }}
|
||||||
</MsButton>
|
</MsButton>
|
||||||
</div>
|
</div>
|
||||||
<div v-show="isSaveAsView" class="flex items-center gap-[8px]">
|
<div v-else class="flex items-center gap-[8px]">
|
||||||
<ViewNameInput
|
<ViewNameInput
|
||||||
ref="saveAsViewNameInputRef"
|
ref="saveAsViewNameInputRef"
|
||||||
v-model:form="saveAsViewForm"
|
v-model:form="saveAsViewForm"
|
||||||
class="w-[240px]"
|
class="w-[240px]"
|
||||||
:all-names="allViewNames"
|
:all-names="allViewNames"
|
||||||
/>
|
/>
|
||||||
<a-button type="primary" @click="handleAddView">{{ t('common.save') }}</a-button>
|
<a-button type="primary" :loading="addLoading" @click="handleAddView">{{ t('common.save') }}</a-button>
|
||||||
<a-button @click="handleCancelSaveAsView">{{ t('common.cancel') }}</a-button>
|
<a-button @click="handleCancelSaveAsView">{{ t('common.cancel') }}</a-button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -221,6 +235,7 @@
|
|||||||
|
|
||||||
import { addView, getViewDetail, updateView } from '@/api/modules/user/index';
|
import { addView, getViewDetail, updateView } from '@/api/modules/user/index';
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
|
import useAppStore from '@/store/modules/app';
|
||||||
|
|
||||||
import { SelectValue } from '@/models/projectManagement/menuManagement';
|
import { SelectValue } from '@/models/projectManagement/menuManagement';
|
||||||
import { FilterType, OperatorEnum, ViewTypeEnum } from '@/enums/advancedFilterEnum';
|
import { FilterType, OperatorEnum, ViewTypeEnum } from '@/enums/advancedFilterEnum';
|
||||||
@ -234,6 +249,8 @@
|
|||||||
viewType: ViewTypeEnum;
|
viewType: ViewTypeEnum;
|
||||||
currentView: string; // 当前视图
|
currentView: string; // 当前视图
|
||||||
allViewNames: string[];
|
allViewNames: string[];
|
||||||
|
canNotAddView: boolean;
|
||||||
|
memberOptions: { label: string; value: string }[];
|
||||||
}>();
|
}>();
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(e: 'handleFilter', value: FilterResult): void;
|
(e: 'handleFilter', value: FilterResult): void;
|
||||||
@ -242,6 +259,7 @@
|
|||||||
const visible = defineModel<boolean>('visible', { required: true });
|
const visible = defineModel<boolean>('visible', { required: true });
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
const appStore = useAppStore();
|
||||||
|
|
||||||
const defaultFormModel: FilterForm = {
|
const defaultFormModel: FilterForm = {
|
||||||
name: '',
|
name: '',
|
||||||
@ -361,6 +379,7 @@
|
|||||||
// 重置
|
// 重置
|
||||||
function handleReset() {
|
function handleReset() {
|
||||||
formModel.value = cloneDeep(savedFormModel.value);
|
formModel.value = cloneDeep(savedFormModel.value);
|
||||||
|
isShowNameInput.value = false;
|
||||||
}
|
}
|
||||||
// 过滤
|
// 过滤
|
||||||
function handleFilter() {
|
function handleFilter() {
|
||||||
@ -378,29 +397,49 @@
|
|||||||
handleFilter();
|
handleFilter();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
watch(
|
||||||
|
() => visible.value,
|
||||||
|
async (val) => {
|
||||||
|
// 新建视图关闭后重新获取数据
|
||||||
|
if (!val && formModel.value?.id !== props.currentView) {
|
||||||
|
await getUserViewDetail(props.currentView);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
const isSaveAsView = ref(false);
|
|
||||||
const saveAsViewForm = ref({ name: '' });
|
|
||||||
const saveAsViewNameInputRef = ref<InstanceType<typeof ViewNameInput>>();
|
|
||||||
// 数据改为新建视图的空数据
|
// 数据改为新建视图的空数据
|
||||||
function resetToNewViewForm() {
|
function resetToNewViewForm() {
|
||||||
// TODO lmy 命名递增数字
|
// 命名递增数字
|
||||||
|
let name = '';
|
||||||
|
for (let i = 1; i <= 10; i++) {
|
||||||
|
const defaultName = `${t('advanceFilter.unnamedView')}${String(i).padStart(3, '0')}`;
|
||||||
|
if (!props.allViewNames.includes(defaultName)) {
|
||||||
|
name = defaultName;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
formModel.value = {
|
formModel.value = {
|
||||||
...cloneDeep(defaultFormModel),
|
...cloneDeep(defaultFormModel),
|
||||||
name: '未命名视图001',
|
name,
|
||||||
};
|
};
|
||||||
savedFormModel.value = cloneDeep(formModel.value);
|
savedFormModel.value = cloneDeep(formModel.value);
|
||||||
}
|
}
|
||||||
// 保存视图
|
// 保存视图
|
||||||
function handleSaveView() {
|
const saveLoading = ref(false);
|
||||||
// TODO lmy 校验名称
|
function realSaveView() {
|
||||||
formRef.value?.validate(async (errors) => {
|
formRef.value?.validate(async (errors) => {
|
||||||
if (!errors) {
|
if (!errors) {
|
||||||
try {
|
try {
|
||||||
|
saveLoading.value = true;
|
||||||
if (formModel.value.id) {
|
if (formModel.value.id) {
|
||||||
await updateView(props.viewType, { ...getParams(), name: formModel.value.name, id: formModel.value.id });
|
await updateView(props.viewType, { ...getParams(), name: formModel.value.name, id: formModel.value.id });
|
||||||
} else {
|
} else {
|
||||||
await addView(props.viewType, { ...getParams(), name: formModel.value.name, id: formModel.value.id });
|
await addView(props.viewType, {
|
||||||
|
...getParams(),
|
||||||
|
scopeId: appStore.currentProjectId,
|
||||||
|
name: formModel.value.name,
|
||||||
|
id: formModel.value.id,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
Message.success(t('common.saveSuccess'));
|
Message.success(t('common.saveSuccess'));
|
||||||
savedFormModel.value = cloneDeep(formModel.value);
|
savedFormModel.value = cloneDeep(formModel.value);
|
||||||
@ -408,15 +447,34 @@
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.log(error);
|
console.log(error);
|
||||||
|
} finally {
|
||||||
|
saveLoading.value = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
function handleSaveView() {
|
||||||
|
if (viewNameInputRef.value) {
|
||||||
|
viewNameInputRef.value?.validateForm(realSaveView);
|
||||||
|
} else {
|
||||||
|
realSaveView();
|
||||||
|
}
|
||||||
|
}
|
||||||
// 开启另存为视图模式
|
// 开启另存为视图模式
|
||||||
|
const isSaveAsView = ref(false);
|
||||||
|
const saveAsViewForm = ref({ name: '' });
|
||||||
|
const saveAsViewNameInputRef = ref<InstanceType<typeof ViewNameInput>>();
|
||||||
function handleToSaveAs() {
|
function handleToSaveAs() {
|
||||||
|
if (props.canNotAddView) {
|
||||||
|
Message.warning(t('advanceFilter.maxViewTip'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
formRef.value?.validate((errors) => {
|
formRef.value?.validate((errors) => {
|
||||||
if (!errors) {
|
if (!errors) {
|
||||||
isSaveAsView.value = true;
|
isSaveAsView.value = true;
|
||||||
|
nextTick(() => {
|
||||||
|
saveAsViewNameInputRef.value?.inputFocus();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -426,17 +484,29 @@
|
|||||||
saveAsViewForm.value.name = '';
|
saveAsViewForm.value.name = '';
|
||||||
}
|
}
|
||||||
// 新增视图
|
// 新增视图
|
||||||
async function handleAddView() {
|
const addLoading = ref(false);
|
||||||
// TODO lmy 校验名称 saveAsViewNameInputRef
|
async function realAddView() {
|
||||||
try {
|
try {
|
||||||
await addView(props.viewType, { ...getParams(), name: formModel.value.name, id: formModel.value.id });
|
addLoading.value = true;
|
||||||
|
await addView(props.viewType, {
|
||||||
|
...getParams(),
|
||||||
|
scopeId: appStore.currentProjectId,
|
||||||
|
name: saveAsViewForm.value.name,
|
||||||
|
id: formModel.value.id,
|
||||||
|
});
|
||||||
Message.success(t('common.saveSuccess'));
|
Message.success(t('common.saveSuccess'));
|
||||||
emit('refreshViewList');
|
emit('refreshViewList');
|
||||||
|
handleCancelSaveAsView();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.log(error);
|
console.log(error);
|
||||||
|
} finally {
|
||||||
|
addLoading.value = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
async function handleAddView() {
|
||||||
|
saveAsViewNameInputRef.value?.validateForm(realAddView);
|
||||||
|
}
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
resetToNewViewForm,
|
resetToNewViewForm,
|
||||||
|
@ -38,6 +38,7 @@ export const operatorOptionsMap: Record<string, { value: string; label: string }
|
|||||||
[FilterType.RADIO]: COMMON_SELECTION_OPERATORS,
|
[FilterType.RADIO]: COMMON_SELECTION_OPERATORS,
|
||||||
[FilterType.CHECKBOX]: COMMON_SELECTION_OPERATORS,
|
[FilterType.CHECKBOX]: COMMON_SELECTION_OPERATORS,
|
||||||
[FilterType.SELECT]: COMMON_SELECTION_OPERATORS,
|
[FilterType.SELECT]: 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, EQUAL, EMPTY, NOT_EMPTY],
|
||||||
|
@ -34,8 +34,9 @@
|
|||||||
<a-select
|
<a-select
|
||||||
v-if="props.viewType"
|
v-if="props.viewType"
|
||||||
v-model:model-value="currentView"
|
v-model:model-value="currentView"
|
||||||
|
:loading="viewListLoading"
|
||||||
:trigger-props="{ contentClass: 'view-select-trigger' }"
|
:trigger-props="{ contentClass: 'view-select-trigger' }"
|
||||||
class="w-[160px]"
|
class="w-[180px]"
|
||||||
show-footer-on-empty
|
show-footer-on-empty
|
||||||
>
|
>
|
||||||
<template #prefix> {{ t('advanceFilter.view') }} </template>
|
<template #prefix> {{ t('advanceFilter.view') }} </template>
|
||||||
@ -45,25 +46,34 @@
|
|||||||
</a-option>
|
</a-option>
|
||||||
</a-optgroup>
|
</a-optgroup>
|
||||||
<a-optgroup :label="t('advanceFilter.myView')">
|
<a-optgroup :label="t('advanceFilter.myView')">
|
||||||
<a-option v-for="item in customViews" :key="item.id" :value="item.id">
|
<template v-for="item in customViews" :key="item.id">
|
||||||
{{ item.name }}
|
<a-option v-show="!item.isShowNameInput" :value="item.id">
|
||||||
<div class="flex">
|
<div>{{ item.name }}</div>
|
||||||
<a-tooltip :content="t('common.rename')">
|
<div class="select-extra flex">
|
||||||
<MsButton type="text" status="secondary" class="!mr-[4px]" @click.stop="handleRenameView(item)">
|
<a-tooltip :content="t('common.rename')">
|
||||||
<MsIcon type="icon-icon_edit_outlined" class="hover:text-[rgb(var(--primary-4))]" size="12" />
|
<MsButton type="text" status="secondary" class="!mr-[4px]" @click="handleToRenameView(item)">
|
||||||
</MsButton>
|
<MsIcon type="icon-icon_edit_outlined" class="hover:text-[rgb(var(--primary-4))]" size="12" />
|
||||||
</a-tooltip>
|
</MsButton>
|
||||||
<a-tooltip :content="t('advanceFilter.deleteView')">
|
</a-tooltip>
|
||||||
<MsButton type="text" status="secondary" @click.stop="handleDeleteView(item)">
|
<a-tooltip :content="t('advanceFilter.deleteView')">
|
||||||
<MsIcon
|
<MsButton type="text" :disabled="deleteLoading" status="secondary" @click="handleDeleteView(item)">
|
||||||
type="icon-icon_delete-trash_outlined1"
|
<MsIcon
|
||||||
class="hover:text-[rgb(var(--primary-4))]"
|
type="icon-icon_delete-trash_outlined1"
|
||||||
size="12"
|
class="hover:text-[rgb(var(--primary-4))]"
|
||||||
/>
|
size="12"
|
||||||
</MsButton>
|
/>
|
||||||
</a-tooltip>
|
</MsButton>
|
||||||
</div>
|
</a-tooltip>
|
||||||
</a-option>
|
</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>
|
</a-optgroup>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<div class="flex cursor-pointer items-center gap-[8px]" @click="toNewView">
|
<div class="flex cursor-pointer items-center gap-[8px]" @click="toNewView">
|
||||||
@ -111,6 +121,8 @@
|
|||||||
:all-view-names="allViewNames"
|
:all-view-names="allViewNames"
|
||||||
:config-list="props.filterConfigList"
|
:config-list="props.filterConfigList"
|
||||||
:custom-list="props.customFieldsConfigList"
|
:custom-list="props.customFieldsConfigList"
|
||||||
|
:can-not-add-view="canNotAddView"
|
||||||
|
:member-options="memberOptions"
|
||||||
@handle-filter="handleFilter"
|
@handle-filter="handleFilter"
|
||||||
@refresh-view-list="getUserViewList"
|
@refresh-view-list="getUserViewList"
|
||||||
/>
|
/>
|
||||||
@ -122,9 +134,11 @@
|
|||||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||||
import MsIcon from '@/components/pure/ms-icon-font/index.vue';
|
import MsIcon from '@/components/pure/ms-icon-font/index.vue';
|
||||||
import MsTag from '../ms-tag/ms-tag.vue';
|
import MsTag from '../ms-tag/ms-tag.vue';
|
||||||
|
import ViewNameInput from './components/viewNameInput.vue';
|
||||||
import FilterDrawer from './filterDrawer.vue';
|
import FilterDrawer from './filterDrawer.vue';
|
||||||
|
|
||||||
import { deleteView, getViewList } from '@/api/modules/user/index';
|
import { getProjectOptions } from '@/api/modules/project-management/projectMember';
|
||||||
|
import { deleteView, getViewList, updateView } from '@/api/modules/user/index';
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
import useAppStore from '@/store/modules/app';
|
import useAppStore from '@/store/modules/app';
|
||||||
|
|
||||||
@ -159,42 +173,94 @@
|
|||||||
const currentView = ref(''); // 当前视图
|
const currentView = ref(''); // 当前视图
|
||||||
const internalViews = ref<ViewItem[]>([]);
|
const internalViews = ref<ViewItem[]>([]);
|
||||||
const customViews = ref<ViewItem[]>([]);
|
const customViews = ref<ViewItem[]>([]);
|
||||||
|
const viewListLoading = ref(false);
|
||||||
const allViewNames = computed(() => [...internalViews.value, ...customViews.value].map((item) => item.name));
|
const allViewNames = computed(() => [...internalViews.value, ...customViews.value].map((item) => item.name));
|
||||||
|
const canNotAddView = computed(() => customViews.value.length >= 10);
|
||||||
async function getUserViewList() {
|
async function getUserViewList() {
|
||||||
try {
|
try {
|
||||||
|
viewListLoading.value = true;
|
||||||
const res = await getViewList(props.viewType as ViewTypeEnum, appStore.currentProjectId);
|
const res = await getViewList(props.viewType as ViewTypeEnum, appStore.currentProjectId);
|
||||||
internalViews.value = res.internalViews;
|
internalViews.value = res.internalViews;
|
||||||
customViews.value = res.customViews;
|
customViews.value = res.customViews;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.log(error);
|
console.log(error);
|
||||||
|
} finally {
|
||||||
|
viewListLoading.value = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const memberOptions = ref<{ label: string; value: string }[]>([]);
|
||||||
|
async function getMemberOptions() {
|
||||||
|
const res = await getProjectOptions(appStore.currentProjectId);
|
||||||
|
memberOptions.value = [{ name: t('common.currentUser'), id: 'CURRENT_USER' }, ...res].map((e: any) => ({
|
||||||
|
label: e.name,
|
||||||
|
value: e.id,
|
||||||
|
}));
|
||||||
|
}
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await getUserViewList();
|
if (props.viewType) {
|
||||||
currentView.value = internalViews.value[0].id;
|
getMemberOptions();
|
||||||
|
await getUserViewList();
|
||||||
|
currentView.value = internalViews.value[0]?.id;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const filterDrawerRef = ref<InstanceType<typeof FilterDrawer>>();
|
const filterDrawerRef = ref<InstanceType<typeof FilterDrawer>>();
|
||||||
function toNewView() {
|
function toNewView() {
|
||||||
|
if (canNotAddView.value) {
|
||||||
|
Message.warning(t('advanceFilter.maxViewTip'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
visible.value = true;
|
visible.value = true;
|
||||||
filterDrawerRef.value?.resetToNewViewForm();
|
filterDrawerRef.value?.resetToNewViewForm();
|
||||||
}
|
}
|
||||||
function handleRenameView(item: ViewItem) {
|
|
||||||
// TODO lmy 重命名
|
type refItem = Element | ComponentPublicInstance | null;
|
||||||
|
const viewNameInputRefMap: Record<string, any> = {};
|
||||||
|
function setNameInputRefMap(el: refItem, item: ViewItem) {
|
||||||
|
if (el) {
|
||||||
|
viewNameInputRefMap[`${item.id}`] = el;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
async function handleDeleteView(item: ViewItem) {
|
const formModel = ref({ name: '', id: '' });
|
||||||
|
function handleToRenameView(item: ViewItem) {
|
||||||
|
formModel.value.id = item.id;
|
||||||
|
formModel.value.name = item.name;
|
||||||
|
item.isShowNameInput = true;
|
||||||
|
nextTick(() => {
|
||||||
|
viewNameInputRefMap[item.id]?.inputFocus();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
async function handleRenameView() {
|
||||||
try {
|
try {
|
||||||
await deleteView(item.viewType, item.id);
|
await updateView(props.viewType as string, { name: formModel.value.name, id: formModel.value.id });
|
||||||
Message.success(t('common.deleteSuccess'));
|
Message.success(t('common.saveSuccess'));
|
||||||
getUserViewList();
|
getUserViewList();
|
||||||
currentView.value = internalViews.value[0].id;
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.log(error);
|
console.log(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 删除试图
|
||||||
|
const deleteLoading = ref(false);
|
||||||
|
async function handleDeleteView(item: ViewItem) {
|
||||||
|
try {
|
||||||
|
deleteLoading.value = true;
|
||||||
|
await deleteView(props.viewType as string, item.id);
|
||||||
|
Message.success(t('common.deleteSuccess'));
|
||||||
|
await getUserViewList();
|
||||||
|
if (item.id === currentView.value) {
|
||||||
|
currentView.value = internalViews.value[0].id;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(error);
|
||||||
|
} finally {
|
||||||
|
deleteLoading.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const isAdvancedSearchMode = ref(false);
|
const isAdvancedSearchMode = ref(false);
|
||||||
const handleFilter = (filter: FilterResult) => {
|
const handleFilter = (filter: FilterResult) => {
|
||||||
keyword.value = '';
|
keyword.value = '';
|
||||||
@ -242,6 +308,14 @@
|
|||||||
.arco-select-option-content {
|
.arco-select-option-content {
|
||||||
@apply flex w-full items-center justify-between;
|
@apply flex w-full items-center justify-between;
|
||||||
}
|
}
|
||||||
|
.select-extra {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
.arco-select-option:hover {
|
||||||
|
.select-extra {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
}
|
||||||
.arco-select-dropdown-list-wrapper {
|
.arco-select-dropdown-list-wrapper {
|
||||||
max-height: 255px;
|
max-height: 255px;
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ export default {
|
|||||||
'advanceFilter.operator.length.le': 'Length less than or equal to',
|
'advanceFilter.operator.length.le': 'Length less than or equal to',
|
||||||
|
|
||||||
'advanceFilter.view': 'View',
|
'advanceFilter.view': 'View',
|
||||||
|
'advanceFilter.unnamedView': 'Unnamed View',
|
||||||
'advanceFilter.systemView': 'System view',
|
'advanceFilter.systemView': 'System view',
|
||||||
'advanceFilter.myView': 'My view',
|
'advanceFilter.myView': 'My view',
|
||||||
'advanceFilter.newView': 'New view',
|
'advanceFilter.newView': 'New view',
|
||||||
@ -40,4 +41,5 @@ export default {
|
|||||||
'advanceFilter.conditionRequired': 'Query condition cannot be empty',
|
'advanceFilter.conditionRequired': 'Query condition cannot be empty',
|
||||||
'advanceFilter.filterContentRequired': 'Filter content cannot be empty',
|
'advanceFilter.filterContentRequired': 'Filter content cannot be empty',
|
||||||
'advanceFilter.filterTip': 'Filter mode, module filtering can only be operated in the current filter',
|
'advanceFilter.filterTip': 'Filter mode, module filtering can only be operated in the current filter',
|
||||||
|
'advanceFilter.maxViewTip': 'Up to 10 views can be added',
|
||||||
};
|
};
|
||||||
|
@ -23,6 +23,7 @@ export default {
|
|||||||
'advanceFilter.operator.length.le': '长度小于等于',
|
'advanceFilter.operator.length.le': '长度小于等于',
|
||||||
|
|
||||||
'advanceFilter.view': '视图',
|
'advanceFilter.view': '视图',
|
||||||
|
'advanceFilter.unnamedView': '未命名视图',
|
||||||
'advanceFilter.systemView': '系统视图',
|
'advanceFilter.systemView': '系统视图',
|
||||||
'advanceFilter.myView': '我的视图',
|
'advanceFilter.myView': '我的视图',
|
||||||
'advanceFilter.newView': '新建视图',
|
'advanceFilter.newView': '新建视图',
|
||||||
@ -40,4 +41,5 @@ export default {
|
|||||||
'advanceFilter.conditionRequired': '查询条件不能为空',
|
'advanceFilter.conditionRequired': '查询条件不能为空',
|
||||||
'advanceFilter.filterContentRequired': '筛选内容不能为空',
|
'advanceFilter.filterContentRequired': '筛选内容不能为空',
|
||||||
'advanceFilter.filterTip': '筛选模式,模块过滤仅可在当前过滤器中操作',
|
'advanceFilter.filterTip': '筛选模式,模块过滤仅可在当前过滤器中操作',
|
||||||
|
'advanceFilter.maxViewTip': '最多可添加 10 个视图',
|
||||||
};
|
};
|
||||||
|
@ -52,7 +52,7 @@ export interface ConditionsItem extends CombineItem {
|
|||||||
|
|
||||||
export interface FilterResult {
|
export interface FilterResult {
|
||||||
// 匹配模式 所有/任一
|
// 匹配模式 所有/任一
|
||||||
searchMode: AccordBelowType;
|
searchMode?: AccordBelowType;
|
||||||
// 高级搜索
|
// 高级搜索
|
||||||
conditions?: ConditionsItem[];
|
conditions?: ConditionsItem[];
|
||||||
combine?: any; // TODO lmy 此为防报错占位 所有高级筛选都完成后 删除这一行
|
combine?: any; // TODO lmy 此为防报错占位 所有高级筛选都完成后 删除这一行
|
||||||
@ -69,6 +69,7 @@ export interface ViewItem {
|
|||||||
pos?: number; // 自定义排序
|
pos?: number; // 自定义排序
|
||||||
createTime?: number;
|
createTime?: number;
|
||||||
updateTime?: number;
|
updateTime?: number;
|
||||||
|
isShowNameInput?: boolean;
|
||||||
}
|
}
|
||||||
export interface ViewList {
|
export interface ViewList {
|
||||||
internalViews: ViewItem[];
|
internalViews: ViewItem[];
|
||||||
|
@ -75,6 +75,11 @@
|
|||||||
background-color: var(--color-text-n8);
|
background-color: var(--color-text-n8);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.ms-button-text {
|
||||||
|
@apply p-0;
|
||||||
|
|
||||||
|
color: rgb(var(--primary-5));
|
||||||
|
}
|
||||||
.ms-button--secondary {
|
.ms-button--secondary {
|
||||||
color: var(--color-text-2);
|
color: var(--color-text-2);
|
||||||
&:not(.ms-button-text, .ms-button--disabled):hover {
|
&:not(.ms-button-text, .ms-button--disabled):hover {
|
||||||
@ -106,9 +111,4 @@
|
|||||||
padding: 0 2px;
|
padding: 0 2px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
.ms-button-text {
|
|
||||||
@apply p-0;
|
|
||||||
|
|
||||||
color: rgb(var(--primary-5));
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
@ -18,6 +18,7 @@ export enum FilterType {
|
|||||||
INPUT = 'Input',
|
INPUT = 'Input',
|
||||||
NUMBER = 'Number',
|
NUMBER = 'Number',
|
||||||
SELECT = 'Select',
|
SELECT = 'Select',
|
||||||
|
MEMBER = 'Member',
|
||||||
DATE_PICKER = 'DatePicker',
|
DATE_PICKER = 'DatePicker',
|
||||||
TAGS_INPUT = 'TagsInput',
|
TAGS_INPUT = 'TagsInput',
|
||||||
TREE_SELECT = 'TreeSelect',
|
TREE_SELECT = 'TreeSelect',
|
||||||
|
@ -208,4 +208,5 @@ export default {
|
|||||||
'common.cutSuccess': 'Cut successfully',
|
'common.cutSuccess': 'Cut successfully',
|
||||||
'common.copySuccessToClipboard': 'Copied to clipboard',
|
'common.copySuccessToClipboard': 'Copied to clipboard',
|
||||||
'common.casePriority': 'Case Priority',
|
'common.casePriority': 'Case Priority',
|
||||||
|
'common.currentUser': 'Current user',
|
||||||
};
|
};
|
||||||
|
@ -208,4 +208,5 @@ export default {
|
|||||||
'common.cutSuccess': '剪切成功',
|
'common.cutSuccess': '剪切成功',
|
||||||
'common.copySuccessToClipboard': '已复制到剪切板',
|
'common.copySuccessToClipboard': '已复制到剪切板',
|
||||||
'common.casePriority': '用例等级',
|
'common.casePriority': '用例等级',
|
||||||
|
'common.currentUser': '当前用户',
|
||||||
};
|
};
|
||||||
|
@ -412,7 +412,6 @@
|
|||||||
} from '@/api/modules/case-management/featureCase';
|
} from '@/api/modules/case-management/featureCase';
|
||||||
import { getSocket } from '@/api/modules/project-management/commonScript';
|
import { getSocket } from '@/api/modules/project-management/commonScript';
|
||||||
import { getCaseRelatedInfo } from '@/api/modules/project-management/menuManagement';
|
import { getCaseRelatedInfo } from '@/api/modules/project-management/menuManagement';
|
||||||
import { getProjectOptions } from '@/api/modules/project-management/projectMember';
|
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
import useModal from '@/hooks/useModal';
|
import useModal from '@/hooks/useModal';
|
||||||
import { useAppStore, useTableStore } from '@/store';
|
import { useAppStore, useTableStore } from '@/store';
|
||||||
@ -774,7 +773,6 @@
|
|||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
const memberOptions = ref<{ label: string; value: string }[]>([]);
|
|
||||||
const filterConfigList = computed<FilterFormItem[]>(() => [
|
const filterConfigList = computed<FilterFormItem[]>(() => [
|
||||||
{
|
{
|
||||||
title: 'caseManagement.featureCase.tableColumnID',
|
title: 'caseManagement.featureCase.tableColumnID',
|
||||||
@ -787,7 +785,7 @@
|
|||||||
type: FilterType.INPUT,
|
type: FilterType.INPUT,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'caseManagement.featureCase.tableColumnModule',
|
title: 'common.belongModule',
|
||||||
dataIndex: 'moduleId',
|
dataIndex: 'moduleId',
|
||||||
type: FilterType.TREE_SELECT,
|
type: FilterType.TREE_SELECT,
|
||||||
treeSelectData: caseTreeData.value,
|
treeSelectData: caseTreeData.value,
|
||||||
@ -800,44 +798,59 @@
|
|||||||
multiple: true,
|
multiple: true,
|
||||||
treeCheckable: true,
|
treeCheckable: true,
|
||||||
treeCheckStrictly: true,
|
treeCheckStrictly: true,
|
||||||
maxTagCount: 2,
|
maxTagCount: 1,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'caseManagement.featureCase.tableColumnVersion',
|
title: 'caseManagement.featureCase.tableColumnReviewResult',
|
||||||
dataIndex: 'versionId',
|
dataIndex: 'reviewStatus',
|
||||||
|
type: FilterType.SELECT,
|
||||||
|
selectProps: {
|
||||||
|
multiple: true,
|
||||||
|
options: reviewResultOptions.value,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'caseManagement.featureCase.tableColumnExecutionResult',
|
||||||
|
dataIndex: 'lastExecuteResult',
|
||||||
|
type: FilterType.SELECT,
|
||||||
|
selectProps: {
|
||||||
|
multiple: true,
|
||||||
|
options: executeResultOptions.value,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'caseManagement.featureCase.associatedDemand',
|
||||||
|
dataIndex: 'demand',
|
||||||
type: FilterType.INPUT,
|
type: FilterType.INPUT,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'caseManagement.featureCase.tableColumnCreateUser',
|
title: 'caseManagement.featureCase.relatedAttachments',
|
||||||
dataIndex: 'createUserName',
|
dataIndex: 'attachment',
|
||||||
type: FilterType.SELECT,
|
type: FilterType.INPUT,
|
||||||
selectProps: {
|
|
||||||
mode: 'static',
|
|
||||||
options: memberOptions.value,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'caseManagement.featureCase.tableColumnCreateTime',
|
title: 'common.creator',
|
||||||
|
dataIndex: 'createUser',
|
||||||
|
type: FilterType.MEMBER,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'common.createTime',
|
||||||
dataIndex: 'createTime',
|
dataIndex: 'createTime',
|
||||||
type: FilterType.DATE_PICKER,
|
type: FilterType.DATE_PICKER,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'caseManagement.featureCase.tableColumnUpdateUser',
|
title: 'common.updateUserName',
|
||||||
dataIndex: 'updateUserName',
|
dataIndex: 'updateUser',
|
||||||
type: FilterType.SELECT,
|
type: FilterType.MEMBER,
|
||||||
selectProps: {
|
|
||||||
mode: 'static',
|
|
||||||
options: memberOptions.value,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'caseManagement.featureCase.tableColumnUpdateTime',
|
title: 'common.updateTime',
|
||||||
dataIndex: 'updateTime',
|
dataIndex: 'updateTime',
|
||||||
type: FilterType.DATE_PICKER,
|
type: FilterType.DATE_PICKER,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'caseManagement.featureCase.tableColumnTag',
|
title: 'common.tag',
|
||||||
dataIndex: 'tags',
|
dataIndex: 'tags',
|
||||||
type: FilterType.TAGS_INPUT,
|
type: FilterType.TAGS_INPUT,
|
||||||
},
|
},
|
||||||
@ -846,8 +859,6 @@
|
|||||||
|
|
||||||
async function initFilter() {
|
async function initFilter() {
|
||||||
const result = await getCustomFieldsTable(currentProjectId.value);
|
const result = await getCustomFieldsTable(currentProjectId.value);
|
||||||
memberOptions.value = await getProjectOptions(appStore.currentProjectId, keyword.value);
|
|
||||||
memberOptions.value = memberOptions.value.map((e: any) => ({ label: e.name, value: e.id }));
|
|
||||||
// 处理系统自定义字段
|
// 处理系统自定义字段
|
||||||
searchCustomFields.value = result.map((item: any) => {
|
searchCustomFields.value = result.map((item: any) => {
|
||||||
const FilterTypeKey: keyof typeof FilterType = CustomTypeMaps[item.type].type;
|
const FilterTypeKey: keyof typeof FilterType = CustomTypeMaps[item.type].type;
|
||||||
|
@ -67,6 +67,7 @@ export default {
|
|||||||
'caseManagement.featureCase.moveTo': 'Move to',
|
'caseManagement.featureCase.moveTo': 'Move to',
|
||||||
'caseManagement.featureCase.copyTo': 'Copy to',
|
'caseManagement.featureCase.copyTo': 'Copy to',
|
||||||
'caseManagement.featureCase.associatedDemand': 'Associated demand',
|
'caseManagement.featureCase.associatedDemand': 'Associated demand',
|
||||||
|
'caseManagement.featureCase.relatedAttachments': 'Related attachments',
|
||||||
'caseManagement.featureCase.generatingDependencies': 'Generative dependency',
|
'caseManagement.featureCase.generatingDependencies': 'Generative dependency',
|
||||||
'caseManagement.featureCase.addToPublic': 'Add to public case',
|
'caseManagement.featureCase.addToPublic': 'Add to public case',
|
||||||
'caseManagement.featureCase.updateCase': 'Update Case',
|
'caseManagement.featureCase.updateCase': 'Update Case',
|
||||||
|
@ -67,6 +67,7 @@ export default {
|
|||||||
'caseManagement.featureCase.moveTo': '移动到',
|
'caseManagement.featureCase.moveTo': '移动到',
|
||||||
'caseManagement.featureCase.copyTo': '复制到',
|
'caseManagement.featureCase.copyTo': '复制到',
|
||||||
'caseManagement.featureCase.associatedDemand': '关联需求',
|
'caseManagement.featureCase.associatedDemand': '关联需求',
|
||||||
|
'caseManagement.featureCase.relatedAttachments': '关联附件',
|
||||||
'caseManagement.featureCase.generatingDependencies': '生成依赖关系',
|
'caseManagement.featureCase.generatingDependencies': '生成依赖关系',
|
||||||
'caseManagement.featureCase.addToPublic': '添加到公共用例库',
|
'caseManagement.featureCase.addToPublic': '添加到公共用例库',
|
||||||
'caseManagement.featureCase.updateCase': '更新用例',
|
'caseManagement.featureCase.updateCase': '更新用例',
|
||||||
|
Loading…
Reference in New Issue
Block a user