feat(测试计划): 测试计划报告自定义保存&报告预览&编辑报告内容联调
This commit is contained in:
parent
c8c096b86a
commit
432ad3f4dd
|
@ -11,7 +11,7 @@ import {
|
|||
UpdateReportDetailParams,
|
||||
} from '@/models/testPlan/report';
|
||||
import type { ExecuteHistoryItem } from '@/models/testPlan/testPlan';
|
||||
import { PlanReportDetail } from '@/models/testPlan/testPlanReport';
|
||||
import { manualReportGenParams, PlanReportDetail } from '@/models/testPlan/testPlanReport';
|
||||
|
||||
// 报告列表
|
||||
export function reportList(data: TableQueryParams) {
|
||||
|
@ -160,5 +160,17 @@ export function getFunctionalExecuteStep(data: { reportId: string; shareId?: str
|
|||
}
|
||||
return MSR.get<ExecuteHistoryItem>({ url: `${reportUrl.ReportFunctionalStepUrl}/${data.reportId}` });
|
||||
}
|
||||
// 手动生成报告
|
||||
export function manualReportGen(data: manualReportGenParams) {
|
||||
return MSR.post({ url: reportUrl.ManualReportGenUrl, data });
|
||||
}
|
||||
|
||||
// 获取报告布局
|
||||
export function getReportLayout(reportId: string, shareId?: string) {
|
||||
if (shareId) {
|
||||
return MSR.get({ url: `${reportUrl.getReportShareLayoutUrl}/${shareId}/${reportId}` });
|
||||
}
|
||||
return MSR.get({ url: `${reportUrl.getReportLayoutUrl}/${reportId}` });
|
||||
}
|
||||
|
||||
export default {};
|
||||
|
|
|
@ -62,3 +62,9 @@ export const ReportPlanPreviewImageUrl = '/test-plan/report/preview/md';
|
|||
export const ReportFunctionalStepUrl = '/test-plan/report/detail/functional/case/step';
|
||||
// 测试计划-报告-详情-功能用例明细-执行历史步骤-分享
|
||||
export const ReportShareFunctionalStepUrl = '/test-plan/report/share/detail/functional/case/step';
|
||||
// 测试计划-报告-详情-手动生成报告
|
||||
export const ManualReportGenUrl = '/test-plan/report/manual-gen';
|
||||
// 测试计划-报告-详情-获取报告布局
|
||||
export const getReportLayoutUrl = '/test-plan/report/get-layout';
|
||||
// 测试计划-报告-详情-获取报告布局-分享
|
||||
export const getReportShareLayoutUrl = '/test-plan/report/share/get-layout';
|
||||
|
|
|
@ -41,7 +41,7 @@ export const planDetailBugPageUrl = '/test-plan/bug/page';
|
|||
// 关注测试计划
|
||||
export const followPlanUrl = '/test-plan/edit/follower';
|
||||
// 生成报告
|
||||
export const GenerateReportUrl = '/test-plan/report/gen';
|
||||
export const GenerateReportUrl = '/test-plan/report/auto-gen';
|
||||
// 复制测试计划
|
||||
export const copyTestPlanUrl = '/test-plan/copy';
|
||||
// 测试计划通过率执行进度
|
||||
|
|
|
@ -51,6 +51,7 @@ export const defaultDetailCount: PassRateCountDetail = {
|
|||
},
|
||||
},
|
||||
nextTriggerTime: 0,
|
||||
status: 'PREPARED',
|
||||
};
|
||||
|
||||
export const defaultExecuteForm = {
|
||||
|
@ -91,6 +92,7 @@ export const defaultReportDetail: PlanReportDetail = {
|
|||
apiBugCount: 0, // 接口用例明细bug总数
|
||||
scenarioBugCount: 0, // 场景用例明细bug总数
|
||||
testPlanName: '',
|
||||
defaultLayout: true, // 是否是默认布局
|
||||
};
|
||||
|
||||
export const statusConfig: StatusListType[] = [
|
||||
|
|
|
@ -7,5 +7,9 @@ export enum ReportCardTypeEnum {
|
|||
SUB_PLAN_DETAIL = 'SUB_PLAN_DETAIL', // 计划组子计划详情
|
||||
CUSTOM_CARD = 'CUSTOM_CARD', // 自定义卡片
|
||||
}
|
||||
export enum FieldTypeEnum {
|
||||
SYSTEM = 'SYSTEM',
|
||||
RICH_TEXT = 'RICH_TEXT',
|
||||
}
|
||||
|
||||
export default {};
|
||||
|
|
|
@ -21,8 +21,9 @@ export interface FeatureCaseItem {
|
|||
|
||||
export interface UpdateReportDetailParams {
|
||||
id: string;
|
||||
summary: string;
|
||||
richTextTmpFileIds: string[];
|
||||
componentId: string;
|
||||
componentValue?: string;
|
||||
richTextTmpFileIds?: string[];
|
||||
}
|
||||
|
||||
export interface ApiOrScenarioCaseItem {
|
||||
|
|
|
@ -238,6 +238,7 @@ export interface PassRateCountDetail {
|
|||
};
|
||||
};
|
||||
nextTriggerTime: number;
|
||||
status: planStatusType;
|
||||
}
|
||||
|
||||
// 执行历史
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { ReportCardTypeEnum } from '@/enums/testPlanReportEnum';
|
||||
import { TriggerModeLabelEnum } from '@/enums/reportEnum';
|
||||
import { FieldTypeEnum, ReportCardTypeEnum } from '@/enums/testPlanReportEnum';
|
||||
|
||||
export interface countDetail {
|
||||
success: number;
|
||||
|
@ -31,6 +32,7 @@ export interface PlanReportDetail {
|
|||
scenarioBugCount: number; // 场景用例明细bug总数
|
||||
testPlanName: string;
|
||||
resultStatus?: string; // 报告结果
|
||||
defaultLayout: boolean; // 报告布局
|
||||
}
|
||||
|
||||
export type detailCountKey = 'functionalCount' | 'apiCaseCount' | 'apiScenarioCount';
|
||||
|
@ -60,8 +62,9 @@ export interface configItem {
|
|||
value: ReportCardTypeEnum;
|
||||
label: string;
|
||||
content?: string;
|
||||
system: boolean;
|
||||
type: FieldTypeEnum;
|
||||
enableEdit: boolean;
|
||||
richTextTmpFileIds?: string[];
|
||||
}
|
||||
|
||||
export interface customValueForm {
|
||||
|
@ -69,3 +72,26 @@ export interface customValueForm {
|
|||
label: string;
|
||||
richTextTmpFileIds?: string[];
|
||||
}
|
||||
|
||||
export interface componentItem {
|
||||
name: ReportCardTypeEnum; // 组件名称
|
||||
label: string; // 组件标题
|
||||
type: FieldTypeEnum; // 组件分类
|
||||
value?: string; // 组件内容
|
||||
pos: number;
|
||||
}
|
||||
|
||||
// 手动生成报告
|
||||
export interface manualReportGenParams {
|
||||
projectId: string;
|
||||
testPlanId: string;
|
||||
triggerMode: TriggerModeLabelEnum; // 触发方式
|
||||
reportName: string;
|
||||
components: componentItem[]; // 自定义组件
|
||||
richTextTmpFileIds?: string[];
|
||||
}
|
||||
|
||||
export type SelectedReportCardTypes =
|
||||
| ReportCardTypeEnum.FUNCTIONAL_DETAIL
|
||||
| ReportCardTypeEnum.API_CASE_DETAIL
|
||||
| ReportCardTypeEnum.SCENARIO_CASE_DETAIL;
|
||||
|
|
|
@ -26,7 +26,9 @@
|
|||
</a-form>
|
||||
<div class="ml-[12px]">
|
||||
<a-button type="secondary" @click="cancelHandler">{{ t('common.cancel') }}</a-button>
|
||||
<a-button class="ml-[12px]" type="primary" @click="handleSave">{{ t('common.save') }}</a-button>
|
||||
<a-button class="ml-[12px]" type="primary" :loading="confirmLoading" @click="handleSave">{{
|
||||
t('common.save')
|
||||
}}</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -70,7 +72,7 @@
|
|||
t(item.label)
|
||||
}}</div>
|
||||
<icon-close
|
||||
v-if="!item.system"
|
||||
v-if="item.type !== FieldTypeEnum.SYSTEM"
|
||||
:style="{ 'font-size': '14px' }"
|
||||
class="cursor-pointer text-[var(--color-text-3)]"
|
||||
@click.stop="removeField(item)"
|
||||
|
@ -107,7 +109,7 @@
|
|||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
import { cloneDeep, isEqual } from 'lodash-es';
|
||||
import { VueDraggable } from 'vue-draggable-plus';
|
||||
|
@ -115,20 +117,30 @@
|
|||
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||
import ViewReport from '@/views/test-plan/report/detail/component/viewReport.vue';
|
||||
|
||||
import { updateReportDetail } from '@/api/modules/test-plan/report';
|
||||
import { manualReportGen } from '@/api/modules/test-plan/report';
|
||||
import { defaultReportDetail } from '@/config/testPlan';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import { useAppStore } from '@/store';
|
||||
import { getGenerateId } from '@/utils';
|
||||
|
||||
import type { configItem, PlanReportDetail } from '@/models/testPlan/testPlanReport';
|
||||
import { ReportCardTypeEnum } from '@/enums/testPlanReportEnum';
|
||||
import type {
|
||||
configItem,
|
||||
manualReportGenParams,
|
||||
PlanReportDetail,
|
||||
SelectedReportCardTypes,
|
||||
} from '@/models/testPlan/testPlanReport';
|
||||
import { TriggerModeLabelEnum } from '@/enums/reportEnum';
|
||||
import { TestPlanRouteEnum } from '@/enums/routeEnum';
|
||||
import { FieldTypeEnum, ReportCardTypeEnum } from '@/enums/testPlanReportEnum';
|
||||
|
||||
import { defaultCustomConfig, defaultGroupConfig, defaultSingleConfig } from './reportConfig';
|
||||
import { defaultCustomConfig, defaultGroupCardConfig, defaultGroupConfig, defaultSingleConfig } from './reportConfig';
|
||||
import { getSummaryDetail } from '@/views/test-plan/report/utils';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
const appStore = useAppStore();
|
||||
const props = defineProps<{
|
||||
detailInfo: PlanReportDetail;
|
||||
isDrawer?: boolean;
|
||||
|
@ -140,11 +152,6 @@
|
|||
}>();
|
||||
|
||||
const detail = ref<PlanReportDetail>({ ...cloneDeep(defaultReportDetail) });
|
||||
const showButton = ref<boolean>(false);
|
||||
|
||||
const richText = ref<{ summary: string; richTextTmpFileIds?: string[] }>({
|
||||
summary: '',
|
||||
});
|
||||
|
||||
const isError = ref(false);
|
||||
const hasChange = ref(false);
|
||||
|
@ -159,22 +166,6 @@
|
|||
isError.value = false;
|
||||
}
|
||||
|
||||
async function handleUpdateReportDetail() {
|
||||
try {
|
||||
await updateReportDetail({
|
||||
id: detail.value.id,
|
||||
summary: richText.value.summary,
|
||||
richTextTmpFileIds: richText.value.richTextTmpFileIds ?? [],
|
||||
});
|
||||
Message.success(t('common.updateSuccess'));
|
||||
showButton.value = false;
|
||||
emit('updateSuccess');
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
watchEffect(() => {
|
||||
if (props.detailInfo) {
|
||||
detail.value = cloneDeep(props.detailInfo);
|
||||
|
@ -182,14 +173,47 @@
|
|||
}
|
||||
});
|
||||
|
||||
const functionalCaseTotal = computed(() => getSummaryDetail(detail.value.functionalCount).caseTotal);
|
||||
const apiCaseTotal = computed(() => getSummaryDetail(detail.value.apiCaseCount).caseTotal);
|
||||
const scenarioCaseTotal = computed(() => getSummaryDetail(detail.value.apiScenarioCount).caseTotal);
|
||||
|
||||
const configList = ref<configItem[]>([]);
|
||||
const cardItemList = ref<configItem[]>([]);
|
||||
|
||||
const detailType = [
|
||||
ReportCardTypeEnum.FUNCTIONAL_DETAIL,
|
||||
ReportCardTypeEnum.API_CASE_DETAIL,
|
||||
ReportCardTypeEnum.SCENARIO_CASE_DETAIL,
|
||||
];
|
||||
|
||||
const hasCaseList = computed<Record<SelectedReportCardTypes, number>>(() => {
|
||||
return {
|
||||
[ReportCardTypeEnum.SCENARIO_CASE_DETAIL]: scenarioCaseTotal.value,
|
||||
[ReportCardTypeEnum.FUNCTIONAL_DETAIL]: functionalCaseTotal.value,
|
||||
[ReportCardTypeEnum.API_CASE_DETAIL]: apiCaseTotal.value,
|
||||
};
|
||||
});
|
||||
|
||||
function filterNotHasCase(list: configItem[]) {
|
||||
return list.filter((item: any) => {
|
||||
if (detailType.includes(item.value)) {
|
||||
return hasCaseList.value[item.value as SelectedReportCardTypes] > 0;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
function initDefaultConfig() {
|
||||
const tempDefaultGroupConfig = filterNotHasCase(defaultGroupConfig);
|
||||
const tempSingleGroupConfig = filterNotHasCase(defaultSingleConfig);
|
||||
configList.value = props.isGroup ? cloneDeep(tempDefaultGroupConfig) : cloneDeep(tempSingleGroupConfig);
|
||||
cardItemList.value = props.isGroup ? cloneDeep(defaultGroupCardConfig) : cloneDeep(configList.value);
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.isGroup,
|
||||
() => {
|
||||
configList.value = props.isGroup ? cloneDeep(defaultGroupConfig) : cloneDeep(defaultSingleConfig);
|
||||
cardItemList.value = cloneDeep(configList.value);
|
||||
initDefaultConfig();
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
|
@ -201,17 +225,17 @@
|
|||
}
|
||||
|
||||
function getHoverClass(cardItem: configItem) {
|
||||
if (getExist(cardItem) && !cardItem.system) {
|
||||
if (getExist(cardItem) && cardItem.type !== FieldTypeEnum.SYSTEM) {
|
||||
return 'hover-selected-item-class';
|
||||
}
|
||||
if (!getExist(cardItem) && cardItem.system) {
|
||||
if (!getExist(cardItem) && cardItem.type === FieldTypeEnum.SYSTEM) {
|
||||
return 'hover-item-class';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
function getLabelClass(cardItem: configItem) {
|
||||
const isSystemColor = cardItem.system ? 'cursor-not-allowed' : '';
|
||||
const isSystemColor = cardItem.type === FieldTypeEnum.SYSTEM ? 'cursor-not-allowed' : '';
|
||||
return getExist(cardItem)
|
||||
? `text-[var(--color-text-4)] ${isSystemColor}`
|
||||
: `text-[var(--color-text-1)] cursor-pointer hover:text-[rgb(var(--primary-4))]`;
|
||||
|
@ -238,8 +262,7 @@
|
|||
|
||||
// 恢复默认
|
||||
function handleReset() {
|
||||
configList.value = props.isGroup ? cloneDeep(defaultGroupConfig) : cloneDeep(defaultSingleConfig);
|
||||
cardItemList.value = cloneDeep(configList.value);
|
||||
initDefaultConfig();
|
||||
nextTick(() => {
|
||||
hasChange.value = false;
|
||||
});
|
||||
|
@ -300,10 +323,6 @@
|
|||
configList.value.splice(currentIndex, 1, currentItem);
|
||||
}
|
||||
|
||||
const functionalCaseTotal = computed(() => getSummaryDetail(detail.value.functionalCount).caseTotal);
|
||||
const apiCaseTotal = computed(() => getSummaryDetail(detail.value.apiCaseCount).caseTotal);
|
||||
const scenarioCaseTotal = computed(() => getSummaryDetail(detail.value.apiScenarioCount).caseTotal);
|
||||
|
||||
function showItem(item: configItem) {
|
||||
switch (item.value) {
|
||||
case ReportCardTypeEnum.FUNCTIONAL_DETAIL:
|
||||
|
@ -316,8 +335,61 @@
|
|||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
function makeParams() {
|
||||
const richFileIds: string[] = [];
|
||||
const addComponentList = cardItemList.value.map((item, index) => {
|
||||
if (item.richTextTmpFileIds) {
|
||||
richFileIds.concat(item.richTextTmpFileIds);
|
||||
}
|
||||
return {
|
||||
// id: item.id,
|
||||
name: item.value,
|
||||
label: t(item.label),
|
||||
type: item.type,
|
||||
value: item.content || '',
|
||||
pos: index + 1,
|
||||
};
|
||||
});
|
||||
return {
|
||||
projectId: appStore.currentProjectId,
|
||||
testPlanId: route.query.id as string,
|
||||
triggerMode: TriggerModeLabelEnum.MANUAL,
|
||||
reportName: reportForm.value.reportName,
|
||||
components: addComponentList,
|
||||
richTextTmpFileIds: richFileIds,
|
||||
};
|
||||
}
|
||||
|
||||
const confirmLoading = ref<boolean>(false);
|
||||
// 保存配置
|
||||
function handleSave() {}
|
||||
async function handleSave() {
|
||||
if (!reportForm.value.reportName) {
|
||||
isError.value = true;
|
||||
Message.error(t('report.detail.reportNameNotEmpty'));
|
||||
return;
|
||||
}
|
||||
confirmLoading.value = true;
|
||||
try {
|
||||
const params: manualReportGenParams = makeParams();
|
||||
const reportId = await manualReportGen(params);
|
||||
Message.success(t('report.detail.manualGenReportSuccess'));
|
||||
if (reportId) {
|
||||
router.push({
|
||||
name: TestPlanRouteEnum.TEST_PLAN_REPORT_DETAIL,
|
||||
query: {
|
||||
id: reportId,
|
||||
type: props.isGroup ? 'GROUP' : 'TEST_PLAN',
|
||||
},
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
} finally {
|
||||
confirmLoading.value = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
|
|
|
@ -26,6 +26,13 @@
|
|||
@click="handleClick"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-show="hasAnyPermission(['PROJECT_TEST_PLAN_REPORT:READ+UPDATE']) && !shareId && props.canEdit"
|
||||
class="mt-[16px] flex items-center gap-[12px]"
|
||||
>
|
||||
<a-button type="primary" @click="handleUpdateReportDetail">{{ t('common.save') }}</a-button>
|
||||
<a-button type="secondary" @click="handleCancel">{{ t('common.cancel') }}</a-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
@ -52,6 +59,7 @@
|
|||
const emit = defineEmits<{
|
||||
(e: 'updateCustom', formValue: customValueForm): void;
|
||||
(e: 'dblclick'): void;
|
||||
(e: 'cancel'): void;
|
||||
}>();
|
||||
|
||||
const innerTextForm = ref<customValueForm>({
|
||||
|
@ -78,10 +86,23 @@
|
|||
});
|
||||
}
|
||||
function emitDoubleClick() {
|
||||
emit('dblclick');
|
||||
if (!props.shareId) {
|
||||
emit('dblclick');
|
||||
}
|
||||
}
|
||||
|
||||
function handleUpdateReportDetail() {
|
||||
emit('updateCustom', {
|
||||
...innerTextForm.value,
|
||||
label: innerTextForm.value.label || t('report.detail.customDefaultCardName'),
|
||||
});
|
||||
}
|
||||
|
||||
const { handleClick } = useDoubleClick(emitDoubleClick);
|
||||
|
||||
function handleCancel() {
|
||||
emit('cancel');
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
|
|
|
@ -3,42 +3,55 @@ import { defaultCount } from '@/config/testPlan';
|
|||
import { ApiOrScenarioCaseItem, FeatureCaseItem, ReportBugItem } from '@/models/testPlan/report';
|
||||
import type { configItem } from '@/models/testPlan/testPlanReport';
|
||||
import { PlanReportDetail } from '@/models/testPlan/testPlanReport';
|
||||
import { ReportCardTypeEnum } from '@/enums/testPlanReportEnum';
|
||||
import { FieldTypeEnum, ReportCardTypeEnum } from '@/enums/testPlanReportEnum';
|
||||
|
||||
export const commonDefaultConfig: configItem[] = [
|
||||
const summaryConfig: configItem[] = [
|
||||
{
|
||||
id: ReportCardTypeEnum.SUMMARY,
|
||||
value: ReportCardTypeEnum.SUMMARY,
|
||||
label: 'report.detail.reportSummary',
|
||||
system: true,
|
||||
type: FieldTypeEnum.SYSTEM,
|
||||
enableEdit: false,
|
||||
},
|
||||
];
|
||||
const subPlanConfig: configItem[] = [
|
||||
{
|
||||
id: ReportCardTypeEnum.SUB_PLAN_DETAIL,
|
||||
value: ReportCardTypeEnum.SUB_PLAN_DETAIL,
|
||||
label: 'report.detail.subPlanDetails',
|
||||
type: FieldTypeEnum.SYSTEM,
|
||||
enableEdit: false,
|
||||
},
|
||||
];
|
||||
|
||||
export const commonDefaultConfig: configItem[] = [
|
||||
...summaryConfig,
|
||||
{
|
||||
id: ReportCardTypeEnum.BUG_DETAIL,
|
||||
value: ReportCardTypeEnum.BUG_DETAIL,
|
||||
label: 'report.detail.bugDetails',
|
||||
system: true,
|
||||
type: FieldTypeEnum.SYSTEM,
|
||||
enableEdit: false,
|
||||
},
|
||||
{
|
||||
id: ReportCardTypeEnum.FUNCTIONAL_DETAIL,
|
||||
value: ReportCardTypeEnum.FUNCTIONAL_DETAIL,
|
||||
label: 'report.detail.featureCaseDetails',
|
||||
system: true,
|
||||
type: FieldTypeEnum.SYSTEM,
|
||||
enableEdit: false,
|
||||
},
|
||||
{
|
||||
id: ReportCardTypeEnum.API_CASE_DETAIL,
|
||||
value: ReportCardTypeEnum.API_CASE_DETAIL,
|
||||
label: 'report.detail.apiCaseDetails',
|
||||
system: true,
|
||||
type: FieldTypeEnum.SYSTEM,
|
||||
enableEdit: false,
|
||||
},
|
||||
{
|
||||
id: ReportCardTypeEnum.SCENARIO_CASE_DETAIL,
|
||||
value: ReportCardTypeEnum.SCENARIO_CASE_DETAIL,
|
||||
label: 'report.detail.scenarioCaseDetails',
|
||||
system: true,
|
||||
type: FieldTypeEnum.SYSTEM,
|
||||
enableEdit: false,
|
||||
},
|
||||
];
|
||||
|
@ -47,24 +60,17 @@ export const defaultCustomConfig: configItem = {
|
|||
id: '',
|
||||
value: ReportCardTypeEnum.CUSTOM_CARD,
|
||||
label: 'report.detail.customDefaultCardName',
|
||||
system: false,
|
||||
type: FieldTypeEnum.RICH_TEXT,
|
||||
enableEdit: false,
|
||||
content: '',
|
||||
};
|
||||
|
||||
// 独立报告默认配置
|
||||
// 独立报告默认选择列表配置
|
||||
export const defaultSingleConfig: configItem[] = [...commonDefaultConfig];
|
||||
// 集合报告默认配置
|
||||
export const defaultGroupConfig: configItem[] = [
|
||||
{
|
||||
id: ReportCardTypeEnum.SUB_PLAN_DETAIL,
|
||||
value: ReportCardTypeEnum.SUB_PLAN_DETAIL,
|
||||
label: 'report.detail.subPlanDetails',
|
||||
system: true,
|
||||
enableEdit: false,
|
||||
},
|
||||
...commonDefaultConfig,
|
||||
];
|
||||
// 集合报告默认选择列表配置
|
||||
export const defaultGroupConfig: configItem[] = [...subPlanConfig, ...commonDefaultConfig];
|
||||
// 集合报告默认展示卡片列表配置
|
||||
export const defaultGroupCardConfig: configItem[] = [...subPlanConfig, ...summaryConfig];
|
||||
|
||||
interface NamedItem {
|
||||
name?: string;
|
||||
|
@ -115,6 +121,7 @@ const subPlanList: PlanReportDetail = {
|
|||
apiBugCount: 0,
|
||||
scenarioBugCount: 0,
|
||||
resultStatus: 'SUCCESS',
|
||||
defaultLayout: true,
|
||||
};
|
||||
|
||||
// 功能用例明细
|
||||
|
|
|
@ -58,9 +58,11 @@
|
|||
reportId: string;
|
||||
shareId?: string;
|
||||
isPreview?: boolean;
|
||||
isGroup?: boolean;
|
||||
}>();
|
||||
const { t } = useI18n();
|
||||
const columns: MsTableColumn = [
|
||||
|
||||
const staticColumns: MsTableColumn = [
|
||||
{
|
||||
title: 'ID',
|
||||
dataIndex: 'num',
|
||||
|
@ -97,6 +99,8 @@
|
|||
},
|
||||
width: 150,
|
||||
},
|
||||
];
|
||||
const lastStaticColumns: MsTableColumn = [
|
||||
{
|
||||
title: 'common.belongModule',
|
||||
dataIndex: 'moduleName',
|
||||
|
@ -123,12 +127,29 @@
|
|||
width: 100,
|
||||
},
|
||||
];
|
||||
// TODO 计划组用例明细字段接口目前还没有
|
||||
const testPlanNameColumns: MsTableColumn = [
|
||||
{
|
||||
title: 'report.plan.name',
|
||||
dataIndex: 'name',
|
||||
showTooltip: true,
|
||||
width: 200,
|
||||
},
|
||||
];
|
||||
|
||||
const columns = computed(() => {
|
||||
if (props.isGroup) {
|
||||
return [...staticColumns, ...testPlanNameColumns, ...lastStaticColumns];
|
||||
}
|
||||
return [...staticColumns, ...lastStaticColumns];
|
||||
});
|
||||
|
||||
const reportFeatureCaseList = () => {
|
||||
return !props.shareId ? getReportFeatureCaseList : getReportShareFeatureCaseList;
|
||||
};
|
||||
const { propsRes, propsEvent, loadList, setLoadListParams } = useTable(reportFeatureCaseList(), {
|
||||
scroll: { x: '100%' },
|
||||
columns,
|
||||
columns: columns.value,
|
||||
heightUsed: 20,
|
||||
showSelectorAll: false,
|
||||
});
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<div :class="`${hasAnyPermission(['PROJECT_TEST_PLAN_REPORT:READ+UPDATE']) && !shareId ? '' : 'cursor-not-allowed'}`">
|
||||
<MsRichText
|
||||
v-model:raw="innerSummary.summary"
|
||||
v-model:raw="innerSummary.content"
|
||||
v-model:filedIds="innerSummary.richTextTmpFileIds"
|
||||
:upload-image="handleUploadImage"
|
||||
:preview-url="ReportPlanPreviewImageUrl"
|
||||
|
@ -45,7 +45,7 @@
|
|||
|
||||
const { t } = useI18n();
|
||||
const props = defineProps<{
|
||||
richText: { summary: string; richTextTmpFileIds?: string[] };
|
||||
richText: { content: string; label: string; richTextTmpFileIds?: string[] };
|
||||
shareId?: string;
|
||||
showButton: boolean;
|
||||
isPlanGroup: boolean;
|
||||
|
@ -128,7 +128,9 @@
|
|||
}
|
||||
|
||||
function emitDoubleClick() {
|
||||
emit('dblclick');
|
||||
if (!props.shareId) {
|
||||
emit('dblclick');
|
||||
}
|
||||
}
|
||||
const { handleClick } = useDoubleClick(emitDoubleClick);
|
||||
</script>
|
||||
|
|
|
@ -157,7 +157,7 @@
|
|||
</a-tooltip>
|
||||
<a-divider v-if="allowEdit(item.value)" direction="vertical" class="!m-0 !mx-2" />
|
||||
<a-tooltip :content="t('common.delete')">
|
||||
<MsIcon type="icon-icon_delete-trash_outlined" size="16" @click="deleteCard(item)" />
|
||||
<MsIcon type="icon-icon_delete-trash_filled" size="16" @click="deleteCard(item)" />
|
||||
</a-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -174,15 +174,19 @@
|
|||
/>
|
||||
<Summary
|
||||
v-else-if="item.value === ReportCardTypeEnum.SUMMARY"
|
||||
v-model:richText="richText"
|
||||
:rich-text="{
|
||||
content: item.content || '',
|
||||
label: t(item.label),
|
||||
richTextTmpFileIds: [],
|
||||
}"
|
||||
:share-id="shareId"
|
||||
:can-edit="item.enableEdit"
|
||||
:show-button="showButton"
|
||||
:is-plan-group="props.isGroup"
|
||||
:detail="detail"
|
||||
@update-summary="handleUpdateReportDetail"
|
||||
@cancel="() => handleCancel(item)"
|
||||
@handle-summary="handleSummary"
|
||||
@update-summary="handleUpdateReportDetail(item)"
|
||||
@cancel="() => handleCancelCustom(item)"
|
||||
@handle-summary="(value:string) => handleSummary(value,item)"
|
||||
@dblclick="handleDoubleClick(item)"
|
||||
/>
|
||||
<BugTable
|
||||
|
@ -197,6 +201,7 @@
|
|||
:report-id="detail.id"
|
||||
:share-id="shareId"
|
||||
:is-preview="props.isPreview"
|
||||
:is-group="props.isGroup"
|
||||
/>
|
||||
<ApiAndScenarioTable
|
||||
v-else-if="
|
||||
|
@ -220,6 +225,7 @@
|
|||
}"
|
||||
@update-custom="(formValue:customValueForm)=>updateCustom(formValue,item)"
|
||||
@dblclick="handleDoubleClick(item)"
|
||||
@cancel="() => handleCancelCustom(item)"
|
||||
/>
|
||||
</MsCard>
|
||||
</div>
|
||||
|
@ -249,11 +255,12 @@
|
|||
import Summary from '@/views/test-plan/report/detail/component/system-card/summary.vue';
|
||||
import SystemTrigger from '@/views/test-plan/report/detail/component/system-card/systemTrigger.vue';
|
||||
|
||||
import { updateReportDetail } from '@/api/modules/test-plan/report';
|
||||
import { getReportLayout, updateReportDetail } from '@/api/modules/test-plan/report';
|
||||
import { commonConfig, defaultCount, defaultReportDetail, seriesConfig, statusConfig } from '@/config/testPlan';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import { addCommasToNumber } from '@/utils';
|
||||
|
||||
import { UpdateReportDetailParams } from '@/models/testPlan/report';
|
||||
import type {
|
||||
configItem,
|
||||
countDetail,
|
||||
|
@ -264,6 +271,7 @@
|
|||
import { customValueForm } from '@/models/testPlan/testPlanReport';
|
||||
import { ReportCardTypeEnum } from '@/enums/testPlanReportEnum';
|
||||
|
||||
import { defaultGroupConfig, defaultSingleConfig } from './reportConfig';
|
||||
import { getSummaryDetail } from '@/views/test-plan/report/utils';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
@ -277,7 +285,6 @@
|
|||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'updateSuccess'): void;
|
||||
(e: 'updateSuccess'): void;
|
||||
(e: 'updateCustom', item: configItem): void;
|
||||
}>();
|
||||
|
@ -293,18 +300,10 @@
|
|||
summary: '',
|
||||
});
|
||||
|
||||
const isError = ref(false);
|
||||
const reportForm = ref({
|
||||
reportName: '',
|
||||
});
|
||||
|
||||
function inputHandler(value: string) {
|
||||
if (value.trim().length === 0) {
|
||||
isError.value = true;
|
||||
}
|
||||
isError.value = false;
|
||||
}
|
||||
|
||||
const getAnalysisHover = computed(() => (props.isPreview ? '' : 'hover-analysis cursor-not-allowed'));
|
||||
|
||||
/**
|
||||
|
@ -388,22 +387,6 @@
|
|||
scenarioCaseOptions.value.series.data = getPassRateData(apiScenarioCount);
|
||||
}
|
||||
|
||||
async function handleUpdateReportDetail() {
|
||||
try {
|
||||
await updateReportDetail({
|
||||
id: detail.value.id,
|
||||
summary: richText.value.summary,
|
||||
richTextTmpFileIds: richText.value.richTextTmpFileIds ?? [],
|
||||
});
|
||||
Message.success(t('common.updateSuccess'));
|
||||
showButton.value = false;
|
||||
emit('updateSuccess');
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
const reportAnalysisList = computed<ReportMetricsItemModel[]>(() => [
|
||||
{
|
||||
name: t('report.detail.threshold'),
|
||||
|
@ -473,12 +456,42 @@
|
|||
return count;
|
||||
});
|
||||
|
||||
const originLayoutInfo = ref([]);
|
||||
|
||||
async function getDefaultLayout() {
|
||||
try {
|
||||
const res = await getReportLayout(detail.value.id, shareId.value);
|
||||
const result = res.map((item: any) => {
|
||||
return {
|
||||
id: item.id,
|
||||
value: item.name,
|
||||
label: item.label,
|
||||
content: item.value || '',
|
||||
type: item.type,
|
||||
enableEdit: false,
|
||||
richTextTmpFileIds: item.richTextTmpFileIds,
|
||||
};
|
||||
});
|
||||
innerCardList.value = result;
|
||||
originLayoutInfo.value = cloneDeep(result);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
watchEffect(() => {
|
||||
if (props.detailInfo) {
|
||||
detail.value = cloneDeep(props.detailInfo);
|
||||
richText.value.summary = detail.value.summary;
|
||||
reportForm.value.reportName = detail.value.name;
|
||||
initOptionsData();
|
||||
if (props.isPreview) {
|
||||
if (!detail.value.defaultLayout && detail.value.id) {
|
||||
getDefaultLayout();
|
||||
} else {
|
||||
innerCardList.value = props.isGroup ? cloneDeep(defaultGroupConfig) : cloneDeep(defaultSingleConfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -491,14 +504,18 @@
|
|||
});
|
||||
});
|
||||
|
||||
function handleCancel(cardItem: configItem) {
|
||||
richText.value = { summary: detail.value.summary };
|
||||
function handleCancelCustom(cardItem: configItem) {
|
||||
const originItem = originLayoutInfo.value.find((item: configItem) => item.id === cardItem.id);
|
||||
const index = originLayoutInfo.value.findIndex((e: configItem) => e.id === cardItem.id);
|
||||
if (originItem && index !== -1) {
|
||||
innerCardList.value.splice(index, 1, originItem);
|
||||
}
|
||||
showButton.value = false;
|
||||
cardItem.enableEdit = false;
|
||||
}
|
||||
|
||||
function handleSummary(content: string) {
|
||||
richText.value.summary = content;
|
||||
function handleSummary(content: string, cardItem: configItem) {
|
||||
cardItem.content = content;
|
||||
}
|
||||
|
||||
const currentMode = ref<string>('drawer');
|
||||
|
@ -512,7 +529,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
const allowEditType = [ReportCardTypeEnum.SUMMARY, ReportCardTypeEnum.CUSTOM_CARD];
|
||||
const allowEditType = [ReportCardTypeEnum.CUSTOM_CARD];
|
||||
function allowEdit(value: ReportCardTypeEnum) {
|
||||
return allowEditType.includes(value);
|
||||
}
|
||||
|
@ -537,26 +554,51 @@
|
|||
const deleteCard = (cardItem: configItem) => {
|
||||
innerCardList.value = innerCardList.value.filter((item) => item.id !== cardItem.id);
|
||||
};
|
||||
|
||||
// 编辑模式和预览模式切换
|
||||
function editField(cardItem: configItem) {
|
||||
if (allowEditType.includes(cardItem.value)) {
|
||||
cardItem.enableEdit = !cardItem.enableEdit;
|
||||
}
|
||||
if (cardItem.value === ReportCardTypeEnum.SUMMARY) {
|
||||
showButton.value = true;
|
||||
}
|
||||
}
|
||||
|
||||
function handleDoubleClick(cardItem: configItem) {
|
||||
editField(cardItem);
|
||||
if (props.isPreview) {
|
||||
if (cardItem.value === ReportCardTypeEnum.SUMMARY) {
|
||||
showButton.value = true;
|
||||
}
|
||||
cardItem.enableEdit = !cardItem.enableEdit;
|
||||
}
|
||||
}
|
||||
|
||||
async function handleUpdateReportDetail(currentItem: configItem) {
|
||||
try {
|
||||
const params: UpdateReportDetailParams = {
|
||||
id: detail.value.id,
|
||||
componentId: currentItem.type,
|
||||
componentValue: currentItem.content,
|
||||
richTextTmpFileIds: currentItem.richTextTmpFileIds,
|
||||
};
|
||||
await updateReportDetail(params);
|
||||
Message.success(t('common.updateSuccess'));
|
||||
if (currentItem.value === ReportCardTypeEnum.SUMMARY) {
|
||||
showButton.value = false;
|
||||
} else {
|
||||
currentItem.enableEdit = !currentItem.enableEdit;
|
||||
}
|
||||
// TODO 此处的更新后后台数据未更新需要验证接口
|
||||
emit('updateSuccess');
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
function updateCustom(formValue: customValueForm, currentItem: configItem) {
|
||||
const newCurrentItem = {
|
||||
const newCurrentItem: configItem = {
|
||||
...currentItem,
|
||||
...formValue,
|
||||
};
|
||||
innerCardList.value = innerCardList.value.map((item) => {
|
||||
innerCardList.value = innerCardList.value.map((item: configItem) => {
|
||||
if (item.id === currentItem.id) {
|
||||
return {
|
||||
...item,
|
||||
|
@ -566,7 +608,11 @@
|
|||
}
|
||||
return item;
|
||||
});
|
||||
emit('updateCustom', newCurrentItem);
|
||||
if (!props.isPreview) {
|
||||
emit('updateCustom', newCurrentItem);
|
||||
} else {
|
||||
handleUpdateReportDetail(newCurrentItem);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
@ -61,6 +61,7 @@
|
|||
apiBugCount: 0,
|
||||
scenarioBugCount: 0,
|
||||
testPlanName: '',
|
||||
defaultLayout: true,
|
||||
});
|
||||
|
||||
const isGroup = computed(() => route.query.type === 'GROUP');
|
||||
|
|
|
@ -1,9 +1,14 @@
|
|||
<template>
|
||||
<ViewReport v-model:card-list="cardItemList" :detail-info="detail" :is-group="isGroup" is-preview />
|
||||
<ViewReport
|
||||
v-model:card-list="cardItemList"
|
||||
:detail-info="detail"
|
||||
:is-group="isGroup"
|
||||
is-preview
|
||||
@update-success="getDetail()"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
// TODO 待联调 需要接口更新后联调下
|
||||
import { ref } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
|
@ -15,8 +20,6 @@
|
|||
|
||||
import type { configItem, PlanReportDetail } from '@/models/testPlan/testPlanReport';
|
||||
|
||||
import { defaultGroupConfig, defaultSingleConfig } from '@/views/test-plan/report/detail/component/reportConfig';
|
||||
|
||||
const route = useRoute();
|
||||
const reportId = ref<string>(route.query.id as string);
|
||||
|
||||
|
@ -27,7 +30,6 @@
|
|||
const cardItemList = ref<configItem[]>([]);
|
||||
|
||||
async function getDetail() {
|
||||
cardItemList.value = isGroup.value ? cloneDeep(defaultGroupConfig) : cloneDeep(defaultSingleConfig);
|
||||
try {
|
||||
detail.value = await getReportDetail(reportId.value);
|
||||
} catch (error) {
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
// TODO 待联调 分享页面也要调整
|
||||
import { ref } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
|
@ -16,8 +15,6 @@
|
|||
|
||||
import type { configItem, PlanReportDetail } from '@/models/testPlan/testPlanReport';
|
||||
|
||||
import { defaultGroupConfig, defaultSingleConfig } from '@/views/test-plan/report/detail/component/reportConfig';
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const reportId = ref<string>(route.query.id as string);
|
||||
|
@ -26,7 +23,6 @@
|
|||
|
||||
const cardItemList = ref<configItem[]>([]);
|
||||
async function getShareDetail() {
|
||||
cardItemList.value = isGroup.value ? cloneDeep(defaultGroupConfig) : cloneDeep(defaultSingleConfig);
|
||||
try {
|
||||
const hrefShareDetail = await planGetShareHref(route.query.shareId as string);
|
||||
reportId.value = hrefShareDetail.reportId;
|
||||
|
@ -51,6 +47,7 @@
|
|||
}
|
||||
detail.value = await getReportDetail(reportId.value, route.query.shareId as string);
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,4 +55,6 @@ export default {
|
|||
'report.detail.customMaxNumber': 'A maximum of 10 can be added',
|
||||
'report.detail.enterReportNamePlaceHolder': 'Please enter a report name',
|
||||
'report.detail.systemInternalTooltip': 'System built-in, not editable',
|
||||
'report.detail.reportNameNotEmpty': 'The report name cannot be empty',
|
||||
'report.detail.manualGenReportSuccess': 'The custom generated report was successful',
|
||||
};
|
||||
|
|
|
@ -55,4 +55,6 @@ export default {
|
|||
'report.detail.customMaxNumber': '最多可添加10个',
|
||||
'report.detail.enterReportNamePlaceHolder': '请输入报告名称',
|
||||
'report.detail.systemInternalTooltip': '系统内置,不可编辑',
|
||||
'report.detail.reportNameNotEmpty': '报告名称不能为空',
|
||||
'report.detail.manualGenReportSuccess': '自定义生成报告成功',
|
||||
};
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
/>
|
||||
<span :class="getIconClass">{{ record.childrenCount || (record.children || []).length || 0 }}</span>
|
||||
</div>
|
||||
<div v-if="record.type === testPlanTypeEnum.TEST_PLAN || !record.integrated" :class="`one-line-text ${hasIndent}`">
|
||||
<div v-if="showButton" :class="`one-line-text ${hasIndent}`">
|
||||
<MsButton type="text" @click="handleAction">
|
||||
<a-tooltip :content="content">
|
||||
<span>{{ record[props.numKey || 'num'] }}</span>
|
||||
|
@ -62,7 +62,7 @@
|
|||
|
||||
const hasIndent = computed(() =>
|
||||
(props.record.type === testPlanTypeEnum.TEST_PLAN && props.record.groupId && props.record.groupId !== 'NONE') ||
|
||||
(!props.record.integrated && props.record.parentId)
|
||||
(!props.record.integrated && props.record.parent)
|
||||
? 'pl-[36px]'
|
||||
: ''
|
||||
);
|
||||
|
@ -76,6 +76,13 @@
|
|||
emit('action');
|
||||
}
|
||||
}
|
||||
|
||||
const showButton = computed(() => {
|
||||
if (props.record.type) {
|
||||
return props.record.type === testPlanTypeEnum.TEST_PLAN;
|
||||
}
|
||||
return !props.record.integrated;
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="less"></style>
|
||||
|
|
|
@ -129,7 +129,8 @@
|
|||
<MsStatusTag :status="filterContent.value" />
|
||||
</template>
|
||||
<template #status="{ record }">
|
||||
<MsStatusTag :status="record.status" />
|
||||
<MsStatusTag v-if="getStatus(record.id)" :status="getStatus(record.id)" />
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
<template #createUser="{ record }">
|
||||
<a-tooltip :content="`${record.createUserName}`" position="tl">
|
||||
|
@ -244,13 +245,13 @@
|
|||
></a-divider>
|
||||
|
||||
<MsButton
|
||||
v-if="hasAnyPermission(['PROJECT_TEST_PLAN:READ+UPDATE']) && record.status !== 'ARCHIVED'"
|
||||
v-if="hasAnyPermission(['PROJECT_TEST_PLAN:READ+UPDATE']) && getStatus(record.id) !== 'ARCHIVED'"
|
||||
class="!mx-0"
|
||||
@click="emit('edit', record)"
|
||||
>{{ t('common.edit') }}</MsButton
|
||||
>
|
||||
<a-divider
|
||||
v-if="hasAnyPermission(['PROJECT_TEST_PLAN:READ+UPDATE']) && record.status !== 'ARCHIVED'"
|
||||
v-if="hasAnyPermission(['PROJECT_TEST_PLAN:READ+UPDATE']) && getStatus(record.id) !== 'ARCHIVED'"
|
||||
direction="vertical"
|
||||
:margin="8"
|
||||
></a-divider>
|
||||
|
@ -259,7 +260,7 @@
|
|||
v-if="
|
||||
!isShowExecuteButton(record) &&
|
||||
hasAnyPermission(['PROJECT_TEST_PLAN:READ+ADD']) &&
|
||||
record.status !== 'ARCHIVED'
|
||||
getStatus(record.id) !== 'ARCHIVED'
|
||||
"
|
||||
class="!mx-0"
|
||||
@click="copyTestPlanOrGroup(record.id)"
|
||||
|
@ -269,7 +270,7 @@
|
|||
v-if="
|
||||
!isShowExecuteButton(record) &&
|
||||
hasAnyPermission(['PROJECT_TEST_PLAN:READ+ADD']) &&
|
||||
record.status !== 'ARCHIVED'
|
||||
getStatus(record.id) !== 'ARCHIVED'
|
||||
"
|
||||
direction="vertical"
|
||||
:margin="8"
|
||||
|
@ -738,17 +739,20 @@
|
|||
function getScheduleEnable(id: string) {
|
||||
return defaultCountDetailMap.value[id].scheduleConfig.enable;
|
||||
}
|
||||
function getStatus(id: string) {
|
||||
return defaultCountDetailMap.value[id]?.status;
|
||||
}
|
||||
|
||||
function isShowExecuteButton(record: TestPlanItem) {
|
||||
return (
|
||||
((record.type === testPlanTypeEnum.TEST_PLAN && getFunctionalCount(record.id) > 0) ||
|
||||
(record.type === testPlanTypeEnum.GROUP && record.childrenCount)) &&
|
||||
record.status !== 'ARCHIVED'
|
||||
getStatus(record.id) !== 'ARCHIVED'
|
||||
);
|
||||
}
|
||||
|
||||
function getMoreActions(record: TestPlanItem) {
|
||||
const { status: planStatus } = record;
|
||||
const planStatus = getStatus(record.id);
|
||||
|
||||
// 有用例数量才可以执行 否则不展示执行
|
||||
const copyAction =
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
hide-back
|
||||
>
|
||||
<template #headerLeft>
|
||||
<MsStatusTag :status="detail.status || 'PREPARED'" />
|
||||
<MsStatusTag :status="countDetail.status" />
|
||||
<a-tooltip :content="`[${detail.num}]${detail.name}`">
|
||||
<div class="one-line-text ml-[8px] max-w-[360px] gap-[4px] font-medium text-[var(--color-text-1)]">
|
||||
<span>[{{ detail.num }}]</span>
|
||||
|
@ -33,7 +33,6 @@
|
|||
<MsIcon type="icon-icon_edit_outlined" class="mr-[8px]" />
|
||||
{{ t('common.edit') }}
|
||||
</MsButton>
|
||||
<!-- TODO 等待联调 接口需要调整和增加 -->
|
||||
<MsTableMoreAction :list="reportMoreAction" @select="handleMoreReportSelect">
|
||||
<MsButton
|
||||
v-if="hasAnyPermission(['PROJECT_TEST_PLAN:READ+EXECUTE']) && detail.status !== 'ARCHIVED'"
|
||||
|
|
|
@ -30,8 +30,6 @@
|
|||
|
||||
import type { configItem, PlanReportDetail } from '@/models/testPlan/testPlanReport';
|
||||
|
||||
import { defaultSingleConfig } from '@/views/test-plan/report/detail/component/reportConfig';
|
||||
|
||||
const props = defineProps<{
|
||||
reportId: string;
|
||||
}>();
|
||||
|
@ -42,7 +40,7 @@
|
|||
|
||||
const route = useRoute();
|
||||
|
||||
const cardItemList = ref<configItem[]>(cloneDeep(defaultSingleConfig));
|
||||
const cardItemList = ref<configItem[]>([]);
|
||||
|
||||
const shareId = ref<string>(route.query.shareId as string);
|
||||
|
||||
|
|
Loading…
Reference in New Issue