feat(接口测试): 接口测试前端页面
This commit is contained in:
parent
a404376e51
commit
f05e536cb3
|
@ -647,13 +647,16 @@ public class ApiScenarioDataTransferService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
List<ApiTestCaseWithBlob> apiTestCaseWithBlobs = extApiTestCaseMapper.selectAllDetailByApiIds(apiCaseIdList);
|
List<ApiTestCaseWithBlob> apiTestCaseWithBlobs = null;
|
||||||
if (CollectionUtils.isNotEmpty(apiCaseIdList)) {
|
if (CollectionUtils.isNotEmpty(apiCaseIdList)) {
|
||||||
apiTestCaseWithBlobs.forEach(item -> {
|
apiTestCaseWithBlobs = extApiTestCaseMapper.selectAllDetailByApiIds(apiCaseIdList);
|
||||||
if (!apiDefinitionIdList.contains(item.getApiDefinitionId())) {
|
if (CollectionUtils.isNotEmpty(apiCaseIdList)) {
|
||||||
apiDefinitionIdList.add(item.getApiDefinitionId());
|
apiTestCaseWithBlobs.forEach(item -> {
|
||||||
}
|
if (!apiDefinitionIdList.contains(item.getApiDefinitionId())) {
|
||||||
});
|
apiDefinitionIdList.add(item.getApiDefinitionId());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, Map<String, String>> projectApiModuleIdMap = new HashMap<>();
|
Map<String, Map<String, String>> projectApiModuleIdMap = new HashMap<>();
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import type { CaseLevel } from '@/components/business/ms-case-associate/types';
|
import type { CaseLevel } from '@/components/business/ms-case-associate/types';
|
||||||
|
|
||||||
import MSR from '@/api/http/index';
|
import MSR from '@/api/http/index';
|
||||||
|
import { ExportDefinitionUrl, StopApiExportUrl } from '@/api/requrls/api-test/management';
|
||||||
import {
|
import {
|
||||||
AddModuleUrl,
|
AddModuleUrl,
|
||||||
AddScenarioUrl,
|
AddScenarioUrl,
|
||||||
|
@ -19,6 +20,7 @@ import {
|
||||||
ExecuteScenarioUrl,
|
ExecuteScenarioUrl,
|
||||||
ExportScenarioUrl,
|
ExportScenarioUrl,
|
||||||
FollowScenarioUrl,
|
FollowScenarioUrl,
|
||||||
|
GetExportScenarioFileUrl,
|
||||||
GetModuleCountUrl,
|
GetModuleCountUrl,
|
||||||
GetModuleTreeUrl,
|
GetModuleTreeUrl,
|
||||||
GetScenarioBatchExportParamsUrl,
|
GetScenarioBatchExportParamsUrl,
|
||||||
|
@ -44,6 +46,7 @@ import {
|
||||||
ScenarioTransferModuleOptionsUrl,
|
ScenarioTransferModuleOptionsUrl,
|
||||||
ScenarioTrashPageUrl,
|
ScenarioTrashPageUrl,
|
||||||
ScenarioUploadTempFileUrl,
|
ScenarioUploadTempFileUrl,
|
||||||
|
StopExportScenarioUrl,
|
||||||
UpdateModuleUrl,
|
UpdateModuleUrl,
|
||||||
UpdateScenarioPriorityUrl,
|
UpdateScenarioPriorityUrl,
|
||||||
UpdateScenarioStatusUrl,
|
UpdateScenarioStatusUrl,
|
||||||
|
@ -51,6 +54,7 @@ import {
|
||||||
} from '@/api/requrls/api-test/scenario';
|
} from '@/api/requrls/api-test/scenario';
|
||||||
|
|
||||||
import { ExecuteConditionProcessor } from '@/models/apiTest/common';
|
import { ExecuteConditionProcessor } from '@/models/apiTest/common';
|
||||||
|
import type { ApiDefinitionBatchExportParams } from '@/models/apiTest/management';
|
||||||
import {
|
import {
|
||||||
ApiScenarioBatchDeleteParams,
|
ApiScenarioBatchDeleteParams,
|
||||||
ApiScenarioBatchEditParams,
|
ApiScenarioBatchEditParams,
|
||||||
|
@ -341,6 +345,22 @@ export function importScenario(params: ImportScenarioParams) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 导出场景
|
// 导出场景
|
||||||
export function exportScenario(data: ExportScenarioParams) {
|
export function exportScenario(data: ExportScenarioParams, type: string) {
|
||||||
return MSR.post({ url: ExportScenarioUrl, data });
|
return MSR.post({ url: `${ExportScenarioUrl}/${type}`, data });
|
||||||
|
}
|
||||||
|
|
||||||
|
// 停止导出场景
|
||||||
|
export function stopScenarioExport(taskId: string) {
|
||||||
|
return MSR.get({ url: `${StopExportScenarioUrl}/${taskId}` });
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取导出的文件
|
||||||
|
export function getScenarioDownloadFile(projectId: string, fileId: string) {
|
||||||
|
return MSR.get(
|
||||||
|
{
|
||||||
|
url: `${GetExportScenarioFileUrl}/${projectId}/${fileId}`,
|
||||||
|
responseType: 'blob',
|
||||||
|
},
|
||||||
|
{ isTransformResponse: false }
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,9 +28,11 @@ 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 UpdateScenarioPriorityUrl = '/api/scenario/update-priority'; // 场景更新等级
|
||||||
export const UpdateScenarioStatusUrl = '/api/scenario/update-status'; // 场景更新状态
|
export const UpdateScenarioStatusUrl = '/api/scenario/update-status'; // 场景更新状态
|
||||||
|
// 场景导入导出相关
|
||||||
export const ImportScenarioUrl = '/api/scenario/import'; // 导入场景
|
export const ImportScenarioUrl = '/api/scenario/import'; // 导入场景
|
||||||
export const ExportScenarioUrl = '/api/scenario/export'; // 导入场景
|
export const ExportScenarioUrl = '/api/scenario/export'; // 导出场景
|
||||||
|
export const StopExportScenarioUrl = '/api/scenario/stop';
|
||||||
|
export const GetExportScenarioFileUrl = '/api/scenario/download/file';
|
||||||
// 场景拖拽排序
|
// 场景拖拽排序
|
||||||
export const dragSortUrl = '/api/scenario/edit/pos';
|
export const dragSortUrl = '/api/scenario/edit/pos';
|
||||||
// 回收站相关
|
// 回收站相关
|
||||||
|
|
|
@ -256,6 +256,12 @@ export enum ScenarioExecuteStatus {
|
||||||
UN_EXECUTE = 'UN_EXECUTE',
|
UN_EXECUTE = 'UN_EXECUTE',
|
||||||
FAKE_ERROR = 'FAKE_ERROR',
|
FAKE_ERROR = 'FAKE_ERROR',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 场景导出配置
|
||||||
|
export enum ScenarioExportType {
|
||||||
|
SIMPLE = 'METERSPHERE_SIMPLE',
|
||||||
|
ALL = 'METERSPHERE_ALL_DATA',
|
||||||
|
}
|
||||||
// 场景步骤类型
|
// 场景步骤类型
|
||||||
export enum ScenarioStepType {
|
export enum ScenarioStepType {
|
||||||
API_CASE = 'API_CASE', // 接口用例
|
API_CASE = 'API_CASE', // 接口用例
|
||||||
|
|
|
@ -108,7 +108,7 @@
|
||||||
async function downloadFile(id: string) {
|
async function downloadFile(id: string) {
|
||||||
try {
|
try {
|
||||||
const response = await getApiDownload.value(appStore.currentProjectId, id);
|
const response = await getApiDownload.value(appStore.currentProjectId, id);
|
||||||
downloadByteFile(response, 'metersphere-export.json');
|
downloadByteFile(response, 'metersphere-definition.zip');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.log(error);
|
console.log(error);
|
||||||
|
|
|
@ -0,0 +1,221 @@
|
||||||
|
<template>
|
||||||
|
<a-modal
|
||||||
|
v-model:visible="visible"
|
||||||
|
:title="t('common.export')"
|
||||||
|
title-align="start"
|
||||||
|
class="ms-modal-upload ms-modal-medium"
|
||||||
|
:width="400"
|
||||||
|
>
|
||||||
|
<a-radio-group v-model:model-value="exportTypeRadio">
|
||||||
|
<a-radio :value="ScenarioExportType.SIMPLE"
|
||||||
|
>{{ t('apiScenario.export.type.simple') }}
|
||||||
|
<a-tooltip :content="t('apiScenario.export.simple.tooltip')" position="tl">
|
||||||
|
<icon-question-circle
|
||||||
|
class="ml-[4px] text-[var(--color-text-4)] hover:text-[rgb(var(--primary-5))]"
|
||||||
|
size="16"
|
||||||
|
/>
|
||||||
|
</a-tooltip>
|
||||||
|
</a-radio>
|
||||||
|
<a-radio :value="ScenarioExportType.ALL">{{ t('apiScenario.export.type.all') }}</a-radio>
|
||||||
|
</a-radio-group>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<div class="flex justify-end">
|
||||||
|
<a-button type="secondary" :disabled="exportLoading" @click="cancelExport">
|
||||||
|
{{ t('common.cancel') }}
|
||||||
|
</a-button>
|
||||||
|
<a-button class="ml-3" type="primary" :loading="exportLoading" @click="exportApi">
|
||||||
|
{{ t('common.export') }}
|
||||||
|
</a-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</a-modal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import { Message } from '@arco-design/web-vue';
|
||||||
|
|
||||||
|
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||||
|
import type { BatchActionQueryParams } from '@/components/pure/ms-table/type';
|
||||||
|
|
||||||
|
import { exportScenario, getScenarioDownloadFile, stopScenarioExport } from '@/api/modules/api-test/scenario';
|
||||||
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
|
import useWebsocket from '@/hooks/useWebsocket';
|
||||||
|
import useAppStore from '@/store/modules/app';
|
||||||
|
import { downloadByteFile, getGenerateId } from '@/utils';
|
||||||
|
|
||||||
|
import { ScenarioExportType } from '@/enums/apiEnum';
|
||||||
|
|
||||||
|
const appStore = useAppStore();
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
batchParams: BatchActionQueryParams;
|
||||||
|
conditionParams: Record<string, any> | (() => Record<string, any>);
|
||||||
|
sorter?: Record<string, any>;
|
||||||
|
isShare?: boolean; // 分享文档id
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const visible = defineModel<boolean>('visible', { required: true });
|
||||||
|
|
||||||
|
const exportLoading = ref(false);
|
||||||
|
const exportTypeRadio = ref(ScenarioExportType.SIMPLE);
|
||||||
|
|
||||||
|
function cancelExport() {
|
||||||
|
visible.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const websocket = ref<WebSocket>();
|
||||||
|
const reportId = ref('');
|
||||||
|
const isShowExportingMessage = ref(false); // 正在导出提示显示中
|
||||||
|
const exportingMessage = ref();
|
||||||
|
|
||||||
|
// 下载文件
|
||||||
|
async function downloadFile(id: string) {
|
||||||
|
try {
|
||||||
|
const response = await getScenarioDownloadFile(appStore.currentProjectId, id);
|
||||||
|
downloadByteFile(response, 'metersphere-scenaro.zip');
|
||||||
|
} catch (error) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 提示:导出成功
|
||||||
|
function showExportSuccessfulMessage(id: string, count: number) {
|
||||||
|
Message.success({
|
||||||
|
content: () =>
|
||||||
|
h('div', { class: 'flex flex-col gap-[8px] items-start' }, [
|
||||||
|
h('div', { class: 'font-medium' }, t('common.exportSuccessful')),
|
||||||
|
h('div', { class: 'flex items-center gap-[12px]' }, [
|
||||||
|
h('div', t('caseManagement.featureCase.exportApiCount', { number: count })),
|
||||||
|
h(
|
||||||
|
MsButton,
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
onClick() {
|
||||||
|
downloadFile(id);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ default: () => t('common.downloadFile') }
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
duration: 10000, // 10s 自动关闭
|
||||||
|
closable: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 开启websocket监听,接收结果
|
||||||
|
async function startWebsocketGetExportResult() {
|
||||||
|
const { createSocket, websocket: _websocket } = useWebsocket({
|
||||||
|
reportId: reportId.value,
|
||||||
|
socketUrl: '/ws/export',
|
||||||
|
onMessage: (event) => {
|
||||||
|
const data = JSON.parse(event.data);
|
||||||
|
if (data.msgType === 'EXEC_RESULT') {
|
||||||
|
exportingMessage.value.close();
|
||||||
|
reportId.value = data.fileId;
|
||||||
|
// taskId.value = data.taskId;
|
||||||
|
if (data.isSuccessful) {
|
||||||
|
showExportSuccessfulMessage(reportId.value, data.count);
|
||||||
|
} else {
|
||||||
|
Message.error({
|
||||||
|
content: t('common.exportFailed'),
|
||||||
|
duration: 999999999, // 一直展示,除非手动关闭
|
||||||
|
closable: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
websocket.value?.close();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
await createSocket();
|
||||||
|
websocket.value = _websocket.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 取消导出
|
||||||
|
async function stopExport(taskId: string) {
|
||||||
|
try {
|
||||||
|
await stopScenarioExport(taskId);
|
||||||
|
exportingMessage.value.close();
|
||||||
|
websocket.value?.close();
|
||||||
|
} catch (error) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 提示:正在导出
|
||||||
|
function showExportingMessage(taskId: string) {
|
||||||
|
if (isShowExportingMessage.value) return;
|
||||||
|
isShowExportingMessage.value = true;
|
||||||
|
exportingMessage.value = Message.loading({
|
||||||
|
content: () =>
|
||||||
|
h('div', { class: 'flex items-center gap-[12px]' }, [
|
||||||
|
h('div', t('common.exporting')),
|
||||||
|
h(
|
||||||
|
MsButton,
|
||||||
|
{
|
||||||
|
type: 'text',
|
||||||
|
onClick() {
|
||||||
|
stopExport(taskId);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ default: () => t('common.cancel') }
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
duration: 999999999, // 一直展示,除非手动关闭
|
||||||
|
closable: true,
|
||||||
|
onClose() {
|
||||||
|
isShowExportingMessage.value = false;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导出接口
|
||||||
|
*/
|
||||||
|
async function exportApi() {
|
||||||
|
try {
|
||||||
|
exportLoading.value = true;
|
||||||
|
reportId.value = getGenerateId();
|
||||||
|
await startWebsocketGetExportResult();
|
||||||
|
const batchConditionParams =
|
||||||
|
typeof props.conditionParams === 'function' ? await props.conditionParams() : props.conditionParams;
|
||||||
|
const { selectedIds, selectAll, excludeIds } = props.batchParams;
|
||||||
|
const res = await exportScenario(
|
||||||
|
{
|
||||||
|
selectIds: selectedIds || [],
|
||||||
|
selectAll: !!selectAll,
|
||||||
|
excludeIds: excludeIds || [],
|
||||||
|
...batchConditionParams,
|
||||||
|
sort: props.sorter || {},
|
||||||
|
fileId: reportId.value,
|
||||||
|
},
|
||||||
|
exportTypeRadio.value
|
||||||
|
);
|
||||||
|
showExportingMessage(res);
|
||||||
|
visible.value = false;
|
||||||
|
} catch (error) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(error);
|
||||||
|
} finally {
|
||||||
|
exportLoading.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="less">
|
||||||
|
.import-item {
|
||||||
|
@apply flex cursor-pointer items-center bg-white;
|
||||||
|
|
||||||
|
padding: 8px;
|
||||||
|
width: 150px;
|
||||||
|
border: 1px solid var(--color-text-n8);
|
||||||
|
border-radius: var(--border-radius-small);
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
.import-item--active {
|
||||||
|
border: 1px solid rgb(var(--primary-5));
|
||||||
|
background-color: rgb(var(--primary-1));
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -465,6 +465,13 @@
|
||||||
is-scenario
|
is-scenario
|
||||||
:report-id="tableRecord?.lastReportId || ''"
|
:report-id="tableRecord?.lastReportId || ''"
|
||||||
/>
|
/>
|
||||||
|
<!-- 场景导出-->
|
||||||
|
<ScenarioExportModal
|
||||||
|
v-model:visible="showExportModal"
|
||||||
|
:batch-params="batchParams"
|
||||||
|
:condition-params="getBatchConditionParams"
|
||||||
|
:sorter="propsRes.sorter || {}"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
@ -488,8 +495,10 @@
|
||||||
import type { MsTreeNodeData } from '@/components/business/ms-tree/types';
|
import type { MsTreeNodeData } from '@/components/business/ms-tree/types';
|
||||||
import apiStatus from '@/views/api-test/components/apiStatus.vue';
|
import apiStatus from '@/views/api-test/components/apiStatus.vue';
|
||||||
import caseAndScenarioReportDrawer from '@/views/api-test/components/caseAndScenarioReportDrawer.vue';
|
import caseAndScenarioReportDrawer from '@/views/api-test/components/caseAndScenarioReportDrawer.vue';
|
||||||
|
import ApiExportModal from '@/views/api-test/management/components/management/api/apiExportModal.vue';
|
||||||
import ExecutionStatus from '@/views/api-test/report/component/reportStatus.vue';
|
import ExecutionStatus from '@/views/api-test/report/component/reportStatus.vue';
|
||||||
import BatchRunModal from '@/views/api-test/scenario/components/batchRunModal.vue';
|
import BatchRunModal from '@/views/api-test/scenario/components/batchRunModal.vue';
|
||||||
|
import ScenarioExportModal from '@/views/api-test/scenario/components/common/exportScenario/scenarioExportModal.vue';
|
||||||
import operationScenarioModuleTree from '@/views/api-test/scenario/components/operationScenarioModuleTree.vue';
|
import operationScenarioModuleTree from '@/views/api-test/scenario/components/operationScenarioModuleTree.vue';
|
||||||
|
|
||||||
import { getEnvList } from '@/api/modules/api-test/common';
|
import { getEnvList } from '@/api/modules/api-test/common';
|
||||||
|
@ -547,7 +556,7 @@
|
||||||
|
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
const cacheStore = useCacheStore();
|
const cacheStore = useCacheStore();
|
||||||
|
const showExportModal = ref(false);
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const { openModal } = useModal();
|
const { openModal } = useModal();
|
||||||
const tableRecord = ref<ApiScenarioTableItem>();
|
const tableRecord = ref<ApiScenarioTableItem>();
|
||||||
|
@ -824,6 +833,11 @@
|
||||||
);
|
);
|
||||||
const batchActions = {
|
const batchActions = {
|
||||||
baseAction: [
|
baseAction: [
|
||||||
|
{
|
||||||
|
label: 'common.export',
|
||||||
|
eventTag: 'export',
|
||||||
|
permission: ['PROJECT_API_SCENARIO:READ+EXPORT'],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: 'common.edit',
|
label: 'common.edit',
|
||||||
eventTag: 'edit',
|
eventTag: 'edit',
|
||||||
|
@ -1067,7 +1081,7 @@
|
||||||
|
|
||||||
const tableSelected = ref<(string | number)[]>([]);
|
const tableSelected = ref<(string | number)[]>([]);
|
||||||
|
|
||||||
const batchParams = ref<BatchActionQueryParams>();
|
const batchParams = ref<BatchActionQueryParams>({ selectAll: false });
|
||||||
const batchOptionParams = ref<any>();
|
const batchOptionParams = ref<any>();
|
||||||
async function getBatchConditionParams() {
|
async function getBatchConditionParams() {
|
||||||
const selectModules = await getModuleIds();
|
const selectModules = await getModuleIds();
|
||||||
|
@ -1445,6 +1459,9 @@
|
||||||
|
|
||||||
batchParams.value = { ...params };
|
batchParams.value = { ...params };
|
||||||
switch (event.eventTag) {
|
switch (event.eventTag) {
|
||||||
|
case 'export':
|
||||||
|
showExportModal.value = true;
|
||||||
|
break;
|
||||||
case 'delete':
|
case 'delete':
|
||||||
deleteScenario(undefined, true, batchParams.value);
|
deleteScenario(undefined, true, batchParams.value);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -286,4 +286,7 @@ export default {
|
||||||
'apiScenario.csvQuote': 'CSV quote',
|
'apiScenario.csvQuote': 'CSV quote',
|
||||||
'apiScenario.csvNameNotNull': 'CSV name cannot be empty',
|
'apiScenario.csvNameNotNull': 'CSV name cannot be empty',
|
||||||
'apiScenario.csvFileNotNull': 'CSV file cannot be empty',
|
'apiScenario.csvFileNotNull': 'CSV file cannot be empty',
|
||||||
|
'apiScenario.export.type.simple': 'Simple',
|
||||||
|
'apiScenario.export.type.all': 'All data',
|
||||||
|
'apiScenario.export.simple.tooltip': 'Process referenced or copied request steps as custom requests',
|
||||||
};
|
};
|
||||||
|
|
|
@ -280,4 +280,7 @@ export default {
|
||||||
'apiScenario.csvQuote': 'CSV 引用',
|
'apiScenario.csvQuote': 'CSV 引用',
|
||||||
'apiScenario.csvNameNotNull': 'CSV 名称不能为空',
|
'apiScenario.csvNameNotNull': 'CSV 名称不能为空',
|
||||||
'apiScenario.csvFileNotNull': 'CSV 文件不能为空',
|
'apiScenario.csvFileNotNull': 'CSV 文件不能为空',
|
||||||
|
'apiScenario.export.type.simple': '普通导出',
|
||||||
|
'apiScenario.export.type.all': '保留引用关系',
|
||||||
|
'apiScenario.export.simple.tooltip': '将引用或复制的请求步骤处理为自定义请求',
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue