refactor(测试计划): 测试计划详情-缺陷列表

This commit is contained in:
teukkk 2024-05-30 19:07:55 +08:00 committed by 刘瑞斌
parent 6653d5497d
commit 327476108f
8 changed files with 101 additions and 71 deletions

View File

@ -163,7 +163,8 @@ export default {
'common.text': '文本', 'common.text': '文本',
'common.resourceDeleted': '资源已被删除', 'common.resourceDeleted': '资源已被删除',
'common.refresh': '刷新', 'common.refresh': '刷新',
'common.searchByNameAndId': '通过ID、名称或标签搜索', 'common.searchByIdName': '通过ID 或名称搜索',
'common.searchByIDNameTag': '通过ID、名称或标签搜索',
'common.archive': '归档', 'common.archive': '归档',
'common.running': '执行中', 'common.running': '执行中',
'common.unExecute': '未执行', 'common.unExecute': '未执行',

View File

@ -4,17 +4,15 @@
<span type="text" class="one-line-text cursor-pointer px-0 text-[rgb(var(--primary-5))]">{{ record.num }}</span> <span type="text" class="one-line-text cursor-pointer px-0 text-[rgb(var(--primary-5))]">{{ record.num }}</span>
</template> </template>
<template #name="{ record }"> <template #name="{ record }">
<div class="flex flex-nowrap items-center"> <a-tooltip :content="record.name">
<a-tooltip :content="record.name"> <div class="one-line-text max-w-[calc(100%-32px)]"> {{ record.name }}</div>
<div class="one-line-text max-w-[200px] flex-auto items-center"> {{ characterLimit(record.name) }}</div> </a-tooltip>
</a-tooltip> <a-popover class="bug-content-popover" title="" position="right" style="width: 480px">
<a-popover class="bug-content-popover" title="" position="right" style="width: 480px"> <span class="ml-1 text-[rgb(var(--primary-5))]">{{ t('caseManagement.featureCase.preview') }}</span>
<span class="ml-1 text-[rgb(var(--primary-5))]">{{ t('caseManagement.featureCase.preview') }}</span> <template #content>
<template #content> <div v-dompurify-html="record.content" class="markdown-body bug-content"> </div>
<div v-dompurify-html="record.content" class="markdown-body bug-content"> </div> </template>
</template> </a-popover>
</a-popover>
</div>
</template> </template>
<template #statusName="{ record }"> <template #statusName="{ record }">
<div class="one-line-text">{{ record.statusName || '-' }}</div> <div class="one-line-text">{{ record.statusName || '-' }}</div>

View File

@ -4,7 +4,7 @@
:filter-config-list="filterConfigList" :filter-config-list="filterConfigList"
:custom-fields-config-list="searchCustomFields" :custom-fields-config-list="searchCustomFields"
:row-count="filterRowCount" :row-count="filterRowCount"
:search-placeholder="t('common.searchByNameAndId')" :search-placeholder="t('common.searchByIDNameTag')"
@keyword-search="fetchData" @keyword-search="fetchData"
@adv-search="fetchData" @adv-search="fetchData"
@refresh="fetchData" @refresh="fetchData"

View File

@ -1,48 +1,52 @@
<template> <template>
<a-popover position="bottom" content-class="case-count-popover" @popup-visible-change="popupChange"> <a-popover position="br" content-class="case-count-popover" @popup-visible-change="popupChange">
<div class="one-line-text cursor-pointer px-0 text-[rgb(var(--primary-5))]">{{ <div class="one-line-text cursor-pointer px-0 text-[rgb(var(--primary-5))]">{{
props.record.relateCase.length props.bugItem.relateCase?.length ?? 0
}}</div> }}</div>
<template #content> <template #content>
<div class="w-[500px]"> <div class="w-[500px]">
<MsBaseTable v-bind="propsRes" v-on="propsEvent"></MsBaseTable> <MsBaseTable v-bind="propsRes" v-on="propsEvent">
<template #num="{ record }">
<MsButton type="text" @click="goCaseDetail(record.id)">{{ record.num }}</MsButton>
</template>
</MsBaseTable>
</div> </div>
</template> </template>
</a-popover> </a-popover>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue'; import { useRouter } from 'vue-router';
import MsButton from '@/components/pure/ms-button/index.vue';
import MsBaseTable from '@/components/pure/ms-table/base-table.vue'; import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
import type { MsTableColumn } from '@/components/pure/ms-table/type'; import type { MsTableColumn } from '@/components/pure/ms-table/type';
import useTable from '@/components/pure/ms-table/useTable'; import useTable from '@/components/pure/ms-table/useTable';
import { useI18n } from '@/hooks/useI18n'; import useAppStore from '@/store/modules/app';
import type { PlanDetailBugItem } from '@/models/testPlan/testPlan'; import type { PlanDetailBugItem } from '@/models/testPlan/testPlan';
import { CaseManagementRouteEnum } from '@/enums/routeEnum';
import { TableKeyEnum } from '@/enums/tableEnum'; import { TableKeyEnum } from '@/enums/tableEnum';
const { t } = useI18n();
const props = defineProps<{ const props = defineProps<{
record: PlanDetailBugItem; bugItem: PlanDetailBugItem;
}>(); }>();
const router = useRouter();
const appStore = useAppStore();
const columns: MsTableColumn = [ const columns: MsTableColumn = [
{ {
title: 'caseManagement.featureCase.tableColumnID', title: 'caseManagement.featureCase.tableColumnID',
dataIndex: 'num', dataIndex: 'num',
slotName: 'num',
width: 100, width: 100,
showInTable: true,
showTooltip: true, showTooltip: true,
showDrag: false,
}, },
{ {
title: 'case.caseName', title: 'case.caseName',
slotName: 'name',
dataIndex: 'name', dataIndex: 'name',
showInTable: true,
showTooltip: true, showTooltip: true,
width: 200, width: 200,
}, },
@ -59,7 +63,15 @@
}); });
function popupChange() { function popupChange() {
propsRes.value.data = props.record.relateCase; propsRes.value.data = props.bugItem.relateCase;
}
function goCaseDetail(id: string) {
window.open(
`${window.location.origin}#${
router.resolve({ name: CaseManagementRouteEnum.CASE_MANAGEMENT_CASE }).fullPath
}?id=${id}&orgId=${appStore.currentOrgId}&pId=${appStore.currentProjectId}`
);
} }
</script> </script>

