fix(接口测试): 场景列表页面增加权限

This commit is contained in:
wxg0103 2024-04-02 17:27:11 +08:00 committed by 刘瑞斌
parent cb4bad71d6
commit a4f567dc31
8 changed files with 115 additions and 21 deletions

View File

@ -1,3 +1,5 @@
import type { CaseLevel } from '@/components/business/ms-case-associate/types';
import MSR from '@/api/http/index'; import MSR from '@/api/http/index';
import { import {
AddModuleUrl, AddModuleUrl,
@ -34,6 +36,8 @@ import {
ScenarioTrashPageUrl, ScenarioTrashPageUrl,
ScenarioUploadTempFileUrl, ScenarioUploadTempFileUrl,
UpdateModuleUrl, UpdateModuleUrl,
UpdateScenarioPriorityUrl,
UpdateScenarioStatusUrl,
UpdateScenarioUrl, UpdateScenarioUrl,
} from '@/api/requrls/api-test/scenario'; } from '@/api/requrls/api-test/scenario';
@ -58,6 +62,7 @@ import {
ScenarioHistoryPageParams, ScenarioHistoryPageParams,
} from '@/models/apiTest/scenario'; } from '@/models/apiTest/scenario';
import { AddModuleParams, CommonList, ModuleTreeNode, MoveModules, TransferFileParams } from '@/models/common'; import { AddModuleParams, CommonList, ModuleTreeNode, MoveModules, TransferFileParams } from '@/models/common';
import { ApiScenarioStatus } from '@/enums/apiEnum';
import type { RequestParam as CaseRequestParam } from '@/views/api-test/components/requestComposition/index.vue'; import type { RequestParam as CaseRequestParam } from '@/views/api-test/components/requestComposition/index.vue';
import type { RequestParam } from '@/views/api-test/scenario/components/common/customApiDrawer.vue'; import type { RequestParam } from '@/views/api-test/scenario/components/common/customApiDrawer.vue';
@ -264,3 +269,12 @@ export function getSystemRequest(data: GetSystemRequestParams) {
export function followScenario(id: string | number) { export function followScenario(id: string | number) {
return MSR.get({ url: FollowScenarioUrl, params: id }); return MSR.get({ url: FollowScenarioUrl, params: id });
} }
// 更新场景状态
export function updateScenarioStatus(id: string | number, status: ApiScenarioStatus | undefined) {
return MSR.get({ url: `${UpdateScenarioStatusUrl}/${id}/${status}` });
}
export function updateScenarioPro(id: string | number, priority: CaseLevel | undefined) {
return MSR.get({ url: `${UpdateScenarioPriorityUrl}/${id}/${priority}` });
}

View File

@ -24,6 +24,8 @@ export const BatchMoveScenarioUrl = '/api/scenario/batch-operation/move'; // 批
export const BatchCopyScenarioUrl = '/api/scenario/batch-operation/copy'; // 批量复制接口场景 export const BatchCopyScenarioUrl = '/api/scenario/batch-operation/copy'; // 批量复制接口场景
export const BatchEditScenarioUrl = '/api/scenario/batch-operation/edit'; // 批量编辑接口场景 export const BatchEditScenarioUrl = '/api/scenario/batch-operation/edit'; // 批量编辑接口场景
export const BatchRunScenarioUrl = '/api/scenario/batch-operation/run'; // 批量执行接口场景 export const BatchRunScenarioUrl = '/api/scenario/batch-operation/run'; // 批量执行接口场景
export const UpdateScenarioPriorityUrl = '/api/scenario/update-priority'; // 场景更新等级
export const UpdateScenarioStatusUrl = '/api/scenario/update-status'; // 场景更新状态
// 回收站相关 // 回收站相关
export const GetTrashModuleTreeUrl = '/api/scenario/module/trash/tree'; export const GetTrashModuleTreeUrl = '/api/scenario/module/trash/tree';

View File

@ -368,6 +368,7 @@
'PROJECT_API_DEFINITION:READ+DELETE', 'PROJECT_API_DEFINITION:READ+DELETE',
'PROJECT_API_DEFINITION:READ+ADD', 'PROJECT_API_DEFINITION:READ+ADD',
'PROJECT_API_DEFINITION:READ+EXECUTE', 'PROJECT_API_DEFINITION:READ+EXECUTE',
'PROJECT_API_DEFINITION:READ+UPDATE',
]) ])
); );
let columns: MsTableColumn = [ let columns: MsTableColumn = [
@ -465,9 +466,13 @@
scroll: { x: '100%' }, scroll: { x: '100%' },
tableKey: props.readOnly ? undefined : TableKeyEnum.API_TEST, tableKey: props.readOnly ? undefined : TableKeyEnum.API_TEST,
showSetting: !props.readOnly, showSetting: !props.readOnly,
selectable: true, selectable: hasAnyPermission([
'PROJECT_API_DEFINITION:READ+DELETE',
'PROJECT_API_DEFINITION:READ+EXECUTE',
'PROJECT_API_DEFINITION:READ+UPDATE',
]),
showSelectAll: !props.readOnly, showSelectAll: !props.readOnly,
draggable: props.readOnly ? undefined : { type: 'handle', width: 32 }, draggable: hasAnyPermission(['PROJECT_API_DEFINITION:READ+UPDATE']) ? { type: 'handle', width: 32 } : undefined,
heightUsed: 308, heightUsed: 308,
showSubdirectory: true, showSubdirectory: true,
}, },

