style(测试计划): 测试计划详情-视图优化-模块/测试点的切换放在左侧

--story=1015918 --user=吕梦园
https://www.tapd.cn/55049933/prong/stories/view/1155049933001015918
This commit is contained in:
teukkk 2024-08-27 14:47:54 +08:00 committed by 刘瑞斌
parent 1bf05cd0c1
commit 5bc575bfbe
9 changed files with 102 additions and 93 deletions

View File

@ -1,5 +1,5 @@
<template> <template>
<div class="p-[16px]"> <div>
<a-input <a-input
v-model:model-value="moduleKeyword" v-model:model-value="moduleKeyword"
:placeholder=" :placeholder="

View File

@ -1,21 +1,27 @@
<template> <template>
<MsSplitBox> <MsSplitBox>
<template #first> <template #first>
<CaseTree <div class="p-[16px]">
ref="caseTreeRef" <a-radio-group v-model:model-value="treeType" size="medium" class="mb-[16px] w-full" type="button">
:modules-count="modulesCount" <a-radio value="COLLECTION">{{ t('ms.case.associate.testSet') }}</a-radio>
:selected-keys="selectedKeys" <a-radio value="MODULE">{{ t('common.module') }}</a-radio>
:tree-type="props.treeType" </a-radio-group>
@folder-node-select="handleFolderNodeSelect" <CaseTree
@init="initModuleTree" ref="caseTreeRef"
@change-protocol="handleProtocolChange" :modules-count="modulesCount"
/> :selected-keys="selectedKeys"
:tree-type="treeType"
@folder-node-select="handleFolderNodeSelect"
@init="initModuleTree"
@change-protocol="handleProtocolChange"
/>
</div>
</template> </template>
<template #second> <template #second>
<CaseTable <CaseTable
ref="caseTableRef" ref="caseTableRef"
:plan-id="planId" :plan-id="planId"
:tree-type="props.treeType" :tree-type="treeType"
:modules-count="modulesCount" :modules-count="modulesCount"
:module-name="moduleName" :module-name="moduleName"
:module-parent-id="moduleParentId" :module-parent-id="moduleParentId"
@ -41,19 +47,20 @@
import CaseTree from './components/caseTree.vue'; import CaseTree from './components/caseTree.vue';
import { getApiCaseModuleCount } from '@/api/modules/test-plan/testPlan'; import { getApiCaseModuleCount } from '@/api/modules/test-plan/testPlan';
import { useI18n } from '@/hooks/useI18n';
import { ModuleTreeNode } from '@/models/common'; import { ModuleTreeNode } from '@/models/common';
import type { PlanDetailApiCaseQueryParams } from '@/models/testPlan/testPlan'; import type { PlanDetailApiCaseQueryParams } from '@/models/testPlan/testPlan';
const props = defineProps<{ const props = defineProps<{
canEdit: boolean; canEdit: boolean;
treeType: 'MODULE' | 'COLLECTION';
}>(); }>();
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'refresh'): void; (e: 'refresh'): void;
}>(); }>();
const { t } = useI18n();
const route = useRoute(); const route = useRoute();
const planId = ref(route.query.id as string); const planId = ref(route.query.id as string);
@ -98,6 +105,7 @@
caseTreeRef.value?.initModules(); caseTreeRef.value?.initModules();
} }
const treeType = ref<'MODULE' | 'COLLECTION'>('COLLECTION');
function getCaseTableList() { function getCaseTableList() {
nextTick(() => { nextTick(() => {
initModules(); initModules();
@ -108,8 +116,17 @@
} }
}); });
} }
watch(
defineExpose({ () => treeType.value,
getCaseTableList, () => {
}); getCaseTableList();
}
);
</script> </script>
<style lang="less" scoped>
:deep(.arco-radio-button) {
flex: 1;
text-align: center;
}
</style>

View File

@ -1,5 +1,5 @@
<template> <template>
<div class="p-[16px]"> <div>
<a-input <a-input
v-model:model-value="moduleKeyword" v-model:model-value="moduleKeyword"
:placeholder=" :placeholder="

View File

@ -1,20 +1,26 @@
<template> <template>
<MsSplitBox> <MsSplitBox>
<template #first> <template #first>
<CaseTree <div class="p-[16px]">
ref="caseTreeRef" <a-radio-group v-model:model-value="treeType" size="medium" class="mb-[16px] w-full" type="button">
:modules-count="modulesCount" <a-radio value="COLLECTION">{{ t('ms.case.associate.testSet') }}</a-radio>
:selected-keys="selectedKeys" <a-radio value="MODULE">{{ t('common.module') }}</a-radio>
:tree-type="props.treeType" </a-radio-group>
@folder-node-select="handleFolderNodeSelect" <CaseTree
@init="initModuleTree" ref="caseTreeRef"
/> :modules-count="modulesCount"
:selected-keys="selectedKeys"
:tree-type="treeType"
@folder-node-select="handleFolderNodeSelect"
@init="initModuleTree"
/>
</div>
</template> </template>
<template #second> <template #second>
<CaseTable <CaseTable
ref="caseTableRef" ref="caseTableRef"
:plan-id="planId" :plan-id="planId"
:tree-type="props.treeType" :tree-type="treeType"
:modules-count="modulesCount" :modules-count="modulesCount"
:module-name="moduleName" :module-name="moduleName"
:module-parent-id="moduleParentId" :module-parent-id="moduleParentId"
@ -39,19 +45,20 @@
import CaseTree from './components/scenarioTree.vue'; import CaseTree from './components/scenarioTree.vue';
import { getApiScenarioModuleCount } from '@/api/modules/test-plan/testPlan'; import { getApiScenarioModuleCount } from '@/api/modules/test-plan/testPlan';
import { useI18n } from '@/hooks/useI18n';
import { ModuleTreeNode } from '@/models/common'; import { ModuleTreeNode } from '@/models/common';
import type { PlanDetailApiScenarioQueryParams } from '@/models/testPlan/testPlan'; import type { PlanDetailApiScenarioQueryParams } from '@/models/testPlan/testPlan';
const props = defineProps<{ const props = defineProps<{
canEdit: boolean; canEdit: boolean;
treeType: 'MODULE' | 'COLLECTION';
}>(); }>();
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'refresh'): void; (e: 'refresh'): void;
}>(); }>();
const { t } = useI18n();
const route = useRoute(); const route = useRoute();
const planId = ref(route.query.id as string); const planId = ref(route.query.id as string);
@ -92,6 +99,7 @@
caseTreeRef.value?.initModules(); caseTreeRef.value?.initModules();
} }
const treeType = ref<'MODULE' | 'COLLECTION'>('COLLECTION');
function getCaseTableList() { function getCaseTableList() {
nextTick(() => { nextTick(() => {
initModules(); initModules();
@ -102,8 +110,17 @@
} }
}); });
} }
watch(
defineExpose({ () => treeType.value,
getCaseTableList, () => {
}); getCaseTableList();
}
);
</script> </script>
<style lang="less" scoped>
:deep(.arco-radio-button) {
flex: 1;
text-align: center;
}
</style>

View File