View File

@ -1,15 +1,15 @@
<template> <template>
<div class="p-[16px]"> <div class="p-[16px]">
<div class="flex items-center justify-between"> <div class="mb-[16px] flex items-center justify-between">
<div <div
>{{ t('testPlan.bugManagement.bug') }} >{{ t('testPlan.bugManagement.bug') }}
<span class="!text-[var(--color-text-n4)]">({{ addCommasToNumber(count) }})</span> <span class="text-[var(--color-text-4)]">({{ addCommasToNumber(count) }})</span>
</div> </div>
<a-input-search <a-input-search
v-model:model-value="keyword" v-model:model-value="keyword"
:placeholder="t('caseManagement.featureCase.searchByName')" :placeholder="t('common.searchByIdName')"
allow-clear allow-clear
class="mx-[8px] w-[240px]" class="w-[240px]"
@search="getFetch" @search="getFetch"
@press-enter="getFetch" @press-enter="getFetch"
@clear="getFetch" @clear="getFetch"
@ -17,23 +17,21 @@
</div> </div>
<MsBaseTable ref="tableRef" v-bind="propsRes" v-on="propsEvent"> <MsBaseTable ref="tableRef" v-bind="propsRes" v-on="propsEvent">
<template #num="{ record }"> <template #num="{ record }">
<a-tooltip :content="`${record.num}`"> <MsButton type="text" @click="toDetail(record.id)">{{ record.num }}</MsButton>
<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>
<template #name="{ record }"> <template #name="{ record }">
<span class="one-line-text max-w-[300px]"> {{ record.name }}</span> <a-tooltip :content="record.title">
<a-popover title="" position="right" style="width: 480px"> <div class="one-line-text max-w-[calc(100%-32px)]"> {{ record.title }}</div>
</a-tooltip>
<a-popover class="bug-content-popover" title="" position="right" style="width: 480px">
<span class="ml-1 text-[rgb(var(--primary-5))]">{{ t('caseManagement.featureCase.preview') }}</span> <span class="ml-1 text-[rgb(var(--primary-5))]">{{ t('caseManagement.featureCase.preview') }}</span>
<template #content> <template #content>
<div v-dompurify-html="record.content" class="markdown-body" style="margin-left: 48px"> </div> <div v-dompurify-html="record.content" class="markdown-body bug-content"> </div>
</template> </template>
</a-popover> </a-popover>
</template> </template>
<template #linkCase="{ record }"> <template #linkCase="{ record }">
<CaseCountPopover :record="record" /> <CaseCountPopover :bug-item="record" />
</template> </template>
</MsBaseTable> </MsBaseTable>
</div> </div>
@ -41,31 +39,35 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue'; import { ref } from 'vue';
import { useRoute } from 'vue-router';
import MsButton from '@/components/pure/ms-button/index.vue';
import MsBaseTable from '@/components/pure/ms-table/base-table.vue'; import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
import type { MsTableColumn } from '@/components/pure/ms-table/type'; import type { MsTableColumn } from '@/components/pure/ms-table/type';
import useTable from '@/components/pure/ms-table/useTable'; import useTable from '@/components/pure/ms-table/useTable';
import CaseCountPopover from './caseCountPopover.vue'; import CaseCountPopover from './caseCountPopover.vue';
import { getCustomOptionHeader } from '@/api/modules/bug-management';
import { planDetailBugPage } from '@/api/modules/test-plan/testPlan'; import { planDetailBugPage } from '@/api/modules/test-plan/testPlan';
import { useI18n } from '@/hooks/useI18n'; import { useI18n } from '@/hooks/useI18n';
import useAppStore from '@/store/modules/app'; import useAppStore from '@/store/modules/app';
import { addCommasToNumber } from '@/utils'; import { addCommasToNumber } from '@/utils';
import { hasAnyPermission } from '@/utils/permission';
// import { BugManagementRouteEnum } from '@/enums/routeEnum';
import { TableKeyEnum } from '@/enums/tableEnum'; import { TableKeyEnum } from '@/enums/tableEnum';
import { makeColumns } from '@/views/case-management/caseManagementFeature/components/utils';
const { t } = useI18n(); const { t } = useI18n();
const route = useRoute();
// const router = useRouter();
const appStore = useAppStore(); const appStore = useAppStore();
const props = defineProps<{
planId: string | undefined;
}>();
const keyword = ref<string>(''); const keyword = ref<string>('');
const planId = ref(route.query.id as string);
function getFetch() {} const columns = ref<MsTableColumn>([
const columns: MsTableColumn = [
{ {
title: 'ID', title: 'ID',
dataIndex: 'num', dataIndex: 'num',
@ -80,21 +82,22 @@
}, },
{ {
title: 'testPlan.bugManagement.bugName', title: 'testPlan.bugManagement.bugName',
slotName: 'title', slotName: 'name',
dataIndex: 'title', dataIndex: 'title',
showInTable: true, showInTable: true,
showTooltip: false,
width: 300, width: 300,
ellipsis: true, ellipsis: true,
showDrag: false, showDrag: false,
}, },
{ {
title: 'testPlan.bugManagement.defectState', title: 'caseManagement.featureCase.defectState',
slotName: 'status',
dataIndex: 'status', dataIndex: 'status',
filterConfig: {
options: [],
labelKey: 'text',
},
showInTable: true, showInTable: true,
showTooltip: true, width: 150,
width: 200,
ellipsis: true, ellipsis: true,
showDrag: false, showDrag: false,
}, },
@ -103,8 +106,7 @@
slotName: 'linkCase', slotName: 'linkCase',
dataIndex: 'linkCase', dataIndex: 'linkCase',
showInTable: true, showInTable: true,
showTooltip: true, width: 150,
width: 300,
ellipsis: true, ellipsis: true,
}, },
{ {
@ -129,10 +131,9 @@
width: 200, width: 200,
showDrag: true, showDrag: true,
}, },
]; ]);
const { propsRes, propsEvent, loadList, setLoadListParams } = useTable(planDetailBugPage, { const { propsRes, propsEvent, loadList, setLoadListParams } = useTable(planDetailBugPage, {
columns, columns: columns.value,
tableKey: TableKeyEnum.TEST_PLAN_DETAIL_BUG_TABLE, tableKey: TableKeyEnum.TEST_PLAN_DETAIL_BUG_TABLE,
scroll: { x: '100%' }, scroll: { x: '100%' },
showSelectorAll: false, showSelectorAll: false,
@ -144,18 +145,40 @@
return propsRes.value.msPagination?.total || 0; return propsRes.value.msPagination?.total || 0;
}); });
function initData() { function getFetch() {
setLoadListParams({ setLoadListParams({
planId: props.planId, planId: planId.value,
keyword: keyword.value, keyword: keyword.value,
projectId: appStore.currentProjectId, projectId: appStore.currentProjectId,
}); });
loadList(); loadList();
} }
const tableRef = ref<InstanceType<typeof MsBaseTable>>();
async function initFilterOptions() {
if (hasAnyPermission(['PROJECT_BUG:READ'])) {
const res = await getCustomOptionHeader(appStore.currentProjectId);
const optionsMap: Record<string, any> = {
status: res.statusOption,
};
columns.value = makeColumns(optionsMap, columns.value);
}
tableRef.value?.initColumn(columns.value);
}
function toDetail(id: string) {
// eslint-disable-next-line no-console
console.log('id', id);
// TODO:
// window.open(
// `${window.location.origin}#${
// router.resolve({ name: BugManagementRouteEnum.BUG_MANAGEMENT_INDEX }).fullPath
// }?id=${id}&orgId=${appStore.currentOrgId}&pId=${appStore.currentProjectId}`
// );
}
onBeforeMount(() => { onBeforeMount(() => {
initData(); initFilterOptions();
getFetch();
}); });
</script> </script>
<style scoped></style>

