feat(测试用例): 功能用例详情抽屉编辑变动为抽屉编辑功能
This commit is contained in:
parent
d99bde8ba9
commit
a0a297f9eb
|
@ -12,9 +12,11 @@
|
||||||
<div class="flex flex-1 items-center">
|
<div class="flex flex-1 items-center">
|
||||||
<!-- 如果设置了tooltipText,则优先展示-->
|
<!-- 如果设置了tooltipText,则优先展示-->
|
||||||
<a-tooltip :content="props.tooltipText ? props.tooltipText : props.title" position="bottom">
|
<a-tooltip :content="props.tooltipText ? props.tooltipText : props.title" position="bottom">
|
||||||
|
<slot name="titleName">
|
||||||
<div class="one-line-text max-w-[300px]">
|
<div class="one-line-text max-w-[300px]">
|
||||||
{{ props.title }}
|
{{ props.title }}
|
||||||
</div>
|
</div>
|
||||||
|
</slot>
|
||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
<div class="ml-4 flex items-center">
|
<div class="ml-4 flex items-center">
|
||||||
<slot name="titleLeft" :loading="loading" :detail="detail"></slot>
|
<slot name="titleLeft" :loading="loading" :detail="detail"></slot>
|
||||||
|
|
|
@ -9,22 +9,45 @@
|
||||||
:detail-id="props.detailId"
|
:detail-id="props.detailId"
|
||||||
:detail-index="props.detailIndex"
|
:detail-index="props.detailIndex"
|
||||||
:get-detail-func="getCaseDetail"
|
:get-detail-func="getCaseDetail"
|
||||||
:pagination="props.pagination"
|
:pagination="!isEditTitle ? props.pagination : undefined"
|
||||||
:table-data="props.tableData"
|
:table-data="props.tableData"
|
||||||
:page-change="props.pageChange"
|
:page-change="props.pageChange"
|
||||||
:mask-closable="true"
|
:mask-closable="true"
|
||||||
:edit-name="true"
|
|
||||||
show-full-screen
|
show-full-screen
|
||||||
:unmount-on-close="true"
|
:unmount-on-close="true"
|
||||||
@loaded="loadedCase"
|
@loaded="loadedCase"
|
||||||
>
|
>
|
||||||
|
<template #titleName>
|
||||||
|
<div :class="`case-title flex items-center ${isEditTitle ? 'w-full' : ''}`">
|
||||||
|
<a-input
|
||||||
|
v-if="isEditTitle"
|
||||||
|
v-model="titleName"
|
||||||
|
:class="`edit-title w-full ${titleName.length ? '' : 'edit-title-error'}`"
|
||||||
|
:placeholder="t('case.caseNamePlaceholder')"
|
||||||
|
allow-clear
|
||||||
|
:max-length="255"
|
||||||
|
@blur="handleEditName"
|
||||||
|
@keydown.enter="handleEditName"
|
||||||
|
/>
|
||||||
|
<div v-else class="flex items-center">
|
||||||
|
<div> 【{{ detailInfo?.num }}】 </div>
|
||||||
|
<div
|
||||||
|
:class="`${
|
||||||
|
hasAnyPermission(['FUNCTIONAL_CASE:READ+UPDATE']) ? 'hover-title-name' : ''
|
||||||
|
} one-line-text max-w-[200px]`"
|
||||||
|
@click="clickTitleHandler"
|
||||||
|
>{{ detailInfo.name }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
<template #titleLeft>
|
<template #titleLeft>
|
||||||
<div class="flex items-center"><caseLevel :case-level="caseLevels" /></div>
|
<div v-if="!isEditTitle" class="flex items-center"><caseLevel :case-level="caseLevels" /></div>
|
||||||
</template>
|
</template>
|
||||||
<template #titleRight="{ loading }">
|
<template #titleRight="{ loading }">
|
||||||
<div class="rightButtons flex items-center">
|
<div class="rightButtons flex items-center">
|
||||||
<MsButton
|
<MsButton
|
||||||
v-permission="['FUNCTIONAL_CASE:READ+UPDATE']"
|
v-if="hasAnyPermission(['FUNCTIONAL_CASE:READ+UPDATE']) && !isEditTitle"
|
||||||
type="icon"
|
type="icon"
|
||||||
status="secondary"
|
status="secondary"
|
||||||
class="mr-4 !rounded-[var(--border-radius-small)]"
|
class="mr-4 !rounded-[var(--border-radius-small)]"
|
||||||
|
@ -36,7 +59,7 @@
|
||||||
{{ t('common.edit') }}
|
{{ t('common.edit') }}
|
||||||
</MsButton>
|
</MsButton>
|
||||||
<MsButton
|
<MsButton
|
||||||
v-permission="['FUNCTIONAL_CASE:READ+UPDATE']"
|
v-if="hasAnyPermission(['FUNCTIONAL_CASE:READ+UPDATE']) && !isEditTitle"
|
||||||
type="icon"
|
type="icon"
|
||||||
status="secondary"
|
status="secondary"
|
||||||
class="mr-4 !rounded-[var(--border-radius-small)]"
|
class="mr-4 !rounded-[var(--border-radius-small)]"
|
||||||
|
@ -48,7 +71,7 @@
|
||||||
{{ t('caseManagement.featureCase.share') }}
|
{{ t('caseManagement.featureCase.share') }}
|
||||||
</MsButton>
|
</MsButton>
|
||||||
<MsButton
|
<MsButton
|
||||||
v-permission="['FUNCTIONAL_CASE:READ+UPDATE']"
|
v-if="hasAnyPermission(['FUNCTIONAL_CASE:READ+UPDATE']) && !isEditTitle"
|
||||||
type="icon"
|
type="icon"
|
||||||
status="secondary"
|
status="secondary"
|
||||||
class="mr-4 !rounded-[var(--border-radius-small)]"
|
class="mr-4 !rounded-[var(--border-radius-small)]"
|
||||||
|
@ -63,7 +86,12 @@
|
||||||
/>
|
/>
|
||||||
{{ t('caseManagement.featureCase.follow') }}
|
{{ t('caseManagement.featureCase.follow') }}
|
||||||
</MsButton>
|
</MsButton>
|
||||||
<MsButton type="icon" status="secondary" class="mr-2 !rounded-[var(--border-radius-small)]">
|
<MsButton
|
||||||
|
v-if="hasAnyPermission(['FUNCTIONAL_CASE:READ+ADD', 'FUNCTIONAL_CASE:READ+DELETE']) && !isEditTitle"
|
||||||
|
type="icon"
|
||||||
|
status="secondary"
|
||||||
|
class="mr-2 !rounded-[var(--border-radius-small)]"
|
||||||
|
>
|
||||||
<a-dropdown position="br" :hide-on-select="false">
|
<a-dropdown position="br" :hide-on-select="false">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<icon-more class="mr-2" />
|
<icon-more class="mr-2" />
|
||||||
|
@ -75,10 +103,14 @@
|
||||||
<!-- <a-doption>
|
<!-- <a-doption>
|
||||||
<a-switch class="mr-1" size="small" type="line" />{{ t('caseManagement.featureCase.addToPublic') }}
|
<a-switch class="mr-1" size="small" type="line" />{{ t('caseManagement.featureCase.addToPublic') }}
|
||||||
</a-doption> -->
|
</a-doption> -->
|
||||||
<a-doption @click="updateHandler('copy')">
|
<a-doption v-if="hasAnyPermission(['FUNCTIONAL_CASE:READ+ADD'])" @click="updateHandler('copy')">
|
||||||
<MsIcon type="icon-icon_copy_filled" class="font-[16px]" />{{ t('common.copy') }}</a-doption
|
<MsIcon type="icon-icon_copy_filled" class="font-[16px]" />{{ t('common.copy') }}
|
||||||
|
</a-doption>
|
||||||
|
<a-doption
|
||||||
|
v-if="hasAnyPermission(['FUNCTIONAL_CASE:READ+DELETE'])"
|
||||||
|
class="error-6 text-[rgb(var(--danger-6))]"
|
||||||
|
@click="deleteHandler"
|
||||||
>
|
>
|
||||||
<a-doption class="error-6 text-[rgb(var(--danger-6))]" @click="deleteHandler">
|
|
||||||
<MsIcon type="icon-icon_delete-trash_outlined1" class="font-[16px] text-[rgb(var(--danger-6))]" />
|
<MsIcon type="icon-icon_delete-trash_outlined1" class="font-[16px] text-[rgb(var(--danger-6))]" />
|
||||||
{{ t('common.delete') }}
|
{{ t('common.delete') }}
|
||||||
</a-doption>
|
</a-doption>
|
||||||
|
@ -110,7 +142,13 @@
|
||||||
} content-wrapper w-full p-[16px] pt-4`"
|
} content-wrapper w-full p-[16px] pt-4`"
|
||||||
>
|
>
|
||||||
<template v-if="activeTab === 'detail'">
|
<template v-if="activeTab === 'detail'">
|
||||||
<TabDetail :form="detailInfo" :allow-edit="true" :form-rules="formItem" @update-success="updateSuccess" />
|
<TabDetail
|
||||||
|
:form="detailInfo"
|
||||||
|
:allow-edit="true"
|
||||||
|
:is-edit="props.isEdit"
|
||||||
|
:form-rules="formItem"
|
||||||
|
@update-success="updateSuccess"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template v-if="activeTab === 'basicInfo'">
|
<template v-if="activeTab === 'basicInfo'">
|
||||||
<BasicInfo :loading="loading" :detail="detail" @update-success="updateSuccess" />
|
<BasicInfo :loading="loading" :detail="detail" @update-success="updateSuccess" />
|
||||||
|
@ -187,6 +225,7 @@
|
||||||
followerCaseRequest,
|
followerCaseRequest,
|
||||||
getCaseDetail,
|
getCaseDetail,
|
||||||
getCaseModuleTree,
|
getCaseModuleTree,
|
||||||
|
updateCaseRequest,
|
||||||
} from '@/api/modules/case-management/featureCase';
|
} from '@/api/modules/case-management/featureCase';
|
||||||
import { PreviewEditorImageUrl } from '@/api/requrls/case-management/featureCase';
|
import { PreviewEditorImageUrl } from '@/api/requrls/case-management/featureCase';
|
||||||
import { defaultCaseDetail } from '@/config/caseManagement';
|
import { defaultCaseDetail } from '@/config/caseManagement';
|
||||||
|
@ -196,6 +235,7 @@
|
||||||
import useFeatureCaseStore from '@/store/modules/case/featureCase';
|
import useFeatureCaseStore from '@/store/modules/case/featureCase';
|
||||||
import useUserStore from '@/store/modules/user';
|
import useUserStore from '@/store/modules/user';
|
||||||
import { characterLimit } from '@/utils';
|
import { characterLimit } from '@/utils';
|
||||||
|
import { hasAnyPermission } from '@/utils/permission';
|
||||||
|
|
||||||
import type { CustomAttributes, DetailCase, TabItemType } from '@/models/caseManagement/featureCase';
|
import type { CustomAttributes, DetailCase, TabItemType } from '@/models/caseManagement/featureCase';
|
||||||
import { ModuleTreeNode } from '@/models/common';
|
import { ModuleTreeNode } from '@/models/common';
|
||||||
|
@ -229,6 +269,7 @@
|
||||||
tableData: any[]; // 表格数据
|
tableData: any[]; // 表格数据
|
||||||
pagination: MsPaginationI; // 分页器对象
|
pagination: MsPaginationI; // 分页器对象
|
||||||
pageChange: (page: number) => Promise<void>; // 分页变更函数
|
pageChange: (page: number) => Promise<void>; // 分页变更函数
|
||||||
|
isEdit?: boolean; // 编辑状态
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const emit = defineEmits(['update:visible', 'success']);
|
const emit = defineEmits(['update:visible', 'success']);
|
||||||
|
@ -249,6 +290,8 @@
|
||||||
const tabSetting = ref<TabItemType[]>([]);
|
const tabSetting = ref<TabItemType[]>([]);
|
||||||
const activeTab = ref<string | number>('detail');
|
const activeTab = ref<string | number>('detail');
|
||||||
|
|
||||||
|
const titleName = ref('');
|
||||||
|
|
||||||
function clickMenu(key: string | number) {
|
function clickMenu(key: string | number) {
|
||||||
activeTab.value = key;
|
activeTab.value = key;
|
||||||
featureCaseStore.setActiveTab(key);
|
featureCaseStore.setActiveTab(key);
|
||||||
|
@ -304,6 +347,7 @@
|
||||||
function loadedCase(detail: DetailCase) {
|
function loadedCase(detail: DetailCase) {
|
||||||
getCaseTree();
|
getCaseTree();
|
||||||
detailInfo.value = { ...detail };
|
detailInfo.value = { ...detail };
|
||||||
|
titleName.value = detail.name;
|
||||||
setCount(detail);
|
setCount(detail);
|
||||||
customFields.value = detailInfo.value?.customFields as CustomAttributes[];
|
customFields.value = detailInfo.value?.customFields as CustomAttributes[];
|
||||||
caseLevels.value = getCaseLevels(customFields.value) as CaseLevel;
|
caseLevels.value = getCaseLevels(customFields.value) as CaseLevel;
|
||||||
|
@ -396,7 +440,6 @@
|
||||||
const formRules = ref<FormItem[]>([]);
|
const formRules = ref<FormItem[]>([]);
|
||||||
const formItem = ref<FormRuleItem[]>([]);
|
const formItem = ref<FormRuleItem[]>([]);
|
||||||
|
|
||||||
const fApi = ref(null);
|
|
||||||
// 初始化表单
|
// 初始化表单
|
||||||
function initForm() {
|
function initForm() {
|
||||||
formRules.value = initFormCreate(customFields.value, ['FUNCTIONAL_CASE:READ+UPDATE']);
|
formRules.value = initFormCreate(customFields.value, ['FUNCTIONAL_CASE:READ+UPDATE']);
|
||||||
|
@ -413,6 +456,59 @@
|
||||||
return featureCaseStore.countMap[key] > 99 ? '99+' : `${count > 0 ? count : ''}`;
|
return featureCaseStore.countMap[key] > 99 ? '99+' : `${count > 0 ? count : ''}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getParams() {
|
||||||
|
const customFieldsArr = (formItem.value || []).map((item: any) => {
|
||||||
|
return {
|
||||||
|
fieldId: item.field,
|
||||||
|
value: Array.isArray(item.value) ? JSON.stringify(item.value) : item.value,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
request: {
|
||||||
|
...detailInfo.value,
|
||||||
|
name: titleName.value,
|
||||||
|
deleteFileMetaIds: [],
|
||||||
|
unLinkFilesIds: [],
|
||||||
|
newAssociateFileListIds: [],
|
||||||
|
customFields: customFieldsArr,
|
||||||
|
caseDetailFileIds: [],
|
||||||
|
},
|
||||||
|
fileList: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const isEditTitle = ref<boolean>(false);
|
||||||
|
const titleLoading = ref<boolean>(false);
|
||||||
|
|
||||||
|
async function handleEditName() {
|
||||||
|
if (!titleName.value.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (titleName.value === detailInfo.value.name) {
|
||||||
|
isEditTitle.value = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
titleLoading.value = true;
|
||||||
|
try {
|
||||||
|
await updateCaseRequest(getParams());
|
||||||
|
Message.success(t('caseManagement.featureCase.editSuccess'));
|
||||||
|
detailInfo.value.name = titleName.value;
|
||||||
|
isEditTitle.value = false;
|
||||||
|
updateSuccess();
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
} finally {
|
||||||
|
titleLoading.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function clickTitleHandler() {
|
||||||
|
if (hasAnyPermission(['FUNCTIONAL_CASE:READ+UPDATE'])) {
|
||||||
|
isEditTitle.value = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => customFields.value,
|
() => customFields.value,
|
||||||
() => {
|
() => {
|
||||||
|
@ -432,6 +528,7 @@
|
||||||
featureCaseStore.setActiveTab(activeTab.value);
|
featureCaseStore.setActiveTab(activeTab.value);
|
||||||
} else {
|
} else {
|
||||||
activeTab.value = '';
|
activeTab.value = '';
|
||||||
|
isEditTitle.value = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -622,4 +719,17 @@
|
||||||
color: rgb(var(--danger-6));
|
color: rgb(var(--danger-6));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.edit-title-error {
|
||||||
|
border-color: rgb(var(--danger-6));
|
||||||
|
}
|
||||||
|
.hover-title-name {
|
||||||
|
padding: 4px 8px;
|
||||||
|
font-size: 16px;
|
||||||
|
border-radius: 4px;
|
||||||
|
color: var(--color-text-1);
|
||||||
|
@apply font-medium;
|
||||||
|
&:hover {
|
||||||
|
background: var(--color-text-n9);
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -142,7 +142,7 @@
|
||||||
</template>
|
</template>
|
||||||
<!-- 渲染自定义字段结束 -->
|
<!-- 渲染自定义字段结束 -->
|
||||||
<template #operation="{ record }">
|
<template #operation="{ record }">
|
||||||
<MsButton v-permission="['FUNCTIONAL_CASE:READ+UPDATE']" class="!mr-0" @click="operateCase(record, 'edit')">
|
<MsButton v-permission="['FUNCTIONAL_CASE:READ+UPDATE']" class="!mr-0" @click="operateCase(record, true)">
|
||||||
{{ t('common.edit') }}
|
{{ t('common.edit') }}
|
||||||
</MsButton>
|
</MsButton>
|
||||||
<a-divider
|
<a-divider
|
||||||
|
@ -151,7 +151,7 @@
|
||||||
direction="vertical"
|
direction="vertical"
|
||||||
:margin="8"
|
:margin="8"
|
||||||
></a-divider>
|
></a-divider>
|
||||||
<MsButton v-permission="['FUNCTIONAL_CASE:READ+ADD']" class="!mr-0" @click="operateCase(record, 'copy')">
|
<MsButton v-permission="['FUNCTIONAL_CASE:READ+ADD']" class="!mr-0" @click="operateCase(record, false)">
|
||||||
{{ t('caseManagement.featureCase.copy') }}
|
{{ t('caseManagement.featureCase.copy') }}
|
||||||
</MsButton>
|
</MsButton>
|
||||||
<a-divider
|
<a-divider
|
||||||
|
@ -336,6 +336,7 @@
|
||||||
:table-data="propsRes.data"
|
:table-data="propsRes.data"
|
||||||
:page-change="propsEvent.pageChange"
|
:page-change="propsEvent.pageChange"
|
||||||
:pagination="propsRes.msPagination!"
|
:pagination="propsRes.msPagination!"
|
||||||
|
:is-edit="isEdit"
|
||||||
@success="initData()"
|
@success="initData()"
|
||||||
/>
|
/>
|
||||||
<AddDemandModal
|
<AddDemandModal
|
||||||
|
@ -1014,18 +1015,36 @@
|
||||||
emitTableParams();
|
emitTableParams();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const showDetailDrawer = ref(false);
|
||||||
|
const activeDetailId = ref<string>('');
|
||||||
|
const activeCaseIndex = ref<number>(0);
|
||||||
|
|
||||||
|
// 抽屉详情
|
||||||
|
function showCaseDetail(id: string, index: number) {
|
||||||
|
activeDetailId.value = id;
|
||||||
|
activeCaseIndex.value = index;
|
||||||
|
showDetailDrawer.value = true;
|
||||||
|
}
|
||||||
|
const isEdit = ref<boolean>(false);
|
||||||
// 编辑&复制
|
// 编辑&复制
|
||||||
function operateCase(record: CaseManagementTable, mode: string) {
|
function operateCase(record: CaseManagementTable, operateType: boolean) {
|
||||||
|
// TODO 这个版本暂时调整为打开详情抽屉编辑
|
||||||
|
isEdit.value = operateType;
|
||||||
|
if (operateType) {
|
||||||
|
const index = propsRes.value.data.findIndex((item) => item.id === record.id);
|
||||||
|
showCaseDetail(record.id, index);
|
||||||
|
} else {
|
||||||
router.push({
|
router.push({
|
||||||
name: CaseManagementRouteEnum.CASE_MANAGEMENT_CASE_DETAIL,
|
name: CaseManagementRouteEnum.CASE_MANAGEMENT_CASE_DETAIL,
|
||||||
query: {
|
query: {
|
||||||
id: record.id,
|
id: record.id,
|
||||||
},
|
},
|
||||||
params: {
|
params: {
|
||||||
mode,
|
mode: operateType ? 'edit' : 'copy',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 删除
|
// 删除
|
||||||
function deleteCase(record: CaseManagementTable) {
|
function deleteCase(record: CaseManagementTable) {
|
||||||
|
@ -1446,19 +1465,10 @@
|
||||||
resetSelector();
|
resetSelector();
|
||||||
initData();
|
initData();
|
||||||
}
|
}
|
||||||
const showDetailDrawer = ref(false);
|
|
||||||
const activeDetailId = ref<string>('');
|
|
||||||
const activeCaseIndex = ref<number>(0);
|
|
||||||
|
|
||||||
// 抽屉详情
|
|
||||||
function showCaseDetail(id: string, index: number) {
|
|
||||||
activeDetailId.value = id;
|
|
||||||
activeCaseIndex.value = index;
|
|
||||||
showDetailDrawer.value = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleCellClick(record: TableData) {
|
function handleCellClick(record: TableData) {
|
||||||
const index = propsRes.value.data.findIndex((item) => item.id === record.id);
|
const index = propsRes.value.data.findIndex((item) => item.id === record.id);
|
||||||
|
isEdit.value = false;
|
||||||
showCaseDetail(record.id, index);
|
showCaseDetail(record.id, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -305,9 +305,11 @@
|
||||||
formRules?: FormRuleItem[]; // 编辑表单
|
formRules?: FormRuleItem[]; // 编辑表单
|
||||||
isTestPlan?: boolean; // 测试计划页面的
|
isTestPlan?: boolean; // 测试计划页面的
|
||||||
isDisabledTestPlan?: boolean; // 测试计划页面-已归档
|
isDisabledTestPlan?: boolean; // 测试计划页面-已归档
|
||||||
|
isEdit?: boolean; // 是否为编辑状态
|
||||||
}>(),
|
}>(),
|
||||||
{
|
{
|
||||||
allowEdit: true, // 是否允许编辑
|
allowEdit: true, // 是否允许编辑
|
||||||
|
isEdit: false,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -344,7 +346,7 @@
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const isEditPreposition = ref<boolean>(false); // 非编辑状态
|
const isEditPreposition = ref<boolean>(props.isEdit); // 非编辑状态
|
||||||
|
|
||||||
// 更改类型
|
// 更改类型
|
||||||
const handleSelectType = (value: string | number | Record<string, any> | undefined) => {
|
const handleSelectType = (value: string | number | Record<string, any> | undefined) => {
|
||||||
|
|
Loading…
Reference in New Issue