View File

@ -30,7 +30,11 @@
> >
{{ t('apiTestManagement.execute') }} {{ t('apiTestManagement.execute') }}
</a-button> </a-button>
<a-dropdown-button type="outline" @click="toEditDefinition"> <a-dropdown-button
v-permission="['PROJECT_API_DEFINITION:READ+UPDATE']"
type="outline"
@click="toEditDefinition"
>
{{ t('common.edit') }} {{ t('common.edit') }}
<template #icon> <template #icon>
<icon-down /> <icon-down />
@ -63,7 +67,12 @@
@update-follow="activeApiTab.follow = !activeApiTab.follow" @update-follow="activeApiTab.follow = !activeApiTab.follow"
/> />
</a-tab-pane> </a-tab-pane>
<a-tab-pane key="definition" :title="t('apiTestManagement.definition')" class="ms-api-tab-pane"> <a-tab-pane
v-if="hasAnyPermission(['PROJECT_API_DEFINITION:READ+UPDATE', 'PROJECT_API_DEFINITION:READ+ADD'])"
key="definition"
:title="t('apiTestManagement.definition')"
class="ms-api-tab-pane"
>
<requestComposition <requestComposition
ref="requestCompositionRef" ref="requestCompositionRef"
v-model:detail-loading="loading" v-model:detail-loading="loading"
@ -88,7 +97,12 @@
@add-done="handleAddDone" @add-done="handleAddDone"
/> />
</a-tab-pane> </a-tab-pane>
<a-tab-pane v-if="!activeApiTab.isNew" key="case" :title="t('apiTestManagement.case')" class="ms-api-tab-pane"> <a-tab-pane
v-if="!activeApiTab.isNew && hasAnyPermission(['PROJECT_API_DEFINITION_CASE:READ'])"
key="case"
:title="t('apiTestManagement.case')"
class="ms-api-tab-pane"
>
<caseTable <caseTable
ref="caseTableRef" ref="caseTableRef"
:is-api="true" :is-api="true"
@ -126,6 +140,7 @@
import { useI18n } from '@/hooks/useI18n'; import { useI18n } from '@/hooks/useI18n';
import useModal from '@/hooks/useModal'; import useModal from '@/hooks/useModal';
import useAppStore from '@/store/modules/app'; import useAppStore from '@/store/modules/app';
import { hasAnyPermission } from '@/utils/permission';
import { ProtocolItem } from '@/models/apiTest/common'; import { ProtocolItem } from '@/models/apiTest/common';
import { ApiDefinitionDetail } from '@/models/apiTest/management'; import { ApiDefinitionDetail } from '@/models/apiTest/management';

View File

@ -562,9 +562,15 @@
scroll: { x: '100%' }, scroll: { x: '100%' },
tableKey: TableKeyEnum.API_TEST_MANAGEMENT_CASE, tableKey: TableKeyEnum.API_TEST_MANAGEMENT_CASE,
showSetting: true, showSetting: true,
selectable: true, selectable: hasAnyPermission([
'PROJECT_API_DEFINITION_CASE:READ+DELETE',
'PROJECT_API_DEFINITION_CASE:READ+EXECUTE',
'PROJECT_API_DEFINITION_CASE:READ+UPDATE',
]),
showSelectAll: true, showSelectAll: true,
draggable: { type: 'handle', width: 32 }, draggable: hasAnyPermission(['PROJECT_API_DEFINITION_CASE:READ+UPDATE'])
? { type: 'handle', width: 32 }
: undefined,
heightUsed: props.isApi ? 356 : 308, heightUsed: props.isApi ? 356 : 308,
showSubdirectory: true, showSubdirectory: true,
}); });

View File

