feat(测试计划): 修改测试计划部分细节和详情缺陷管理列表页面

This commit is contained in:
xinxin.wu 2024-05-10 15:11:37 +08:00 committed by 刘瑞斌
parent 92d441eaa8
commit 2c48d8f947
21 changed files with 382 additions and 48 deletions

View File

@ -3,7 +3,9 @@ import {
addTestPlanModuleUrl,
AddTestPlanUrl,
archivedPlanUrl,
batchCopyPlanUrl,
batchDeletePlanUrl,
batchMovePlanUrl,
deletePlanUrl,
DeleteTestPlanModuleUrl,
getStatisticalCountUrl,
@ -12,6 +14,7 @@ import {
GetTestPlanModuleCountUrl,
GetTestPlanModuleUrl,
MoveTestPlanModuleUrl,
planDetailBugPageUrl,
updateTestPlanModuleUrl,
UpdateTestPlanUrl,
} from '@/api/requrls/test-plan/testPlan';
@ -19,7 +22,13 @@ import {
import type { CreateOrUpdateModule, UpdateModule } from '@/models/caseManagement/featureCase';
import type { CommonList, MoveModules, TableQueryParams } from '@/models/common';
import { ModuleTreeNode } from '@/models/common';
import type { AddTestPlanParams, TestPlanDetail, TestPlanItem, UseCountType } from '@/models/testPlan/testPlan';
import type {
AddTestPlanParams,
PlanDetailBugItem,
TestPlanDetail,
TestPlanItem,
UseCountType,
} from '@/models/testPlan/testPlan';
// 获取模块树
export function getTestPlanModule(params: TableQueryParams) {
@ -86,3 +95,15 @@ export function getStatisticalCount(id: string) {
export function archivedPlan(id: string | undefined) {
return MSR.get({ url: `${archivedPlanUrl}/${id}` });
}
// 批量复制测试计划
export function batchCopyPlan(data: TableQueryParams) {
return MSR.post({ url: batchCopyPlanUrl, data });
}
// 批量移动测试计划
export function batchMovePlan(data: TableQueryParams) {
return MSR.post({ url: batchMovePlanUrl, data });
}
// 计划详情缺陷管理列表
export function planDetailBugPage(data: TableQueryParams) {
return MSR.post<CommonList<PlanDetailBugItem>>({ url: planDetailBugPageUrl, data });
}

View File

@ -26,3 +26,9 @@ export const deletePlanUrl = '/test-plan/delete';
export const getStatisticalCountUrl = '/test-plan/getCount';
// 归档
export const archivedPlanUrl = '/test-plan/archived';
// 批量复制
export const batchCopyPlanUrl = '/test-plan/batch/copy';
// 批量移动
export const batchMovePlanUrl = '/test-plan/batch/move';
// 计划详情缺陷管理列表
export const planDetailBugPageUrl = '/test-plan/bug/page';

View File

@ -63,6 +63,8 @@ export enum TableKeyEnum {
PROJECT_MANAGEMENT_ENV_ALL_PARAM_HEADER = 'projectManagementEnvAllParamHeader',
PROJECT_MANAGEMENT_ENV_ALL_PARAM_VARIABLE = 'projectManagementEnvAllParamVariable',
TEST_PLAN_ALL_TABLE = 'testPlanAllTable',
TEST_PLAN_DETAIL_BUG_TABLE = 'testPlanDetailBug',
TEST_PLAN_DETAIL_BUG_TABLE_CASE_COUNT = 'testPlanDetailBugCaseCount',
TASK_API_CASE_SYSTEM = 'taskCenterApiCaseSystem',
TASK_API_CASE_ORGANIZATION = 'taskCenterApiCaseOrganization',
TASK_API_CASE_PROJECT = 'taskCenterApiCaseProject',

View File

@ -139,6 +139,7 @@ export default {
'common.yes': 'Yes',
'common.no': 'No',
'common.creator': 'Creator',
'common.createTime': 'Created time',
'common.followSuccess': 'Followed',
'common.unFollowSuccess': 'Unfollow successfully',
'common.share': 'Share',

View File

@ -139,6 +139,7 @@ export default {
'common.yes': '是',
'common.no': '否',
'common.creator': '创建人',
'common.createTime': '创建时间',
'common.followSuccess': '关注成功',
'common.unFollowSuccess': '取消关注成功',
'common.share': '分享',

View File

@ -98,4 +98,20 @@ export interface UseCountType {
testProgress: string; // 测试进度
}
// 计划详情缺陷列表
export interface PlanDetailBugItem {
id: string;
num: string;
title: string;
relateCase: {
id: string;
bugId: string;
name: string;
}[];
handleUser: string;
status: string;
createUser: string;
createTime: number;
}
export default {};

View File

@ -35,7 +35,7 @@ export default {
'apiTestManagement.closeOther': 'Close other tabs',
'apiTestManagement.showSubdirectory': 'Show subdirectory use case',
'apiTestManagement.searchPlaceholder': 'Enter ID/name/api path search',
'apiTestManagement.searchTaskPlaceholder': 'Enter resource Id/name search',
'apiTestManagement.searchTaskPlaceholder': 'Enter resource Id/name/URL search',
'apiTestManagement.apiName': 'Api name',
'apiTestManagement.apiType': 'Api type',
'apiTestManagement.apiStatus': 'Status',

View File

@ -34,7 +34,7 @@ export default {
'apiTestManagement.closeOther': '关闭其他tab',
'apiTestManagement.showSubdirectory': '显示子目录用例',
'apiTestManagement.searchPlaceholder': '输入 ID/名称/api路径搜索',
'apiTestManagement.searchTaskPlaceholder': '输入资源ID/名称搜索',
'apiTestManagement.searchTaskPlaceholder': '输入资源ID/名称/URL搜索',
'apiTestManagement.apiName': '接口名称',
'apiTestManagement.apiType': '请求类型',
'apiTestManagement.apiStatus': '状态',
@ -79,7 +79,7 @@ export default {
'apiTestManagement.importSwaggerFileTip1': '支持 Swagger 3.0 版本的 json 文件,',
'apiTestManagement.importSwaggerFileTip2': '2.0 文件可以在官网一键转换 3.0',
'apiTestManagement.importSwaggerFileTip3': ',大小不超过 50M',
'apiTestManagement.urlImportPlaceholder': '请输入OpenAPI/Swagger URL',
'apiTestManagement.urlImportPlaceholder': '请输入OpenAPI/URL',
'apiTestManagement.swaggerURLRequired': 'SwaggerURL 不能为空',
'apiTestManagement.basicAuth': 'Basic Auth 认证',
'apiTestManagement.account': '账号',

View File

@ -175,7 +175,6 @@
import { ref } from 'vue';
import { useRoute } from 'vue-router';
import MsChart from '@/components/pure/chart/index.vue';
import SetReportChart from './case/setReportChart.vue';
import ReportDetailHeader from './reportDetailHeader.vue';
import reportInfoHeader from './step/reportInfoHeaders.vue';

View File

@ -174,7 +174,7 @@
},
];
const { propsRes, propsEvent, loadList, setLoadListParams, setKeyword } = useTable(getAssociatedCasePage, {
const { propsRes, propsEvent, loadList, setLoadListParams } = useTable(getAssociatedCasePage, {
columns,
tableKey: TableKeyEnum.CASE_MANAGEMENT_TAB_DEPENDENCY_PRE_CASE,
scroll: { x: '100%' },
@ -184,7 +184,6 @@
});
const innerVisible = ref(false);
const innerProject = ref(currentProjectId.value);
const associateForm = ref({
reviewers: [],

View File

@ -9,7 +9,11 @@
<div class="items-right flex gap-[8px]">
<a-input-search
v-model:model-value="keyword"
:placeholder="t('system.organization.searchIndexPlaceholder')"
:placeholder="
props.moduleType === 'API_IMPORT'
? t('apiTestManagement.searchTaskPlaceholder')
: t('system.organization.searchIndexPlaceholder')
"
allow-clear
class="mx-[8px] w-[240px]"
@search="searchList"

View File

@ -51,7 +51,7 @@ export default {
'system.organization.updateOrganizationSuccess': '更新组织成功',
'system.organization.createProject': '创建项目',
'system.organization.subordinateOrg': '所属组织',
'system.organization.searchIndexPlaceholder': '通过ID名称搜索',
'system.organization.searchIndexPlaceholder': '通过ID/名称搜索',
'system.organization.searchUserPlaceholder': '通过名称/邮箱/手机搜索',
'system.organization.organizationAdminRequired': '组织管理员不能为空',
'system.project.enableTitle': '启用项目',

View File

@ -4,10 +4,6 @@
title-align="start"
class="ms-modal-no-padding ms-modal-small"
:mask-closable="false"
:ok-text="props.mode === 'move' ? t('common.move') : t('common.copy')"
:ok-button-props="{ disabled: innerSelectedModuleKeys.length === 0 }"
:cancel-button-props="{ disabled: props.okLoading }"
:on-before-ok="handleCaseMoveOrCopy"
@close="handleMoveCaseModalCancel"
>
<template #title>
@ -55,6 +51,18 @@
</template>
</MsTree>
</a-spin>
<template #footer>
<a-button type="secondary" @click="handleMoveCaseModalCancel">{{ t('common.cancel') }}</a-button>
<a-button
class="ml-[12px]"
type="primary"
:loading="props.okLoading"
:disabled="innerSelectedModuleKeys.length === 0"
@click="handleCaseMoveOrCopy"
>
{{ props.mode === 'move' ? t('common.move') : t('common.copy') }}
</a-button>
</template>
</a-modal>
</template>

View File

@ -24,7 +24,7 @@
</a-radio-group> -->
<a-popover title="" position="bottom">
<div class="flex">
<div class="one-line-text mr-1 max-h-[32px] max-w-[116px] text-[var(--color-text-1)]">
<div class="one-line-text mr-1 max-h-[32px] max-w-[300px] text-[var(--color-text-1)]">
{{ props.activeFolder === 'all' ? t('testPlan.testPlanIndex.allTestPlan') : props.nodeName }}
</div>
<span class="text-[var(--color-text-4)]"> ({{ props.modulesCount[props.activeFolder] || 0 }})</span>
@ -279,11 +279,21 @@
import StatusProgress from './statusProgress.vue';
import statusTag from '@/views/case-management/caseReview/components/statusTag.vue';
import { archivedPlan, batchDeletePlan, getTestPlanList, getTestPlanModule } from '@/api/modules/test-plan/testPlan';
import {
archivedPlan,
batchCopyPlan,
batchDeletePlan,
batchMovePlan,
getTestPlanDetail,
getTestPlanList,
getTestPlanModule,
updateTestPlan,
} from '@/api/modules/test-plan/testPlan';
import { useI18n } from '@/hooks/useI18n';
import useModal from '@/hooks/useModal';
import { useAppStore, useTableStore } from '@/store';
import { characterLimit } from '@/utils';
import { hasAnyPermission } from '@/utils/permission';
import type { planStatusType, TestPlanItem } from '@/models/testPlan/testPlan';
import { TestPlanRouteEnum } from '@/enums/routeEnum';
@ -316,7 +326,7 @@
title: 'testPlan.testPlanIndex.ID',
slotName: 'num',
dataIndex: 'num',
width: 200,
width: 150,
showInTable: true,
showDrag: false,
showTooltip: true,
@ -329,7 +339,7 @@
showInTable: true,
showTooltip: true,
width: 180,
editType: ColumnEditTypeEnum.INPUT,
editType: hasAnyPermission(['PROJECT_TEST_PLAN:READ+UPDATE']) ? ColumnEditTypeEnum.INPUT : undefined,
sortable: {
sortDirections: ['ascend', 'descend'],
sorter: true,
@ -446,10 +456,18 @@
/**
* 更新测试计划名称
*/
async function updatePlanName() {
async function updatePlanName(record: TestPlanItem) {
try {
Message.success(t('common.updateSuccess'));
return Promise.resolve(true);
if (record.id) {
const detail = await getTestPlanDetail(record.id);
const params = {
...detail,
name: record.name,
};
await updateTestPlan(params);
Message.success(t('common.updateSuccess'));
return Promise.resolve(true);
}
} catch (error) {
console.log(error);
return Promise.resolve(false);
@ -553,13 +571,15 @@
showSetting: true,
heightUsed: 128,
paginationSize: 'mini',
showSelectorAll: false,
},
(item) => {
return {
...item,
tags: (item.tags || []).map((e: string) => ({ id: e, name: e })),
};
}
},
updatePlanName
);
const batchParams = ref<BatchActionQueryParams>({
@ -605,9 +625,8 @@
loadList();
}
async function fetchData() {
resetSelector();
await loadPlanList();
//
async function emitTableParams() {
const tableParams = await initTableParams();
emit('init', {
...tableParams,
@ -616,6 +635,12 @@
});
}
async function fetchData() {
resetSelector();
await loadPlanList();
emitTableParams();
}
//
function openDetail(id: string) {
router.push({
@ -666,23 +691,25 @@
try {
const params = {
selectIds: batchParams.value.selectedIds || [],
selectAll: !!batchParams.value?.selectAll,
excludeIds: batchParams.value?.excludeIds || [],
condition: {
keyword: keyword.value,
filter: {
reviewStatus: statusFilters.value,
},
filter: {},
combine: batchParams.value.condition,
},
projectId: appStore.currentProjectId,
moduleIds: [...selectNodeKeys.value],
type: showType.value,
moduleId: selectNodeKeys.value[0],
};
if (modeType.value === 'copy') {
await batchCopyPlan(params);
Message.success(t('common.batchCopySuccess'));
} else {
await batchMovePlan(params);
Message.success(t('common.batchMoveSuccess'));
}
showBatchModal.value = false;
fetchData();
} catch (error) {
console.log(error);
} finally {
@ -812,9 +839,9 @@
}
}
function deletePlan(record: any) {}
function deletePlan(record: TestPlanItem) {}
function copyHandler() {}
function copyHandler(record: TestPlanItem) {}
const showScheduledTaskModal = ref<boolean>(false);
function handleScheduledTask() {
@ -854,7 +881,7 @@
function handleMoreActionSelect(item: ActionsItem, record: TestPlanItem) {
switch (item.eventTag) {
case 'copy':
copyHandler();
copyHandler(record);
break;
case 'createScheduledTask':
handleScheduledTask();
@ -928,7 +955,8 @@
});
defineExpose({
loadPlanList,
fetchData,
emitTableParams,
});
await tableStore.initColumn(TableKeyEnum.TEST_PLAN_ALL_TABLE, columns, 'drawer');

View File

@ -3,7 +3,7 @@
<MsTree
v-model:focus-node-key="focusNodeKey"
:selected-keys="props.selectedKeys"
:data="caseTree"
:data="testPlanTree"
:keyword="groupKeyword"
:node-more-actions="caseMoreActions"
:expand-all="props.isExpandAll"
@ -18,8 +18,8 @@
count: 'count',
}"
title-tooltip-position="left"
@select="caseNodeSelect"
@more-action-select="handleCaseMoreSelect"
@select="planNodeSelect"
@more-action-select="handlePlanMoreSelect"
@more-actions-close="moreActionsClose"
@drop="handleDrag"
>
@ -111,7 +111,7 @@
const groupKeyword = ref<string>('');
const caseTree = ref<ModuleTreeNode[]>([]);
const testPlanTree = ref<ModuleTreeNode[]>([]);
const setFocusKey = (node: MsTreeNodeData) => {
focusNodeKey.value = node.id || '';
@ -152,19 +152,18 @@
try {
loading.value = true;
const res = await getTestPlanModule({ projectId: currentProjectId.value });
caseTree.value = mapTree<ModuleTreeNode>(res, (e) => {
testPlanTree.value = mapTree<ModuleTreeNode>(res, (e) => {
return {
...e,
hideMoreAction: e.id === 'root',
draggable: e.id !== 'root',
disabled: e.id === props.activeFolder,
count: props.modulesCount?.[e.id] || 0,
};
});
if (isSetDefaultKey) {
selectedNodeKeys.value = [caseTree.value[0].id];
selectedNodeKeys.value = [testPlanTree.value[0].id];
}
emits('init', caseTree.value);
emits('init', testPlanTree.value);
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
@ -188,7 +187,7 @@
try {
await deletePlanModuleTree(node.id);
Message.success(t('common.deleteSuccess'));
initModules(true);
initModules(selectedNodeKeys.value[0] === node.id);
} catch (error) {
console.log(error);
}
@ -207,7 +206,7 @@
}
//
const caseNodeSelect = (selectedKeys: (string | number)[], node: MsTreeNodeData) => {
const planNodeSelect = (selectedKeys: (string | number)[], node: MsTreeNodeData) => {
const offspringIds: string[] = [];
mapTree(node.children || [], (e) => {
offspringIds.push(e.id);
@ -217,7 +216,7 @@
};
//
const handleCaseMoreSelect = (item: ActionsItem, node: MsTreeNodeData) => {
const handlePlanMoreSelect = (item: ActionsItem, node: MsTreeNodeData) => {
switch (item.eventTag) {
case 'delete':
deleteHandler(node);
@ -266,7 +265,7 @@
if (dropPosition === 0) {
treeNode.value.children.push(dragNode);
}
caseNodeSelect(dropNode.id, treeNode.value);
planNodeSelect(dropNode.id, treeNode.value);
emits('dragUpdate');
}
}
@ -347,7 +346,7 @@
watch(
() => props.modulesCount,
(obj) => {
caseTree.value = mapTree<ModuleTreeNode>(caseTree.value, (node) => {
testPlanTree.value = mapTree<ModuleTreeNode>(testPlanTree.value, (node) => {
return {
...node,
count: obj?.[node.id] || 0,

View File

@ -0,0 +1,74 @@
<template>
<a-popover position="bottom" content-class="case-count-popover" @popup-visible-change="popupChange">
<div class="one-line-text cursor-pointer px-0 text-[rgb(var(--primary-5))]">{{
props.record.relateCase.length
}}</div>
<template #content>
<div class="w-[500px]">
<MsBaseTable v-bind="propsRes" v-on="propsEvent"></MsBaseTable>
</div>
</template>
</a-popover>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
import type { MsTableColumn } from '@/components/pure/ms-table/type';
import useTable from '@/components/pure/ms-table/useTable';
import { useI18n } from '@/hooks/useI18n';
import type { PlanDetailBugItem } from '@/models/testPlan/testPlan';
import { TableKeyEnum } from '@/enums/tableEnum';
const { t } = useI18n();
const props = defineProps<{
record: PlanDetailBugItem;
}>();
const columns: MsTableColumn = [
{
title: 'caseManagement.featureCase.tableColumnID',
dataIndex: 'num',
width: 100,
showInTable: true,
showTooltip: true,
showDrag: false,
},
{
title: 'case.caseName',
slotName: 'name',
dataIndex: 'name',
showInTable: true,
showTooltip: true,
width: 200,
},
];
const { propsRes, propsEvent } = useTable(undefined, {
columns,
tableKey: TableKeyEnum.TEST_PLAN_DETAIL_BUG_TABLE_CASE_COUNT,
scroll: { x: '100%' },
showSelectorAll: false,
heightUsed: 340,
enableDrag: false,
showPagination: false,
});
function popupChange() {
propsRes.value.data = props.record.relateCase;
}
</script>
<style scoped lang="less">
.case-count-popover {
width: 540px;
height: 500px;
.arco-popover-content {
@apply h-full;
}
}
</style>

View File

@ -0,0 +1,161 @@
<template>
<div class="p-[16px]">
<div class="flex items-center justify-between">
<div
>{{ t('testPlan.bugManagement.bug') }}
<span class="!text-[var(--color-text-n4)]">({{ addCommasToNumber(count) }})</span>
</div>
<a-input-search
v-model:model-value="keyword"
:placeholder="t('caseManagement.featureCase.searchByName')"
allow-clear
class="mx-[8px] w-[240px]"
@search="getFetch"
@press-enter="getFetch"
@clear="getFetch"
/>
</div>
<MsBaseTable ref="tableRef" v-bind="propsRes" v-on="propsEvent">
<template #num="{ record }">
<a-tooltip :content="`${record.num}`">
<a-button type="text" class="px-0 !text-[14px] !leading-[22px]" size="mini">
<div class="one-line-text max-w-[168px]">{{ record.num }}</div>
</a-button>
</a-tooltip>
</template>
<template #name="{ record }">
<span class="one-line-text max-w-[300px]"> {{ record.name }}</span>
<a-popover title="" position="right" style="width: 480px">
<span class="ml-1 text-[rgb(var(--primary-5))]">{{ t('caseManagement.featureCase.preview') }}</span>
<template #content>
<div v-dompurify-html="record.content" class="markdown-body" style="margin-left: 48px"> </div>
</template>
</a-popover>
</template>
<template #linkCase="{ record }">
<CaseCountPopover :record="record" />
</template>
</MsBaseTable>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
import type { MsTableColumn } from '@/components/pure/ms-table/type';
import useTable from '@/components/pure/ms-table/useTable';
import CaseCountPopover from './caseCountPopover.vue';
import { planDetailBugPage } from '@/api/modules/test-plan/testPlan';
import { useI18n } from '@/hooks/useI18n';
import useAppStore from '@/store/modules/app';
import { addCommasToNumber } from '@/utils';
import { TableKeyEnum } from '@/enums/tableEnum';
const { t } = useI18n();
const appStore = useAppStore();
const props = defineProps<{
planId: string | undefined;
}>();
const keyword = ref<string>('');
function getFetch() {}
const columns: MsTableColumn = [
{
title: 'ID',
dataIndex: 'num',
slotName: 'num',
sortIndex: 1,
sortable: {
sortDirections: ['ascend', 'descend'],
sorter: true,
},
showTooltip: true,
width: 100,
},
{
title: 'testPlan.bugManagement.bugName',
slotName: 'title',
dataIndex: 'title',
showInTable: true,
showTooltip: false,
width: 300,
ellipsis: true,
showDrag: false,
},
{
title: 'testPlan.bugManagement.defectState',
slotName: 'statusName',
dataIndex: 'statusName',
showInTable: true,
showTooltip: true,
width: 200,
ellipsis: true,
showDrag: false,
},
{
title: 'caseManagement.featureCase.linkCase',
slotName: 'linkCase',
dataIndex: 'linkCase',
showInTable: true,
showTooltip: true,
width: 300,
ellipsis: true,
},
{
title: 'caseManagement.featureCase.updateUser',
slotName: 'handleUser',
dataIndex: 'handleUser',
titleSlotName: 'handleUserFilter',
showInTable: true,
showTooltip: true,
width: 300,
ellipsis: true,
},
{
title: 'common.createTime',
slotName: 'createTime',
dataIndex: 'createTime',
showInTable: true,
sortable: {
sortDirections: ['ascend', 'descend'],
sorter: true,
},
width: 200,
showDrag: true,
},
];
const { propsRes, propsEvent, loadList, setLoadListParams } = useTable(planDetailBugPage, {
columns,
tableKey: TableKeyEnum.TEST_PLAN_DETAIL_BUG_TABLE,
scroll: { x: '100%' },
showSelectorAll: false,
heightUsed: 340,
enableDrag: false,
});
const count = computed(() => {
return propsRes.value.msPagination?.total || 0;
});
function initData() {
setLoadListParams({
planId: props.planId,
keyword: keyword.value,
projectId: appStore.currentProjectId,
});
loadList();
}
onBeforeMount(() => {
initData();
});
</script>
<style scoped></style>

View File

@ -72,7 +72,9 @@
</a-tabs>
</MsCard>
<!-- special-height的174: 上面卡片高度158 + mt的16 -->
<MsCard class="mt-[16px]" :special-height="174" simple has-breadcrumb no-content-padding></MsCard>
<MsCard class="mt-[16px]" :special-height="174" simple has-breadcrumb no-content-padding>
<BugManagement v-if="activeTab === 'defectList'" :plan-id="detail.id" />
</MsCard>
</template>
<script setup lang="ts">
@ -84,6 +86,7 @@
import MsIcon from '@/components/pure/ms-icon-font/index.vue';
import MsTableMoreAction from '@/components/pure/ms-table-more-action/index.vue';
import { ActionsItem } from '@/components/pure/ms-table-more-action/types';
import BugManagement from './bugManagement/index.vue';
import passRateLine from '@/views/case-management/caseReview/components/passRateLine.vue';
import statusTag from '@/views/case-management/caseReview/components/statusTag.vue';

View File

@ -76,6 +76,7 @@
:modules-count="modulesCount"
@plan-tree-node-select="planNodeSelect"
@init="setRootModules"
@drag-update="dragUpdate"
></TestPlanTree>
</div>
</div>
@ -244,7 +245,10 @@
planId.value = '';
}
function loadPlanList() {
planTableRef.value?.loadPlanList();
planTableRef.value?.fetchData();
}
function dragUpdate() {
planTableRef.value?.emitTableParams();
}
</script>

View File

@ -81,4 +81,8 @@ export default {
'testPlan.planForm.repeatCaseTip2': 'Close: Cannot be associated with the same case repeatedly',
'testPlan.planForm.pickCases': 'Select cases',
'testPlan.testPlanDetail.executed': 'Executed',
'testPlan.bugManagement.bug': 'Defect list',
'testPlan.bugManagement.bugName': 'name',
'testPlan.bugManagement.defectState': 'Defect state',
'testPlan.bugManagement.caseClassification': 'Classification',
};

View File

@ -79,4 +79,8 @@ export default {
'testPlan.planForm.repeatCaseTip2': '关闭:不可重复关联同一用例',
'testPlan.planForm.pickCases': '选择用例',
'testPlan.testPlanDetail.executed': '已执行',
'testPlan.bugManagement.bug': '缺陷列表',
'testPlan.bugManagement.bugName': '名称',
'testPlan.bugManagement.defectState': '缺陷状态',
'testPlan.bugManagement.caseClassification': '用例分类',
};