feat(测试用例): 功能用例批量关联需求优化

This commit is contained in:
xinxin.wu 2024-09-10 12:48:16 +08:00 committed by Craftsman
parent 5843371237
commit c0e7d517db
6 changed files with 100 additions and 301 deletions
frontend/src/views
bug-management
case-management/caseManagementFeature/components
test-plan/testPlan/detail

View File

@ -452,7 +452,6 @@
}); });
function updateHandler() { function updateHandler() {
showDrawerVisible.value = false;
router.push({ router.push({
name: RouteEnum.BUG_MANAGEMENT_DETAIL, name: RouteEnum.BUG_MANAGEMENT_DETAIL,
query: { query: {

View File

@ -809,6 +809,10 @@
} }
}); });
onDeactivated(() => {
detailVisible.value = false;
});
onBeforeUnmount(() => { onBeforeUnmount(() => {
detailVisible.value = false; detailVisible.value = false;
}); });

View File

@ -375,7 +375,12 @@
import { MsExportDrawerMap, MsExportDrawerOption } from '@/components/pure/ms-export-drawer/types'; import { MsExportDrawerMap, MsExportDrawerOption } from '@/components/pure/ms-export-drawer/types';
import MsIcon from '@/components/pure/ms-icon-font/index.vue'; import MsIcon from '@/components/pure/ms-icon-font/index.vue';
import MsBaseTable from '@/components/pure/ms-table/base-table.vue'; import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
import type { BatchActionParams, BatchActionQueryParams, MsTableColumn } from '@/components/pure/ms-table/type'; import type {
BatchActionConfig,
BatchActionParams,
BatchActionQueryParams,
MsTableColumn,
} from '@/components/pure/ms-table/type';
import { MsTableProps } from '@/components/pure/ms-table/type'; import { MsTableProps } from '@/components/pure/ms-table/type';
import useTable from '@/components/pure/ms-table/useTable'; import useTable from '@/components/pure/ms-table/useTable';
import MsTableMoreAction from '@/components/pure/ms-table-more-action/index.vue'; import MsTableMoreAction from '@/components/pure/ms-table-more-action/index.vue';
@ -707,7 +712,40 @@
]; ];
const platformInfo = ref<Record<string, any>>({}); const platformInfo = ref<Record<string, any>>({});
const tableBatchActions = {
const batchMoreActions = computed<BatchActionParams[]>(() => {
const addDemandAction = [
{
label: 'caseManagement.featureCase.addDemand',
eventTag: 'addDemand',
permission: ['FUNCTIONAL_CASE:READ+UPDATE'],
},
];
const linkDemandAction = [
{
label: 'caseManagement.featureCase.associatedDemand',
eventTag: 'associatedDemand',
permission: ['FUNCTIONAL_CASE:READ+UPDATE'],
},
];
const deleteMoreAction = [
{
isDivider: true,
},
{
label: 'common.delete',
eventTag: 'delete',
permission: ['FUNCTIONAL_CASE:READ+DELETE'],
danger: true,
},
];
if (!Object.keys(platformInfo.value).length) {
return [...addDemandAction, ...deleteMoreAction];
}
return [...addDemandAction, ...linkDemandAction, ...deleteMoreAction];
});
const tableBatchActions: BatchActionConfig = {
baseAction: [ baseAction: [
{ {
label: 'caseManagement.featureCase.export', label: 'caseManagement.featureCase.export',
@ -740,35 +778,7 @@
permission: ['FUNCTIONAL_CASE:READ+ADD'], permission: ['FUNCTIONAL_CASE:READ+ADD'],
}, },
], ],
moreAction: [ moreAction: [],
{
label: 'caseManagement.featureCase.addDemand',
eventTag: 'addDemand',
permission: ['FUNCTIONAL_CASE:READ+UPDATE'],
},
{
label: 'caseManagement.featureCase.associatedDemand',
eventTag: 'associatedDemand',
permission: ['FUNCTIONAL_CASE:READ+UPDATE'],
},
// {
// label: 'caseManagement.featureCase.generatingDependencies',
// eventTag: 'generatingDependencies',
// },
// {
// label: 'caseManagement.featureCase.addToPublic',
// eventTag: 'addToPublic',
// },
{
isDivider: true,
},
{
label: 'common.delete',
eventTag: 'delete',
permission: ['FUNCTIONAL_CASE:READ+DELETE'],
danger: true,
},
],
}; };
const filterConfigList = computed<FilterFormItem[]>(() => [ const filterConfigList = computed<FilterFormItem[]>(() => [
@ -1776,12 +1786,7 @@
if (result && result.platform_key) { if (result && result.platform_key) {
platformInfo.value = { ...result }; platformInfo.value = { ...result };
} }
if (Object.keys(result).length === 0) { tableBatchActions.moreAction = batchMoreActions.value;
tableBatchActions.moreAction = [
...tableBatchActions.moreAction.slice(0, 1),
...tableBatchActions.moreAction.slice(-2),
];
}
} catch (error) { } catch (error) {
console.log(error); console.log(error);
} }

View File

@ -40,7 +40,7 @@
@cancel="cancelLink" @cancel="cancelLink"
@open="openDemandUrl" @open="openDemandUrl"
@associate="linkDemandDrawer = true" @associate="linkDemandDrawer = true"
></AssociatedDemandTable> />
<AddDemandModal <AddDemandModal
ref="demandModalRef" ref="demandModalRef"
v-model:visible="showAddModel" v-model:visible="showAddModel"
@ -50,54 +50,13 @@
@save="saveHandler" @save="saveHandler"
@success="searchList()" @success="searchList()"
/> />
<MsDrawer <ThirdDemandDrawer
v-model:visible="linkDemandDrawer" v-model:visible="linkDemandDrawer"
:ok-disabled="tableSelected.length < 1" :case-id="caseId"
:mask="false" :drawer-loading="drawerLoading"
:title="t('caseManagement.featureCase.associatedDemand')" :platform-info="platformInfo"
:ok-text="t('caseManagement.featureCase.associated')" @save="handleDrawerConfirm"
:ok-loading="drawerLoading" />
:width="960"
unmount-on-close
:show-continue="false"
@confirm="handleDrawerConfirm"
@cancel="handleDrawerCancel"
>
<div class="flex items-center justify-between">
<div>
<span class="font-medium">{{ platName }}</span>
<span class="ml-1 text-[var(--color-text-4)]">({{ propsRes?.msPagination?.total || 0 }})</span>
</div>
<a-input-search
v-model="platformKeyword"
:max-length="255"
:placeholder="t('caseManagement.featureCase.searchByIdAndName')"
allow-clear
class="mx-[8px] w-[240px]"
@search="searchHandler"
@press-enter="searchHandler"
@clear="searchHandler"
></a-input-search>
</div>
<ms-base-table ref="tableRef" v-bind="propsRes" v-on="propsEvent">
<template #demandId="{ record }">
<a-tooltip :content="record.demandId" :mouse-enter-delay="300">
<div class="one-line-text max-w-[300px]">
{{ record.demandId }}
</div>
</a-tooltip>
</template>
<template #demandName="{ record }">
<span class="ml-1 text-[rgb(var(--primary-5))]">
{{ record.demandName }}
<span v-if="(record.children || []).length"> ({{ (record.children || []).length || 0 }}) </span>
</span>
</template>
<template v-for="item in customFields" :key="item.slotName" #[item.dataIndex]="{ record }">
<span> {{ getSlotName(record, item) }} </span>
</template>
</ms-base-table>
</MsDrawer>
</div> </div>
</template> </template>
@ -106,17 +65,13 @@
import { Message } from '@arco-design/web-vue'; import { Message } from '@arco-design/web-vue';
import { debounce } from 'lodash-es'; import { debounce } from 'lodash-es';
import MsDrawer from '@/components/pure/ms-drawer/index.vue';
import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
import type { MsTableColumn, MsTableColumnData } from '@/components/pure/ms-table/type';
import useTable from '@/components/pure/ms-table/useTable';
import AddDemandModal from './addDemandModal.vue'; import AddDemandModal from './addDemandModal.vue';
import AssociatedDemandTable from './associatedDemandTable.vue'; import AssociatedDemandTable from './associatedDemandTable.vue';
import ThirdDemandDrawer from './thirdDemandDrawer.vue';
import { import {
addDemandRequest, addDemandRequest,
cancelAssociationDemand, cancelAssociationDemand,
getThirdDemandList,
updateDemandReq, updateDemandReq,
} from '@/api/modules/case-management/featureCase'; } from '@/api/modules/case-management/featureCase';
import { getCaseRelatedInfo } from '@/api/modules/project-management/menuManagement'; import { getCaseRelatedInfo } from '@/api/modules/project-management/menuManagement';
@ -124,9 +79,6 @@
import { useAppStore } from '@/store'; import { useAppStore } from '@/store';
import type { CreateOrUpdateDemand, DemandItem } from '@/models/caseManagement/featureCase'; import type { CreateOrUpdateDemand, DemandItem } from '@/models/caseManagement/featureCase';
import { TableKeyEnum } from '@/enums/tableEnum';
import { getPlatName } from '@/views/case-management/caseManagementFeature/components/utils';
const { t } = useI18n(); const { t } = useI18n();
const appStore = useAppStore(); const appStore = useAppStore();
@ -170,137 +122,14 @@
modelForm.value = { ...record }; modelForm.value = { ...record };
} }
const columns: MsTableColumn = [
{
title: 'caseManagement.featureCase.tableColumnID',
slotName: 'demandId',
dataIndex: 'demandId',
width: 200,
showTooltip: true,
},
{
title: 'caseManagement.featureCase.demandName',
slotName: 'demandName',
dataIndex: 'demandName',
width: 300,
showTooltip: true,
},
// {
// title: 'caseManagement.featureCase.platformDemandState',
// width: 300,
// dataIndex: 'status',
// showTooltip: true,
// ellipsis: true,
// },
// {
// title: 'caseManagement.featureCase.platformDemandHandler',
// width: 300,
// dataIndex: 'handler',
// showTooltip: true,
// ellipsis: true,
// },
];
let fullColumns: MsTableColumn = [...columns];
const { propsRes, propsEvent, loadList, setLoadListParams, resetSelector } = useTable(getThirdDemandList, {
tableKey: TableKeyEnum.CASE_MANAGEMENT_TAB_DEMAND_PLATFORM,
columns: fullColumns,
rowKey: 'demandId',
scroll: { x: '100%' },
heightUsed: 290,
selectable: true,
showSelectorAll: false,
showSetting: false,
rowSelectionDisabledConfig: {
checkStrictly: false,
disabledKey: 'disabled',
},
});
const drawerLoading = ref<boolean>(false); const drawerLoading = ref<boolean>(false);
const tableSelected = computed(() => {
const selectedIds = [...propsRes.value.selectedKeys];
const filteredData: DemandItem[] = [];
function filterData(data: DemandItem[]) {
for (let i = 0; i < data.length; i++) {
const item: DemandItem = data[i];
if (selectedIds.includes(item.demandId)) {
filteredData.push(item);
}
if (item.children) {
filterData(item.children);
}
}
}
filterData(propsRes.value.data);
return filteredData;
});
const platformKeyword = ref<string>('');
const tableRef = ref();
const initData = async () => {
tableRef.value?.initColumn(fullColumns);
setLoadListParams({ keyword: platformKeyword.value, projectId: currentProjectId.value, caseId: props.caseId });
loadList();
};
const customFields = ref<any[]>([]);
async function initColumn() {
fullColumns = [...columns];
try {
const res = await getThirdDemandList({
current: 1,
pageSize: 10,
projectId: currentProjectId.value,
caseId: props.caseId,
});
customFields.value = (res.data.customHeaders || []).map((item: any) => {
return {
title: item.name,
slotName: item.id,
dataIndex: item.id,
width: 200,
options: item.options,
};
}) as any;
fullColumns = [...columns, ...customFields.value];
} catch (error) {
console.log(error);
}
}
// //
const linkDemandDrawer = ref<boolean>(false); const linkDemandDrawer = ref<boolean>(false);
function associatedDemand() { function associatedDemand() {
initColumn();
linkDemandDrawer.value = true; linkDemandDrawer.value = true;
} }
const searchHandler = () => {
if (linkDemandDrawer.value) {
initData();
resetSelector();
}
};
function getSlotName(record: any, item: MsTableColumnData) {
if (item?.options) {
const currentRecord = {
...record,
...record.customFields,
};
const currentValue = currentRecord[item.dataIndex as string];
const currentOptions = (JSON.parse(item.options) || []).find((it: any) => it.value === currentValue);
if (currentOptions) {
return currentOptions.text;
}
}
return record.customFields[item.dataIndex as string] || '-';
}
function openDemandUrl(record: DemandItem) { function openDemandUrl(record: DemandItem) {
if (record.demandUrl) { if (record.demandUrl) {
window.open(record.demandUrl); window.open(record.demandUrl);
@ -308,44 +137,30 @@
} }
const platformInfo = ref<Record<string, any>>({}); const platformInfo = ref<Record<string, any>>({});
async function handleDrawerConfirm() {
const demandList = tableSelected.value.map((item) => {
return {
demandId: item.demandId,
parent: item.parent,
demandName: item.demandName,
demandUrl: item.demandUrl,
};
});
const params = { async function handleDrawerConfirm(associatedParams: CreateOrUpdateDemand) {
id: JSON.parse(platformInfo.value.demand_platform_config).zentaoId,
caseId: props.caseId,
demandPlatform: platformInfo.value.platform_key,
demandList: propsRes.value.selectorStatus === 'all' ? [] : demandList,
functionalDemandBatchRequest: {
keyword: platformKeyword.value,
excludeIds: [...propsRes.value.excludeKeys],
selectAll: propsRes.value.selectorStatus === 'all',
},
};
try { try {
drawerLoading.value = true; drawerLoading.value = true;
const { demandPlatform, demandList, functionalDemandBatchRequest } = associatedParams;
const params = {
id: JSON.parse(platformInfo.value.demand_platform_config).zentaoId,
caseId: props.caseId,
demandPlatform,
demandList,
functionalDemandBatchRequest,
};
await addDemandRequest(params); await addDemandRequest(params);
Message.success(t('caseManagement.featureCase.associatedSuccess')); Message.success(t('caseManagement.featureCase.associatedSuccess'));
linkDemandDrawer.value = false; linkDemandDrawer.value = false;
demandRef.value.initData(); demandRef.value.initData();
} catch (error) { } catch (error) {
// eslint-disable-next-line no-console
console.log(error); console.log(error);
} finally { } finally {
drawerLoading.value = false; drawerLoading.value = false;
} }
} }
function handleDrawerCancel() {
linkDemandDrawer.value = false;
platformKeyword.value = '';
}
// //
async function cancelLink(record: DemandItem) { async function cancelLink(record: DemandItem) {
try { try {
@ -353,6 +168,7 @@
Message.success(t('caseManagement.featureCase.cancelLinkSuccess')); Message.success(t('caseManagement.featureCase.cancelLinkSuccess'));
demandRef.value.initData(); demandRef.value.initData();
} catch (error) { } catch (error) {
// eslint-disable-next-line no-console
console.log(error); console.log(error);
} }
} }
@ -365,26 +181,11 @@
caseEnable.value = platformInfo.value.case_enable !== 'false'; caseEnable.value = platformInfo.value.case_enable !== 'false';
} }
} catch (error) { } catch (error) {
// eslint-disable-next-line no-console
console.log(error); console.log(error);
} }
} }
watch(
() => linkDemandDrawer.value,
(val) => {
if (val) {
resetSelector();
nextTick(async () => {
await tableRef.value?.initColumn(fullColumns);
initData();
});
}
},
{
immediate: true,
}
);
const confirmLoading = ref<boolean>(false); const confirmLoading = ref<boolean>(false);
const demandModalRef = ref(); const demandModalRef = ref();
@ -404,6 +205,7 @@
demandModalRef.value.resetForm(); demandModalRef.value.resetForm();
demandRef.value.initData(); demandRef.value.initData();
} catch (error) { } catch (error) {
// eslint-disable-next-line no-console
console.log(error); console.log(error);
} finally { } finally {
confirmLoading.value = false; confirmLoading.value = false;
@ -418,19 +220,6 @@
onMounted(async () => { onMounted(async () => {
initPlatform(); initPlatform();
}); });
const platName = computed(() => {
return getPlatName(platformInfo.value.platform_key);
});
</script> </script>
<style scoped lang="less"> <style scoped lang="less"></style>
:deep(.arco-table-cell-align-left) > span:first-child {
padding-left: 0 !important;
}
:deep(.arco-table-cell-align-left) {
.arco-table-cell-inline-icon + .arco-table-td-content {
padding-right: 19px !important;
}
}
</style>

View File

@ -13,10 +13,10 @@
@cancel="handleDrawerCancel" @cancel="handleDrawerCancel"
> >
<div class="flex items-center justify-between"> <div class="flex items-center justify-between">
<div <div>
><span class="font-medium">{{ platName }}</span <span class="font-medium">{{ platName }}</span>
><span class="ml-1 text-[var(--color-text-4)]">({{ propsRes?.msPagination?.total || 0 }})</span></div <span class="ml-1 text-[var(--color-text-4)]">({{ propsRes?.msPagination?.total || 0 }})</span>
> </div>
<a-input-search <a-input-search
v-model="platformKeyword" v-model="platformKeyword"
:max-length="255" :max-length="255"
@ -26,7 +26,7 @@
@search="searchHandler" @search="searchHandler"
@press-enter="searchHandler" @press-enter="searchHandler"
@clear="searchHandler" @clear="searchHandler"
></a-input-search> />
</div> </div>
<ms-base-table ref="tableRef" v-bind="propsRes" v-on="propsEvent"> <ms-base-table ref="tableRef" v-bind="propsRes" v-on="propsEvent">
<template #demandName="{ record }"> <template #demandName="{ record }">
@ -65,7 +65,7 @@
const currentProjectId = computed(() => appStore.currentProjectId); const currentProjectId = computed(() => appStore.currentProjectId);
const props = defineProps<{ const props = defineProps<{
visible: boolean; visible: boolean;
caseId: string; caseId?: string; // id
drawerLoading: boolean; drawerLoading: boolean;
platformInfo: Record<string, any>; platformInfo: Record<string, any>;
}>(); }>();
@ -93,6 +93,7 @@
width: 300, width: 300,
showTooltip: true, showTooltip: true,
}, },
// TODO
// { // {
// title: 'caseManagement.featureCase.platformDemandState', // title: 'caseManagement.featureCase.platformDemandState',
// width: 300, // width: 300,
@ -118,7 +119,13 @@
rowKey: 'demandId', rowKey: 'demandId',
scroll: { x: '100%' }, scroll: { x: '100%' },
selectable: true, selectable: true,
heightUsed: 290,
showSetting: false, showSetting: false,
showSelectorAll: !props.caseId,
rowSelectionDisabledConfig: {
checkStrictly: false,
disabledKey: props.caseId ? 'disabled' : '',
},
}); });
const tableSelected = computed(() => { const tableSelected = computed(() => {
@ -188,7 +195,7 @@
} }
const initData = async () => { const initData = async () => {
setLoadListParams({ keyword: platformKeyword.value, projectId: currentProjectId.value }); setLoadListParams({ keyword: platformKeyword.value, projectId: currentProjectId.value, caseId: props.caseId });
loadList(); loadList();
}; };
@ -220,31 +227,17 @@
fullColumns = [...columns, ...customFields.value]; fullColumns = [...columns, ...customFields.value];
} catch (error) { } catch (error) {
// eslint-disable-next-line no-console
console.log(error); console.log(error);
} }
} }
// watch(
// () => props.platformInfo.demand_platform_config,
// (val) => {
// if (val) {
// console.log(val);
// initColumn();
// }
// }
// );
// watchEffect(() => {
// if (props.platformInfo.demand_platform_config) {
// }
// });
watch( watch(
() => innerLinkDemandVisible.value, () => innerLinkDemandVisible.value,
async (val) => { async (val) => {
if (val) { if (val) {
resetSelector(); resetSelector();
platformKeyword.value = '';
if (props.platformInfo.demand_platform_config) { if (props.platformInfo.demand_platform_config) {
nextTick(() => { nextTick(() => {
tableRef.value?.initColumn(fullColumns); tableRef.value?.initColumn(fullColumns);
@ -256,4 +249,13 @@
); );
</script> </script>
<style scoped></style> <style scoped lang="less">
:deep(.arco-table-cell-align-left) > span:first-child {
padding-left: 0 !important;
}
:deep(.arco-table-cell-align-left) {
.arco-table-cell-inline-icon + .arco-table-td-content {
padding-right: 18px !important;
}
}
</style>

View File

@ -173,6 +173,7 @@
import { defaultDetailCount, testPlanDefaultDetail } from '@/config/testPlan'; import { defaultDetailCount, testPlanDefaultDetail } from '@/config/testPlan';
import { useI18n } from '@/hooks/useI18n'; import { useI18n } from '@/hooks/useI18n';
import useModal from '@/hooks/useModal'; import useModal from '@/hooks/useModal';
import useOpenNewPage from '@/hooks/useOpenNewPage';
import useAppStore from '@/store/modules/app'; import useAppStore from '@/store/modules/app';
import useCacheStore from '@/store/modules/cache/cache'; import useCacheStore from '@/store/modules/cache/cache';
import useMinderStore from '@/store/modules/components/minder-editor'; import useMinderStore from '@/store/modules/components/minder-editor';
@ -194,6 +195,8 @@
const appStore = useAppStore(); const appStore = useAppStore();
const { openModal } = useModal(); const { openModal } = useModal();
const { t } = useI18n(); const { t } = useI18n();
const { openNewPage } = useOpenNewPage();
const route = useRoute(); const route = useRoute();
const router = useRouter(); const router = useRouter();
const minderStore = useMinderStore(); const minderStore = useMinderStore();
@ -417,12 +420,9 @@
testPlanId: detail.value.id as string, testPlanId: detail.value.id as string,
triggerMode: 'MANUAL', triggerMode: 'MANUAL',
}); });
router.push({ openNewPage(TestPlanRouteEnum.TEST_PLAN_REPORT_DETAIL, {
name: TestPlanRouteEnum.TEST_PLAN_REPORT_DETAIL, id: reportId,
query: { type: testPlanTypeEnum.TEST_PLAN,
id: reportId,
type: testPlanTypeEnum.TEST_PLAN,
},
}); });
Message.success(t('testPlan.testPlanDetail.successfullyGenerated')); Message.success(t('testPlan.testPlanDetail.successfullyGenerated'));
} catch (error) { } catch (error) {