@ -101,7 +101,7 @@
const currentTab = ref('api'); const currentTab = ref('api');
const tabOptions = [ const tabOptions = [
{ label: 'API', value: 'api' }, { label: 'API', value: 'api' },
{ label: 'CASE', value: 'case' }, ...(hasAnyPermission(['PROJECT_API_DEFINITION_CASE:READ']) ? [{ label: 'CASE', value: 'case' }] : []),
]; ];
const apiRef = ref<InstanceType<typeof api>>(); const apiRef = ref<InstanceType<typeof api>>();

View File

@ -61,6 +61,37 @@
</template> </template>
</a-trigger> </a-trigger>
</template> </template>
<template #priorityFilter="{ columnConfig }">
<a-trigger
v-model:popup-visible="priorityFilterVisible"
trigger="click"
@popup-visible-change="handleFilterHidden"
>
<MsButton type="text" class="arco-btn-text--secondary ml-[10px]" @click="priorityFilterVisible = true">
{{ t(columnConfig.title as string) }}
<icon-down :class="priorityFilterVisible ? 'text-[rgb(var(--primary-5))]' : ''" />
</MsButton>
<template #content>
<div class="arco-table-filters-content">
<div class="ml-[6px] flex items-center justify-start px-[6px] py-[2px]">
<a-checkbox-group v-model:model-value="priorityFilters" direction="vertical" size="small">
<a-checkbox v-for="item of casePriorityOptions" :key="item.value" :value="item.value">
<caseLevel :case-level="item.label as CaseLevel" />
</a-checkbox>
</a-checkbox-group>
</div>
<div class="filter-button">
<a-button size="mini" class="mr-[8px]" @click="resetPriorityFilter">
{{ t('common.reset') }}
</a-button>
<a-button type="primary" size="mini" @click="handleFilterHidden(false)">
{{ t('system.orgTemplate.confirm') }}
</a-button>
</div>
</div>
</template>
</a-trigger>
</template>
<template #num="{ record }"> <template #num="{ record }">
<div> <div>
<MsButton type="text" class="float-left" style="margin-right: 4px" @click="openScenarioTab(record)">{{ <MsButton type="text" class="float-left" style="margin-right: 4px" @click="openScenarioTab(record)">{{
@ -105,7 +136,9 @@
</template> </template>
<template #status="{ record }"> <template #status="{ record }">
<a-select <a-select
v-if="hasAnyPermission(['PROJECT_API_SCENARIO:READ+UPDATE'])"
v-model:model-value="record.status" v-model:model-value="record.status"
v-permission="['PROJECT_API_SCENARIO:READ+UPDATE']"
class="param-input w-full" class="param-input w-full"
size="mini" size="mini"
@change="() => handleStatusChange(record)" @change="() => handleStatusChange(record)"
@ -117,9 +150,11 @@
<apiStatus :status="item" size="small" /> <apiStatus :status="item" size="small" />
</a-option> </a-option>
</a-select> </a-select>
<apiStatus v-else :status="record.status" size="small" />
</template> </template>
<template #priority="{ record }"> <template #priority="{ record }">
<a-select <a-select
v-if="hasAnyPermission(['PROJECT_API_SCENARIO:READ+UPDATE'])"
v-model:model-value="record.priority" v-model:model-value="record.priority"
:placeholder="t('common.pleaseSelect')" :placeholder="t('common.pleaseSelect')"
class="param-input w-full" class="param-input w-full"
@ -135,6 +170,7 @@
<caseLevel :case-level="item.text as CaseLevel" /> <caseLevel :case-level="item.text as CaseLevel" />
</a-option> </a-option>
</a-select> </a-select>
<span v-else class="text-[var(--color-text-2)]"> <caseLevel :case-level="record.priority" /></span>
</template> </template>
<!-- 报告结果筛选 --> <!-- 报告结果筛选 -->
<template #lastReportStatusFilter="{ columnConfig }"> <template #lastReportStatusFilter="{ columnConfig }">
@ -536,7 +572,8 @@
getScenarioPage, getScenarioPage,
recycleScenario, recycleScenario,
scenarioScheduleConfig, scenarioScheduleConfig,
updateScenario, updateScenarioPro,
updateScenarioStatus,
} from '@/api/modules/api-test/scenario'; } from '@/api/modules/api-test/scenario';
import { useI18n } from '@/hooks/useI18n'; import { useI18n } from '@/hooks/useI18n';
import useModal from '@/hooks/useModal'; import useModal from '@/hooks/useModal';
@ -550,6 +587,8 @@
import { ReportEnum, ReportStatus } from '@/enums/reportEnum'; import { ReportEnum, ReportStatus } from '@/enums/reportEnum';
import { TableKeyEnum } from '@/enums/tableEnum'; import { TableKeyEnum } from '@/enums/tableEnum';
import { casePriorityOptions } from '@/views/api-test/components/config';
const props = defineProps<{ const props = defineProps<{
class?: string; class?: string;
activeModule: string; activeModule: string;
@ -572,7 +611,8 @@
const { openModal } = useModal(); const { openModal } = useModal();
const tableRecord = ref<ApiScenarioTableItem>(); const tableRecord = ref<ApiScenarioTableItem>();
const scheduleModalTitle = ref(''); const scheduleModalTitle = ref('');
const priorityFilterVisible = ref(false);
const priorityFilters = ref<string[]>([]);
const scheduleConfig = ref<ApiScenarioScheduleConfig>({ const scheduleConfig = ref<ApiScenarioScheduleConfig>({
scenarioId: '', scenarioId: '',
enable: false, enable: false,
@ -647,7 +687,12 @@
dataIndex: 'priority', dataIndex: 'priority',
slotName: 'priority', slotName: 'priority',
showDrag: true, showDrag: true,
width: 100, sortable: {
sortDirections: ['ascend', 'descend'],
sorter: true,
},
titleSlotName: 'priorityFilter',
width: 140,
}, },
{ {
title: 'apiScenario.table.columns.status', title: 'apiScenario.table.columns.status',
@ -748,9 +793,13 @@
scroll: { x: '100%' }, scroll: { x: '100%' },
tableKey: TableKeyEnum.API_SCENARIO, tableKey: TableKeyEnum.API_SCENARIO,
showSetting: !props.readOnly, showSetting: !props.readOnly,
selectable: true, selectable: hasAnyPermission([
'PROJECT_API_SCENARIO:READ+UPDATE',
'PROJECT_API_SCENARIO:READ+EXECUTE',
'PROJECT_API_SCENARIO:READ+DELETE',
]),
showSelectAll: !props.readOnly, showSelectAll: !props.readOnly,
draggable: props.readOnly ? undefined : { type: 'handle', width: 32 }, draggable: hasAnyPermission(['PROJECT_API_SCENARIO:READ+UPDATE']) ? { type: 'handle', width: 32 } : undefined,
heightUsed: 374, heightUsed: 374,
showSubdirectory: true, showSubdirectory: true,
}, },
@ -864,6 +913,7 @@
filter: { filter: {
lastReportStatus: lastReportStatusListFilters.value, lastReportStatus: lastReportStatusListFilters.value,
status: statusFilters.value, status: statusFilters.value,
priority: priorityFilters.value,
}, },
}; };
setLoadListParams(params); setLoadListParams(params);
@ -877,6 +927,7 @@
if (!val) { if (!val) {
lastReportStatusFilterVisible.value = false; lastReportStatusFilterVisible.value = false;
statusFilterVisible.value = false; statusFilterVisible.value = false;
priorityFilterVisible.value = false;
loadScenarioList(false); loadScenarioList(false);
} }
} }
@ -887,6 +938,12 @@
loadScenarioList(); loadScenarioList();
} }
function resetPriorityFilter() {
priorityFilterVisible.value = false;
priorityFilters.value = [];
loadScenarioList();
}
function resetLastReportStatusFilter() { function resetLastReportStatusFilter() {
lastReportStatusFilterVisible.value = false; lastReportStatusFilterVisible.value = false;
lastReportStatusListFilters.value = []; lastReportStatusListFilters.value = [];
@ -895,10 +952,7 @@
async function handleStatusChange(record: ApiScenarioUpdateDTO) { async function handleStatusChange(record: ApiScenarioUpdateDTO) {
try { try {
await updateScenario({ await updateScenarioStatus(record.id, record.status);
id: record.id,
status: record.status,
});
Message.success(t('common.updateSuccess')); Message.success(t('common.updateSuccess'));
} catch (error) { } catch (error) {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
@ -908,10 +962,7 @@
async function handlePriorityStatusChange(record: ApiScenarioUpdateDTO) { async function handlePriorityStatusChange(record: ApiScenarioUpdateDTO) {
try { try {
await updateScenario({ await updateScenarioPro(record.id, record.priority);
id: record.id,
priority: record.priority,
});
Message.success(t('common.updateSuccess')); Message.success(t('common.updateSuccess'));
} catch (error) { } catch (error) {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console

View File

@ -4,6 +4,7 @@
<MsEditableTab <MsEditableTab
v-model:active-tab="activeScenarioTab" v-model:active-tab="activeScenarioTab"
v-model:tabs="scenarioTabs" v-model:tabs="scenarioTabs"
v-permission="['PROJECT_API_SCENARIO:READ+ADD']"
class="flex-1 overflow-hidden" class="flex-1 overflow-hidden"
@add="() => newTab()" @add="() => newTab()"
> >