@ -14,7 +14,7 @@
@adv-search="loadCaseList()" @adv-search="loadCaseList()"
@refresh="handleRefreshAll" @refresh="handleRefreshAll"
> >
<template v-if="props.treeType === 'MODULE'" #right> <template #right>
<a-radio-group <a-radio-group
v-model:model-value="showType" v-model:model-value="showType"
type="button" type="button"
@ -263,6 +263,7 @@
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'refresh'): void; (e: 'refresh'): void;
(e: 'setTreeTypeToModule'): void; // TODO lmy v3.4
(e: 'selectParentNode', tree: ModuleTreeNode[]): void; (e: 'selectParentNode', tree: ModuleTreeNode[]): void;
}>(); }>();
@ -549,6 +550,7 @@
} }
); );
// TODO lmy v3.4
watch( watch(
() => props.treeType, () => props.treeType,
(val) => { (val) => {
@ -628,18 +630,14 @@
refresh(); refresh();
} }
function handleTreeTypeChange() {
if (showType.value !== 'list') {
showType.value = 'list';
}
loadCaseList(true);
}
function handleShowTypeChange(val: string | number | boolean) { function handleShowTypeChange(val: string | number | boolean) {
if (val === 'minder') { if (val === 'minder') {
keyword.value = ''; keyword.value = '';
// if (props.treeType === 'COLLECTION') {
getModuleCount(); emit('setTreeTypeToModule'); // TODO lmy v3.4
return;
}
getModuleCount(); //
} else { } else {
loadCaseList(); loadCaseList();
} }
@ -907,7 +905,7 @@
defineExpose({ defineExpose({
resetSelector, resetSelector,
handleTreeTypeChange, refresh,
}); });
await tableStore.initColumn(TableKeyEnum.TEST_PLAN_DETAIL_FEATURE_CASE_TABLE, columns.value, 'drawer', true); await tableStore.initColumn(TableKeyEnum.TEST_PLAN_DETAIL_FEATURE_CASE_TABLE, columns.value, 'drawer', true);

View File

@ -2,9 +2,13 @@
<MsSplitBox> <MsSplitBox>
<template #first> <template #first>
<div class="p-[16px]"> <div class="p-[16px]">
<a-radio-group v-model:model-value="treeType" size="medium" class="mb-[16px] w-full" type="button">
<a-radio value="COLLECTION">{{ t('ms.case.associate.testSet') }}</a-radio>
<a-radio value="MODULE">{{ t('common.module') }}</a-radio>
</a-radio-group>
<CaseTree <CaseTree
ref="caseTreeRef" ref="caseTreeRef"
:tree-type="props.treeType" :tree-type="treeType"
:modules-count="modulesCount" :modules-count="modulesCount"
:selected-keys="selectedKeys" :selected-keys="selectedKeys"
@folder-node-select="handleFolderNodeSelect" @folder-node-select="handleFolderNodeSelect"
@ -14,7 +18,7 @@
<template #second> <template #second>
<CaseTable <CaseTable
ref="caseTableRef" ref="caseTableRef"
:tree-type="props.treeType" :tree-type="treeType"
:plan-id="planId" :plan-id="planId"
:modules-count="modulesCount" :modules-count="modulesCount"
:module-name="moduleName" :module-name="moduleName"
@ -24,6 +28,7 @@
:can-edit="props.canEdit" :can-edit="props.canEdit"
@select-parent-node="selectParentNode" @select-parent-node="selectParentNode"
@refresh="emit('refresh')" @refresh="emit('refresh')"
@set-tree-type-to-module="setTreeTypeToModule"
></CaseTable> ></CaseTable>
</template> </template>
</MsSplitBox> </MsSplitBox>
@ -37,19 +42,20 @@
import CaseTable from './components/caseTable.vue'; import CaseTable from './components/caseTable.vue';
import CaseTree from './components/caseTree.vue'; import CaseTree from './components/caseTree.vue';
import { useI18n } from '@/hooks/useI18n';
import useTestPlanFeatureCaseStore from '@/store/modules/testPlan/testPlanFeatureCase'; import useTestPlanFeatureCaseStore from '@/store/modules/testPlan/testPlanFeatureCase';
import { ModuleTreeNode } from '@/models/common'; import { ModuleTreeNode } from '@/models/common';
const props = defineProps<{ const props = defineProps<{
canEdit: boolean; canEdit: boolean;
treeType: 'MODULE' | 'COLLECTION';
}>(); }>();
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'refresh'): void; (e: 'refresh'): void;
}>(); }>();
const { t } = useI18n();
const route = useRoute(); const route = useRoute();
const testPlanFeatureCaseStore = useTestPlanFeatureCaseStore(); const testPlanFeatureCaseStore = useTestPlanFeatureCaseStore();
@ -79,18 +85,31 @@
caseTreeRef.value?.selectParentNode(folderTree); caseTreeRef.value?.selectParentNode(folderTree);
} }
const treeType = ref<'MODULE' | 'COLLECTION'>('COLLECTION');
function setTreeTypeToModule() {
treeType.value = 'MODULE'; // TODO lmy v3.4
}
function getCaseTableList() { function getCaseTableList() {
nextTick(async () => { nextTick(async () => {
await caseTreeRef.value?.initModules(); await caseTreeRef.value?.initModules();
if (activeFolderId.value !== 'all') { if (activeFolderId.value !== 'all') {
caseTreeRef.value?.setActiveFolder('all'); caseTreeRef.value?.setActiveFolder('all');
} else { } else {
caseTableRef.value?.handleTreeTypeChange(); caseTableRef.value?.refresh();
} }
}); });
} }
watch(
defineExpose({ () => treeType.value,
getCaseTableList, () => {
}); getCaseTableList();
}
);
</script> </script>
<style lang="less" scoped>
:deep(.arco-radio-button) {
flex: 1;
text-align: center;
}
</style>

View File

