feat(测试计划): 测试计划详情-功能用例列表-批量执行和批量修改执行人
This commit is contained in:
parent
1d3331f5ff
commit
7a1b2f96c6
|
@ -9,6 +9,8 @@ import {
|
||||||
batchDeletePlanUrl,
|
batchDeletePlanUrl,
|
||||||
BatchDisassociateCaseUrl,
|
BatchDisassociateCaseUrl,
|
||||||
batchMovePlanUrl,
|
batchMovePlanUrl,
|
||||||
|
BatchRunCaseUrl,
|
||||||
|
BatchUpdateCaseExecutorUrl,
|
||||||
copyTestPlanUrl,
|
copyTestPlanUrl,
|
||||||
deletePlanUrl,
|
deletePlanUrl,
|
||||||
DeleteTestPlanModuleUrl,
|
DeleteTestPlanModuleUrl,
|
||||||
|
@ -36,7 +38,9 @@ import { ModuleTreeNode } from '@/models/common';
|
||||||
import type {
|
import type {
|
||||||
AddTestPlanParams,
|
AddTestPlanParams,
|
||||||
AssociateCaseRequestType,
|
AssociateCaseRequestType,
|
||||||
|
BatchExecuteFeatureCaseParams,
|
||||||
BatchFeatureCaseParams,
|
BatchFeatureCaseParams,
|
||||||
|
BatchUpdateCaseExecutorParams,
|
||||||
DisassociateCaseParams,
|
DisassociateCaseParams,
|
||||||
FollowPlanParams,
|
FollowPlanParams,
|
||||||
PassRateCountDetail,
|
PassRateCountDetail,
|
||||||
|
@ -166,6 +170,14 @@ export function disassociateCase(data: DisassociateCaseParams) {
|
||||||
export function batchDisassociateCase(data: BatchFeatureCaseParams) {
|
export function batchDisassociateCase(data: BatchFeatureCaseParams) {
|
||||||
return MSR.post({ url: BatchDisassociateCaseUrl, data });
|
return MSR.post({ url: BatchDisassociateCaseUrl, data });
|
||||||
}
|
}
|
||||||
|
// 计划详情-功能用例列表-批量执行
|
||||||
|
export function batchExecuteCase(data: BatchExecuteFeatureCaseParams) {
|
||||||
|
return MSR.post({ url: BatchRunCaseUrl, data });
|
||||||
|
}
|
||||||
|
// 计划详情-功能用例列表-批量更新执行人
|
||||||
|
export function batchUpdateCaseExecutor(data: BatchUpdateCaseExecutorParams) {
|
||||||
|
return MSR.post({ url: BatchUpdateCaseExecutorUrl, data });
|
||||||
|
}
|
||||||
// 计划详情-功能用例-执行
|
// 计划详情-功能用例-执行
|
||||||
export function runFeatureCase(data: RunFeatureCaseParams) {
|
export function runFeatureCase(data: RunFeatureCaseParams) {
|
||||||
return MSR.post({ url: RunFeatureCaseUrl, data });
|
return MSR.post({ url: RunFeatureCaseUrl, data });
|
||||||
|
|
|
@ -54,3 +54,7 @@ export const DisassociateCaseUrl = '/test-plan/functional/case/disassociate';
|
||||||
export const BatchDisassociateCaseUrl = '/test-plan/functional/case/batch/disassociate';
|
export const BatchDisassociateCaseUrl = '/test-plan/functional/case/batch/disassociate';
|
||||||
// 计划详情-功能用例-执行
|
// 计划详情-功能用例-执行
|
||||||
export const RunFeatureCaseUrl = '/test-plan/functional/case/run';
|
export const RunFeatureCaseUrl = '/test-plan/functional/case/run';
|
||||||
|
// 计划详情-功能用例-批量执行
|
||||||
|
export const BatchRunCaseUrl = '/test-plan/functional/case/batch/run';
|
||||||
|
// 计划详情-功能用例-批量更新执行人
|
||||||
|
export const BatchUpdateCaseExecutorUrl = '/test-plan/functional/case/batch/update/executor';
|
||||||
|
|
|
@ -162,6 +162,30 @@ export interface DisassociateCaseParams {
|
||||||
export interface BatchFeatureCaseParams extends BatchActionQueryParams {
|
export interface BatchFeatureCaseParams extends BatchActionQueryParams {
|
||||||
testPlanId: string;
|
testPlanId: string;
|
||||||
moduleIds?: string[];
|
moduleIds?: string[];
|
||||||
|
projectId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ExecuteFeatureCaseFormParams {
|
||||||
|
lastExecResult: LastExecuteResults;
|
||||||
|
content?: string;
|
||||||
|
commentIds?: string[];
|
||||||
|
planCommentFileIds?: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RunFeatureCaseParams extends ExecuteFeatureCaseFormParams {
|
||||||
|
projectId: string;
|
||||||
|
id: string;
|
||||||
|
testPlanId: string;
|
||||||
|
caseId: string;
|
||||||
|
notifier?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BatchExecuteFeatureCaseParams extends BatchFeatureCaseParams, ExecuteFeatureCaseFormParams {
|
||||||
|
notifier?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BatchUpdateCaseExecutorParams extends BatchFeatureCaseParams {
|
||||||
|
userId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PassRateCountDetail {
|
export interface PassRateCountDetail {
|
||||||
|
@ -180,19 +204,4 @@ export interface PassRateCountDetail {
|
||||||
apiScenarioCount: number;
|
apiScenarioCount: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ExecuteFeatureCaseFormParams {
|
|
||||||
lastExecResult: LastExecuteResults;
|
|
||||||
content?: string;
|
|
||||||
commentIds?: string[];
|
|
||||||
planCommentFileIds?: string[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface RunFeatureCaseParams extends ExecuteFeatureCaseFormParams {
|
|
||||||
projectId: string;
|
|
||||||
id: string;
|
|
||||||
testPlanId: string;
|
|
||||||
caseId: string;
|
|
||||||
notifier?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default {};
|
export default {};
|
||||||
|
|
|
@ -47,7 +47,12 @@
|
||||||
<span v-else class="text-[var(--color-text-2)]"><ExecuteResult :execute-result="record.lastExecResult" /></span>
|
<span v-else class="text-[var(--color-text-2)]"><ExecuteResult :execute-result="record.lastExecResult" /></span>
|
||||||
</template>
|
</template>
|
||||||
<template #operation="{ record }">
|
<template #operation="{ record }">
|
||||||
<MsButton v-permission="['PROJECT_API_DEFINITION_CASE:READ+EXECUTE']" type="text" class="!mr-0">
|
<MsButton
|
||||||
|
v-permission="['PROJECT_API_DEFINITION_CASE:READ+EXECUTE']"
|
||||||
|
type="text"
|
||||||
|
class="!mr-0"
|
||||||
|
@click="toCaseDetail(record)"
|
||||||
|
>
|
||||||
{{ t('common.execute') }}
|
{{ t('common.execute') }}
|
||||||
</MsButton>
|
</MsButton>
|
||||||
<a-divider v-permission="['PROJECT_TEST_PLAN:READ+ASSOCIATION']" direction="vertical" :margin="8"></a-divider>
|
<a-divider v-permission="['PROJECT_TEST_PLAN:READ+ASSOCIATION']" direction="vertical" :margin="8"></a-divider>
|
||||||
|
@ -74,13 +79,79 @@
|
||||||
</MsButton>
|
</MsButton>
|
||||||
</template>
|
</template>
|
||||||
</MsBaseTable>
|
</MsBaseTable>
|
||||||
|
<!-- 批量执行 -->
|
||||||
|
<a-modal
|
||||||
|
v-model:visible="batchExecuteModalVisible"
|
||||||
|
title-align="start"
|
||||||
|
body-class="p-0"
|
||||||
|
:width="800"
|
||||||
|
:cancel-button-props="{ disabled: batchLoading }"
|
||||||
|
:ok-loading="batchLoading"
|
||||||
|
:ok-text="t('caseManagement.caseReview.commitResult')"
|
||||||
|
@before-ok="handleBatchExecute"
|
||||||
|
@close="resetBatchForm"
|
||||||
|
>
|
||||||
|
<template #title>
|
||||||
|
{{ t('testPlan.testPlanIndex.batchExecution') }}
|
||||||
|
<div class="text-[var(--color-text-4)]">
|
||||||
|
{{
|
||||||
|
t('testPlan.testPlanIndex.selectedCount', {
|
||||||
|
count: batchParams.currentSelectCount || tableSelected.length,
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<ExecuteForm v-model:form="batchExecuteForm" />
|
||||||
|
</a-modal>
|
||||||
|
<!-- 批量修改执行人 -->
|
||||||
|
<a-modal
|
||||||
|
v-model:visible="batchUpdateExecutorModalVisible"
|
||||||
|
title-align="start"
|
||||||
|
body-class="p-0"
|
||||||
|
:cancel-button-props="{ disabled: batchLoading }"
|
||||||
|
:ok-loading="batchLoading"
|
||||||
|
:ok-button-props="{ disabled: batchUpdateExecutorDisabled }"
|
||||||
|
:ok-text="t('common.update')"
|
||||||
|
@before-ok="handleBatchUpdateExecutor"
|
||||||
|
@close="resetBatchForm"
|
||||||
|
>
|
||||||
|
<template #title>
|
||||||
|
{{ t('testPlan.featureCase.batchChangeExecutor') }}
|
||||||
|
<div class="text-[var(--color-text-4)]">
|
||||||
|
{{
|
||||||
|
t('testPlan.testPlanIndex.selectedCount', {
|
||||||
|
count: batchParams.currentSelectCount || tableSelected.length,
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<a-form ref="batchUpdateExecutorFormRef" :model="batchUpdateExecutorForm" layout="vertical">
|
||||||
|
<a-form-item
|
||||||
|
field="userId"
|
||||||
|
:label="t('testPlan.featureCase.executor')"
|
||||||
|
:rules="[{ required: true, message: t('testPlan.featureCase.requestExecutorRequired') }]"
|
||||||
|
asterisk-position="end"
|
||||||
|
class="mb-0"
|
||||||
|
>
|
||||||
|
<MsSelect
|
||||||
|
v-model:modelValue="batchUpdateExecutorForm.userId"
|
||||||
|
mode="static"
|
||||||
|
:placeholder="t('common.pleaseSelect')"
|
||||||
|
:loading="batchLoading"
|
||||||
|
:options="userOptions"
|
||||||
|
:search-keys="['label']"
|
||||||
|
allow-search
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</a-form>
|
||||||
|
</a-modal>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, onBeforeMount, ref } from 'vue';
|
import { computed, onBeforeMount, ref } from 'vue';
|
||||||
import { useRoute, useRouter } from 'vue-router';
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
import { Message } from '@arco-design/web-vue';
|
import { FormInstance, Message, SelectOptionData } from '@arco-design/web-vue';
|
||||||
|
|
||||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||||
import MsPopconfirm from '@/components/pure/ms-popconfirm/index.vue';
|
import MsPopconfirm from '@/components/pure/ms-popconfirm/index.vue';
|
||||||
|
@ -89,12 +160,17 @@
|
||||||
import useTable from '@/components/pure/ms-table/useTable';
|
import useTable from '@/components/pure/ms-table/useTable';
|
||||||
import CaseLevel from '@/components/business/ms-case-associate/caseLevel.vue';
|
import CaseLevel from '@/components/business/ms-case-associate/caseLevel.vue';
|
||||||
import ExecuteResult from '@/components/business/ms-case-associate/executeResult.vue';
|
import ExecuteResult from '@/components/business/ms-case-associate/executeResult.vue';
|
||||||
|
import MsSelect from '@/components/business/ms-select';
|
||||||
|
import ExecuteForm from '@/views/test-plan/testPlan/detail/featureCase/components/executeForm.vue';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
batchDisassociateCase,
|
batchDisassociateCase,
|
||||||
|
batchExecuteCase,
|
||||||
|
batchUpdateCaseExecutor,
|
||||||
disassociateCase,
|
disassociateCase,
|
||||||
getPlanDetailFeatureCaseList,
|
getPlanDetailFeatureCaseList,
|
||||||
} from '@/api/modules/test-plan/testPlan';
|
} from '@/api/modules/test-plan/testPlan';
|
||||||
|
import { defaultExecuteForm } from '@/config/testPlan';
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
import useModal from '@/hooks/useModal';
|
import useModal from '@/hooks/useModal';
|
||||||
import useTableStore from '@/hooks/useTableStore';
|
import useTableStore from '@/hooks/useTableStore';
|
||||||
|
@ -102,7 +178,11 @@
|
||||||
import { hasAnyPermission } from '@/utils/permission';
|
import { hasAnyPermission } from '@/utils/permission';
|
||||||
|
|
||||||
import { ModuleTreeNode } from '@/models/common';
|
import { ModuleTreeNode } from '@/models/common';
|
||||||
import type { PlanDetailFeatureCaseItem, PlanDetailFeatureCaseListQueryParams } from '@/models/testPlan/testPlan';
|
import type {
|
||||||
|
ExecuteFeatureCaseFormParams,
|
||||||
|
PlanDetailFeatureCaseItem,
|
||||||
|
PlanDetailFeatureCaseListQueryParams,
|
||||||
|
} from '@/models/testPlan/testPlan';
|
||||||
import { LastExecuteResults } from '@/enums/caseEnum';
|
import { LastExecuteResults } from '@/enums/caseEnum';
|
||||||
import { TestPlanRouteEnum } from '@/enums/routeEnum';
|
import { TestPlanRouteEnum } from '@/enums/routeEnum';
|
||||||
import { TableKeyEnum } from '@/enums/tableEnum';
|
import { TableKeyEnum } from '@/enums/tableEnum';
|
||||||
|
@ -124,6 +204,7 @@
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(e: 'getModuleCount', params: PlanDetailFeatureCaseListQueryParams): void;
|
(e: 'getModuleCount', params: PlanDetailFeatureCaseListQueryParams): void;
|
||||||
|
(e: 'executeDone'): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
@ -270,14 +351,6 @@
|
||||||
eventTag: 'disassociate',
|
eventTag: 'disassociate',
|
||||||
permission: ['PROJECT_TEST_PLAN:READ+ASSOCIATION'],
|
permission: ['PROJECT_TEST_PLAN:READ+ASSOCIATION'],
|
||||||
},
|
},
|
||||||
{
|
|
||||||
isDivider: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'common.delete',
|
|
||||||
eventTag: 'delete',
|
|
||||||
danger: true,
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -362,16 +435,79 @@
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 批量执行
|
||||||
|
const batchLoading = ref(false);
|
||||||
|
const batchExecuteModalVisible = ref(false);
|
||||||
|
const batchExecuteForm = ref<ExecuteFeatureCaseFormParams>({ ...defaultExecuteForm });
|
||||||
|
async function handleBatchExecute() {
|
||||||
|
try {
|
||||||
|
batchLoading.value = true;
|
||||||
|
await batchExecuteCase({
|
||||||
|
...batchParams.value,
|
||||||
|
...tableParams.value,
|
||||||
|
...batchExecuteForm.value,
|
||||||
|
notifier: batchExecuteForm.value?.commentIds?.join(';'),
|
||||||
|
});
|
||||||
|
Message.success(t('common.updateSuccess'));
|
||||||
|
resetSelector();
|
||||||
|
loadList();
|
||||||
|
emit('executeDone');
|
||||||
|
} catch (error) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(error);
|
||||||
|
} finally {
|
||||||
|
batchLoading.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 批量修改执行人
|
||||||
|
const batchUpdateExecutorFormRef = ref<FormInstance>();
|
||||||
|
const batchUpdateExecutorModalVisible = ref(false);
|
||||||
|
const batchUpdateExecutorForm = ref<{ userId: string }>({ userId: '' });
|
||||||
|
const batchUpdateExecutorDisabled = computed(() => !batchUpdateExecutorForm.value.userId.length);
|
||||||
|
const userOptions = ref<SelectOptionData[]>([]); // TODO 接口联调
|
||||||
|
async function handleBatchUpdateExecutor() {
|
||||||
|
batchUpdateExecutorFormRef.value?.validate(async (errors) => {
|
||||||
|
if (!errors) {
|
||||||
|
try {
|
||||||
|
batchLoading.value = true;
|
||||||
|
await batchUpdateCaseExecutor({
|
||||||
|
...batchParams.value,
|
||||||
|
...tableParams.value,
|
||||||
|
...batchUpdateExecutorForm.value,
|
||||||
|
});
|
||||||
|
Message.success(t('common.updateSuccess'));
|
||||||
|
resetSelector();
|
||||||
|
loadList();
|
||||||
|
} catch (error) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(error);
|
||||||
|
} finally {
|
||||||
|
batchLoading.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetBatchForm() {
|
||||||
|
batchExecuteForm.value = { ...defaultExecuteForm };
|
||||||
|
batchUpdateExecutorForm.value = { userId: '' };
|
||||||
|
}
|
||||||
|
|
||||||
// 处理表格选中后批量操作
|
// 处理表格选中后批量操作
|
||||||
function handleTableBatch(event: BatchActionParams, params: BatchActionQueryParams) {
|
function handleTableBatch(event: BatchActionParams, params: BatchActionQueryParams) {
|
||||||
tableSelected.value = params?.selectedIds || [];
|
tableSelected.value = params?.selectedIds || [];
|
||||||
batchParams.value = params;
|
batchParams.value = params;
|
||||||
switch (event.eventTag) {
|
switch (event.eventTag) {
|
||||||
case 'execute':
|
case 'execute':
|
||||||
|
batchExecuteModalVisible.value = true;
|
||||||
break;
|
break;
|
||||||
case 'disassociate':
|
case 'disassociate':
|
||||||
handleBatchDisassociateCase();
|
handleBatchDisassociateCase();
|
||||||
break;
|
break;
|
||||||
|
case 'changeExecutor':
|
||||||
|
batchUpdateExecutorModalVisible.value = true;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@
|
||||||
import { executionResultMap } from '@/views/case-management/caseManagementFeature/components/utils';
|
import { executionResultMap } from '@/views/case-management/caseManagementFeature/components/utils';
|
||||||
|
|
||||||
const form = defineModel<ExecuteFeatureCaseFormParams>('form', {
|
const form = defineModel<ExecuteFeatureCaseFormParams>('form', {
|
||||||
default: () => ({ ...defaultExecuteForm }),
|
required: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
const formRef = ref<FormInstance>();
|
const formRef = ref<FormInstance>();
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
:offspring-ids="offspringIds"
|
:offspring-ids="offspringIds"
|
||||||
:module-tree="moduleTree"
|
:module-tree="moduleTree"
|
||||||
@get-module-count="getModuleCount"
|
@get-module-count="getModuleCount"
|
||||||
|
@execute-done="emit('executeDone')"
|
||||||
></CaseTable>
|
></CaseTable>
|
||||||
</template>
|
</template>
|
||||||
</MsSplitBox>
|
</MsSplitBox>
|
||||||
|
@ -36,6 +37,10 @@
|
||||||
import { ModuleTreeNode } from '@/models/common';
|
import { ModuleTreeNode } from '@/models/common';
|
||||||
import type { PlanDetailFeatureCaseListQueryParams } from '@/models/testPlan/testPlan';
|
import type { PlanDetailFeatureCaseListQueryParams } from '@/models/testPlan/testPlan';
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'executeDone'): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
|
||||||
const planId = ref(route.query.id as string);
|
const planId = ref(route.query.id as string);
|
||||||
|
|
|
@ -88,7 +88,7 @@
|
||||||
</MsCard>
|
</MsCard>
|
||||||
<!-- special-height的174: 上面卡片高度158 + mt的16 -->
|
<!-- special-height的174: 上面卡片高度158 + mt的16 -->
|
||||||
<MsCard class="mt-[16px]" :special-height="174" simple has-breadcrumb no-content-padding>
|
<MsCard class="mt-[16px]" :special-height="174" simple has-breadcrumb no-content-padding>
|
||||||
<FeatureCase v-if="activeTab === 'featureCase'" />
|
<FeatureCase v-if="activeTab === 'featureCase'" @execute-done="getStatistics" />
|
||||||
<!-- TODO 先不上 -->
|
<!-- TODO 先不上 -->
|
||||||
<!-- <BugManagement v-if="activeTab === 'defectList'" :plan-id="detail.id" /> -->
|
<!-- <BugManagement v-if="activeTab === 'defectList'" :plan-id="detail.id" /> -->
|
||||||
</MsCard>
|
</MsCard>
|
||||||
|
|
|
@ -90,6 +90,8 @@ export default {
|
||||||
'testPlan.featureCase.bugCount': 'Bug count',
|
'testPlan.featureCase.bugCount': 'Bug count',
|
||||||
'testPlan.featureCase.executor': 'Executor',
|
'testPlan.featureCase.executor': 'Executor',
|
||||||
'testPlan.featureCase.changeExecutor': 'Change executor',
|
'testPlan.featureCase.changeExecutor': 'Change executor',
|
||||||
|
'testPlan.featureCase.batchChangeExecutor': 'Batch modification executor',
|
||||||
|
'testPlan.featureCase.requestExecutorRequired': 'Executor cannot be empty',
|
||||||
'testPlan.featureCase.sort': 'sort',
|
'testPlan.featureCase.sort': 'sort',
|
||||||
'testPlan.featureCase.executionHistory': 'Execution History',
|
'testPlan.featureCase.executionHistory': 'Execution History',
|
||||||
'testPlan.featureCase.noBugDataTooltip': 'No related defects, please',
|
'testPlan.featureCase.noBugDataTooltip': 'No related defects, please',
|
||||||
|
|
|
@ -88,6 +88,8 @@ export default {
|
||||||
'testPlan.featureCase.bugCount': '缺陷数',
|
'testPlan.featureCase.bugCount': '缺陷数',
|
||||||
'testPlan.featureCase.executor': '执行人',
|
'testPlan.featureCase.executor': '执行人',
|
||||||
'testPlan.featureCase.changeExecutor': '修改执行人',
|
'testPlan.featureCase.changeExecutor': '修改执行人',
|
||||||
|
'testPlan.featureCase.batchChangeExecutor': '批量修改执行人',
|
||||||
|
'testPlan.featureCase.requestExecutorRequired': '执行人不能为空',
|
||||||
'testPlan.featureCase.sort': '排序',
|
'testPlan.featureCase.sort': '排序',
|
||||||
'testPlan.featureCase.executionHistory': '执行历史',
|
'testPlan.featureCase.executionHistory': '执行历史',
|
||||||
'testPlan.featureCase.noBugDataTooltip': '暂无可关联缺陷,请 ',
|
'testPlan.featureCase.noBugDataTooltip': '暂无可关联缺陷,请 ',
|
||||||
|
|
Loading…
Reference in New Issue