style: 接口调试/用例/定义/场景展示布局优化

This commit is contained in:
teukkk 2024-05-06 20:11:39 +08:00 committed by Craftsman
parent f4fb8a7a04
commit ecae5a4d99
21 changed files with 626 additions and 896 deletions

View File

@ -364,9 +364,10 @@
<style lang="less" scoped> <style lang="less" scoped>
.ms-code-editor { .ms-code-editor {
@apply z-10; @apply z-10;
// TODO:
width: v-bind(width); width: v-bind(width);
height: v-bind(height); height: v-bind(height);
min-height: 200px;
// &.MS-text[data-mode-id='plaintext'] { // &.MS-text[data-mode-id='plaintext'] {
// :deep(.mtk1) { // :deep(.mtk1) {
// color: rgb(var(--primary-5)); // color: rgb(var(--primary-5));

View File

@ -342,7 +342,7 @@
.handle { .handle {
@apply absolute left-0 top-0 flex h-full items-center; @apply absolute left-0 top-0 flex h-full items-center;
z-index: 10; z-index: 200;
width: 8px; width: 8px;
background-color: var(--color-neutral-3); background-color: var(--color-neutral-3);
cursor: col-resize; cursor: col-resize;

View File

@ -231,7 +231,6 @@
:disabled-param-value="props.disabled" :disabled-param-value="props.disabled"
:scroll="{ x: '100%' }" :scroll="{ x: '100%' }"
:columns="scriptColumns" :columns="scriptColumns"
:height-used="heightUsed"
:selectable="false" :selectable="false"
@change="() => emit('change')" @change="() => emit('change')"
/> />
@ -375,7 +374,6 @@
:selectable="false" :selectable="false"
:scroll="{ x: '700px' }" :scroll="{ x: '700px' }"
:response="props.response" :response="props.response"
:height-used="props.heightUsed"
@change="handleExtractParamTableChange" @change="handleExtractParamTableChange"
@more-action-select="(e,r)=> handleExtractParamMoreActionSelect(e,r as ExpressionConfig)" @more-action-select="(e,r)=> handleExtractParamMoreActionSelect(e,r as ExpressionConfig)"
> >
@ -529,7 +527,6 @@
defineProps<{ defineProps<{
disabled?: boolean; disabled?: boolean;
response?: string; // response?: string; //
heightUsed?: number;
isBuildIn?: boolean; // isBuildIn?: boolean; //
showAssociatedScene?: boolean; // showAssociatedScene?: boolean; //
requestRadioTextProps?: Record<string, any>; // requestRadioTextProps?: Record<string, any>; //

View File

@ -39,7 +39,6 @@
:disabled="props.disabled" :disabled="props.disabled"
:total-list="list" :total-list="list"
:response="props.response" :response="props.response"
:height-used="props.heightUsed"
:show-associated-scene="props.showAssociatedScene" :show-associated-scene="props.showAssociatedScene"
:show-pre-post-request="props.showPrePostRequest" :show-pre-post-request="props.showPrePostRequest"
:request-radio-text-props="props.requestRadioTextProps" :request-radio-text-props="props.requestRadioTextProps"
@ -70,7 +69,6 @@
conditionTypes: Array<ConditionType>; conditionTypes: Array<ConditionType>;
addText: string; addText: string;
requestRadioTextProps?: Record<string, any>; requestRadioTextProps?: Record<string, any>;
heightUsed?: number;
response?: string; // response?: string; //
showAssociatedScene?: boolean; showAssociatedScene?: boolean;
showPrePostRequest?: boolean; // showPrePostRequest?: boolean; //

View File

@ -25,7 +25,6 @@
:draggable="!props.disabledExceptParam" :draggable="!props.disabledExceptParam"
:scroll="{ minWidth: 1160 }" :scroll="{ minWidth: 1160 }"
:columns="columns" :columns="columns"
:height-used="heightUsed"
:show-setting="true" :show-setting="true"
:table-key="TableKeyEnum.API_TEST_DEBUG_FORM_DATA" :table-key="TableKeyEnum.API_TEST_DEBUG_FORM_DATA"
:default-param-item="defaultBodyParamsItem" :default-param-item="defaultBodyParamsItem"
@ -44,7 +43,6 @@
:draggable="!props.disabledExceptParam" :draggable="!props.disabledExceptParam"
:scroll="{ minWidth: 1160 }" :scroll="{ minWidth: 1160 }"
:columns="columns" :columns="columns"
:height-used="heightUsed"
:show-setting="true" :show-setting="true"
:table-key="TableKeyEnum.API_TEST_DEBUG_FORM_URL_ENCODE" :table-key="TableKeyEnum.API_TEST_DEBUG_FORM_URL_ENCODE"
:default-param-item="defaultBodyParamsItem" :default-param-item="defaultBodyParamsItem"
@ -135,11 +133,8 @@
const props = defineProps<{ const props = defineProps<{
params: ExecuteBody; params: ExecuteBody;
layout: 'horizontal' | 'vertical';
disabledParamValue?: boolean; // disabledParamValue?: boolean; //
disabledExceptParam?: boolean; // disabledExceptParam?: boolean; //
secondBoxHeight: number;
isDrawer?: boolean;
uploadTempFileApi?: (file: File) => Promise<any>; // uploadTempFileApi?: (file: File) => Promise<any>; //
fileSaveAsSourceId?: string | number; // id fileSaveAsSourceId?: string | number; // id
fileSaveAsApi?: (params: TransferFileParams) => Promise<string>; // fileSaveAsApi?: (params: TransferFileParams) => Promise<string>; //
@ -260,31 +255,6 @@
]; ];
}); });
const heightUsed = ref<number | undefined>(undefined);
watch(
() => props.layout,
(val) => {
const otherHeight = props.isDrawer ? 328 : 372;
heightUsed.value = val === 'horizontal' ? otherHeight : otherHeight + props.secondBoxHeight;
},
{
immediate: true,
}
);
watch(
() => props.secondBoxHeight,
(val) => {
if (props.layout === 'vertical') {
heightUsed.value = (props.isDrawer ? 328 : 372) + val;
}
},
{
immediate: true,
}
);
const showParamTable = computed(() => { const showParamTable = computed(() => {
// FORM_DATAX_WWW_FORM_URLENCODED // FORM_DATAX_WWW_FORM_URLENCODED
return [RequestBodyFormat.FORM_DATA, RequestBodyFormat.WWW_FORM].includes(innerParams.value.bodyType); return [RequestBodyFormat.FORM_DATA, RequestBodyFormat.WWW_FORM].includes(innerParams.value.bodyType);

View File

@ -7,7 +7,6 @@
:disabled-param-value="props.disabledParamValue" :disabled-param-value="props.disabledParamValue"
:disabled-except-param="props.disabledExceptParam" :disabled-except-param="props.disabledExceptParam"
:columns="columns" :columns="columns"
:height-used="heightUsed"
:scroll="scroll" :scroll="scroll"
:default-param-item="defaultHeaderParamsItem" :default-param-item="defaultHeaderParamsItem"
:draggable="!props.disabledExceptParam" :draggable="!props.disabledExceptParam"
@ -41,11 +40,9 @@
const props = defineProps<{ const props = defineProps<{
params: EnableKeyValueParam[]; params: EnableKeyValueParam[];
layout: 'horizontal' | 'vertical'; layout: 'horizontal' | 'vertical';
secondBoxHeight: number;
disabledParamValue?: boolean; // disabledParamValue?: boolean; //
disabledExceptParam?: boolean; // disabledExceptParam?: boolean; //
typeTitle?: string; typeTitle?: string;
isDrawer?: boolean;
}>(); }>();
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'update:selectedKeys', value: string[]): void; (e: 'update:selectedKeys', value: string[]): void;
@ -88,12 +85,6 @@
]); ]);
const batchAddKeyValVisible = ref(false); const batchAddKeyValVisible = ref(false);
const heightUsed = computed(() => {
if (props.layout === 'horizontal') {
return props.isDrawer ? 328 : 372;
}
return (props.isDrawer ? 328 : 372) + props.secondBoxHeight;
});
const scroll = computed(() => (props.layout === 'horizontal' ? { x: '700px' } : { x: '100%' })); const scroll = computed(() => (props.layout === 'horizontal' ? { x: '700px' } : { x: '100%' }));
/** /**

View File

@ -187,33 +187,16 @@
<div v-if="isUrlError" class="url-input-tip"> <div v-if="isUrlError" class="url-input-tip">
<span>{{ t('apiTestDebug.apiUrlRequired') }}</span> <span>{{ t('apiTestDebug.apiUrlRequired') }}</span>
</div> </div>
<div class="px-[16px]"> <div :class="`${!props.isCase ? 'request-tab-and-response' : ''} mt-[8px] flex-1`">
<MsTab <MsTab
v-model:active-key="requestVModel.activeTab" v-model:active-key="requestVModel.activeTab"
:content-tab-list="contentTabList" :content-tab-list="contentTabList"
:get-text-func="getTabBadge" :get-text-func="getTabBadge"
class="no-content relative mt-[8px] border-b" class="sticky-content no-content relative top-0 border-b px-[16px]"
/> />
</div> <div :class="`request-content-and-response ${activeLayout}`">
<div ref="splitContainerRef" class="request-and-response h-[calc(100%-92px)]"> <a-spin class="request" :loading="requestVModel.executeLoading || loading">
<MsSplitBox <div class="request-tab-pane flex flex-col p-[16px]">
ref="verticalSplitBoxRef"
v-model:size="splitBoxSize"
:max="!showResponse ? 1 : 0.98"
min="10px"
:direction="activeLayout"
second-container-class="!overflow-y-hidden"
:class="!showResponse ? 'hidden-second' : 'show-second'"
@expand-change="handleVerticalExpandChange"
>
<template #first>
<a-spin class="block h-full w-full" :loading="requestVModel.executeLoading || loading">
<div
:class="`flex h-full min-w-[800px] flex-col p-[16px] ${
activeLayout === 'horizontal' ? ' pr-[16px]' : ''
}`"
>
<div class="tab-pane-container">
<apiBaseForm <apiBaseForm
v-if="!props.isCase && props.isDefinition" v-if="!props.isCase && props.isDefinition"
v-show="requestVModel.activeTab === RequestComposition.BASE_INFO" v-show="requestVModel.activeTab === RequestComposition.BASE_INFO"
@ -243,14 +226,11 @@
v-if="requestVModel.activeTab === RequestComposition.HEADER" v-if="requestVModel.activeTab === RequestComposition.HEADER"
v-model:params="requestVModel.headers" v-model:params="requestVModel.headers"
:layout="activeLayout" :layout="activeLayout"
:second-box-height="secondBoxHeight"
@change="handleActiveDebugChange" @change="handleActiveDebugChange"
/> />
<httpBody <httpBody
v-else-if="requestVModel.activeTab === RequestComposition.BODY" v-else-if="requestVModel.activeTab === RequestComposition.BODY"
v-model:params="requestVModel.body" v-model:params="requestVModel.body"
:layout="activeLayout"
:second-box-height="secondBoxHeight"
:upload-temp-file-api="props.uploadTempFileApi" :upload-temp-file-api="props.uploadTempFileApi"
:file-save-as-source-id="props.fileSaveAsSourceId" :file-save-as-source-id="props.fileSaveAsSourceId"
:file-save-as-api="props.fileSaveAsApi" :file-save-as-api="props.fileSaveAsApi"
@ -260,15 +240,11 @@
<httpQuery <httpQuery
v-else-if="requestVModel.activeTab === RequestComposition.QUERY" v-else-if="requestVModel.activeTab === RequestComposition.QUERY"
v-model:params="requestVModel.query" v-model:params="requestVModel.query"
:layout="activeLayout"
:second-box-height="secondBoxHeight"
@change="handleActiveDebugChange" @change="handleActiveDebugChange"
/> />
<httpRest <httpRest
v-else-if="requestVModel.activeTab === RequestComposition.REST" v-else-if="requestVModel.activeTab === RequestComposition.REST"
v-model:params="requestVModel.rest" v-model:params="requestVModel.rest"
:layout="activeLayout"
:second-box-height="secondBoxHeight"
@change="handleActiveDebugChange" @change="handleActiveDebugChange"
/> />
<precondition <precondition
@ -281,8 +257,6 @@
v-else-if="requestVModel.activeTab === RequestComposition.POST_CONDITION" v-else-if="requestVModel.activeTab === RequestComposition.POST_CONDITION"
v-model:config="requestVModel.children[0].postProcessorConfig" v-model:config="requestVModel.children[0].postProcessorConfig"
:response="requestVModel.response?.requestResults[0]?.responseResult.body" :response="requestVModel.response?.requestResults[0]?.responseResult.body"
:layout="activeLayout"
:second-box-height="secondBoxHeight"
:is-definition="props.isDefinition" :is-definition="props.isDefinition"
@change="handleActiveDebugChange" @change="handleActiveDebugChange"
/> />
@ -305,16 +279,14 @@
@change="handleActiveDebugChange" @change="handleActiveDebugChange"
/> />
</div> </div>
</div>
</a-spin> </a-spin>
</template>
<template #second>
<response <response
v-show="showResponse" v-show="showResponse"
ref="responseRef" ref="responseRef"
v-model:active-layout="activeLayout" v-model:active-layout="activeLayout"
v-model:active-tab="requestVModel.responseActiveTab" v-model:active-tab="requestVModel.responseActiveTab"
v-model:response-definition="requestVModel.responseDefinition" v-model:response-definition="requestVModel.responseDefinition"
class="response"
:show-response-result-button="requestVModel.mode === 'debug'" :show-response-result-button="requestVModel.mode === 'debug'"
:is-http-protocol="isHttpProtocol" :is-http-protocol="isHttpProtocol"
:is-priority-local-exec="isPriorityLocalExec" :is-priority-local-exec="isPriorityLocalExec"
@ -327,13 +299,10 @@
:upload-temp-file-api="props.uploadTempFileApi" :upload-temp-file-api="props.uploadTempFileApi"
:loading="requestVModel.executeLoading || loading" :loading="requestVModel.executeLoading || loading"
:is-definition="props.isDefinition" :is-definition="props.isDefinition"
@change-expand="changeVerticalExpand"
@change-layout="handleActiveLayoutChange"
@change="handleActiveDebugChange" @change="handleActiveDebugChange"
@execute="(executeType) => (props.isCase ? emit('execute', executeType) : execute(executeType))" @execute="(executeType) => (props.isCase ? emit('execute', executeType) : execute(executeType))"
/> />
</template> </div>
</MsSplitBox>
</div> </div>
</div> </div>
<a-modal <a-modal
@ -461,7 +430,6 @@
import { TabItem } from '@/components/pure/ms-editable-tab/types'; import { TabItem } from '@/components/pure/ms-editable-tab/types';
import MsFormCreate from '@/components/pure/ms-form-create/formCreate.vue'; import MsFormCreate from '@/components/pure/ms-form-create/formCreate.vue';
import MsIcon from '@/components/pure/ms-icon-font/index.vue'; import MsIcon from '@/components/pure/ms-icon-font/index.vue';
import MsSplitBox from '@/components/pure/ms-split-box/index.vue';
import MsTab from '@/components/pure/ms-tab/index.vue'; import MsTab from '@/components/pure/ms-tab/index.vue';
import MsTagsInput from '@/components/pure/ms-tags-input/index.vue'; import MsTagsInput from '@/components/pure/ms-tags-input/index.vue';
import assertion from '@/components/business/ms-assertion/index.vue'; import assertion from '@/components/business/ms-assertion/index.vue';
@ -913,58 +881,12 @@
requestVModel.value.response?.requestResults[0]?.responseResult.responseCode || requestVModel.value.response?.requestResults[0]?.responseResult.responseCode ||
props.isCase props.isCase
); );
const splitBoxSize = ref<string | number>(!showResponse.value ? 1 : 0.6);
const activeLayout = ref<'horizontal' | 'vertical'>('vertical'); const activeLayout = ref<'horizontal' | 'vertical'>('vertical');
const splitContainerRef = ref<HTMLElement>(); const responseRef = ref<InstanceType<typeof response>>();
const secondBoxHeight = ref(0); const isVerticalExpanded = computed(() => activeLayout.value === 'vertical');
watch(
() => showResponse.value,
(val) => {
if (val) {
splitBoxSize.value = 0.6;
} else {
splitBoxSize.value = 1;
}
}
);
watch(
() => splitBoxSize.value,
debounce((val) => {
// 300ms
if (splitContainerRef.value) {
if (typeof val === 'string' && val.includes('px')) {
val = Number(val.split('px')[0]);
secondBoxHeight.value = splitContainerRef.value.clientHeight - val;
} else {
secondBoxHeight.value = splitContainerRef.value.clientHeight * (1 - val);
}
}
}, 300),
{
immediate: true,
}
);
const verticalSplitBoxRef = ref<InstanceType<typeof MsSplitBox>>();
const isVerticalExpanded = ref(true);
function handleVerticalExpandChange(val: boolean) {
isVerticalExpanded.value = val;
}
function changeVerticalExpand(val: boolean) { function changeVerticalExpand(val: boolean) {
isVerticalExpanded.value = val; responseRef.value?.changeExpand(val);
if (val) {
verticalSplitBoxRef.value?.expand(0.6);
} else {
verticalSplitBoxRef.value?.collapse(
splitContainerRef.value
? `${splitContainerRef.value.clientHeight - (props.hideResponseLayoutSwitch ? 37 : 42)}px`
: 0
);
} }
}
watch( watch(
() => showResponse.value, () => showResponse.value,
(val) => { (val) => {
@ -976,12 +898,6 @@
} }
); );
function handleActiveLayoutChange() {
isVerticalExpanded.value = true;
splitBoxSize.value = 0.6;
verticalSplitBoxRef.value?.expand(0.6);
}
const saveModalVisible = ref(false); const saveModalVisible = ref(false);
const saveModalForm = ref({ const saveModalForm = ref({
name: '', name: '',
@ -1232,8 +1148,6 @@
requestVModel.value.executeLoading = false; requestVModel.value.executeLoading = false;
} }
const responseRef = ref<InstanceType<typeof response>>();
watch( watch(
() => requestVModel.value.id, () => requestVModel.value.id,
async () => { async () => {
@ -1696,10 +1610,6 @@
.btn-base-primary-disabled(); .btn-base-primary-disabled();
} }
} }
.tab-pane-container {
@apply flex-1 overflow-y-auto;
.ms-scroll-bar();
}
:deep(.no-content) { :deep(.no-content) {
.arco-tabs-content { .arco-tabs-content {
display: none; display: none;
@ -1711,16 +1621,6 @@
:deep(.arco-tabs-tab) { :deep(.arco-tabs-tab) {
@apply leading-none; @apply leading-none;
} }
.hidden-second {
:deep(.arco-split-trigger) {
@apply hidden;
}
}
.show-second {
:deep(.arco-split-trigger) {
@apply block;
}
}
.url-input-tip { .url-input-tip {
margin-top: 2px 0 250px; margin-top: 2px 0 250px;
font-size: 12px; font-size: 12px;
@ -1728,4 +1628,45 @@
line-height: 16px; line-height: 16px;
@apply flex flex-col flex-nowrap items-center justify-start; @apply flex flex-col flex-nowrap items-center justify-start;
} }
.request-tab-and-response {
overflow-x: hidden;
overflow-y: auto;
.ms-scroll-bar();
}
.sticky-content {
@apply sticky bg-white;
z-index: 101; // .arco-scrollbar-track100
}
.request-content-and-response {
display: flex;
&.vertical {
flex-direction: column;
.response :deep(.response-head) {
@apply sticky bg-white;
top: 48px; // tab(border-bottom)
z-index: 11;
}
.request-tab-pane {
min-height: 400px;
}
}
&.horizontal {
flex-direction: row;
min-height: calc(100% - 49px); // 49px:tab
.request {
flex: 1;
overflow-x: auto;
.ms-scroll-bar();
.request-tab-pane {
min-width: 800px;
}
}
.response {
width: 500px;
border-left: 1px solid var(--color-text-n8);
}
}
}
</style> </style>

View File

@ -6,7 +6,6 @@
add-text="apiTestDebug.postCondition" add-text="apiTestDebug.postCondition"
:response="props.response" :response="props.response"
:disabled="props.disabled" :disabled="props.disabled"
:height-used="heightUsed"
:sql-code-editor-height="props.sqlCodeEditorHeight" :sql-code-editor-height="props.sqlCodeEditorHeight"
@change="emit('change')" @change="emit('change')"
> >
@ -43,8 +42,6 @@
const props = defineProps<{ const props = defineProps<{
config: ExecuteConditionConfig; config: ExecuteConditionConfig;
secondBoxHeight?: number;
layout: 'horizontal' | 'vertical';
response?: string; // response?: string; //
isDefinition?: boolean; // isDefinition?: boolean; //
isScenario?: boolean; // isScenario?: boolean; //
@ -59,12 +56,6 @@
const { t } = useI18n(); const { t } = useI18n();
const innerConfig = useVModel(props, 'config', emit); const innerConfig = useVModel(props, 'config', emit);
const heightUsed = computed(() => {
if (props.layout === 'horizontal') {
return 328;
}
return 328 + (props.secondBoxHeight || 0);
});
const conditionTypes = computed(() => { const conditionTypes = computed(() => {
if (props.isDefinition) { if (props.isDefinition) {

View File

@ -15,7 +15,6 @@
:disabled-param-value="props.disabledParamValue" :disabled-param-value="props.disabledParamValue"
:disabled-except-param="props.disabledExceptParam" :disabled-except-param="props.disabledExceptParam"
:columns="columns" :columns="columns"
:height-used="heightUsed"
:scroll="{ minWidth: 1160 }" :scroll="{ minWidth: 1160 }"
:show-setting="true" :show-setting="true"
:table-key="TableKeyEnum.API_TEST_DEBUG_QUERY" :table-key="TableKeyEnum.API_TEST_DEBUG_QUERY"
@ -51,11 +50,8 @@
const props = defineProps<{ const props = defineProps<{
params: ExecuteRequestCommonParam[]; params: ExecuteRequestCommonParam[];
layout: 'horizontal' | 'vertical';
disabledParamValue?: boolean; // disabledParamValue?: boolean; //
disabledExceptParam?: boolean; // disabledExceptParam?: boolean; //
secondBoxHeight: number;
isDrawer?: boolean;
}>(); }>();
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'update:params', value: any[]): void; (e: 'update:params', value: any[]): void;
@ -124,30 +120,6 @@
]); ]);
const batchAddKeyValVisible = ref(false); const batchAddKeyValVisible = ref(false);
const heightUsed = ref<number | undefined>(undefined);
watch(
() => props.layout,
(val) => {
const otherHeight = props.isDrawer ? 328 : 372;
heightUsed.value = val === 'horizontal' ? otherHeight : otherHeight + props.secondBoxHeight;
},
{
immediate: true,
}
);
watch(
() => props.secondBoxHeight,
(val) => {
if (props.layout === 'vertical') {
heightUsed.value = (props.isDrawer ? 328 : 372) + val;
}
},
{
immediate: true,
}
);
/** /**
* 批量参数代码转换为参数表格数据 * 批量参数代码转换为参数表格数据

View File

@ -117,7 +117,6 @@
activeResponse.body.bodyType activeResponse.body.bodyType
) )
" "
class="h-[calc(100%-35px)]"
> >
<!-- <MsJsonSchema <!-- <MsJsonSchema
v-if="activeResponse.body.jsonBody.enableJsonSchema" v-if="activeResponse.body.jsonBody.enableJsonSchema"
@ -129,7 +128,6 @@
v-model:model-value="currentBodyCode" v-model:model-value="currentBodyCode"
:language="currentCodeLanguage" :language="currentCodeLanguage"
theme="vs" theme="vs"
height="100%"
:show-full-screen="false" :show-full-screen="false"
:show-theme-change="false" :show-theme-change="false"
:show-language-change="false" :show-language-change="false"
@ -477,11 +475,7 @@
<style lang="less" scoped> <style lang="less" scoped>
.response-container { .response-container {
@apply overflow-y-auto;
.ms-scroll-bar();
margin-top: 8px; margin-top: 8px;
height: calc(100% - 88px);
} }
:deep(.arco-table-th) { :deep(.arco-table-th) {
background-color: var(--color-text-n9); background-color: var(--color-text-n9);

View File

@ -1,25 +1,25 @@
<template> <template>
<div class="response flex h-full min-w-[300px] flex-col"> <div class="response flex min-w-[300px] flex-col">
<div :class="['response-head', props.isExpanded ? '' : 'border-t']"> <div :class="['response-head', activeLayout === 'vertical' ? 'border-t' : '']">
<slot name="titleLeft"> <slot name="titleLeft">
<div class="flex items-center justify-between"> <div class="flex items-center justify-between">
<template v-if="activeLayout === 'vertical'"> <template v-if="activeLayout === 'vertical'">
<MsButton <MsButton
v-if="props.isExpanded" v-show="innerIsExpanded"
type="icon" type="icon"
class="!mr-0 !rounded-full bg-[rgb(var(--primary-1))]" class="!mr-0 !rounded-full bg-[rgb(var(--primary-1))]"
size="small" size="small"
@click="emit('changeExpand', false)" @click="changeExpand(false)"
> >
<icon-down :size="8" /> <icon-down :size="8" />
</MsButton> </MsButton>
<MsButton <MsButton
v-else v-show="!innerIsExpanded"
type="icon" type="icon"
status="secondary" status="secondary"
class="!mr-0 !rounded-full bg-[rgb(var(--primary-1))]" class="!mr-0 !rounded-full bg-[rgb(var(--primary-1))]"
size="small" size="small"
@click="emit('changeExpand', true)" @click="changeExpand(true)"
> >
<icon-right :size="8" /> <icon-right :size="8" />
</MsButton> </MsButton>
@ -58,8 +58,9 @@
<responseCodeTimeSize :request-result="props.requestResult" /> <responseCodeTimeSize :request-result="props.requestResult" />
</div> </div>
<a-spin <a-spin
v-show="innerIsExpanded"
:loading="props.loading" :loading="props.loading"
:class="[isResponseModel ? 'h-[381px] w-full' : 'h-[calc(100%-35px)] w-full px-[16px] pb-[16px]']" :class="[isResponseModel ? 'h-[381px] w-full' : 'w-full px-[16px] pb-[16px]']"
> >
<edit <edit
v-if="props.isEdit && activeResponseType === 'content' && responseDefinition" v-if="props.isEdit && activeResponseType === 'content' && responseDefinition"
@ -119,7 +120,6 @@
} }
); );
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'changeExpand', value: boolean): void;
(e: 'changeLayout', value: Direction): void; (e: 'changeLayout', value: Direction): void;
(e: 'change'): void; (e: 'change'): void;
(e: 'execute', executeType: 'localExec' | 'serverExec'): void; (e: 'execute', executeType: 'localExec' | 'serverExec'): void;
@ -136,6 +136,23 @@
const responseDefinition = defineModel<ResponseItem[]>('responseDefinition', { const responseDefinition = defineModel<ResponseItem[]>('responseDefinition', {
default: [], default: [],
}); });
const innerIsExpanded = defineModel<boolean>('isExpanded', {
default: true,
});
function changeExpand(isExpanded: boolean) {
innerIsExpanded.value = isExpanded;
}
watch(
() => activeLayout.value,
(val) => {
if (val === 'horizontal') {
changeExpand(true);
}
}
);
watchEffect(() => { watchEffect(() => {
// null // null
let hasInvalid = false; let hasInvalid = false;
@ -210,6 +227,7 @@
defineExpose({ defineExpose({
setActiveResponse, setActiveResponse,
changeExpand,
}); });
</script> </script>

View File

@ -135,9 +135,7 @@
<style lang="less" scoped> <style lang="less" scoped>
.response-container { .response-container {
overflow: hidden;
margin-top: 8px; margin-top: 8px;
height: calc(100% - 48px);
} }
:deep(.arco-table-th) { :deep(.arco-table-th) {
background-color: var(--color-text-n9); background-color: var(--color-text-n9);

View File

@ -16,7 +16,6 @@
:draggable="!props.disabledExceptParam" :draggable="!props.disabledExceptParam"
:disabled-param-value="props.disabledParamValue" :disabled-param-value="props.disabledParamValue"
:disabled-except-param="props.disabledExceptParam" :disabled-except-param="props.disabledExceptParam"
:height-used="heightUsed"
:scroll="{ minWidth: 1160 }" :scroll="{ minWidth: 1160 }"
:show-setting="true" :show-setting="true"
:table-key="TableKeyEnum.API_TEST_DEBUG_REST" :table-key="TableKeyEnum.API_TEST_DEBUG_REST"
@ -51,11 +50,8 @@
const props = defineProps<{ const props = defineProps<{
params: ExecuteRequestCommonParam[]; params: ExecuteRequestCommonParam[];
layout: 'horizontal' | 'vertical';
secondBoxHeight: number;
disabledParamValue?: boolean; // disabledParamValue?: boolean; //
disabledExceptParam?: boolean; // disabledExceptParam?: boolean; //
isDrawer?: boolean;
}>(); }>();
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'update:params', value: any[]): void; (e: 'update:params', value: any[]): void;
@ -125,30 +121,6 @@
]); ]);
const batchAddKeyValVisible = ref(false); const batchAddKeyValVisible = ref(false);
const heightUsed = ref<number | undefined>(undefined);
watch(
() => props.layout,
(val) => {
const otherHeight = props.isDrawer ? 328 : 372;
heightUsed.value = val === 'horizontal' ? otherHeight : otherHeight + props.secondBoxHeight;
},
{
immediate: true,
}
);
watch(
() => props.secondBoxHeight,
(val) => {
if (props.layout === 'vertical') {
heightUsed.value = (props.isDrawer ? 328 : 372) + val;
}
},
{
immediate: true,
}
);
/** /**
* 批量参数代码转换为参数表格数据 * 批量参数代码转换为参数表格数据

View File

@ -14,19 +14,17 @@
@cancel="handleSaveCaseCancel" @cancel="handleSaveCaseCancel"
> >
<div class="flex h-full flex-col overflow-hidden"> <div class="flex h-full flex-col overflow-hidden">
<div class="px-[16px] pt-[16px]">
<MsDetailCard <MsDetailCard
:title="`【${apiDetailInfo.num}】${apiDetailInfo.name}`" :title="`【${apiDetailInfo.num}】${apiDetailInfo.name}`"
:description="description" :description="description"
class="!flex-row justify-between" class="m-[16px] !flex-row justify-between"
> >
<template #type="{ value }"> <template #type="{ value }">
<apiMethodName :method="value as RequestMethods" tag-size="small" is-tag /> <apiMethodName :method="value as RequestMethods" tag-size="small" is-tag />
</template> </template>
</MsDetailCard> </MsDetailCard>
<a-form ref="formRef" class="mt-[16px]" :model="detailForm" layout="vertical"> <a-form ref="formNameRef" class="flex-row items-start gap-[8px] px-[16px]" :model="detailForm" layout="vertical">
<a-form-item field="name" label="" :rules="[{ required: true, message: t('case.caseNameRequired') }]"> <a-form-item field="name" label="" :rules="[{ required: true, message: t('case.caseNameRequired') }]">
<div class="flex w-full items-center gap-[8px]">
<a-input <a-input
v-model:model-value="detailForm.name" v-model:model-value="detailForm.name"
:placeholder="t('case.caseNamePlaceholder')" :placeholder="t('case.caseNamePlaceholder')"
@ -34,6 +32,7 @@
:max-length="255" :max-length="255"
show-word-limit show-word-limit
/> />
</a-form-item>
<MsEnvironmentSelect ref="environmentSelectRef" :env="environmentId" /> <MsEnvironmentSelect ref="environmentSelectRef" :env="environmentId" />
<executeButton <executeButton
ref="executeRef" ref="executeRef"
@ -42,9 +41,9 @@
@stop-debug="stopDebug" @stop-debug="stopDebug"
@execute="handleExecute" @execute="handleExecute"
/> />
</div> </a-form>
</a-form-item> <div class="request-tab-and-response flex-1">
<div class="flex gap-[16px]"> <a-form ref="formRef" class="flex-row gap-[16px] px-[16px]" :model="detailForm" layout="vertical">
<a-form-item field="priority" :label="t('case.caseLevel')"> <a-form-item field="priority" :label="t('case.caseLevel')">
<a-select v-model:model-value="detailForm.priority" :placeholder="t('common.pleaseSelect')"> <a-select v-model:model-value="detailForm.priority" :placeholder="t('common.pleaseSelect')">
<template #label> <template #label>
@ -68,11 +67,8 @@
<a-form-item field="tags" :label="t('common.tag')"> <a-form-item field="tags" :label="t('common.tag')">
<MsTagsInput v-model:model-value="detailForm.tags" :max-tag-count="1" /> <MsTagsInput v-model:model-value="detailForm.tags" :max-tag-count="1" />
</a-form-item> </a-form-item>
</div>
</a-form> </a-form>
</div>
<div class="px-[16px] font-medium">{{ t('apiTestManagement.requestParams') }}</div> <div class="px-[16px] font-medium">{{ t('apiTestManagement.requestParams') }}</div>
<div class="flex-1 overflow-hidden">
<requestComposition <requestComposition
ref="requestCompositionRef" ref="requestCompositionRef"
v-model:request="detailForm" v-model:request="detailForm"
@ -174,6 +170,7 @@
); );
const formRef = ref<FormInstance>(); const formRef = ref<FormInstance>();
const formNameRef = ref<FormInstance>();
const requestCompositionRef = ref<InstanceType<typeof requestComposition>>(); const requestCompositionRef = ref<InstanceType<typeof requestComposition>>();
const defaultCaseParams = inject<RequestParam>('defaultCaseParams'); const defaultCaseParams = inject<RequestParam>('defaultCaseParams');
const defaultDetail = computed<RequestParam>(() => { const defaultDetail = computed<RequestParam>(() => {
@ -239,10 +236,11 @@
isEdit.value = false; isEdit.value = false;
innerVisible.value = false; innerVisible.value = false;
formRef.value?.resetFields(); formRef.value?.resetFields();
formNameRef.value?.resetFields();
} }
function handleDrawerConfirm(isContinue: boolean) { function handleDrawerConfirm(isContinue: boolean) {
formRef.value?.validate(async (errors) => { formNameRef.value?.validate(async (errors) => {
if (!errors) { if (!errors) {
// //
if (requestCompositionRef.value?.getFlattenedMessages()?.length) { if (requestCompositionRef.value?.getFlattenedMessages()?.length) {
@ -393,10 +391,12 @@
max-width: 50%; max-width: 50%;
} }
} }
:deep(.arco-form > .arco-form-item):nth-child(1) .arco-form-item-label-col { :deep(.arco-form):nth-of-type(1) > .arco-form-item .arco-form-item-label-col {
display: none; display: none;
} }
:deep(.request-and-response) { .request-tab-and-response {
height: calc(100% - 56px); overflow-x: hidden;
overflow-y: auto;
.ms-scroll-bar();
} }
</style> </style>

View File

@ -100,8 +100,7 @@
</template> </template>
</a-empty> </a-empty>
<div v-show="!pluginError || isHttpProtocol" class="flex h-full flex-col"> <div v-show="!pluginError || isHttpProtocol" class="flex h-full flex-col">
<div class="px-[18px] pt-[8px]"> <div class="flex flex-wrap items-center justify-between gap-[12px] px-[18px] pt-[8px]">
<div class="flex flex-wrap items-center justify-between gap-[12px]">
<div class="flex flex-1 items-center gap-[16px]"> <div class="flex flex-1 items-center gap-[16px]">
<a-select <a-select
v-if="requestVModel.isNew" v-if="requestVModel.isNew"
@ -184,6 +183,8 @@
</a-button> </a-button>
</div> </div>
</div> </div>
<div class="request-tab-and-response flex-1">
<div class="px-[18px]">
<a-input <a-input
v-if="props.step?.stepType && _stepType.isQuoteApi && isHttpProtocol" v-if="props.step?.stepType && _stepType.isQuoteApi && isHttpProtocol"
v-model:model-value="requestVModel.name" v-model:model-value="requestVModel.name"
@ -191,37 +192,19 @@
:placeholder="t('apiTestManagement.apiNamePlaceholder')" :placeholder="t('apiTestManagement.apiNamePlaceholder')"
:disabled="!isEditableApi" :disabled="!isEditableApi"
allow-clear allow-clear
class="mt-[8px]" class="my-[8px]"
/> />
</div> </div>
<div class="px-[16px]">
<MsTab <MsTab
v-if="requestVModel.activeTab" v-if="requestVModel.activeTab"
v-model:active-key="requestVModel.activeTab" v-model:active-key="requestVModel.activeTab"
:content-tab-list="contentTabList" :content-tab-list="contentTabList"
:get-text-func="getTabBadge" :get-text-func="getTabBadge"
class="no-content relative mt-[8px] border-b" class="sticky-content no-content relative top-0 mx-[16px] border-b"
/> />
</div> <div :class="`request-content-and-response ${activeLayout}`">
<div ref="splitContainerRef" class="h-[calc(100%-97px)]"> <a-spin class="request block h-full w-full" :loading="requestVModel.executeLoading || loading">
<MsSplitBox <div class="request-tab-pane flex flex-col p-[16px]">
ref="verticalSplitBoxRef"
v-model:size="splitBoxSize"
:max="!showResponse ? 1 : 0.98"
min="10px"
:direction="activeLayout"
second-container-class="!overflow-y-hidden"
:class="!showResponse ? 'hidden-second' : 'show-second'"
@expand-change="handleVerticalExpandChange"
>
<template #first>
<a-spin class="block h-full w-full" :loading="requestVModel.executeLoading || loading">
<div
:class="`flex h-full min-w-[800px] flex-col p-[16px] ${
activeLayout === 'horizontal' ? ' pr-[16px]' : ''
}`"
>
<div class="tab-pane-container">
<a-spin <a-spin
v-show="requestVModel.activeTab === RequestComposition.PLUGIN" v-show="requestVModel.activeTab === RequestComposition.PLUGIN"
:loading="pluginLoading" :loading="pluginLoading"
@ -246,42 +229,31 @@
:disabled-param-value="!isEditableApi && !isEditableParamValue" :disabled-param-value="!isEditableApi && !isEditableParamValue"
:disabled-except-param="!isEditableApi" :disabled-except-param="!isEditableApi"
:layout="activeLayout" :layout="activeLayout"
:second-box-height="secondBoxHeight"
is-drawer
@change="handleActiveDebugChange" @change="handleActiveDebugChange"
/> />
<httpBody <httpBody
v-else-if="requestVModel.activeTab === RequestComposition.BODY" v-else-if="requestVModel.activeTab === RequestComposition.BODY"
v-model:params="requestVModel.body" v-model:params="requestVModel.body"
:layout="activeLayout"
:disabled-param-value="!isEditableApi && !isEditableParamValue" :disabled-param-value="!isEditableApi && !isEditableParamValue"
:disabled-except-param="!isEditableApi" :disabled-except-param="!isEditableApi"
:second-box-height="secondBoxHeight"
:upload-temp-file-api="uploadTempFile" :upload-temp-file-api="uploadTempFile"
:file-save-as-source-id="scenarioId" :file-save-as-source-id="scenarioId"
:file-save-as-api="transferFile" :file-save-as-api="transferFile"
:file-module-options-api="getTransferOptions" :file-module-options-api="getTransferOptions"
is-drawer
@change="handleActiveDebugChange" @change="handleActiveDebugChange"
/> />
<httpQuery <httpQuery
v-else-if="requestVModel.activeTab === RequestComposition.QUERY" v-else-if="requestVModel.activeTab === RequestComposition.QUERY"
v-model:params="requestVModel.query" v-model:params="requestVModel.query"
:layout="activeLayout"
:disabled-param-value="!isEditableApi && !isEditableParamValue" :disabled-param-value="!isEditableApi && !isEditableParamValue"
:disabled-except-param="!isEditableApi" :disabled-except-param="!isEditableApi"
:second-box-height="secondBoxHeight"
is-drawer
@change="handleActiveDebugChange" @change="handleActiveDebugChange"
/> />
<httpRest <httpRest
v-else-if="requestVModel.activeTab === RequestComposition.REST" v-else-if="requestVModel.activeTab === RequestComposition.REST"
v-model:params="requestVModel.rest" v-model:params="requestVModel.rest"
:layout="activeLayout"
:disabled-param-value="!isEditableApi && !isEditableParamValue" :disabled-param-value="!isEditableApi && !isEditableParamValue"
:disabled-except-param="!isEditableApi" :disabled-except-param="!isEditableApi"
:second-box-height="secondBoxHeight"
is-drawer
@change="handleActiveDebugChange" @change="handleActiveDebugChange"
/> />
<precondition <precondition
@ -296,9 +268,7 @@
v-else-if="requestVModel.activeTab === RequestComposition.POST_CONDITION" v-else-if="requestVModel.activeTab === RequestComposition.POST_CONDITION"
v-model:config="requestVModel.children[0].postProcessorConfig" v-model:config="requestVModel.children[0].postProcessorConfig"
:response="responseResultBody" :response="responseResultBody"
:layout="activeLayout"
:disabled="!isEditableApi" :disabled="!isEditableApi"
:second-box-height="secondBoxHeight"
:tip-content="t('apiScenario.openGlobalPostConditionTip')" :tip-content="t('apiScenario.openGlobalPostConditionTip')"
is-definition is-definition
@change="handleActiveDebugChange" @change="handleActiveDebugChange"
@ -325,15 +295,15 @@
@change="handleActiveDebugChange" @change="handleActiveDebugChange"
/> />
</div> </div>
</div>
</a-spin> </a-spin>
</template>
<template #second>
<response <response
v-if="visible" v-if="visible"
v-show="showResponse" v-show="showResponse"
ref="responseRef"
v-model:active-layout="activeLayout" v-model:active-layout="activeLayout"
v-model:active-tab="requestVModel.responseActiveTab" v-model:active-tab="requestVModel.responseActiveTab"
class="response"
:is-http-protocol="isHttpProtocol" :is-http-protocol="isHttpProtocol"
:is-priority-local-exec="isPriorityLocalExec" :is-priority-local-exec="isPriorityLocalExec"
:request-url="requestVModel.url" :request-url="requestVModel.url"
@ -344,16 +314,13 @@
is-definition is-definition
hide-layout-switch hide-layout-switch
:loading="requestVModel.executeLoading || loading" :loading="requestVModel.executeLoading || loading"
@change-expand="changeVerticalExpand"
@change-layout="handleActiveLayoutChange"
@execute="execute" @execute="execute"
> >
<template #titleRight> <template #titleRight>
<loopPagination v-model:current-loop="currentLoop" :loop-total="loopTotal" /> <loopPagination v-model:current-loop="currentLoop" :loop-total="loopTotal" />
</template> </template>
</response> </response>
</template> </div>
</MsSplitBox>
</div> </div>
</div> </div>
<!-- <addDependencyDrawer v-model:visible="showAddDependencyDrawer" :mode="addDependencyMode" /> --> <!-- <addDependencyDrawer v-model:visible="showAddDependencyDrawer" :mode="addDependencyMode" /> -->
@ -368,7 +335,6 @@
import MsDrawer from '@/components/pure/ms-drawer/index.vue'; import MsDrawer from '@/components/pure/ms-drawer/index.vue';
import MsFormCreate from '@/components/pure/ms-form-create/formCreate.vue'; import MsFormCreate from '@/components/pure/ms-form-create/formCreate.vue';
import MsIcon from '@/components/pure/ms-icon-font/index.vue'; import MsIcon from '@/components/pure/ms-icon-font/index.vue';
import MsSplitBox from '@/components/pure/ms-split-box/index.vue';
import MsTab from '@/components/pure/ms-tab/index.vue'; import MsTab from '@/components/pure/ms-tab/index.vue';
import assertion from '@/components/business/ms-assertion/index.vue'; import assertion from '@/components/business/ms-assertion/index.vue';
import loopPagination from './loopPagination.vue'; import loopPagination from './loopPagination.vue';
@ -936,47 +902,13 @@
const showResponse = computed( const showResponse = computed(
() => isHttpProtocol.value || requestVModel.value.response?.requestResults[0]?.responseResult.responseCode () => isHttpProtocol.value || requestVModel.value.response?.requestResults[0]?.responseResult.responseCode
); );
const splitBoxSize = ref<string | number>(!showResponse.value ? 1 : 0.6);
const activeLayout = ref<'horizontal' | 'vertical'>('vertical'); const activeLayout = ref<'horizontal' | 'vertical'>('vertical');
const splitContainerRef = ref<HTMLElement>(); const isVerticalExpanded = computed(() => activeLayout.value === 'vertical');
const secondBoxHeight = ref(0); const responseRef = ref<InstanceType<typeof response>>();
watch(
() => splitBoxSize.value,
debounce((val) => {
// 300ms
if (splitContainerRef.value) {
if (typeof val === 'string' && val.includes('px')) {
val = Number(val.split('px')[0]);
secondBoxHeight.value = splitContainerRef.value.clientHeight - val;
} else {
secondBoxHeight.value = splitContainerRef.value.clientHeight * (1 - val);
}
}
}, 300),
{
immediate: true,
}
);
const verticalSplitBoxRef = ref<InstanceType<typeof MsSplitBox>>();
const isVerticalExpanded = ref(true);
function handleVerticalExpandChange(val: boolean) {
isVerticalExpanded.value = val;
}
function changeVerticalExpand(val: boolean) { function changeVerticalExpand(val: boolean) {
isVerticalExpanded.value = val; responseRef.value?.changeExpand(val);
if (val) {
verticalSplitBoxRef.value?.expand(0.6);
} else {
verticalSplitBoxRef.value?.collapse(
splitContainerRef.value ? `${splitContainerRef.value.clientHeight - 42}px` : 0
);
} }
}
watch( watch(
() => showResponse.value, () => showResponse.value,
(val) => { (val) => {
@ -984,19 +916,12 @@
if (val) { if (val) {
changeVerticalExpand(true); changeVerticalExpand(true);
} else { } else {
isVerticalExpanded.value = false; changeVerticalExpand(false);
verticalSplitBoxRef.value?.collapse(1);
} }
}); });
} }
); );
function handleActiveLayoutChange() {
isVerticalExpanded.value = true;
splitBoxSize.value = 0.6;
verticalSplitBoxRef.value?.expand(0.6);
}
/** /**
* 生成请求参数 * 生成请求参数
* @param executeType 执行类型执行时传入 * @param executeType 执行类型执行时传入
@ -1373,10 +1298,6 @@
.btn-base-primary-disabled(); .btn-base-primary-disabled();
} }
} }
.tab-pane-container {
@apply flex-1 overflow-y-auto;
.ms-scroll-bar();
}
:deep(.no-content) { :deep(.no-content) {
.arco-tabs-content { .arco-tabs-content {
display: none; display: none;
@ -1388,4 +1309,29 @@
:deep(.arco-tabs-tab) { :deep(.arco-tabs-tab) {
@apply leading-none; @apply leading-none;
} }
.request-tab-and-response {
overflow-x: hidden;
overflow-y: auto;
.ms-scroll-bar();
}
.sticky-content {
@apply sticky bg-white;
z-index: 101;
}
.request-content-and-response {
display: flex;
&.vertical {
flex-direction: column;
.response :deep(.response-head) {
@apply sticky bg-white;
top: 48px; // tab(border-bottom)
z-index: 11;
}
.request-tab-pane {
min-height: 400px;
}
}
}
</style> </style>

View File

@ -114,34 +114,17 @@
</a-button> </a-button>
</div> </div>
</div> </div>
<div class="px-[16px]"> <div class="request-tab-and-response flex-1">
<MsTab <MsTab
v-model:active-key="requestVModel.activeTab" v-model:active-key="requestVModel.activeTab"
:content-tab-list="contentTabList" :content-tab-list="contentTabList"
:get-text-func="getTabBadge" :get-text-func="getTabBadge"
no-content no-content
class="relative mt-[8px] border-b" class="sticky-content relative top-0 mx-[16px] border-b"
/> />
</div> <div :class="`request-content-and-response ${activeLayout}`">
<div ref="splitContainerRef" class="h-[calc(100%-97px)]"> <a-spin class="request block h-full w-full" :loading="requestVModel.executeLoading || loading">
<MsSplitBox <div class="request-tab-pane flex flex-col p-[16px]">
ref="verticalSplitBoxRef"
v-model:size="splitBoxSize"
:max="!showResponse ? 1 : 0.98"
min="10px"
:direction="activeLayout"
second-container-class="!overflow-y-hidden"
:class="!showResponse ? 'hidden-second' : 'show-second'"
@expand-change="handleVerticalExpandChange"
>
<template #first>
<a-spin class="block h-full w-full" :loading="requestVModel.executeLoading || loading">
<div
:class="`flex h-full min-w-[800px] flex-col p-[16px] ${
activeLayout === 'horizontal' ? ' pr-[16px]' : ''
}`"
>
<div class="tab-pane-container">
<a-spin <a-spin
v-show="requestVModel.activeTab === RequestComposition.PLUGIN" v-show="requestVModel.activeTab === RequestComposition.PLUGIN"
:loading="pluginLoading" :loading="pluginLoading"
@ -166,16 +149,13 @@
:disabled-param-value="!isEditableApi" :disabled-param-value="!isEditableApi"
:disabled-except-param="!isEditableApi" :disabled-except-param="!isEditableApi"
:layout="activeLayout" :layout="activeLayout"
:second-box-height="secondBoxHeight"
@change="handleActiveDebugChange" @change="handleActiveDebugChange"
/> />
<httpBody <httpBody
v-else-if="requestVModel.activeTab === RequestComposition.BODY" v-else-if="requestVModel.activeTab === RequestComposition.BODY"
v-model:params="requestVModel.body" v-model:params="requestVModel.body"
:layout="activeLayout"
:disabled-param-value="!isEditableApi" :disabled-param-value="!isEditableApi"
:disabled-except-param="!isEditableApi" :disabled-except-param="!isEditableApi"
:second-box-height="secondBoxHeight"
:upload-temp-file-api="uploadTempFileCase" :upload-temp-file-api="uploadTempFileCase"
:file-save-as-source-id="scenarioId" :file-save-as-source-id="scenarioId"
:file-save-as-api="transferFileCase" :file-save-as-api="transferFileCase"
@ -185,19 +165,15 @@
<httpQuery <httpQuery
v-else-if="requestVModel.activeTab === RequestComposition.QUERY" v-else-if="requestVModel.activeTab === RequestComposition.QUERY"
v-model:params="requestVModel.query" v-model:params="requestVModel.query"
:layout="activeLayout"
:disabled-param-value="!isEditableApi" :disabled-param-value="!isEditableApi"
:disabled-except-param="!isEditableApi" :disabled-except-param="!isEditableApi"
:second-box-height="secondBoxHeight"
@change="handleActiveDebugChange" @change="handleActiveDebugChange"
/> />
<httpRest <httpRest
v-else-if="requestVModel.activeTab === RequestComposition.REST" v-else-if="requestVModel.activeTab === RequestComposition.REST"
v-model:params="requestVModel.rest" v-model:params="requestVModel.rest"
:layout="activeLayout"
:disabled-param-value="!isEditableApi" :disabled-param-value="!isEditableApi"
:disabled-except-param="!isEditableApi" :disabled-except-param="!isEditableApi"
:second-box-height="secondBoxHeight"
@change="handleActiveDebugChange" @change="handleActiveDebugChange"
/> />
<precondition <precondition
@ -211,9 +187,7 @@
v-else-if="requestVModel.activeTab === RequestComposition.POST_CONDITION" v-else-if="requestVModel.activeTab === RequestComposition.POST_CONDITION"
v-model:config="requestVModel.children[0].postProcessorConfig" v-model:config="requestVModel.children[0].postProcessorConfig"
:response="responseResultBody" :response="responseResultBody"
:layout="activeLayout"
:disabled="!isEditableApi" :disabled="!isEditableApi"
:second-box-height="secondBoxHeight"
is-definition is-definition
@change="handleActiveDebugChange" @change="handleActiveDebugChange"
/> />
@ -240,15 +214,14 @@
@change="handleActiveDebugChange" @change="handleActiveDebugChange"
/> />
</div> </div>
</div>
</a-spin> </a-spin>
</template>
<template #second>
<response <response
v-if="visible" v-if="visible"
v-show="showResponse" v-show="showResponse"
ref="responseRef"
v-model:active-layout="activeLayout" v-model:active-layout="activeLayout"
v-model:active-tab="requestVModel.responseActiveTab" v-model:active-tab="requestVModel.responseActiveTab"
class="response"
:is-http-protocol="isHttpProtocol" :is-http-protocol="isHttpProtocol"
:is-priority-local-exec="isPriorityLocalExec" :is-priority-local-exec="isPriorityLocalExec"
:request-url="requestVModel.url" :request-url="requestVModel.url"
@ -259,16 +232,13 @@
is-definition is-definition
hide-layout-switch hide-layout-switch
:loading="requestVModel.executeLoading || loading" :loading="requestVModel.executeLoading || loading"
@change-expand="changeVerticalExpand"
@change-layout="handleActiveLayoutChange"
@execute="execute" @execute="execute"
> >
<template #titleRight> <template #titleRight>
<loopPagination v-model:current-loop="currentLoop" :loop-total="loopTotal" class="!mb-0" /> <loopPagination v-model:current-loop="currentLoop" :loop-total="loopTotal" class="!mb-0" />
</template> </template>
</response> </response>
</template> </div>
</MsSplitBox>
</div> </div>
</div> </div>
</MsDrawer> </MsDrawer>
@ -282,7 +252,6 @@
import MsButton from '@/components/pure/ms-button/index.vue'; import MsButton from '@/components/pure/ms-button/index.vue';
import MsDrawer from '@/components/pure/ms-drawer/index.vue'; import MsDrawer from '@/components/pure/ms-drawer/index.vue';
import MsFormCreate from '@/components/pure/ms-form-create/formCreate.vue'; import MsFormCreate from '@/components/pure/ms-form-create/formCreate.vue';
import MsSplitBox from '@/components/pure/ms-split-box/index.vue';
import MsTab from '@/components/pure/ms-tab/index.vue'; import MsTab from '@/components/pure/ms-tab/index.vue';
import assertion from '@/components/business/ms-assertion/index.vue'; import assertion from '@/components/business/ms-assertion/index.vue';
import loopPagination from './loopPagination.vue'; import loopPagination from './loopPagination.vue';
@ -772,47 +741,13 @@
const showResponse = computed( const showResponse = computed(
() => isHttpProtocol.value || requestVModel.value.response?.requestResults[0]?.responseResult.responseCode () => isHttpProtocol.value || requestVModel.value.response?.requestResults[0]?.responseResult.responseCode
); );
const splitBoxSize = ref<string | number>(!showResponse.value ? 1 : 0.6);
const activeLayout = ref<'horizontal' | 'vertical'>('vertical'); const activeLayout = ref<'horizontal' | 'vertical'>('vertical');
const splitContainerRef = ref<HTMLElement>(); const isVerticalExpanded = computed(() => activeLayout.value === 'vertical');
const secondBoxHeight = ref(0); const responseRef = ref<InstanceType<typeof response>>();
watch(
() => splitBoxSize.value,
debounce((val) => {
// 300ms
if (splitContainerRef.value) {
if (typeof val === 'string' && val.includes('px')) {
val = Number(val.split('px')[0]);
secondBoxHeight.value = splitContainerRef.value.clientHeight - val;
} else {
secondBoxHeight.value = splitContainerRef.value.clientHeight * (1 - val);
}
}
}, 300),
{
immediate: true,
}
);
const verticalSplitBoxRef = ref<InstanceType<typeof MsSplitBox>>();
const isVerticalExpanded = ref(true);
function handleVerticalExpandChange(val: boolean) {
isVerticalExpanded.value = val;
}
function changeVerticalExpand(val: boolean) { function changeVerticalExpand(val: boolean) {
isVerticalExpanded.value = val; responseRef.value?.changeExpand(val);
if (val) {
verticalSplitBoxRef.value?.expand(0.6);
} else {
verticalSplitBoxRef.value?.collapse(
splitContainerRef.value ? `${splitContainerRef.value.clientHeight - 42}px` : 0
);
} }
}
watch( watch(
() => showResponse.value, () => showResponse.value,
(val) => { (val) => {
@ -820,19 +755,12 @@
if (val) { if (val) {
changeVerticalExpand(true); changeVerticalExpand(true);
} else { } else {
isVerticalExpanded.value = false; changeVerticalExpand(false);
verticalSplitBoxRef.value?.collapse(1);
} }
}); });
} }
); );
function handleActiveLayoutChange() {
isVerticalExpanded.value = true;
splitBoxSize.value = 0.6;
verticalSplitBoxRef.value?.expand(0.6);
}
/** /**
* 生成请求参数 * 生成请求参数
* @param executeType 执行类型执行时传入 * @param executeType 执行类型执行时传入
@ -1132,14 +1060,35 @@
.btn-base-primary-disabled(); .btn-base-primary-disabled();
} }
} }
.tab-pane-container {
@apply flex-1 overflow-y-auto;
.ms-scroll-bar();
}
:deep(.arco-tabs-tab:first-child) { :deep(.arco-tabs-tab:first-child) {
margin-left: 0; margin-left: 0;
} }
:deep(.arco-tabs-tab) { :deep(.arco-tabs-tab) {
@apply leading-none; @apply leading-none;
} }
.request-tab-and-response {
overflow-x: hidden;
overflow-y: auto;
.ms-scroll-bar();
}
.sticky-content {
@apply sticky bg-white;
z-index: 101;
}
.request-content-and-response {
display: flex;
&.vertical {
flex-direction: column;
.response :deep(.response-head) {
@apply sticky bg-white;
top: 48px; // tab(border-bottom)
z-index: 11;
}
.request-tab-pane {
min-height: 400px;
}
}
}
</style> </style>

View File

@ -24,7 +24,6 @@
<postcondition <postcondition
v-model:config="postProcessorConfig" v-model:config="postProcessorConfig"
:is-definition="false" :is-definition="false"
:layout="activeLayout"
sql-code-editor-height="300px" sql-code-editor-height="300px"
:tip-content="t('apiScenario.openGlobalPostConditionTip')" :tip-content="t('apiScenario.openGlobalPostConditionTip')"
is-scenario is-scenario
@ -57,7 +56,6 @@
const { t } = useI18n(); const { t } = useI18n();
const activeLayout = ref<'horizontal' | 'vertical'>('vertical');
const preProcessorConfig = defineModel<ExecuteConditionConfig>('preProcessorConfig', { const preProcessorConfig = defineModel<ExecuteConditionConfig>('preProcessorConfig', {
required: true, required: true,
}); });

View File

@ -4,7 +4,6 @@
:condition-types="[RequestConditionProcessor.SCRIPT, RequestConditionProcessor.SQL]" :condition-types="[RequestConditionProcessor.SCRIPT, RequestConditionProcessor.SQL]"
add-text="apiTestDebug.postCondition" add-text="apiTestDebug.postCondition"
response="" response=""
:height-used="600"
:show-associated-scene="props.showAssociatedScene" :show-associated-scene="props.showAssociatedScene"
:show-pre-post-request="props.showPrePostRequest" :show-pre-post-request="props.showPrePostRequest"
:request-radio-text-props="props.requestRadioTextProps" :request-radio-text-props="props.requestRadioTextProps"

View File

@ -4,7 +4,6 @@
:condition-types="[RequestConditionProcessor.SCRIPT, RequestConditionProcessor.SQL]" :condition-types="[RequestConditionProcessor.SCRIPT, RequestConditionProcessor.SQL]"
add-text="apiTestDebug.precondition" add-text="apiTestDebug.precondition"
response="" response=""
:height-used="600"
:show-associated-scene="props.showAssociatedScene" :show-associated-scene="props.showAssociatedScene"
:show-pre-post-request="props.showPrePostRequest" :show-pre-post-request="props.showPrePostRequest"
:request-radio-text-props="props.requestRadioTextProps" :request-radio-text-props="props.requestRadioTextProps"

View File

@ -175,7 +175,6 @@
:layout="activeLayout" :layout="activeLayout"
:disabled-param-value="false" :disabled-param-value="false"
:disabled-except-param="false" :disabled-except-param="false"
:second-box-height="secondBoxHeight"
:type-title="t('project.environmental.requestHeader')" :type-title="t('project.environmental.requestHeader')"
/> />
<a-form-item class="mt-4" asterisk-position="end" field="path" :label="t('project.environmental.http.authType')"> <a-form-item class="mt-4" asterisk-position="end" field="path" :label="t('project.environmental.http.authType')">
@ -303,7 +302,6 @@
const form = ref<HttpForm>({ ...initForm }); const form = ref<HttpForm>({ ...initForm });
const hostType = ref<string>('http://'); const hostType = ref<string>('http://');
const secondBoxHeight = ref(0);
const activeLayout = ref<'horizontal' | 'vertical'>('vertical'); const activeLayout = ref<'horizontal' | 'vertical'>('vertical');
const httpRef = ref(); const httpRef = ref();

View File

@ -4,7 +4,6 @@
:layout="activeLayout" :layout="activeLayout"
:disabled-param-value="props.disabledParamValue" :disabled-param-value="props.disabledParamValue"
:disabled-except-param="props.disabledExceptParam" :disabled-except-param="props.disabledExceptParam"
:second-box-height="secondBoxHeight"
@change="emit('change')" @change="emit('change')"
/> />
</template> </template>
@ -32,7 +31,6 @@
}>(); }>();
const innerParams = useVModel(props, 'params', emit); const innerParams = useVModel(props, 'params', emit);
const secondBoxHeight = ref(0);
const activeLayout = ref<'horizontal' | 'vertical'>('vertical'); const activeLayout = ref<'horizontal' | 'vertical'>('vertical');
</script> </script>