@ -19,16 +19,6 @@
</a-tooltip> </a-tooltip>
</template> </template>
<template #headerRight> <template #headerRight>
<a-switch
v-model="treeType"
size="small"
type="line"
checked-value="MODULE"
unchecked-value="COLLECTION"
class="mr-[4px]"
@change="loadActiveTabList"
/>
<span class="mr-[14px]">{{ t('testPlan.testPlanDetail.moduleView') }}</span>
<MsButton v-if="isEnableEdit" type="button" status="default" @click="editorCopyHandler(false)"> <MsButton v-if="isEnableEdit" type="button" status="default" @click="editorCopyHandler(false)">
<MsIcon type="icon-icon_edit_outlined" class="mr-[8px]" /> <MsIcon type="icon-icon_edit_outlined" class="mr-[8px]" />
{{ t('common.edit') }} {{ t('common.edit') }}
@ -117,8 +107,6 @@
/> />
<FeatureCase <FeatureCase
v-else-if="activeTab === 'featureCase'" v-else-if="activeTab === 'featureCase'"
ref="featureCaseRef"
:tree-type="treeType"
:can-edit="countDetail.status !== 'ARCHIVED'" :can-edit="countDetail.status !== 'ARCHIVED'"
@refresh="initDetail" @refresh="initDetail"
/> />
@ -127,17 +115,9 @@
:can-edit="countDetail.status !== 'ARCHIVED'" :can-edit="countDetail.status !== 'ARCHIVED'"
@refresh="initDetail" @refresh="initDetail"
/> />
<ApiCase <ApiCase v-else-if="activeTab === 'apiCase'" :can-edit="countDetail.status !== 'ARCHIVED'" @refresh="initDetail" />
v-else-if="activeTab === 'apiCase'"
ref="apiCaseRef"
:tree-type="treeType"
:can-edit="countDetail.status !== 'ARCHIVED'"
@refresh="initDetail"
/>
<ApiScenario <ApiScenario
v-else-if="activeTab === 'apiScenario'" v-else-if="activeTab === 'apiScenario'"
ref="apiScenarioRef"
:tree-type="treeType"
:can-edit="countDetail.status !== 'ARCHIVED'" :can-edit="countDetail.status !== 'ARCHIVED'"
@refresh="initDetail" @refresh="initDetail"
/> />
@ -217,7 +197,6 @@
const detail = ref<TestPlanDetail>({ const detail = ref<TestPlanDetail>({
...testPlanDefaultDetail, ...testPlanDefaultDetail,
}); });
const treeType = ref<'MODULE' | 'COLLECTION'>('COLLECTION');
const countDetail = ref<PassRateCountDetail>({ ...defaultDetailCount }); const countDetail = ref<PassRateCountDetail>({ ...defaultDetailCount });
@ -531,25 +510,6 @@
} }
} }
const featureCaseRef = ref<InstanceType<typeof FeatureCase>>();
const apiCaseRef = ref<InstanceType<typeof ApiCase>>();
const apiScenarioRef = ref<InstanceType<typeof ApiScenario>>();
function loadActiveTabList() {
switch (activeTab.value) {
case 'featureCase':
featureCaseRef.value?.getCaseTableList();
return;
case 'apiCase':
apiCaseRef.value?.getCaseTableList();
return;
case 'apiScenario':
apiScenarioRef.value?.getCaseTableList();
return;
default:
return '';
}
}
function changeTabInterceptor(newVal: string | number, oldVal: string | number, done: () => void) { function changeTabInterceptor(newVal: string | number, oldVal: string | number, done: () => void) {
if (oldVal === 'plan' && minderStore.minderUnsaved) { if (oldVal === 'plan' && minderStore.minderUnsaved) {
openModal({ openModal({

View File

@ -96,7 +96,6 @@ export default {
'testPlan.planForm.pickCases': 'Select cases', 'testPlan.planForm.pickCases': 'Select cases',
'testPlan.testPlanDetail.executed': 'Executed', 'testPlan.testPlanDetail.executed': 'Executed',
'testPlan.testPlanDetail.generateReport': 'Generate report', 'testPlan.testPlanDetail.generateReport': 'Generate report',
'testPlan.testPlanDetail.moduleView': 'Module View',
'testPlan.testPlanDetail.successfullyGenerated': 'Successfully generated', 'testPlan.testPlanDetail.successfullyGenerated': 'Successfully generated',
'testPlan.bugManagement.bug': 'Defect list', 'testPlan.bugManagement.bug': 'Defect list',
'testPlan.bugManagement.bugName': 'name', 'testPlan.bugManagement.bugName': 'name',

View File

@ -92,7 +92,6 @@ export default {
'testPlan.planForm.pickCases': '选择用例', 'testPlan.planForm.pickCases': '选择用例',
'testPlan.testPlanDetail.executed': '已执行', 'testPlan.testPlanDetail.executed': '已执行',
'testPlan.testPlanDetail.generateReport': '生成报告', 'testPlan.testPlanDetail.generateReport': '生成报告',
'testPlan.testPlanDetail.moduleView': '模块视图',
'testPlan.testPlanDetail.successfullyGenerated': '生成成功', 'testPlan.testPlanDetail.successfullyGenerated': '生成成功',
'testPlan.bugManagement.bug': '缺陷列表', 'testPlan.bugManagement.bug': '缺陷列表',
'testPlan.bugManagement.bugName': '名称', 'testPlan.bugManagement.bugName': '名称',