View File

@ -107,8 +107,7 @@
:can-edit="detail.status !== 'ARCHIVED'" :can-edit="detail.status !== 'ARCHIVED'"
@refresh="initDetail" @refresh="initDetail"
/> />
<!-- TODO 先不上 --> <BugManagement v-if="activeTab === 'defectList'" />
<!-- <BugManagement v-if="activeTab === 'defectList'" :plan-id="detail.id" /> -->
</MsCard> </MsCard>
<AssociateDrawer <AssociateDrawer
v-model:visible="caseAssociateVisible" v-model:visible="caseAssociateVisible"
@ -303,11 +302,10 @@
value: 'featureCase', value: 'featureCase',
label: t('menu.caseManagement.featureCase'), label: t('menu.caseManagement.featureCase'),
}, },
// TODO {
// { value: 'defectList',
// key: 'defectList', label: t('caseManagement.featureCase.defectList'),
// title: t('caseManagement.featureCase.defectList'), },
// },
]); ]);
const hasSelectedIds = ref<string[]>([]); const hasSelectedIds = ref<string[]>([]);
const caseAssociateVisible = ref(false); const caseAssociateVisible = ref(false);

View File

@ -90,7 +90,6 @@ export default {
'testPlan.bugManagement.bug': 'Defect list', 'testPlan.bugManagement.bug': 'Defect list',
'testPlan.bugManagement.bugName': 'name', 'testPlan.bugManagement.bugName': 'name',
'testPlan.bugManagement.defectState': 'Defect state', 'testPlan.bugManagement.defectState': 'Defect state',
'testPlan.bugManagement.caseClassification': 'Classification',
'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',

View File

@ -85,7 +85,6 @@ export default {
'testPlan.bugManagement.bug': '缺陷列表', 'testPlan.bugManagement.bug': '缺陷列表',
'testPlan.bugManagement.bugName': '名称', 'testPlan.bugManagement.bugName': '名称',
'testPlan.bugManagement.defectState': '缺陷状态', 'testPlan.bugManagement.defectState': '缺陷状态',
'testPlan.bugManagement.caseClassification': '用例分类',
'testPlan.featureCase.bugCount': '缺陷数', 'testPlan.featureCase.bugCount': '缺陷数',
'testPlan.featureCase.bug': '缺陷', 'testPlan.featureCase.bug': '缺陷',
'testPlan.featureCase.executor': '执行人', 'testPlan.featureCase.executor': '执行人',