feat(测试计划): 修改测试计划部分细节和详情缺陷管理列表页面
This commit is contained in:
parent
92d441eaa8
commit
2c48d8f947
|
@ -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 });
|
||||
}
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -139,6 +139,7 @@ export default {
|
|||
'common.yes': '是',
|
||||
'common.no': '否',
|
||||
'common.creator': '创建人',
|
||||
'common.createTime': '创建时间',
|
||||
'common.followSuccess': '关注成功',
|
||||
'common.unFollowSuccess': '取消关注成功',
|
||||
'common.share': '分享',
|
||||
|
|
|
@ -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 {};
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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': '账号',
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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: [],
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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': '启用项目',
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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 {
|
||||
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');
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
|
@ -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';
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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',
|
||||
};
|
||||
|
|
|
@ -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': '用例分类',
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue