feat(测试计划): 脑图执行用例-缺陷和更多
This commit is contained in:
parent
c56ca2975d
commit
b9128515e1
|
@ -208,6 +208,10 @@
|
|||
onBeforeMount(() => {
|
||||
loadBugList();
|
||||
});
|
||||
|
||||
defineExpose({
|
||||
handleShowTypeChange,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
|
|
@ -33,10 +33,10 @@
|
|||
</MsButton>
|
||||
</a-tooltip>
|
||||
<template #content>
|
||||
<a-doption v-permission="['PROJECT_BUG:READ+ADD']" value="new">
|
||||
<a-doption v-permission="['PROJECT_BUG:READ+ADD']" value="new" @click="showAddDefectDrawer = true">
|
||||
{{ t('testPlan.featureCase.noBugDataNewBug') }}
|
||||
</a-doption>
|
||||
<a-doption v-permission="['PROJECT_BUG:READ']" value="link">
|
||||
<a-doption v-permission="['PROJECT_BUG:READ']" value="link" @click="showLinkDefectDrawer = true">
|
||||
{{ t('caseManagement.featureCase.linkDefect') }}
|
||||
</a-doption>
|
||||
</template>
|
||||
|
@ -82,6 +82,7 @@
|
|||
/>
|
||||
<BugList
|
||||
v-else-if="activeExtraKey === 'bug'"
|
||||
ref="bugListRef"
|
||||
:active-case="activeCaseInfo"
|
||||
is-test-plan-case
|
||||
:show-disassociate-button="props.canEdit && hasAnyPermission(['PROJECT_TEST_PLAN:READ+EXECUTE'])"
|
||||
|
@ -95,10 +96,29 @@
|
|||
/>
|
||||
</template>
|
||||
</MsMinderEditor>
|
||||
<LinkDefectDrawer
|
||||
v-model:visible="showLinkDefectDrawer"
|
||||
:case-id="selectNode?.data?.caseId ?? ''"
|
||||
:drawer-loading="linkDrawerLoading"
|
||||
:show-selector-all="false"
|
||||
@save="associateSuccessHandler"
|
||||
/>
|
||||
<AddDefectDrawer
|
||||
v-model:visible="showAddDefectDrawer"
|
||||
:case-id="selectNode?.data?.id ?? ''"
|
||||
:extra-params="{
|
||||
testPlanCaseId: selectNode?.data?.id,
|
||||
caseId: selectNode?.data?.caseId,
|
||||
testPlanId: props.planId,
|
||||
}"
|
||||
@success="handleAddBugDone"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
|
||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||
import MsDescription, { Description } from '@/components/pure/ms-description/index.vue';
|
||||
import MsMinderEditor from '@/components/pure/ms-minder-editor/minderEditor.vue';
|
||||
|
@ -114,16 +134,19 @@
|
|||
import { MsFileItem } from '@/components/pure/ms-upload/types';
|
||||
import Attachment from '@/components/business/ms-minders/featureCaseMinder/attachment.vue';
|
||||
import BugList from '@/components/business/ms-minders/featureCaseMinder/bugList.vue';
|
||||
import AddDefectDrawer from '@/views/case-management/caseManagementFeature/components/tabContent/tabBug/addDefectDrawer.vue';
|
||||
import LinkDefectDrawer from '@/views/case-management/caseManagementFeature/components/tabContent/tabBug/linkDefectDrawer.vue';
|
||||
import ReviewCommentList from '@/views/case-management/caseManagementFeature/components/tabContent/tabComment/reviewCommentList.vue';
|
||||
|
||||
import { getCasePlanMinder } from '@/api/modules/case-management/caseReview';
|
||||
import { executeHistory, getCaseDetail } from '@/api/modules/test-plan/testPlan';
|
||||
import { associateBugToPlan, executeHistory, getCaseDetail } from '@/api/modules/test-plan/testPlan';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import useMinderStore from '@/store/modules/components/minder-editor/index';
|
||||
import useTestPlanFeatureCaseStore from '@/store/modules/testPlan/testPlanFeatureCase';
|
||||
import { findNodeByKey, mapTree, replaceNodeInTree } from '@/utils';
|
||||
import { hasAllPermission, hasAnyPermission } from '@/utils/permission';
|
||||
|
||||
import type { TableQueryParams } from '@/models/common';
|
||||
import { ModuleTreeNode } from '@/models/common';
|
||||
import type { ExecuteHistoryItem } from '@/models/testPlan/testPlan';
|
||||
import { MinderEventName, MinderKeyEnum } from '@/enums/minderEnum';
|
||||
|
@ -143,6 +166,7 @@
|
|||
|
||||
const emit = defineEmits<{
|
||||
(e: 'operation', type: string, node: MinderJsonNode): void;
|
||||
(e: 'handleAddBugDone'): void;
|
||||
}>();
|
||||
|
||||
const { t } = useI18n();
|
||||
|
@ -531,6 +555,37 @@
|
|||
extraVisible.value = false;
|
||||
}
|
||||
|
||||
// 添加缺陷
|
||||
const showLinkDefectDrawer = ref(false);
|
||||
const showAddDefectDrawer = ref(false);
|
||||
const linkDrawerLoading = ref(false);
|
||||
const bugListRef = ref<InstanceType<typeof BugList>>();
|
||||
function handleAddBugDone() {
|
||||
if (extraVisible.value && activeExtraKey.value === 'bug') {
|
||||
bugListRef.value?.handleShowTypeChange();
|
||||
}
|
||||
emit('handleAddBugDone');
|
||||
}
|
||||
async function associateSuccessHandler(params: TableQueryParams) {
|
||||
try {
|
||||
linkDrawerLoading.value = true;
|
||||
await associateBugToPlan({
|
||||
...params,
|
||||
testPlanCaseId: selectNode.value.data?.id,
|
||||
caseId: selectNode.value.data?.caseId,
|
||||
testPlanId: props.planId,
|
||||
});
|
||||
Message.success(t('caseManagement.featureCase.associatedSuccess'));
|
||||
linkDrawerLoading.value = false;
|
||||
handleAddBugDone();
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
} finally {
|
||||
linkDrawerLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
initCaseTree,
|
||||
});
|
||||
|
@ -542,5 +597,6 @@
|
|||
}
|
||||
:deep(.ms-list) {
|
||||
margin: 0;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
>
|
||||
<template #title>
|
||||
{{ t('testPlan.featureCase.batchChangeExecutor') }}
|
||||
<div class="ml-1 text-[var(--color-text-4)]">
|
||||
<div v-show="props.showTitleCount" class="ml-1 text-[var(--color-text-4)]">
|
||||
{{
|
||||
t('common.selectedCount', {
|
||||
count: props.count,
|
||||
|
@ -66,6 +66,7 @@
|
|||
count: number;
|
||||
params?: BatchUpdateCaseExecutorParams;
|
||||
batchUpdateExecutor: (...args: any) => Promise<any>; // 更新执行人接口
|
||||
showTitleCount: boolean;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
|
|
|
@ -116,6 +116,8 @@
|
|||
:module-tree="moduleTree"
|
||||
:plan-id="props.planId"
|
||||
:can-edit="props.canEdit"
|
||||
@operation="handleMinderOperation"
|
||||
@handle-add-bug-done="emit('refresh')"
|
||||
/>
|
||||
</div>
|
||||
<!-- 批量执行 -->
|
||||
|
@ -147,6 +149,7 @@
|
|||
v-model:visible="batchUpdateExecutorModalVisible"
|
||||
:count="batchParams.currentSelectCount || tableSelected.length"
|
||||
:params="batchUpdateParams"
|
||||
:show-title-count="showType === 'list'"
|
||||
:batch-update-executor="batchUpdateCaseExecutor"
|
||||
@load-list="resetSelectorAndCaseList"
|
||||
/>
|
||||
|
@ -166,9 +169,11 @@
|
|||
import { computed, onBeforeMount, ref } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
|
||||
import { MsAdvanceFilter } from '@/components/pure/ms-advance-filter';
|
||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||
import type { MinderJsonNode, MinderJsonNodeData } from '@/components/pure/ms-minder-editor/props';
|
||||
import MsPopconfirm from '@/components/pure/ms-popconfirm/index.vue';
|
||||
import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
|
||||
import type {
|
||||
|
@ -180,6 +185,7 @@
|
|||
import useTable from '@/components/pure/ms-table/useTable';
|
||||
import CaseLevel from '@/components/business/ms-case-associate/caseLevel.vue';
|
||||
import ExecuteResult from '@/components/business/ms-case-associate/executeResult.vue';
|
||||
import { getMinderOperationParams } from '@/components/business/ms-minders/caseReviewMinder/utils';
|
||||
import MsTestPlanFeatureCaseMinder from '@/components/business/ms-minders/testPlanFeatureCaseMinder/index.vue';
|
||||
import BugCountPopover from './bugCountPopover.vue';
|
||||
import BatchApiMoveModal from '@/views/test-plan/testPlan/components/batchApiMoveModal.vue';
|
||||
|
@ -205,7 +211,7 @@
|
|||
import { characterLimit } from '@/utils';
|
||||
import { hasAllPermission, hasAnyPermission } from '@/utils/permission';
|
||||
|
||||
import { DragSortParams } from '@/models/common';
|
||||
import { DragSortParams, ModuleTreeNode } from '@/models/common';
|
||||
import type { ExecuteFeatureCaseFormParams, PlanDetailFeatureCaseItem } from '@/models/testPlan/testPlan';
|
||||
import { LastExecuteResults } from '@/enums/caseEnum';
|
||||
import { TestPlanRouteEnum } from '@/enums/routeEnum';
|
||||
|
@ -227,6 +233,7 @@
|
|||
|
||||
const emit = defineEmits<{
|
||||
(e: 'refresh'): void;
|
||||
(e: 'selectParentNode', tree: ModuleTreeNode[]): void;
|
||||
}>();
|
||||
|
||||
const { t } = useI18n();
|
||||
|
@ -558,8 +565,10 @@
|
|||
}
|
||||
|
||||
function resetSelectorAndCaseList() {
|
||||
resetSelector();
|
||||
loadList();
|
||||
if (showType.value === 'list') {
|
||||
resetSelector();
|
||||
loadList();
|
||||
}
|
||||
}
|
||||
|
||||
// 拖拽排序
|
||||
|
@ -613,29 +622,39 @@
|
|||
}
|
||||
}
|
||||
|
||||
const batchUpdateParams = ref();
|
||||
const minderSelectData = ref<MinderJsonNodeData>(); // 当前脑图选中的数据
|
||||
|
||||
// 批量取消关联用例
|
||||
function handleBatchDisassociateCase() {
|
||||
const count =
|
||||
showType.value !== 'list'
|
||||
? minderSelectData.value?.count
|
||||
: batchParams.value.currentSelectCount || tableSelected.value.length;
|
||||
const batchDisassociateTitle =
|
||||
showType.value !== 'list' && minderSelectData.value?.resource?.includes(t('common.case'))
|
||||
? t('testPlan.featureCase.disassociateTip', { name: characterLimit(minderSelectData.value?.text) })
|
||||
: t('caseManagement.caseReview.disassociateConfirmTitle', { count });
|
||||
openModal({
|
||||
type: 'warning',
|
||||
title: t('caseManagement.caseReview.disassociateConfirmTitle', {
|
||||
count: batchParams.value.currentSelectCount || tableSelected.value.length,
|
||||
}),
|
||||
title: batchDisassociateTitle,
|
||||
content: t('testPlan.featureCase.batchDisassociateTipContent'),
|
||||
okText: t('common.cancelLink'),
|
||||
cancelText: t('common.cancel'),
|
||||
onBeforeOk: async () => {
|
||||
try {
|
||||
const tableParams = await getTableParams(true);
|
||||
await batchDisassociateCase({
|
||||
selectIds: tableSelected.value as string[],
|
||||
selectAll: batchParams.value.selectAll,
|
||||
excludeIds: batchParams.value?.excludeIds || [],
|
||||
...tableParams,
|
||||
});
|
||||
await batchDisassociateCase(batchUpdateParams.value);
|
||||
Message.success(t('common.updateSuccess'));
|
||||
resetCaseList();
|
||||
initModules();
|
||||
const tree = cloneDeep(moduleTree.value);
|
||||
emit('refresh');
|
||||
await initModules();
|
||||
await getModuleCount();
|
||||
if (!Object.keys(modulesCount.value).includes(props.activeModule)) {
|
||||
// 模块树选中返回上一级
|
||||
emit('selectParentNode', tree);
|
||||
} else {
|
||||
refresh(false);
|
||||
}
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
|
@ -678,22 +697,11 @@
|
|||
}
|
||||
|
||||
// 批量修改执行人 和 批量移动
|
||||
const batchUpdateParams = ref();
|
||||
const batchUpdateExecutorModalVisible = ref(false);
|
||||
const batchMoveModalVisible = ref(false);
|
||||
|
||||
// 处理表格选中后批量操作
|
||||
async function handleTableBatch(event: BatchActionParams, params: BatchActionQueryParams) {
|
||||
tableSelected.value = params?.selectedIds || [];
|
||||
batchParams.value = { ...params, selectIds: params?.selectedIds };
|
||||
const tableParams = await getTableParams(true);
|
||||
batchUpdateParams.value = {
|
||||
selectIds: tableSelected.value as string[],
|
||||
selectAll: batchParams.value.selectAll,
|
||||
excludeIds: batchParams.value?.excludeIds || [],
|
||||
...tableParams,
|
||||
};
|
||||
switch (event.eventTag) {
|
||||
function handleOperation(type?: string) {
|
||||
switch (type) {
|
||||
case 'execute':
|
||||
batchExecuteModalVisible.value = true;
|
||||
break;
|
||||
|
@ -710,6 +718,30 @@
|
|||
break;
|
||||
}
|
||||
}
|
||||
// 脑图操作
|
||||
function handleMinderOperation(type: string, node: MinderJsonNode) {
|
||||
minderSelectData.value = node.data;
|
||||
batchUpdateParams.value = {
|
||||
...getMinderOperationParams(node),
|
||||
testPlanId: props.planId,
|
||||
projectId: node.data?.id !== 'NONE' ? node.data?.projectId : '',
|
||||
};
|
||||
handleOperation(type);
|
||||
}
|
||||
|
||||
// 处理表格选中后批量操作
|
||||
async function handleTableBatch(event: BatchActionParams, params: BatchActionQueryParams) {
|
||||
tableSelected.value = params?.selectedIds || [];
|
||||
batchParams.value = { ...params, selectIds: params?.selectedIds };
|
||||
const tableParams = await getTableParams(true);
|
||||
batchUpdateParams.value = {
|
||||
selectIds: tableSelected.value as string[],
|
||||
selectAll: batchParams.value.selectAll,
|
||||
excludeIds: batchParams.value?.excludeIds || [],
|
||||
...tableParams,
|
||||
};
|
||||
handleOperation(event.eventTag);
|
||||
}
|
||||
|
||||
// 去用例详情页面
|
||||
function toCaseDetail(record: PlanDetailFeatureCaseItem) {
|
||||
|
|
|
@ -135,6 +135,25 @@
|
|||
emit('folderNodeSelect', _selectedKeys as string[], offspringIds, node.name, getNodeParentId(node));
|
||||
}
|
||||
|
||||
/**
|
||||
* 选中父节点
|
||||
* @param tree 原来的模块树
|
||||
*/
|
||||
function selectParentNode(tree: ModuleTreeNode[]) {
|
||||
mapTree(tree || [], (e) => {
|
||||
if (e.id === selectedKeys.value[0]) {
|
||||
if (e.parentId) {
|
||||
selectedKeys.value = [e.parentId];
|
||||
folderNodeSelect([e.parentId], e.parent);
|
||||
} else {
|
||||
setActiveFolder('all');
|
||||
}
|
||||
return e;
|
||||
}
|
||||
return e;
|
||||
});
|
||||
}
|
||||
|
||||
onBeforeMount(() => {
|
||||
setIsExpandAll();
|
||||
initModules();
|
||||
|
@ -160,5 +179,6 @@
|
|||
defineExpose({
|
||||
setActiveFolder,
|
||||
initModules,
|
||||
selectParentNode,
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
:active-module="activeFolderId"
|
||||
:offspring-ids="offspringIds"
|
||||
:can-edit="props.canEdit"
|
||||
@select-parent-node="selectParentNode"
|
||||
@refresh="emit('refresh')"
|
||||
></CaseTable>
|
||||
</template>
|
||||
|
@ -38,6 +39,8 @@
|
|||
|
||||
import useTestPlanFeatureCaseStore from '@/store/modules/testPlan/testPlanFeatureCase';
|
||||
|
||||
import { ModuleTreeNode } from '@/models/common';
|
||||
|
||||
const props = defineProps<{
|
||||
canEdit: boolean;
|
||||
treeType: 'MODULE' | 'COLLECTION';
|
||||
|
@ -72,6 +75,10 @@
|
|||
|
||||
const caseTreeRef = ref<InstanceType<typeof CaseTree>>();
|
||||
|
||||
function selectParentNode(folderTree: ModuleTreeNode[]) {
|
||||
caseTreeRef.value?.selectParentNode(folderTree);
|
||||
}
|
||||
|
||||
function getCaseTableList() {
|
||||
nextTick(async () => {
|
||||
await caseTreeRef.value?.initModules();
|
||||
|
|
Loading…
Reference in New Issue