fix(接口测试): 协议调整

This commit is contained in:
teukkk 2024-06-07 15:03:58 +08:00 committed by 刘瑞斌
parent a6749b8ee7
commit f5ae0cd2a2
25 changed files with 377 additions and 179 deletions

View File

@ -1,7 +1,7 @@
@font-face {
font-family: iconfont; /* Project id 3462279 */
src: url('iconfont.woff2?t=1716970683831') format('woff2'), url('iconfont.woff?t=1716970683831') format('woff'),
url('iconfont.ttf?t=1716970683831') format('truetype'), url('iconfont.svg?t=1716970683831#iconfont') format('svg');
src: url('iconfont.woff2?t=1717669877554') format('woff2'), url('iconfont.woff?t=1717669877554') format('woff'),
url('iconfont.ttf?t=1717669877554') format('truetype'), url('iconfont.svg?t=1717669877554#iconfont') format('svg');
}
.iconfont {
font-size: 16px;
@ -10,6 +10,18 @@
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-icon_title-top-align_outlined1::before {
content: '\e7be';
}
.icon-icon_title-left-align_outlined1::before {
content: '\e7bf';
}
.icon-icon_protocol::before {
content: '\e7bd';
}
.icon-icon_info_outlined1::before {
content: '\e7bc';
}
.icon-icon_github::before {
content: '\e7b9';
}

File diff suppressed because one or more lines are too long

View File

@ -5,6 +5,34 @@
"css_prefix_text": "icon-",
"description": "DE、MS项目icon管理",
"glyphs": [
{
"icon_id": "40628129",
"name": "icon_title-top-align_outlined",
"font_class": "icon_title-top-align_outlined1",
"unicode": "e7be",
"unicode_decimal": 59326
},
{
"icon_id": "40628128",
"name": "icon_title-left-align_outlined",
"font_class": "icon_title-left-align_outlined1",
"unicode": "e7bf",
"unicode_decimal": 59327
},
{
"icon_id": "40547513",
"name": "icon_protocol",
"font_class": "icon_protocol",
"unicode": "e7bd",
"unicode_decimal": 59325
},
{
"icon_id": "40530999",
"name": "icon_info_outlined",
"font_class": "icon_info_outlined1",
"unicode": "e7bc",
"unicode_decimal": 59324
},
{
"icon_id": "40529317",
"name": "icon_github",

View File

@ -14,6 +14,14 @@
/>
<missing-glyph />
<glyph glyph-name="icon_title-top-align_outlined1" unicode="&#59326;" d="M128 682.666667h597.333333a42.666667 42.666667 0 0 0 42.666667-42.666667v-85.333333a42.666667 42.666667 0 0 0-42.666667-42.666667H128a42.666667 42.666667 0 0 0-42.666667 42.666667V640a42.666667 42.666667 0 0 0 42.666667 42.666667z m768-256a42.666667 42.666667 0 0 0 42.666667-42.666667v-256a42.666667 42.666667 0 0 0-42.666667-42.666667H128a42.666667 42.666667 0 0 0-42.666667 42.666667v256a42.666667 42.666667 0 0 0 42.666667 42.666667h768z m-42.666667-85.333334H170.666667v-170.666666h682.666666v170.666666z" horiz-adv-x="1024" />
<glyph glyph-name="icon_title-left-align_outlined1" unicode="&#59327;" d="M981.333333 554.666667a42.666667 42.666667 0 0 0 42.666667-42.666667v-256a42.666667 42.666667 0 0 0-42.666667-42.666667H426.666667a42.666667 42.666667 0 0 0-42.666667 42.666667V512a42.666667 42.666667 0 0 0 42.666667 42.666667h554.666666z m-42.666666-85.333334H469.333333v-170.666666h469.333334v170.666666zM42.666667 469.333333h213.333333a42.666667 42.666667 0 0 0 42.666667-42.666666v-85.333334a42.666667 42.666667 0 0 0-42.666667-42.666666H42.666667a42.666667 42.666667 0 0 0-42.666667 42.666666v85.333334a42.666667 42.666667 0 0 0 42.666667 42.666666z" horiz-adv-x="1024" />
<glyph glyph-name="icon_protocol" unicode="&#59325;" d="M896.288427 341.333333a128 128 0 0 0 42.666666-248.746666V0a42.666667 42.666667 0 0 0-42.666666-42.666667H128.288427a42.666667 42.666667 0 0 0-42.666667 42.666667l-0.042667 298.709333h85.333334L170.955093 42.666667h682.666667v49.962666A128.042667 128.042667 0 0 0 896.288427 341.333333z m0-85.333333a42.666667 42.666667 0 1 1 0-85.333333 42.666667 42.666667 0 0 1 0 85.333333zM399.307093 564.906667l68.266667-266.24h-63.146667l-15.36 62.464H307.488427L292.46976 298.666667H234.10176l67.925333 266.24h97.28z m186.368 0c63.146667 0 97.28-27.989333 97.28-87.722667 0-65.536-43.008-94.208-103.765333-94.208h-21.162667V298.666667h-59.733333V564.906667h87.381333z m197.973334 0V298.666667h-63.146667V564.906667h63.146667zM896.288427 810.666667a42.666667 42.666667 0 0 0 42.666666-42.666667v-300.16a42.666667 42.666667 0 0 0-42.666666-42.666667l-4.992 0.298667a42.666667 42.666667 0 0 0-37.674667 42.368V725.333333H170.955093l-0.042666-92.586666A128.042667 128.042667 0 0 0 128.288427 384a128 128 0 0 0-42.752 248.704L85.62176 768a42.666667 42.666667 0 0 0 37.674667 42.368L128.288427 810.666667h768zM349.472427 529.749333h-1.706667a402.858667 402.858667 0 0 0-4.906667-24.490666l-23.765333-96.341334H377.46176L356.98176 493.226667a329.813333 329.813333 0 0 0-7.509333 36.522666z m233.130666-9.216h-24.576v-93.184h24.576c21.845333 0 37.205333 13.653333 37.205334 46.421334 0 32.085333-15.36 46.762667-37.205334 46.762666zM128.288427 554.666667a42.666667 42.666667 0 1 1 0-85.333334 42.666667 42.666667 0 0 1 0 85.333334z" horiz-adv-x="1024" />
<glyph glyph-name="icon_info_outlined1" unicode="&#59324;" d="M512-85.333333C252.8-85.333333 42.666667 124.8 42.666667 384S252.8 853.333333 512 853.333333s469.333333-210.133333 469.333333-469.333333-210.133333-469.333333-469.333333-469.333333z m0 85.333333a384 384 0 1 1 0 768 384 384 0 0 1 0-768z m42.581333 533.333333a21.333333 21.333333 0 0 0-21.333333-21.333333h-42.666667a21.333333 21.333333 0 0 0-21.333333 21.333333v42.666667a21.333333 21.333333 0 0 0 21.333333 21.333333h42.666667a21.333333 21.333333 0 0 0 21.333333-21.333333v-42.666667z m0-341.333333a21.333333 21.333333 0 0 0-21.333333-21.333333h-42.666667a21.333333 21.333333 0 0 0-21.333333 21.333333v256a21.333333 21.333333 0 0 0 21.333333 21.333333h42.666667a21.333333 21.333333 0 0 0 21.333333-21.333333v-256z" horiz-adv-x="1024" />
<glyph glyph-name="icon_github" unicode="&#59321;" d="M892.501333 789.973333c1.365333-18.730667-0.426667-38.058667-5.632-75.776l-0.597333-4.608c-1.877333-13.44-3.114667-22.613333-3.925333-29.738666l-0.853334-7.68a251.477333 251.477333 0 0 1-0.981333-13.397334l-0.042667-3.157333 1.877334-2.346667c33.877333-44.458667 53.376-95.189333 56.021333-148.437333l0.298667-12.330667c0-91.306667-41.984-178.730667-116.224-234.410666-28.288-21.205333-61.738667-38.272-99.242667-51.072 8.704-20.138667 13.141333-39.893333 13.141333-59.392v-194.304a44.928 44.928 0 1 0-89.813333 0V147.626667c0 14.506667-8.533333 34.730667-27.776 59.946666l-0.341333 0.426667a44.586667 44.586667 0 0 0-7.936 17.664l-0.085334 0.426667a44.8 44.8 0 0 0-0.512 3.2l0.597334-3.626667a45.397333 45.397333 0 0 0-0.938667 9.642667v0.597333a45.141333 45.141333 0 0 0 1.109333 8.746667l0.256 0.981333a45.098667 45.098667 0 0 0 15.872 24.533333l0.469334 0.341334a44.416 44.416 0 0 0 18.090666 8.277333c49.92 10.368 92.074667 27.818667 123.221334 51.2 51.2 38.4 80.298667 98.944 80.298666 162.56 0 40.106667-15.061333 78.933333-43.733333 113.493333-13.866667 16.725333-15.786667 34.133333-14.08 61.909334 0.853333 13.653333 2.133333 24.405333 6.229333 53.888l0.64 4.565333 1.194667 8.832 0.768 6.186667-2.645333-1.493334-11.392-6.144-5.12-2.730666c-56.448-29.781333-91.306667-41.472-127.146667-30.848a420.266667 420.266667 0 0 1-119.125333 16.853333c-36.053333 0-71.253333-4.352-104.533334-12.842667-46.634667-11.904-78.08 0.042667-141.141333 37.973334a2285.056 2285.056 0 0 1-10.368 6.229333l-0.426667-2.901333c-0.298667-5.12-0.512-10.837333-0.64-17.066667l-0.170666-9.770667-0.042667-7.68-0.042667-29.44c-0.085333-13.866667-0.256-21.333333-0.725333-29.610666-1.322667-22.272-3.754667-34.944-14.506667-48.298667-27.434667-33.962667-41.813333-71.936-41.813333-111.146667 0-59.648 33.109333-121.898667 87.296-162.56 36.096-27.050667 83.157333-45.653333 138.922667-55.04l2.304-0.426666-2.304 0.426666a45.397333 45.397333 0 0 0 18.346666-7.509333l1.152-0.853333a40.149333 40.149333 0 0 0 2.773334-2.261334l0.426666-0.426666 0.512-0.426667c0.938667-0.853333 1.834667-1.792 2.688-2.730667l-3.157333 3.157334a45.312 45.312 0 0 0 11.52-16.64l0.298667-0.64a44.714667 44.714667 0 0 0-8.32-45.653334l-0.426667-0.469333c-19.2-21.077333-27.392-38.272-27.392-51.370667v-195.754666a44.928 44.928 0 0 0-89.813333 0l-0.042667 78.464H305.92c-43.093333 0-80.981333 23.68-116.266667 62.421333-20.864 22.869333-35.712 44.416-52.906666 72.874667-2.474667 4.053333-5.162667 5.717333-11.989334 6.528a44.928 44.928 0 0 0 5.973334 89.514666l4.906666-0.341333c33.578667-4.096 60.842667-20.992 77.866667-49.152 32.469333-53.546667 67.584-92.032 92.416-92.032h48.853333v27.477333c0 17.834667 3.882667 35.413333 11.306667 52.778667-42.325333 13.141333-80.213333 31.872-112.64 56.234667-76.245333 57.173333-123.221333 145.621333-123.221333 234.410666 0 56.405333 18.944 110.421333 53.930666 157.568l2.133334 2.816 0.085333 0.682667 0.256 3.669333c0.426667 6.357333 0.512 12.885333 0.554667 25.514667v12.458667l0.042666 16.298666 0.085334 8.192c0.384 34.432 2.218667 58.026667 7.509333 77.781334 11.136 41.514667 43.392 69.12 87.893333 50.005333 6.826667-2.986667 13.866667-6.4 21.248-10.325333 8.96-4.821333 15.488-8.618667 31.018667-17.962667 41.941333-25.173333 58.581333-31.573333 72.746667-27.946667a513.706667 513.706667 0 0 0 126.72 15.658667c50.005333 0 98.816-7.04 144.597333-20.608 3.84-1.109333 25.685333 6.229333 59.733333 24.192l9.813334 5.248 4.266666 2.304 1.365334 0.768 25.173333 13.653333 1.706667 0.938667c10.368 5.546667 18.816 9.856 26.709333 13.525333 49.28 22.954667 81.408-11.733333 84.650667-56.96z" horiz-adv-x="1024" />
<glyph glyph-name="icon_forum" unicode="&#59322;" d="M768 810.666667a42.666667 42.666667 0 0 0 42.666667-42.666667v-298.666667h128a42.666667 42.666667 0 0 0 42.666666-42.666666v-341.333334a42.666667 42.666667 0 0 0-42.666666-42.666666h-89.002667l-51.498667-51.498667a42.666667 42.666667 0 0 0-56.32-3.541333l-4.010666 3.541333L686.293333 42.666667H469.333333a42.666667 42.666667 0 0 0-42.368 37.674666L426.666667 85.333333v128H380.330667l-72.832-72.832a42.666667 42.666667 0 0 0-56.32-3.541333l-4.010667 3.541333L174.293333 213.333333H85.333333a42.666667 42.666667 0 0 0-42.368 37.674667L42.666667 256V768a42.666667 42.666667 0 0 0 42.666666 42.666667h682.666667z m128-426.666667h-85.333333v-128a42.666667 42.666667 0 0 0-37.674667-42.368L768 213.333333h-256v-85.333333h192a42.666667 42.666667 0 0 0 25.941333-8.789333l4.266667-3.712 33.792-33.792 33.834667 33.792a42.666667 42.666667 0 0 0 24.576 12.117333L832 128H896v256z m-170.666667 341.333333H128v-426.666666h64a42.666667 42.666667 0 0 0 25.941333-8.789334l4.266667-3.712L277.333333 231.04l55.168 55.125333a42.666667 42.666667 0 0 0 24.576 12.117334L362.666667 298.666667H725.333333V725.333333z m-341.333333-256a42.666667 42.666667 0 0 0 0-85.333333H256a42.666667 42.666667 0 0 0 0 85.333333h128z m128 170.666667a42.666667 42.666667 0 0 0 0-85.333333H256a42.666667 42.666667 0 1 0 0 85.333333h256z" horiz-adv-x="1024" />

Before

Width:  |  Height:  |  Size: 465 KiB

After

Width:  |  Height:  |  Size: 468 KiB

View File

@ -27,7 +27,7 @@
import { addCommasToNumber } from '@/utils';
const props = defineProps<{
activeFolder: string; //
activeFolder?: string; //
folderName: string; //
allCount: number; //
}>();

View File

@ -100,7 +100,8 @@ export interface ApiDefinitionGetModuleParams {
filter?: Record<string, any>;
combine?: Record<string, any>;
moduleIds: string[];
protocol: string;
protocols?: string[]; // TODO 协议 必填
protocol?: string; // TODO 协议 改完回收站删除这行
projectId: string;
versionId?: string;
refId?: string;
@ -137,7 +138,7 @@ export interface Environment {
export interface ApiDefinitionPageParams extends TableQueryParams {
id: string;
name: string;
protocol: string;
protocols: string[];
projectId: string;
versionId: string;
refId: string;
@ -180,7 +181,8 @@ export interface mockParams {
}
// 批量操作参数
export interface ApiDefinitionBatchParams extends BatchApiParams {
protocol: string;
protocols?: string[]; // TODO 协议 必填
protocol?: string; // TODO 协议 改完回收站删除这行
}
// 批量更新定义参数
export interface ApiDefinitionBatchUpdateParams extends ApiDefinitionBatchParams {
@ -292,7 +294,7 @@ export interface BatchRecoverApiParams extends ApiDefinitionBatchParams {
// --------------------用例
// 用例列表查询参数
export interface ApiCasePageParams extends TableQueryParams {
protocol: string;
protocols: string[];
projectId: string;
versionId?: string;
refId?: string;
@ -332,7 +334,8 @@ export interface ApiCaseDetail extends ExecuteRequestParams {
}
// 批量操作参数
export interface ApiCaseBatchParams extends BatchApiParams {
protocol: string;
protocols?: string[]; // TODO 协议 必填
protocol?: string; // TODO 协议 改完回收站删除这行
apiDefinitionId?: string;
versionId?: string;
}
@ -368,7 +371,7 @@ export interface ApiRunModeRequest {
// 接口用例批量执行参数
export interface ApiCaseBatchExecuteParams extends BatchApiParams {
apiDefinitionId?: string | number;
protocol: string;
protocols: string[];
versionId?: string;
refId?: string;
runModeConfig: ApiRunModeRequest;

View File

@ -91,4 +91,5 @@ export interface BatchEditMockParams extends BatchApiParams {
tags: string[]; // 标签
append: boolean; // 是否追加
enable: boolean; // 是否启用
protocols: string[]; // 协议集合
}

View File

@ -50,6 +50,7 @@ export interface BatchApiParams {
moduleIds?: (string | number)[]; // 模块 ID 集合
versionId?: string; // 版本 ID
refId?: string; // 版本来源
protocols?: string[]; // 协议集合
}
// 移动模块树

View File

@ -37,8 +37,8 @@
const colorMaps = [
{
color: 'rgb(var(--success-6))',
includes: [RequestMethods.GET, RequestMethods.HEAD],
color: 'rgb(var(--success-7))',
includes: [RequestMethods.GET, RequestMethods.HEAD, 'HTTP'],
},
{
color: 'rgb(var(--warning-7))',

View File

@ -0,0 +1,155 @@
<template>
<MsFolderAll
v-model:isExpandAll="isExpandAll"
:active-folder="props.activeFolder"
:folder-name="props.folderName"
:all-count="props.allCount"
@set-active-folder="(val: string) => emit('setActiveFolder', val)"
>
<template #expandLeft>
<a-dropdown v-model:popup-visible="visible" :hide-on-select="false">
<MsButton type="icon" status="secondary" class="!mr-[4px] p-[4px]" @click="visible = !visible">
<MsIcon :type="`${showExpandApi ? 'icon-icon_more_outlined' : 'icon-icon_protocol'}`" />
</MsButton>
<template #content>
<!-- 展开请求的开关 -->
<template v-if="showExpandApi">
<a-doption class="api-expend w-full">
{{ t('apiScenario.api') }}
<a-switch v-model:model-value="isExpandApi" size="small" @click.stop @change="emit('changeApiExpand')" />
</a-doption>
<a-dsubmenu>
<template #default>{{ t('ms.paramsInput.protocol') }}</template>
<template #content>
<a-checkbox :model-value="isCheckedAll" :indeterminate="indeterminate" @change="handleChangeAll"
>{{ t('common.all') }}
</a-checkbox>
<a-checkbox-group direction="vertical" :model-value="selectedProtocols" @change="handleGroupChange">
<a-checkbox v-for="item in allProtocolList" :key="item.value" :value="item.value">
{{ item.label }}
</a-checkbox>
</a-checkbox-group>
</template>
</a-dsubmenu>
</template>
<!-- 没有 展开请求的开关 -->
<template v-else>
<a-checkbox :model-value="isCheckedAll" :indeterminate="indeterminate" @change="handleChangeAll"
>{{ t('common.all') }}
</a-checkbox>
<a-checkbox-group direction="vertical" :model-value="selectedProtocols" @change="handleGroupChange">
<a-checkbox v-for="item in allProtocolList" :key="item.value" :value="item.value">
{{ item.label }}
</a-checkbox>
</a-checkbox-group>
</template>
</template>
</a-dropdown>
</template>
<template #expandRight>
<slot name="expandRight"></slot>
</template>
</MsFolderAll>
</template>
<script setup lang="ts">
import { CheckboxOption } from '@arco-design/web-vue';
import MsButton from '@/components/pure/ms-button/index.vue';
import MsFolderAll from '@/components/business/ms-folder-all/index.vue';
import { getProtocolList } from '@/api/modules/api-test/common';
import { useI18n } from '@/hooks/useI18n';
import useAppStore from '@/store/modules/app';
const props = defineProps<{
activeFolder?: string; //
folderName: string; //
allCount: number; //
showExpandApi?: boolean; //
}>();
const emit = defineEmits<{
(e: 'setActiveFolder', val: string): void;
(e: 'changeApiExpand'): void;
(e: 'selectedProtocolsChange'): void;
}>();
const isExpandAll = defineModel<boolean>('isExpandAll', {
required: true,
});
const isExpandApi = defineModel<boolean>('isExpandApi', {
required: false,
default: undefined,
});
const selectedProtocols = defineModel<string[]>('selectedProtocols', {
required: true,
});
const { t } = useI18n();
const appStore = useAppStore();
const visible = ref(false);
const selectedList = ref<CheckboxOption[]>([]); //
const allProtocolList = ref<CheckboxOption[]>([]); //
const isCheckedAll = computed(() => {
return selectedList.value.length === allProtocolList.value.length;
});
const indeterminate = computed(() => {
return selectedList.value.length > 0 && selectedList.value.length < allProtocolList.value.length;
});
const handleChangeAll = (value: boolean | (string | number | boolean)[]) => {
if (value) {
selectedList.value = allProtocolList.value;
} else {
selectedList.value = [];
}
};
const handleGroupChange = (value: (string | number | boolean)[]) => {
selectedList.value = allProtocolList.value.filter((e: CheckboxOption) => value.includes(e.value));
};
async function initProtocolList() {
try {
const res = await getProtocolList(appStore.currentOrgId);
allProtocolList.value = res.map((e) => ({
label: e.protocol,
value: e.protocol,
polymorphicName: e.polymorphicName,
pluginId: e.pluginId,
}));
selectedList.value = allProtocolList.value;
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
}
}
watch(
() => selectedList.value,
(val) => {
selectedProtocols.value = val.map((e) => e.value as string);
emit('selectedProtocolsChange');
}
);
onBeforeMount(() => {
initProtocolList();
});
</script>
<style lang="less" scoped>
.arco-dropdown {
padding: 8px;
.arco-dropdown-list .arco-dropdown-option {
margin: 0;
}
}
.api-expend {
:deep(.arco-dropdown-option-content) {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
}
}
</style>

View File

@ -18,7 +18,7 @@
:active-module="activeModule"
:offspring-ids="offspringIds"
class="flex-1 overflow-hidden !pl-0 !pr-[16px]"
:protocol="protocol"
:selected-protocols="selectedProtocols"
:member-options="memberOptions"
read-only
/>
@ -50,15 +50,15 @@
const folderTree = ref<ModuleTreeNode[]>([]);
const activeModule = ref<string>('all');
const offspringIds = ref<string[]>([]);
const protocol = ref('HTTP');
const selectedProtocols = ref<string[]>([]);
function handleNodeSelect(keys: string[], _offspringIds: string[]) {
[activeModule.value] = keys;
offspringIds.value = _offspringIds;
}
function handleProtocolChange(val: string) {
protocol.value = val;
function handleProtocolChange(val: string[]) {
selectedProtocols.value = val;
}
</script>

View File

@ -31,7 +31,7 @@
@drag-change="handleTableDragSort"
@module-change="loadApiList(false)"
>
<template v-if="props.protocol === 'HTTP'" #[FilterSlotNameEnum.API_TEST_API_REQUEST_METHODS]="{ filterContent }">
<template #[FilterSlotNameEnum.API_TEST_API_REQUEST_METHODS]="{ filterContent }">
<apiMethodName :method="filterContent.value" />
</template>
<template #[FilterSlotNameEnum.API_TEST_API_REQUEST_API_STATUS]="{ filterContent }">
@ -40,22 +40,11 @@
<template #num="{ record }">
<MsButton type="text" @click="openApiTab(record)">{{ record.num }}</MsButton>
</template>
<template #protocol="{ record }">
<apiMethodName :method="record.protocol" />
</template>
<template #method="{ record }">
<a-select
v-if="props.protocol === 'HTTP' && hasAnyPermission(['PROJECT_API_DEFINITION:READ+UPDATE'])"
v-model:model-value="record.method"
class="param-input w-full"
size="mini"
@change="() => handleMethodChange(record)"
>
<template #label>
<apiMethodName :method="record.method" is-tag />
</template>
<a-option v-for="item of Object.values(RequestMethods)" :key="item" :value="item">
<apiMethodName :method="item" is-tag />
</a-option>
</a-select>
<apiMethodName v-else :method="record.method" is-tag />
<apiMethodName :method="record.method" is-tag />
</template>
<template #caseTotal="{ record }">
{{ record.caseTotal }}
@ -279,6 +268,7 @@
import apiStatus from '@/views/api-test/components/apiStatus.vue';
import moduleTree from '@/views/api-test/management/components/moduleTree.vue';
import { getProtocolList } from '@/api/modules/api-test/common';
import {
batchDeleteDefinition,
batchMoveDefinition,
@ -295,6 +285,7 @@
import { characterLimit, operationWidth } from '@/utils';
import { hasAnyPermission } from '@/utils/permission';
import { ProtocolItem } from '@/models/apiTest/common';
import { ApiDefinitionDetail, ApiDefinitionGetModuleParams } from '@/models/apiTest/management';
import { DragSortParams } from '@/models/common';
import { RequestDefinitionStatus, RequestMethods } from '@/enums/apiEnum';
@ -305,7 +296,7 @@
class?: string;
activeModule: string;
offspringIds: string[];
protocol: string; //
selectedProtocols: string[]; //
readOnly?: boolean; //
refreshTimeStamp?: number;
memberOptions: { label: string; value: string }[];
@ -341,13 +332,38 @@
])
);
// TODO: store
const protocolList = ref<ProtocolItem[]>([]);
async function initProtocolList() {
try {
const res = await getProtocolList(appStore.currentOrgId);
protocolList.value = res.map((e) => ({
protocol: e.protocol,
polymorphicName: e.polymorphicName,
pluginId: e.pluginId,
}));
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
}
}
const requestMethodsOptions = computed(() => {
return Object.values(RequestMethods).map((e) => {
const otherMethods = protocolList.value
.filter((e) => e.protocol !== 'HTTP')
.map((item) => {
return {
value: item.protocol,
key: item.protocol,
};
});
const httpMethods = Object.values(RequestMethods).map((e) => {
return {
value: e,
key: e,
};
});
return [...httpMethods, ...otherMethods];
});
const requestApiStatus = computed(() => {
return Object.values(RequestDefinitionStatus).map((e) => {
@ -386,8 +402,9 @@
{
title: 'apiTestManagement.protocol',
dataIndex: 'protocol',
slotName: 'protocol',
showTooltip: true,
width: 200,
width: 150,
showDrag: true,
},
{
@ -397,7 +414,7 @@
width: 140,
showDrag: true,
filterConfig: {
options: requestMethodsOptions.value,
options: [],
filterSlotName: FilterSlotNameEnum.API_TEST_API_REQUEST_METHODS,
},
},
@ -494,7 +511,7 @@
...item,
filterConfig: {
...item.filterConfig,
options: props.protocol === 'HTTP' ? requestMethodsOptions.value : [],
options: requestMethodsOptions.value,
},
};
}
@ -588,7 +605,7 @@
keyword: keyword.value,
projectId: appStore.currentProjectId,
moduleIds,
protocol: props.protocol,
protocols: props.selectedProtocols,
filter: propsRes.value.filter,
};
@ -597,7 +614,7 @@
keyword: keyword.value,
filter: propsRes.value.filter,
moduleIds: [],
protocol: props.protocol,
protocols: props.selectedProtocols,
projectId: appStore.currentProjectId,
});
}
@ -624,26 +641,13 @@
);
watch(
() => props.protocol,
() => props.selectedProtocols,
() => {
resetSelector();
loadApiList(true);
}
);
async function handleMethodChange(record: ApiDefinitionDetail) {
try {
await updateDefinition({
id: record.id,
method: record.method,
});
Message.success(t('common.updateSuccess'));
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
}
}
async function handleStatusChange(record: ApiDefinitionDetail) {
try {
await updateDefinition({
@ -658,6 +662,7 @@
}
onBeforeMount(() => {
initProtocolList();
loadApiList(true);
});
@ -705,7 +710,7 @@
projectId: appStore.currentProjectId,
moduleIds: await getModuleIds(),
deleteAll: true,
protocol: props.protocol,
protocols: props.selectedProtocols,
});
} else {
await deleteDefinition(record?.id as string);
@ -770,10 +775,11 @@
},
];
const attrOptions = computed(() => {
if (props.protocol === 'HTTP') {
return fullAttrs;
}
return fullAttrs.filter((e) => e.value !== 'method');
// TODO HTTP
// if (props.protocol === 'HTTP') {
return fullAttrs;
// }
// return fullAttrs.filter((e) => e.value !== 'method');
});
const valueOptions = computed(() => {
switch (batchForm.value.attr) {
@ -827,7 +833,7 @@
},
projectId: appStore.currentProjectId,
moduleIds: await getModuleIds(),
protocol: props.protocol,
protocols: props.selectedProtocols,
type: batchForm.value.attr,
append: batchForm.value.append,
[batchForm.value.attr]: batchForm.value.attr === 'tags' ? batchForm.value.values : batchForm.value.value,
@ -869,7 +875,7 @@
projectId: appStore.currentProjectId,
moduleIds: await getModuleIds(),
moduleId: selectedModuleKeys.value[0],
protocol: props.protocol,
protocols: props.selectedProtocols,
});
Message.success(t('common.batchMoveSuccess'));
if (isBatchMove.value) {
@ -958,12 +964,10 @@
const apiTableRef = ref();
watch(
() => props.protocol,
(val) => {
if (val) {
initFilterColumn();
apiTableRef.value.initColumn(columns);
}
() => requestMethodsOptions.value,
() => {
initFilterColumn();
apiTableRef.value.initColumn(columns);
}
);
</script>
@ -972,15 +976,12 @@
:deep(.param-input:not(.arco-input-focus, .arco-select-view-focus)) {
&:not(:hover) {
border-color: transparent !important;
.arco-input::placeholder {
@apply invisible;
}
.arco-select-view-icon {
@apply invisible;
}
.arco-select-view-value {
color: var(--color-text-brand);
}

View File

@ -4,7 +4,7 @@
<apiTable
:active-module="props.activeModule"
:offspring-ids="props.offspringIds"
:protocol="props.protocol"
:selected-protocols="props.selectedProtocols"
:refresh-time-stamp="refreshTableTimeStamp"
:member-options="memberOptions"
@open-api-tab="(record, isExecute) => openApiTab({ apiInfo: record, isCopy: false, isExecute })"
@ -99,7 +99,7 @@
ref="caseTableRef"
:is-api="true"
:active-module="props.activeModule"
:protocol="activeApiTab.protocol"
:selected-protocols="[activeApiTab.protocol]"
:api-detail="activeApiTab"
:offspring-ids="props.offspringIds"
:member-options="memberOptions"
@ -116,7 +116,7 @@
:active-module="props.activeModule"
:offspring-ids="props.offspringIds"
:definition-detail="activeApiTab"
:protocol="activeApiTab.protocol"
:selected-protocols="[activeApiTab.protocol]"
:height-used="48"
is-api
@debug="openApiTabAndDebugMock"
@ -188,7 +188,7 @@
activeModule: string;
offspringIds: string[];
moduleTree: ModuleTreeNode[]; //
protocol: string;
selectedProtocols: string[];
currentTab: string;
memberOptions: { label: string; value: string }[];
}>();

View File

@ -51,6 +51,9 @@
{{ record.num }}
</MsButton>
</template>
<template #protocol="{ record }">
<apiMethodName :method="record.protocol" />
</template>
<template #caseLevel="{ record }">
<a-select
v-if="hasAnyPermission(['PROJECT_API_DEFINITION_CASE:READ+UPDATE'])"
@ -295,6 +298,7 @@
import type { CaseLevel } from '@/components/business/ms-case-associate/types';
import caseDetailDrawer from './caseDetailDrawer.vue';
import createAndEditCaseDrawer from './createAndEditCaseDrawer.vue';
import apiMethodName from '@/views/api-test/components/apiMethodName.vue';
import apiStatus from '@/views/api-test/components/apiStatus.vue';
import BatchRunModal from '@/views/api-test/components/batchRunModal.vue';
import caseAndScenarioReportDrawer from '@/views/api-test/components/caseAndScenarioReportDrawer.vue';
@ -332,7 +336,7 @@
const props = defineProps<{
isApi: boolean; // case tab
activeModule: string;
protocol: string; //
selectedProtocols: string[]; //
apiDetail?: RequestParam;
offspringIds: string[];
memberOptions: { label: string; value: string }[];
@ -403,8 +407,9 @@
{
title: 'apiTestManagement.protocol',
dataIndex: 'protocol',
slotName: 'protocol',
showTooltip: true,
width: 200,
width: 150,
showDrag: true,
},
{
@ -598,7 +603,7 @@
keyword: keyword.value,
projectId: appStore.currentProjectId,
moduleIds: selectModules,
protocol: props.protocol,
protocols: props.selectedProtocols,
};
setLoadListParams(params);
loadList();
@ -620,7 +625,7 @@
);
watch(
() => props.protocol,
() => props.selectedProtocols,
() => {
if (props.isApi) return;
loadCaseListAndResetSelector();
@ -675,7 +680,7 @@
filter: propsRes.value.filter,
},
projectId: appStore.currentProjectId,
protocol: props.protocol,
protocols: props.selectedProtocols,
moduleIds: selectModules,
apiDefinitionId: props.apiDetail?.id as string,
};

View File

@ -6,7 +6,7 @@
:offspring-ids="props.offspringIds"
:is-api="false"
:active-module="props.activeModule"
:protocol="props.protocol"
:selected-protocols="props.selectedProtocols"
:member-options="memberOptions"
@open-case-tab="openCaseTab"
@open-case-tab-and-execute="openCaseTabAndExecute"
@ -44,7 +44,7 @@
const props = defineProps<{
activeModule: string;
protocol: string;
selectedProtocols: string[];
offspringIds: string[];
moduleTree: ModuleTreeNode[]; //
memberOptions: { label: string; value: string }[];

View File

@ -41,7 +41,7 @@
v-model:api-tabs="apiTabs"
:active-module="props.activeModule"
:offspring-ids="props.offspringIds"
:protocol="props.protocol"
:selected-protocols="props.selectedProtocols"
:module-tree="props.moduleTree"
:current-tab="currentTab"
:member-options="memberOptions"
@ -54,7 +54,7 @@
v-model:api-tabs="apiTabs"
v-model:active-api-tab="activeApiTab"
:active-module="props.activeModule"
:protocol="props.protocol"
:selected-protocols="props.selectedProtocols"
:module-tree="props.moduleTree"
:current-tab="currentTab"
:offspring-ids="props.offspringIds"
@ -65,7 +65,7 @@
v-if="activeApiTab.id === 'all' && currentTab === 'mock'"
:active-module="props.activeModule"
:offspring-ids="props.offspringIds"
:protocol="props.protocol"
:selected-protocols="props.selectedProtocols"
:definition-detail="activeApiTab"
@debug="handleMockDebug"
/>
@ -108,7 +108,7 @@
const props = defineProps<{
activeModule: string;
offspringIds: string[];
protocol: string;
selectedProtocols: string[];
moduleTree: ModuleTreeNode[]; //
}>();
const emit = defineEmits<{

View File

@ -42,6 +42,9 @@
{{ record.expectNum }}
</MsButton>
</template>
<template #protocol="{ record }">
<apiMethodName :method="record.protocol" />
</template>
<template #enable="{ record }">
<a-switch
v-model="record.enable"
@ -112,7 +115,7 @@
asterisk-position="end"
>
<a-select v-model="batchForm.attr" :placeholder="t('common.pleaseSelect')">
<a-option v-for="item of attrOptions" :key="item.value" :value="item.value">
<a-option v-for="item of fullAttrs" :key="item.value" :value="item.value">
{{ t(item.name) }}
</a-option>
</a-select>
@ -240,7 +243,7 @@
offspringIds: string[];
definitionDetail: RequestParam;
readOnly?: boolean; //
protocol: string; //
selectedProtocols: string[]; //
heightUsed?: number;
}>();
const emit = defineEmits<{
@ -289,8 +292,8 @@
{
title: 'apiTestManagement.protocol',
dataIndex: 'protocol',
showTooltip: true,
width: 200,
slotName: 'protocol',
width: 150,
showDrag: true,
},
{
@ -401,7 +404,7 @@
const params = {
keyword: keyword.value,
projectId: appStore.currentProjectId,
protocol: props.protocol,
protocols: props.selectedProtocols,
apiDefinitionId: props.definitionDetail.id !== 'all' ? props.definitionDetail.id : undefined,
filter: {},
moduleIds: selectModules,
@ -418,11 +421,13 @@
});
}
watchEffect(() => {
if (props.activeModule || props.protocol) {
watch(
[() => props.activeModule, () => props.selectedProtocols],
() => {
loadMockList();
}
});
},
{ immediate: true }
);
async function handleBeforeEnableChange(record: ApiDefinitionMockDetail) {
try {
@ -477,6 +482,7 @@
condition: { keyword: keyword.value },
projectId: appStore.currentProjectId,
moduleIds: selectModules,
protocols: props.selectedProtocols,
});
} else {
await deleteMock({
@ -559,12 +565,6 @@
value: 'Tags',
},
];
const attrOptions = computed(() => {
if (props.protocol === 'HTTP') {
return fullAttrs;
}
return fullAttrs.filter((e) => e.value !== 'method');
});
function cancelBatch() {
showBatchModal.value = false;
@ -595,6 +595,7 @@
append: batchForm.value.append,
tags: batchForm.value.attr === 'Tags' ? batchForm.value.values : [],
enable: batchForm.value.attr === 'Status' ? batchForm.value.value : false,
protocols: props.selectedProtocols,
});
Message.success(t('common.updateSuccess'));
cancelBatch();

View File

@ -1,13 +1,6 @@
<template>
<div>
<template v-if="!props.isModal">
<a-select
v-if="!props.readOnly"
v-model:model-value="moduleProtocol"
:options="moduleProtocolOptions"
class="mb-[8px]"
@change="() => handleProtocolChange()"
/>
<div class="mb-[8px] flex items-center gap-[8px]">
<a-input
v-model:model-value="moduleKeyword"
@ -17,7 +10,7 @@
<template v-if="!props.readOnly && !props.trash">
<a-dropdown-button
v-if="
moduleProtocol === 'HTTP' &&
selectedProtocols.includes('HTTP') &&
hasAllPermission(['PROJECT_API_DEFINITION:READ+ADD', 'PROJECT_API_DEFINITION:READ+IMPORT'])
"
type="primary"
@ -35,7 +28,7 @@
</a-dropdown-button>
<a-button
v-else-if="
moduleProtocol === 'HTTP' &&
selectedProtocols.includes('HTTP') &&
!hasAnyPermission(['PROJECT_API_DEFINITION:READ+ADD']) &&
hasAnyPermission(['PROJECT_API_DEFINITION:READ+IMPORT'])
"
@ -54,27 +47,20 @@
</a-button>
</template>
</div>
<div class="folder" @click="setActiveFolder('all')">
<div :class="allFolderClass">
<MsIcon type="icon-icon_folder_filled1" class="folder-icon" />
<div class="folder-name">{{ t('apiTestManagement.allApi') }}</div>
<div class="folder-count">({{ allFileCount }})</div>
</div>
<div class="ml-auto flex items-center">
<a-tooltip
v-if="!props.readOnly && !props.trash"
:content="isExpandApi ? t('apiTestManagement.collapseApi') : t('apiTestManagement.expandApi')"
>
<MsButton type="icon" status="secondary" class="!mr-0 p-[4px]" @click="changeApiExpand">
<icon-eye-invisible v-if="isExpandApi" />
<icon-eye v-else />
</MsButton>
</a-tooltip>
<a-tooltip :content="isExpandAll ? t('common.collapseAll') : t('common.expandAll')">
<MsButton type="icon" status="secondary" class="!mr-0 p-[4px]" @click="changeExpand">
<MsIcon :type="isExpandAll ? 'icon-icon_folder_collapse1' : 'icon-icon_folder_expansion1'" />
</MsButton>
</a-tooltip>
<TreeFolderAll
v-if="!props.readOnly"
v-model:isExpandApi="isExpandApi"
v-model:isExpandAll="isExpandAll"
v-model:selectedProtocols="selectedProtocols"
:folder-name="t('apiTestManagement.allApi')"
:all-count="allFileCount"
:active-folder="selectedKeys[0] as string"
:show-expand-api="!props.readOnly && !props.trash"
@set-active-folder="setActiveFolder"
@change-api-expand="changeApiExpand"
@selected-protocols-change="selectedProtocolsChange"
>
<template #expandRight>
<popConfirm
v-if="hasAnyPermission(['PROJECT_API_DEFINITION:READ+ADD']) && !props.readOnly && !props.trash"
mode="add"
@ -91,8 +77,8 @@
/>
</MsButton>
</popConfirm>
</div>
</div>
</template>
</TreeFolderAll>
<a-divider class="my-[8px]" />
</template>
<a-input
@ -188,6 +174,7 @@
import type { MsTreeNodeData } from '@/components/business/ms-tree/types';
import apiMethodName from '@/views/api-test/components/apiMethodName.vue';
import popConfirm from '@/views/api-test/components/popConfirm.vue';
import TreeFolderAll from '@/views/api-test/components/treeFolderAll.vue';
import { getProtocolList } from '@/api/modules/api-test/common';
import {
@ -247,7 +234,7 @@
const { openModal } = useModal();
const { copy, isSupported } = useClipboard({ legacy: true });
const moduleProtocol = ref('HTTP');
const selectedProtocols = ref<string[]>([]);
const moduleProtocolOptions = ref<SelectOptionData[]>([]);
const protocolLoading = ref(false);
@ -303,9 +290,6 @@
const folderTree = ref<ModuleTreeNode[]>([]);
const focusNodeKey = ref<string | number>('');
const selectedKeys = ref<Array<string | number>>([props.activeModule]);
const allFolderClass = computed(() =>
selectedKeys.value[0] === 'all' ? 'folder-text folder-text--active' : 'folder-text'
);
const loading = ref(false);
function setActiveFolder(id: string) {
@ -372,13 +356,13 @@
const lastModuleCountParam = ref<ApiDefinitionGetModuleParams>({
projectId: appStore.currentProjectId,
keyword: '',
protocol: moduleProtocol.value,
protocols: selectedProtocols.value,
moduleIds: [],
});
async function initModuleCount(params: ApiDefinitionGetModuleParams) {
try {
lastModuleCountParam.value = params;
lastModuleCountParam.value.protocol = moduleProtocol.value;
lastModuleCountParam.value.protocols = selectedProtocols.value;
let res;
if (props.trash) {
res = await getTrashModuleCount(params);
@ -428,7 +412,7 @@
res = await getTrashModuleTree({
//
keyword: '',
protocol: moduleProtocol.value,
protocols: selectedProtocols.value,
projectId: appStore.currentProjectId,
moduleIds: [],
});
@ -436,7 +420,7 @@
//
res = await getModuleTree({
keyword: '',
protocol: moduleProtocol.value,
protocols: selectedProtocols.value,
projectId: appStore.currentProjectId,
moduleIds: [],
});
@ -444,7 +428,7 @@
res = await getModuleTreeOnlyModules({
//
keyword: '',
protocol: moduleProtocol.value,
protocols: selectedProtocols.value,
projectId: appStore.currentProjectId,
moduleIds: [],
});
@ -484,7 +468,7 @@
if (isSetDefaultKey) {
selectedKeys.value = [folderTree.value[0].id];
}
emit('init', folderTree.value, moduleProtocol.value, nodePathObj);
emit('init', folderTree.value, selectedProtocols.value, nodePathObj);
} catch (error) {
// eslint-disable-next-line no-console
console.log(error);
@ -494,9 +478,9 @@
}
}
function handleProtocolChange() {
emit('changeProtocol', moduleProtocol.value);
lastModuleCountParam.value.protocol = moduleProtocol.value;
function selectedProtocolsChange() {
emit('changeProtocol', selectedProtocols.value);
lastModuleCountParam.value.protocols = selectedProtocols.value;
initModules();
}
@ -507,12 +491,7 @@
}
);
function changeExpand() {
isExpandAll.value = !isExpandAll.value;
}
function changeApiExpand() {
isExpandApi.value = !isExpandApi.value;
initModules();
}
@ -675,7 +654,6 @@
onBeforeMount(() => {
initProtocolList();
initModules();
});
async function refresh() {

View File

@ -21,6 +21,7 @@
</template>
</MsEditableTab>
</div>
<!-- TODO 协议 -->
<api
v-show="currentTab === 'api'"
ref="apiRef"
@ -28,14 +29,15 @@
:module-tree="props.moduleTree"
:active-module="props.activeModule"
:offspring-ids="props.offspringIds"
:protocol="protocol"
:protocol="props.selectedProtocols[0]"
/>
<!-- TODO 协议 -->
<api-case
v-show="currentTab === 'case'"
:member-options="memberOptions"
:active-module="props.activeModule"
:offspring-ids="props.offspringIds"
:protocol="protocol"
:protocol="props.selectedProtocols[0]"
></api-case>
</template>
@ -55,7 +57,7 @@
const props = defineProps<{
activeModule: string;
offspringIds: string[];
protocol: string;
selectedProtocols: string[]; //
moduleTree: ModuleTreeNode[]; //
}>();

View File

@ -54,7 +54,7 @@
:module-tree="folderTree"
:active-module="activeModule"
:offspring-ids="offspringIds"
:protocol="protocol"
:selected-protocols="selectedProtocols"
@import="importDrawerVisible = true"
/>
</div>
@ -93,14 +93,14 @@
const folderTreePathMap = ref<Record<string, any>>({});
const importDrawerVisible = ref(false);
const offspringIds = ref<string[]>([]);
const protocol = ref('HTTP');
const selectedProtocols = ref<string[]>([]);
const activeNodeId = ref<string | number>('all');
const moduleTreeRef = ref<InstanceType<typeof moduleTree>>();
const managementRef = ref<InstanceType<typeof management>>();
function handleModuleInit(tree: ModuleTreeNode[], _protocol: string, pathMap: Record<string, any>) {
function handleModuleInit(tree: ModuleTreeNode[], _protocols: string[], pathMap: Record<string, any>) {
folderTree.value = tree;
protocol.value = _protocol;
selectedProtocols.value = _protocols;
folderTreePathMap.value = pathMap;
}
@ -128,8 +128,8 @@
}
}
function handleProtocolChange(val: string) {
protocol.value = val;
function handleProtocolChange(val: string[]) {
selectedProtocols.value = val;
}
const appStore = useAppStore();
@ -139,7 +139,7 @@
projectId: appStore.currentProjectId,
keyword: '',
moduleIds: [],
protocol: protocol.value,
protocols: selectedProtocols.value,
});
recycleModulesCount.value = res.all;
}

View File

@ -20,7 +20,7 @@
:module-tree="folderTree"
:active-module="activeModule"
:offspring-ids="offspringIds"
:protocol="protocol"
:selected-protocols="selectedProtocols"
/>
</div>
</template>
@ -44,14 +44,14 @@
const folderTree = ref<ModuleTreeNode[]>([]);
const folderTreePathMap = ref<Record<string, any>>({});
const offspringIds = ref<string[]>([]);
const protocol = ref('HTTP');
const selectedProtocols = ref<string[]>([]);
const activeApi = ref<RequestParam>();
const moduleTreeRef = ref<InstanceType<typeof moduleTree>>();
const managementRef = ref<InstanceType<typeof management>>();
function handleModuleInit(tree: ModuleTreeNode[], _protocol: string, pathMap: Record<string, any>) {
function handleModuleInit(tree: ModuleTreeNode[], _protocol: string[], pathMap: Record<string, any>) {
folderTree.value = tree;
protocol.value = _protocol;
selectedProtocols.value = _protocol;
folderTreePathMap.value = pathMap;
}
@ -60,8 +60,8 @@
offspringIds.value = _offspringIds;
}
function handleProtocolChange(val: string) {
protocol.value = val;
function handleProtocolChange(val: string[]) {
selectedProtocols.value = val;
}
function refreshModuleTree() {

View File

@ -7,11 +7,13 @@
class="mb-[8px]"
:max-length="255"
/>
<MsFolderAll
<TreeFolderAll
v-model:isExpandAll="isExpandAll"
v-model:selectedProtocols="selectedProtocols"
:active-folder="activeFolder"
:folder-name="t('apiTestManagement.allApi')"
:all-count="allCount"
:show-expand-api="false"
@set-active-folder="setActiveFolder"
/>
<a-divider class="my-[8px]" />
@ -50,9 +52,9 @@
import { useRoute } from 'vue-router';
import { useVModel } from '@vueuse/core';
import MsFolderAll from '@/components/business/ms-folder-all/index.vue';
import MsTree from '@/components/business/ms-tree/index.vue';
import type { MsTreeNodeData } from '@/components/business/ms-tree/types';
import TreeFolderAll from '@/views/api-test/components/treeFolderAll.vue';
import { getFeatureCaseModule } from '@/api/modules/test-plan/testPlan';
import { useI18n } from '@/hooks/useI18n';
@ -94,6 +96,7 @@
const folderTree = ref<ModuleTreeNode[]>([]);
const loading = ref(false);
const selectedKeys = useVModel(props, 'selectedKeys', emit);
const selectedProtocols = ref<string[]>([]);
//
async function initModules() {