feat(全局): 接口调试-前置条件&用例评审部分接口联调&部分组件调整&axios、vue-draggable-plus 升级
This commit is contained in:
parent
cbe6c19c45
commit
057b286c19
|
@ -96,6 +96,7 @@ module.exports = {
|
|||
'^echarts$',
|
||||
'^color$',
|
||||
'^localforage$',
|
||||
'vue-draggable-plus',
|
||||
], // node依赖
|
||||
['.*/assets/.*', '^@/assets$'], // 项目静态资源
|
||||
['^@/components/pure/.*', '^@/components/business/.*', '.*\\.vue$'], // 组件
|
||||
|
|
|
@ -48,7 +48,7 @@
|
|||
"@vueuse/core": "^10.4.1",
|
||||
"ace-builds": "^1.24.2",
|
||||
"ahooks-vue": "^0.15.1",
|
||||
"axios": "^0.24.0",
|
||||
"axios": "^1.6.5",
|
||||
"dayjs": "^1.11.9",
|
||||
"echarts": "^5.4.3",
|
||||
"fastq": "^1.15.0",
|
||||
|
@ -67,7 +67,7 @@
|
|||
"tippy.js": "^6.3.7",
|
||||
"vue": "^3.3.4",
|
||||
"vue-dompurify-html": "^4.1.4",
|
||||
"vue-draggable-plus": "^0.2.7",
|
||||
"vue-draggable-plus": "^0.3.5",
|
||||
"vue-echarts": "^6.6.1",
|
||||
"vue-i18n": "^9.3.0",
|
||||
"vue-router": "^4.2.4",
|
||||
|
|
|
@ -8,7 +8,7 @@ import { ContentTypeEnum } from '@/enums/httpEnum';
|
|||
import { AxiosCanceler } from './axiosCancel';
|
||||
import type { CreateAxiosOptions } from './axiosTransform';
|
||||
import type { RequestOptions, Result, UploadFileParams } from '#/axios';
|
||||
import type { AxiosError, AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';
|
||||
import type { AxiosError, AxiosInstance, AxiosRequestConfig, AxiosResponse, InternalAxiosRequestConfig } from 'axios';
|
||||
|
||||
export * from './axiosTransform';
|
||||
|
||||
|
@ -56,7 +56,7 @@ export class MSAxios {
|
|||
if (requestInterceptors && isFunction(requestInterceptors)) {
|
||||
config = requestInterceptors(config, this.options);
|
||||
}
|
||||
return config;
|
||||
return config as InternalAxiosRequestConfig; // TODO: 拦截配置升级了,暂时 as 处理
|
||||
}, undefined);
|
||||
|
||||
// 响应拦截器
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import MSR from '@/api/http/index';
|
||||
import { ProjectListUrl } from '@/api/requrls/project-management/project';
|
||||
import { ProjectListUrl, ProjectSwitchUrl } from '@/api/requrls/project-management/project';
|
||||
|
||||
import type { ProjectListItem } from '@/models/setting/project';
|
||||
|
||||
|
@ -7,4 +7,6 @@ export function getProjectList(organizationId: string) {
|
|||
return MSR.get<ProjectListItem[]>({ url: ProjectListUrl, params: organizationId });
|
||||
}
|
||||
|
||||
export default {};
|
||||
export function switchProject(data: { projectId: string; userId: string }) {
|
||||
return MSR.post({ url: ProjectSwitchUrl, data });
|
||||
}
|
||||
|
|
|
@ -1,3 +1,2 @@
|
|||
export const ProjectListUrl = '/project/list/options';
|
||||
|
||||
export default {};
|
||||
export const ProjectListUrl = '/project/list/options'; // 项目列表
|
||||
export const ProjectSwitchUrl = '/project/switch'; // 切换项目
|
||||
|
|
|
@ -604,15 +604,24 @@
|
|||
}
|
||||
|
||||
/** 开关 **/
|
||||
.arco-switch:not(.arco-switch-disabled) {
|
||||
background: var(--color-fill-4) !important;
|
||||
}
|
||||
.arco-switch-checked:not(.arco-switch-disabled) {
|
||||
background: rgb(var(--primary-6)) !important;
|
||||
}
|
||||
.arco-switch[disabled] {
|
||||
background: var(--color-text-n8);
|
||||
}
|
||||
.arco-switch-type-line.arco-switch-small {
|
||||
height: 14px;
|
||||
line-height: 14px;
|
||||
}
|
||||
.arco-switch-type-line.arco-switch-small {
|
||||
.arco-switch-handle {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
}
|
||||
}
|
||||
.arco-switch-type-line.arco-switch-small.arco-switch-checked {
|
||||
.arco-switch-handle {
|
||||
left: calc(100% - 14px - 0px);
|
||||
}
|
||||
}
|
||||
|
||||
/** 分页 **/
|
||||
.ms-pagination {
|
||||
|
|
|
@ -208,6 +208,7 @@
|
|||
&::before {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 1;
|
||||
width: 100%;
|
||||
height: 10px;
|
||||
|
@ -222,6 +223,7 @@
|
|||
&::after {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 1;
|
||||
width: 100%;
|
||||
height: 10px;
|
||||
|
|
|
@ -122,6 +122,7 @@
|
|||
class="mt-[8px]"
|
||||
:style="{ 'margin-top': index === 0 && !props.isShowDrag ? '36px' : '' }"
|
||||
size="small"
|
||||
type="line"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
|
@ -159,6 +160,7 @@
|
|||
|
||||
<script setup lang="ts">
|
||||
import { ref, unref, watchEffect } from 'vue';
|
||||
import { VueDraggable } from 'vue-draggable-plus';
|
||||
|
||||
import MsTagsInput from '@/components/pure/ms-tags-input/index.vue';
|
||||
|
||||
|
@ -167,7 +169,6 @@
|
|||
|
||||
import type { FormItemModel, FormMode } from './types';
|
||||
import type { FormInstance, ValidatedError } from '@arco-design/web-vue';
|
||||
import { VueDraggable } from 'vue-draggable-plus';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
|
|
|
@ -129,6 +129,7 @@
|
|||
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import { useVModel } from '@vueuse/core';
|
||||
|
||||
import { CustomTypeMaps, MsAdvanceFilter } from '@/components/pure/ms-advance-filter';
|
||||
import { FilterFormItem, FilterType } from '@/components/pure/ms-advance-filter/type';
|
||||
|
@ -206,8 +207,8 @@
|
|||
selectedModuleKeys.value = [];
|
||||
}
|
||||
|
||||
const innerVisible = ref(props.visible);
|
||||
const innerProject = ref(props.projectId);
|
||||
const innerVisible = useVModel(props, 'visible', emit);
|
||||
const innerProject = useVModel(props, 'projectId', emit);
|
||||
|
||||
const protocolType = ref('HTTP'); // 协议类型
|
||||
const protocolOptions = ref(['HTTP']);
|
||||
|
@ -559,7 +560,6 @@
|
|||
watch(
|
||||
() => props.visible,
|
||||
(val) => {
|
||||
innerVisible.value = val;
|
||||
if (val) {
|
||||
resetSelector();
|
||||
initModules();
|
||||
|
@ -569,16 +569,6 @@
|
|||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => innerVisible.value,
|
||||
(val) => {
|
||||
emit('update:visible', val);
|
||||
if (val) {
|
||||
initModules();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// 用例类型改变
|
||||
watch(
|
||||
() => caseType.value,
|
||||
|
@ -591,19 +581,9 @@
|
|||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.projectId,
|
||||
(val) => {
|
||||
if (val) {
|
||||
innerProject.value = val;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => innerProject.value,
|
||||
(val) => {
|
||||
emit('update:project', val);
|
||||
() => {
|
||||
if (innerVisible.value) {
|
||||
searchCase();
|
||||
resetSelector();
|
||||
|
|
|
@ -71,6 +71,7 @@
|
|||
v-model:model-value="item.enable"
|
||||
size="small"
|
||||
:before-change="() => handleBeforeEnableChange(item)"
|
||||
type="line"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
size="small"
|
||||
:disabled="apiConfig.id === '' || testApiLoading"
|
||||
:before-change="(val) => handleApiPriorityBeforeChange(val)"
|
||||
type="line"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -86,6 +87,7 @@
|
|||
size="small"
|
||||
:disabled="uiConfig.id === '' || testUiLoading"
|
||||
:before-change="(val) => handleUiPriorityBeforeChange(val)"
|
||||
type="line"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -416,6 +416,8 @@
|
|||
width: calc(100% - 8px);
|
||||
}
|
||||
.arco-tree-node-drag-icon {
|
||||
@apply cursor-move;
|
||||
|
||||
right: 4px;
|
||||
.arco-icon {
|
||||
font-size: 14px;
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
:default-value="(defaultValue as number)"
|
||||
@change="handleChange"
|
||||
/>
|
||||
<a-switch v-else :default-checked="(defaultValue as boolean)" size="small" @change="handleChange" />
|
||||
<a-switch v-else :default-checked="(defaultValue as boolean)" size="small" type="line" @change="handleChange" />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<div ref="fullRef" class="rounded-[4px] bg-[var(--color-fill-1)] p-[12px]">
|
||||
<div class="mb-[12px] flex justify-between pr-[12px]">
|
||||
<div ref="fullRef" class="h-full rounded-[4px] bg-[var(--color-fill-1)] p-[12px]">
|
||||
<div v-if="showTitleLine" class="mb-[12px] flex justify-between pr-[12px]">
|
||||
<slot name="title">
|
||||
<span class="font-medium">{{ title }}</span>
|
||||
</slot>
|
||||
|
@ -19,7 +19,8 @@
|
|||
{{ t('msCodeEditor.fullScreen') }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex w-full flex-row">
|
||||
<!-- 这里的 32px 是顶部标题的 32px -->
|
||||
<div :class="`flex ${showTitleLine ? 'h-[calc(100%-32px)]' : 'h-full'} w-full flex-row`">
|
||||
<div ref="codeEditBox" :class="['ms-code-editor', isFullscreen ? 'ms-code-editor-full-screen' : '']"></div>
|
||||
<slot name="rightBox"> </slot>
|
||||
</div>
|
||||
|
@ -27,7 +28,7 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, onBeforeUnmount, onMounted, ref, watch } from 'vue';
|
||||
import { computed, defineComponent, onBeforeUnmount, onMounted, ref, watch } from 'vue';
|
||||
import { useFullscreen } from '@vueuse/core';
|
||||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
|
@ -36,8 +37,6 @@
|
|||
import MsCodeEditorTheme from './themes';
|
||||
import { CustomTheme, editorProps, Theme } from './types';
|
||||
import * as monaco from 'monaco-editor/esm/vs/editor/editor.api';
|
||||
import prettier from 'prettier';
|
||||
import parserBabel from 'prettier/parser-babel';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'MonacoEditor',
|
||||
|
@ -60,6 +59,7 @@
|
|||
value: item,
|
||||
}))
|
||||
);
|
||||
const showTitleLine = computed(() => props.title || props.showThemeChange || props.showFullScreen);
|
||||
|
||||
watch(
|
||||
() => props.theme,
|
||||
|
@ -167,6 +167,7 @@
|
|||
isFullscreen,
|
||||
currentTheme,
|
||||
themeOptions,
|
||||
showTitleLine,
|
||||
toggle,
|
||||
t,
|
||||
handleThemeChange,
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
<slot name="footer">
|
||||
<div class="flex" :class="[props.switchProps?.showSwitch ? 'justify-between' : 'justify-end']">
|
||||
<div v-if="props.switchProps?.showSwitch" class="flex flex-row items-center justify-center">
|
||||
<a-switch v-model="switchEnable" class="mr-1" size="small" />
|
||||
<a-switch v-model="switchEnable" class="mr-1" size="small" type="line" />
|
||||
<a-tooltip v-if="props.switchProps?.switchTooltip" :content="t(props.switchProps?.switchTooltip)">
|
||||
<span class="flex items-center">
|
||||
<span class="mr-1">{{ props.switchProps?.switchName }}</span>
|
||||
|
|
|
@ -117,6 +117,7 @@
|
|||
* @description 系统管理-模版-模版管理-创建模板-添加字段到模板抽屉
|
||||
*/
|
||||
import { computed, ref } from 'vue';
|
||||
import { VueDraggable } from 'vue-draggable-plus';
|
||||
|
||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||
import MsDrawer from '@/components/pure/ms-drawer/index.vue';
|
||||
|
@ -125,7 +126,6 @@
|
|||
import { useI18n } from '@/hooks/useI18n';
|
||||
|
||||
import { MsExportDrawerMap, MsExportDrawerOption } from './types';
|
||||
import { VueDraggable } from 'vue-draggable-plus';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
|
|
|
@ -3,38 +3,45 @@
|
|||
v-bind="props"
|
||||
ref="listRef"
|
||||
:data="data"
|
||||
:class="['ms-list', containerStatusClass]"
|
||||
:class="['ms-list', containerStatusClass, props.class]"
|
||||
@reach-bottom="handleReachBottom"
|
||||
>
|
||||
<template #item="{ item, index }">
|
||||
<slot name="item" :item="item" :index="index">
|
||||
<div
|
||||
:key="index"
|
||||
:key="item.id"
|
||||
:class="[
|
||||
'ms-list-item',
|
||||
props.noHover ? 'ms-list-item--no-hover' : '',
|
||||
props.itemBorder ? 'ms-list-item--bordered' : '',
|
||||
props.itemClass,
|
||||
innerFocusItemKey === item[itemKeyField] ? 'ms-list-item--focus' : '',
|
||||
innerActiveItemKey === item[itemKeyField] ? props.activeItemClass : '',
|
||||
]"
|
||||
@click="emit('itemClick', item, index)"
|
||||
>
|
||||
<slot name="title" :item="item" :index="index"></slot>
|
||||
<div
|
||||
v-if="$slots['itemAction'] || (props.itemMoreActions && props.itemMoreActions.length > 0)"
|
||||
class="ms-list-item-actions"
|
||||
>
|
||||
<slot name="itemAction" :item="item" :index="index"></slot>
|
||||
<MsTableMoreAction
|
||||
v-if="props.itemMoreActions && props.itemMoreActions.length > 0"
|
||||
:list="props.itemMoreActions"
|
||||
trigger="click"
|
||||
@select="handleMoreActionSelect($event, item)"
|
||||
@close="handleMoreActionClose"
|
||||
<div class="flex-1" @click="emit('itemClick', item, index)">
|
||||
<slot name="title" :item="item" :index="index"></slot>
|
||||
</div>
|
||||
<div class="flex items-center gap-[4px]">
|
||||
<icon-drag-dot-vertical v-if="props.draggable" class="ms-list-drag-icon" />
|
||||
<div
|
||||
v-if="$slots['itemAction'] || (props.itemMoreActions && props.itemMoreActions.length > 0)"
|
||||
class="ms-list-item-actions"
|
||||
>
|
||||
<MsButton type="icon" size="mini" class="ms-list-item-actions-btn" @click="handleClickMore(item)">
|
||||
<MsIcon type="icon-icon_more_outlined" size="14" class="text-[var(--color-text-4)]" />
|
||||
</MsButton>
|
||||
</MsTableMoreAction>
|
||||
<slot name="itemAction" :item="item" :index="index"></slot>
|
||||
<MsTableMoreAction
|
||||
v-if="props.itemMoreActions && props.itemMoreActions.length > 0"
|
||||
:list="props.itemMoreActions"
|
||||
trigger="click"
|
||||
@select="handleMoreActionSelect($event, item)"
|
||||
@close="handleMoreActionClose"
|
||||
>
|
||||
<MsButton type="icon" size="mini" class="ms-list-item-actions-btn" @click="handleClickMore(item)">
|
||||
<MsIcon type="icon-icon_more_outlined" size="14" class="text-[var(--color-text-4)]" />
|
||||
</MsButton>
|
||||
</MsTableMoreAction>
|
||||
</div>
|
||||
<slot name="itemRight" :item="item" :index="index"></slot>
|
||||
</div>
|
||||
<div
|
||||
v-if="props.mode === 'remote' && index === props.data.length - 1"
|
||||
|
@ -60,6 +67,8 @@
|
|||
|
||||
<script setup lang="ts">
|
||||
import { nextTick, Ref, ref, watch } from 'vue';
|
||||
import { useVModel } from '@vueuse/core';
|
||||
import { useDraggable } from 'vue-draggable-plus';
|
||||
|
||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||
import MsIcon from '@/components/pure/ms-icon-font/index.vue';
|
||||
|
@ -69,10 +78,14 @@
|
|||
import useContainerShadow from '@/hooks/useContainerShadow';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
|
||||
import type { VirtualListProps } from '@arco-design/web-vue/es/_components/virtual-list-v2/interface';
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
mode?: 'static' | 'remote'; // 静态数据或者远程数据
|
||||
data: Record<string, any>[];
|
||||
bordered?: boolean; // 是否显示边框
|
||||
activeItemKey?: string | number; // 当前选中的项的 key
|
||||
focusItemKey?: string | number; // 聚焦的项的 key
|
||||
itemMoreActions?: ActionsItem[]; // 每一项的更多操作
|
||||
itemKeyField?: string; // 唯一值 key 的字段名,默认为 key
|
||||
|
@ -81,16 +94,25 @@
|
|||
noMoreData?: boolean; // 远程模式下,是否没有更多数据
|
||||
noHover?: boolean; // 是否不显示列表项的 hover 效果
|
||||
itemBorder?: boolean; // 是否显示列表项的边框
|
||||
class?: string;
|
||||
itemClass?: string;
|
||||
activeItemClass?: string;
|
||||
draggable?: boolean;
|
||||
virtualListProps?: VirtualListProps;
|
||||
}>(),
|
||||
{
|
||||
mode: 'static',
|
||||
itemKeyField: 'key',
|
||||
itemHeight: 20,
|
||||
bordered: false,
|
||||
draggable: false,
|
||||
}
|
||||
);
|
||||
|
||||
const emit = defineEmits([
|
||||
'update:data',
|
||||
'update:focusItemKey',
|
||||
'update:activeItemKey',
|
||||
'itemClick',
|
||||
'close',
|
||||
'moreActionSelect',
|
||||
|
@ -101,21 +123,9 @@
|
|||
|
||||
const { t } = useI18n();
|
||||
|
||||
const innerFocusItemKey = ref(props.focusItemKey || ''); // 聚焦的节点,一般用于在操作扩展按钮时,高亮当前节点,保持扩展按钮持续显示
|
||||
|
||||
watch(
|
||||
() => props.focusItemKey,
|
||||
(val) => {
|
||||
innerFocusItemKey.value = val || '';
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => innerFocusItemKey.value,
|
||||
(val) => {
|
||||
emit('update:focusItemKey', val);
|
||||
}
|
||||
);
|
||||
const innerFocusItemKey = useVModel(props, 'focusItemKey', emit); // 聚焦的节点,一般用于在操作扩展按钮时,高亮当前节点,保持扩展按钮持续显示
|
||||
const innerActiveItemKey = useVModel(props, 'activeItemKey', emit); // 激活的节点,搭配activeItemClass使用,用于高亮当前节点
|
||||
const innerData = useVModel(props, 'data', emit);
|
||||
|
||||
const popVisible = ref(false);
|
||||
|
||||
|
@ -148,6 +158,21 @@
|
|||
props.data,
|
||||
() => {
|
||||
if (props.data.length > 0 && !isInitListener.value) {
|
||||
// 如果数据不为空,且没有初始化容器的滚动监听器
|
||||
if (props.draggable) {
|
||||
// 如果开启拖拽
|
||||
if (props.virtualListProps) {
|
||||
// 如果开启虚拟滚动,需要将拖拽的容器设置为虚拟滚动的容器
|
||||
useDraggable('.arco-list-content div div', innerData, {
|
||||
ghostClass: 'ms-list-ghost',
|
||||
});
|
||||
} else {
|
||||
// 否则直接设置为列表容器
|
||||
useDraggable('.arco-list-content', innerData, {
|
||||
ghostClass: 'ms-list-ghost',
|
||||
});
|
||||
}
|
||||
}
|
||||
nextTick(() => {
|
||||
const listContent = listRef.value?.$el.querySelector('.arco-list-content');
|
||||
setContainer(listContent);
|
||||
|
@ -179,10 +204,16 @@
|
|||
border-radius: var(--border-radius-small);
|
||||
&:hover {
|
||||
background-color: rgb(var(--primary-1));
|
||||
.ms-list-drag-icon {
|
||||
@apply visible;
|
||||
}
|
||||
.ms-list-item-actions {
|
||||
@apply visible;
|
||||
}
|
||||
}
|
||||
.ms-list-drag-icon {
|
||||
@apply invisible cursor-move;
|
||||
}
|
||||
.ms-list-item-actions {
|
||||
@apply invisible flex items-center justify-end;
|
||||
.ms-list-item-actions-btn {
|
||||
|
@ -221,5 +252,16 @@
|
|||
margin-right: 4px;
|
||||
}
|
||||
}
|
||||
:deep(.arco-scrollbar),
|
||||
:deep(.arco-list),
|
||||
:deep(.arco-list-content-wrapper) {
|
||||
@apply h-full;
|
||||
}
|
||||
:deep(.arco-list-content) {
|
||||
.ms-scroll-bar();
|
||||
}
|
||||
}
|
||||
.ms-list-ghost {
|
||||
opacity: 0.5;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -55,7 +55,7 @@
|
|||
>
|
||||
<template #title>
|
||||
<div class="flex w-full flex-row flex-nowrap items-center">
|
||||
<slot :name="item.titleSlotName">
|
||||
<slot :name="item.titleSlotName" :column-config="item">
|
||||
<div class="text-[var(--color-text-3)]">{{ t(item.title as string) }}</div>
|
||||
</slot>
|
||||
<icon-settings
|
||||
|
@ -96,7 +96,7 @@
|
|||
<template
|
||||
v-if="!record[item.dataIndex as string] || (Array.isArray(record[item.dataIndex as string]) && record[item.dataIndex as string].length === 0)"
|
||||
>
|
||||
<slot :name="item.slotName" v-bind="{ record, rowIndex, column }"> - </slot>
|
||||
<slot :name="item.slotName" v-bind="{ record, rowIndex, column, columnConfig: item }"> - </slot>
|
||||
</template>
|
||||
<MsTagGroup
|
||||
v-else
|
||||
|
@ -107,7 +107,7 @@
|
|||
/>
|
||||
</template>
|
||||
<template v-else-if="item.slotName === SpecialColumnEnum.OPERATION">
|
||||
<slot name="operation" v-bind="{ record, rowIndex }" />
|
||||
<slot name="operation" v-bind="{ record, rowIndex, columnConfig: item }" />
|
||||
</template>
|
||||
<template v-else-if="item.slotName === SpecialColumnEnum.ACTION">
|
||||
<slot name="action" v-bind="{ record, rowIndex }" />
|
||||
|
@ -126,7 +126,7 @@
|
|||
/>
|
||||
<a-tooltip v-else placement="top" :content="String(record[item.dataIndex as string])">
|
||||
<div class="one-line-text max-w-[300px]">
|
||||
<slot :name="item.slotName" v-bind="{ record, rowIndex, column }">
|
||||
<slot :name="item.slotName" v-bind="{ record, rowIndex, column, columnConfig: item }">
|
||||
{{ record[item.dataIndex as string] || (attrs.emptyDataShowLine ? '-' : '') }}
|
||||
</slot>
|
||||
</div>
|
||||
|
@ -146,11 +146,14 @@
|
|||
/>
|
||||
</div>
|
||||
<div>
|
||||
<slot :name="item.revokeDeletedSlot" v-bind="{ record, rowIndex, column }"></slot>
|
||||
<slot :name="item.revokeDeletedSlot" v-bind="{ record, rowIndex, column, columnConfig: item }"></slot>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<slot :name="item.slotName" v-bind="{ record, rowIndex, column, dataIndex: item.dataIndex }">
|
||||
<slot
|
||||
:name="item.slotName"
|
||||
v-bind="{ record, rowIndex, column, dataIndex: item.dataIndex, columnConfig: item }"
|
||||
>
|
||||
{{ record[item.dataIndex as string] || (attrs.emptyDataShowLine ? '-' : '') }}
|
||||
</slot>
|
||||
</template>
|
||||
|
|
|
@ -58,6 +58,7 @@
|
|||
v-model="item.showInTable"
|
||||
size="small"
|
||||
:disabled="item.dataIndex === 'name' || item.dataIndex === 'operation'"
|
||||
type="line"
|
||||
@change="handleSwitchChange"
|
||||
/>
|
||||
</div>
|
||||
|
@ -73,7 +74,7 @@
|
|||
<MsIcon type="icon-icon_drag" class="text-[16px] text-[var(--color-text-4)]" />
|
||||
<span class="ml-[8px]">{{ t((element.title || element.columnTitle) as string) }}</span>
|
||||
</div>
|
||||
<a-switch v-model="element.showInTable" size="small" @update="handleSwitchChange" />
|
||||
<a-switch v-model="element.showInTable" size="small" type="line" @update="handleSwitchChange" />
|
||||
</div>
|
||||
</VueDraggable>
|
||||
</div>
|
||||
|
@ -82,6 +83,7 @@
|
|||
|
||||
<script lang="ts" setup>
|
||||
import { onBeforeMount, ref } from 'vue';
|
||||
import { VueDraggable } from 'vue-draggable-plus';
|
||||
|
||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||
import MsDrawer from '@/components/pure/ms-drawer/index.vue';
|
||||
|
@ -93,7 +95,6 @@
|
|||
import { TableOpenDetailMode } from '@/store/modules/components/ms-table/types';
|
||||
|
||||
import { MsTableColumn } from './type';
|
||||
import { VueDraggable } from 'vue-draggable-plus';
|
||||
|
||||
const tableStore = useTableStore();
|
||||
const { t } = useI18n();
|
||||
|
|
|
@ -51,6 +51,8 @@ export interface MsTableColumnData extends TableColumnData {
|
|||
columnTitle?: string;
|
||||
// 是否是自定义字段
|
||||
isCustomParam?: boolean;
|
||||
// 自定义属性
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
export type MsTableErrorStatus = boolean | 'error' | 'empty';
|
||||
|
|
|
@ -48,7 +48,7 @@
|
|||
allowClear: true,
|
||||
}
|
||||
);
|
||||
const emit = defineEmits(['update:modelValue', 'update:inputValue']);
|
||||
const emit = defineEmits(['update:modelValue', 'update:inputValue', 'change']);
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
|
@ -72,6 +72,7 @@
|
|||
tagsLength.value = val.length;
|
||||
}
|
||||
emit('update:modelValue', val);
|
||||
emit('change', val);
|
||||
}
|
||||
);
|
||||
|
||||
|
|
|
@ -113,66 +113,6 @@
|
|||
</template>
|
||||
</a-dropdown>
|
||||
</li>
|
||||
<!-- <li>
|
||||
<a-tooltip :content="isFullscreen ? t('settings.navbar.screen.toExit') : t('settings.navbar.screen.toFull')">
|
||||
<a-button class="nav-btn" type="outline" :shape="'circle'" @click="toggleFullScreen">
|
||||
<template #icon>
|
||||
<icon-fullscreen-exit v-if="isFullscreen" />
|
||||
<icon-fullscreen v-else />
|
||||
</template>
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
</li> -->
|
||||
<!-- <li>
|
||||
<a-tooltip :content="t('settings.title')">
|
||||
<a-button class="nav-btn" type="outline" :shape="'circle'" @click="setVisible">
|
||||
<template #icon>
|
||||
<icon-settings />
|
||||
</template>
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
</li> -->
|
||||
<!-- <li>
|
||||
<a-dropdown trigger="click">
|
||||
<a-avatar :size="32" :style="{ marginRight: '8px', cursor: 'pointer' }">
|
||||
<img alt="avatar" :src="avatar" />
|
||||
</a-avatar>
|
||||
<template #content>
|
||||
<a-doption>
|
||||
<a-space @click="switchRoles">
|
||||
<icon-tag />
|
||||
<span>
|
||||
{{ t('messageBox.switchRoles') }}
|
||||
</span>
|
||||
</a-space>
|
||||
</a-doption>
|
||||
<a-doption>
|
||||
<a-space @click="$router.push({ name: 'Info' })">
|
||||
<icon-user />
|
||||
<span>
|
||||
{{ t('messageBox.userCenter') }}
|
||||
</span>
|
||||
</a-space>
|
||||
</a-doption>
|
||||
<a-doption>
|
||||
<a-space @click="$router.push({ name: 'Setting' })">
|
||||
<icon-settings />
|
||||
<span>
|
||||
{{ t('messageBox.userSettings') }}
|
||||
</span>
|
||||
</a-space>
|
||||
</a-doption>
|
||||
<a-doption>
|
||||
<a-space @click="handleLogout">
|
||||
<icon-export />
|
||||
<span>
|
||||
{{ t('messageBox.logout') }}
|
||||
</span>
|
||||
</a-space>
|
||||
</a-doption>
|
||||
</template>
|
||||
</a-dropdown>
|
||||
</li> -->
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -181,19 +121,17 @@
|
|||
import { computed, onBeforeMount, Ref, ref, watch } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
|
||||
// import useUser from '@/hooks/useUser';
|
||||
import TopMenu from '@/components/business/ms-top-menu/index.vue';
|
||||
import MessageBox from '../message-box/index.vue';
|
||||
|
||||
import { getProjectList } from '@/api/modules/project-management/project';
|
||||
import { getProjectList, switchProject } from '@/api/modules/project-management/project';
|
||||
import { MENU_LEVEL, type PathMapRoute } from '@/config/pathMap';
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import usePathMap from '@/hooks/usePathMap';
|
||||
import { LOCALE_OPTIONS } from '@/locale';
|
||||
import useLocale from '@/locale/useLocale';
|
||||
// import { Message } from '@arco-design/web-vue';
|
||||
// import { useFullscreen } from '@vueuse/core';
|
||||
import { useAppStore } from '@/store';
|
||||
import useAppStore from '@/store/modules/app';
|
||||
import useUserStore from '@/store/modules/user';
|
||||
|
||||
import type { ProjectListItem } from '@/models/setting/project';
|
||||
|
||||
|
@ -206,7 +144,7 @@
|
|||
}>();
|
||||
|
||||
const appStore = useAppStore();
|
||||
// const { logout } = useUser();
|
||||
const userStore = useUserStore();
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const { t } = useI18n();
|
||||
|
@ -240,18 +178,28 @@
|
|||
return getRouteLevelByKey(route.name as PathMapRoute) === MENU_LEVEL[2];
|
||||
});
|
||||
|
||||
function selectProject(
|
||||
async function selectProject(
|
||||
value: string | number | boolean | Record<string, any> | (string | number | boolean | Record<string, any>)[]
|
||||
) {
|
||||
appStore.setCurrentProjectId(value as string);
|
||||
router.replace({
|
||||
path: route.path,
|
||||
query: {
|
||||
...route.query,
|
||||
organizationId: appStore.currentOrgId,
|
||||
projectId: appStore.currentProjectId,
|
||||
},
|
||||
});
|
||||
try {
|
||||
await switchProject({
|
||||
projectId: value as string,
|
||||
userId: userStore.id || '',
|
||||
});
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(error);
|
||||
} finally {
|
||||
router.replace({
|
||||
path: route.path,
|
||||
query: {
|
||||
...route.query,
|
||||
organizationId: appStore.currentOrgId,
|
||||
projectId: appStore.currentProjectId,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const helpCenterList = [
|
||||
|
@ -278,14 +226,8 @@
|
|||
];
|
||||
|
||||
const { changeLocale, currentLocale } = useLocale();
|
||||
// const { isFullscreen, toggle: toggleFullScreen } = useFullscreen();
|
||||
const locales = [...LOCALE_OPTIONS];
|
||||
// const avatar = computed(() => {
|
||||
// return userStore.avatar;
|
||||
// });
|
||||
// const setVisible = () => {
|
||||
// appStore.updateSettings({ globalSettings: true });
|
||||
// };
|
||||
|
||||
const refBtn = ref();
|
||||
const setPopoverVisible = () => {
|
||||
const event = new MouseEvent('click', {
|
||||
|
@ -295,13 +237,6 @@
|
|||
});
|
||||
refBtn.value.dispatchEvent(event);
|
||||
};
|
||||
// const handleLogout = () => {
|
||||
// logout();
|
||||
// };
|
||||
// const switchRoles = async () => {
|
||||
// const res = await userStore.switchRoles();
|
||||
// Message.success(res as string);
|
||||
// };
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
|
|
|
@ -92,4 +92,7 @@ export default {
|
|||
'common.file': 'File',
|
||||
'common.desc': 'Description',
|
||||
'common.root': 'Default Module',
|
||||
'common.revoke': 'Revoke',
|
||||
'common.clear': 'Clear',
|
||||
'common.tag': 'Tag',
|
||||
};
|
||||
|
|
|
@ -93,4 +93,7 @@ export default {
|
|||
'common.file': '文件',
|
||||
'common.desc': '描述',
|
||||
'common.root': '默认模块',
|
||||
'common.revoke': '撤销',
|
||||
'common.clear': '清空',
|
||||
'common.tag': '标签',
|
||||
};
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
<template>
|
||||
<MsBaseTable v-bind="propsRes" id="headerTable" :hoverable="false" v-on="propsEvent">
|
||||
<MsBaseTable v-bind="propsRes" id="headerTable" :hoverable="false" no-disable v-on="propsEvent">
|
||||
<!-- 表格头 slot -->
|
||||
<template #encodeTitle>
|
||||
<div class="flex items-center text-[var(--color-text-3)]">
|
||||
{{ t('apiTestDebug.encode') }}
|
||||
<a-tooltip>
|
||||
<a-tooltip position="right">
|
||||
<icon-question-circle
|
||||
class="ml-[4px] text-[var(--color-text-brand)] hover:text-[rgb(var(--primary-5))]"
|
||||
size="16"
|
||||
|
@ -15,6 +16,18 @@
|
|||
</a-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
<template #typeTitle="{ columnConfig }">
|
||||
<div class="flex items-center text-[var(--color-text-3)]">
|
||||
{{ t('apiTestDebug.paramType') }}
|
||||
<a-tooltip :content="columnConfig.typeTitleTooltip" position="right">
|
||||
<icon-question-circle
|
||||
class="ml-[4px] text-[var(--color-text-brand)] hover:text-[rgb(var(--primary-5))]"
|
||||
size="16"
|
||||
/>
|
||||
</a-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
<!-- 表格列 slot -->
|
||||
<template #name="{ record }">
|
||||
<a-popover position="tl" :disabled="!record.name || record.name.trim() === ''" class="ms-params-input-popover">
|
||||
<template #content>
|
||||
|
@ -33,8 +46,11 @@
|
|||
/>
|
||||
</a-popover>
|
||||
</template>
|
||||
<template #type="{ record }">
|
||||
<a-tooltip :content="t(record.required ? 'apiTestDebug.paramRequired' : 'apiTestDebug.paramNotRequired')">
|
||||
<template #type="{ record, columnConfig }">
|
||||
<a-tooltip
|
||||
v-if="columnConfig.hasRequired"
|
||||
:content="t(record.required ? 'apiTestDebug.paramRequired' : 'apiTestDebug.paramNotRequired')"
|
||||
>
|
||||
<MsButton
|
||||
type="icon"
|
||||
:class="[
|
||||
|
@ -48,13 +64,35 @@
|
|||
</a-tooltip>
|
||||
<a-select
|
||||
v-model:model-value="record.type"
|
||||
:options="typeOptions"
|
||||
:options="columnConfig.typeOptions || []"
|
||||
class="param-input"
|
||||
@change="(val) => handleTypeChange(val, record)"
|
||||
></a-select>
|
||||
/>
|
||||
</template>
|
||||
<template #value="{ record }">
|
||||
<template #value="{ record, columnConfig }">
|
||||
<a-popover
|
||||
v-if="columnConfig.isNormal"
|
||||
position="tl"
|
||||
:disabled="!record.value || record.value.trim() === ''"
|
||||
class="ms-params-input-popover"
|
||||
>
|
||||
<template #content>
|
||||
<div class="param-popover-title">
|
||||
{{ t('apiTestDebug.paramValue') }}
|
||||
</div>
|
||||
<div class="param-popover-value">
|
||||
{{ record.value }}
|
||||
</div>
|
||||
</template>
|
||||
<a-input
|
||||
v-model:model-value="record.value"
|
||||
class="param-input"
|
||||
:placeholder="t('apiTestDebug.commonPlaceholder')"
|
||||
@input="(val) => addTableLine(val)"
|
||||
/>
|
||||
</a-popover>
|
||||
<MsParamsInput
|
||||
v-else
|
||||
v-model:value="record.value"
|
||||
@change="addTableLine"
|
||||
@dblclick="quickInputParams(record)"
|
||||
|
@ -78,6 +116,19 @@
|
|||
></a-input-number>
|
||||
</div>
|
||||
</template>
|
||||
<template #tag="{ record }">
|
||||
<a-popover position="tl" :disabled="record.tag.length === 0" class="ms-params-input-popover">
|
||||
<template #content>
|
||||
<div class="param-popover-title">
|
||||
{{ t('common.tag') }}
|
||||
</div>
|
||||
<div class="param-popover-value">
|
||||
<MsTagsGroup is-string-tag :tag-list="record.tag" />
|
||||
</div>
|
||||
</template>
|
||||
<MsTagsInput v-model:model-value="record.tag" :max-tag-count="1" class="param-input" @change="addTableLine" />
|
||||
</a-popover>
|
||||
</template>
|
||||
<template #desc="{ record }">
|
||||
<paramDescInput
|
||||
v-model:desc="record.desc"
|
||||
|
@ -91,12 +142,16 @@
|
|||
v-model:model-value="record.encode"
|
||||
size="small"
|
||||
class="param-input-switch"
|
||||
type="line"
|
||||
@change="(val) => addTableLine(val.toString())"
|
||||
></a-switch>
|
||||
/>
|
||||
</template>
|
||||
<template #operation="{ record, rowIndex }">
|
||||
<template #mustContain="{ record }">
|
||||
<a-checkbox v-model:model-value="record.mustContain" @change="(val) => addTableLine(val)" />
|
||||
</template>
|
||||
<template #operation="{ record, rowIndex, columnConfig }">
|
||||
<a-trigger
|
||||
v-if="props.format && props.format !== RequestBodyFormat.X_WWW_FORM_URLENCODED"
|
||||
v-if="columnConfig.format && columnConfig.format !== RequestBodyFormat.X_WWW_FORM_URLENCODED"
|
||||
trigger="click"
|
||||
position="br"
|
||||
>
|
||||
|
@ -109,10 +164,17 @@
|
|||
:options="Object.values(RequestContentTypeEnum).map((e) => ({ label: e, value: e }))"
|
||||
allow-create
|
||||
@change="(val) => addTableLine(val as string)"
|
||||
></a-select>
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</a-trigger>
|
||||
<a-switch
|
||||
v-if="columnConfig.hasEnable"
|
||||
v-model:model-value="record.enable"
|
||||
size="small"
|
||||
type="line"
|
||||
@change="(val) => addTableLine(val)"
|
||||
/>
|
||||
<icon-minus-circle
|
||||
v-if="paramsLength > 1 && rowIndex !== paramsLength - 1"
|
||||
class="cursor-pointer text-[var(--color-text-4)]"
|
||||
|
@ -120,14 +182,12 @@
|
|||
@click="deleteParam(rowIndex)"
|
||||
/>
|
||||
</template>
|
||||
<template #mustContain="{ record }">
|
||||
<a-checkbox v-model:model-value="record.mustContain"></a-checkbox>
|
||||
</template>
|
||||
</MsBaseTable>
|
||||
<a-modal
|
||||
v-model:visible="showQuickInputParam"
|
||||
:title="t('ms.paramsInput.value')"
|
||||
:ok-text="t('apiTestDebug.apply')"
|
||||
:ok-button-props="{ disabled: !quickInputParamValue || quickInputParamValue.trim() === '' }"
|
||||
class="ms-modal-form"
|
||||
body-class="!p-0"
|
||||
:width="680"
|
||||
|
@ -177,14 +237,18 @@
|
|||
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||
import MsCodeEditor from '@/components/pure/ms-code-editor/index.vue';
|
||||
import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
|
||||
import type { MsTableColumn } from '@/components/pure/ms-table/type';
|
||||
import type { MsTableColumnData } from '@/components/pure/ms-table/type';
|
||||
import useTable from '@/components/pure/ms-table/useTable';
|
||||
import MsTagsGroup from '@/components/pure/ms-tag/ms-tag-group.vue';
|
||||
import MsTagsInput from '@/components/pure/ms-tags-input/index.vue';
|
||||
import MsParamsInput from '@/components/business/ms-params-input/index.vue';
|
||||
import paramDescInput from './paramDescInput.vue';
|
||||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import useTableStore from '@/hooks/useTableStore';
|
||||
|
||||
import { RequestBodyFormat, RequestContentTypeEnum } from '@/enums/apiEnum';
|
||||
import { TableKeyEnum } from '@/enums/tableEnum';
|
||||
|
||||
interface Param {
|
||||
id: number;
|
||||
|
@ -197,21 +261,60 @@
|
|||
contentType: RequestContentTypeEnum;
|
||||
desc: string;
|
||||
encode: boolean;
|
||||
tag: string[];
|
||||
enable: boolean;
|
||||
mustContain: boolean;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
const props = defineProps<{
|
||||
params: any[];
|
||||
columns: MsTableColumn;
|
||||
format?: RequestBodyFormat | 'query' | 'rest';
|
||||
scroll?: {
|
||||
x?: number | string;
|
||||
y?: number | string;
|
||||
maxHeight?: number | string;
|
||||
minWidth?: number | string;
|
||||
};
|
||||
heightUsed?: number;
|
||||
}>();
|
||||
export type ParamTableColumn = MsTableColumnData & {
|
||||
isNormal?: boolean; // 用于 value 列区分是普通输入框还是 MsParamsInput
|
||||
hasRequired?: boolean; // 用于 type 列区分是否有 required 星号
|
||||
typeOptions?: { label: string; value: string }[]; // 用于 type 列选择器选项
|
||||
typeTitleTooltip?: string; // 用于 type 表头列展示的 tooltip
|
||||
hasEnable?: boolean; // 用于 operation 列区分是否有 enable 开关
|
||||
format?: RequestBodyFormat | 'query' | 'rest'; // 用于 operation 列区分是否有请求体格式选择器
|
||||
};
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
params: any[];
|
||||
defaultParamItem?: Partial<Param>; // 默认参数项,用于添加新行时的默认值
|
||||
columns: ParamTableColumn[];
|
||||
scroll?: {
|
||||
x?: number | string;
|
||||
y?: number | string;
|
||||
maxHeight?: number | string;
|
||||
minWidth?: number | string;
|
||||
};
|
||||
heightUsed?: number;
|
||||
draggable?: boolean;
|
||||
selectable?: boolean;
|
||||
showSetting?: boolean; // 是否显示列设置
|
||||
tableKey?: TableKeyEnum; // 表格key showSetting为true时必传
|
||||
disabled?: boolean; // 是否禁用
|
||||
showSelectorAll?: boolean; // 是否显示全选
|
||||
}>(),
|
||||
{
|
||||
selectable: true,
|
||||
showSetting: false,
|
||||
tableKey: undefined,
|
||||
defaultParamItem: () => ({
|
||||
required: false,
|
||||
name: '',
|
||||
type: 'string',
|
||||
value: '',
|
||||
min: undefined,
|
||||
max: undefined,
|
||||
contentType: RequestContentTypeEnum.TEXT,
|
||||
tag: [],
|
||||
desc: '',
|
||||
encode: false,
|
||||
enable: false,
|
||||
mustContain: false,
|
||||
}),
|
||||
}
|
||||
);
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:params', value: any[]): void;
|
||||
(e: 'change', data: any[], isInit?: boolean): void;
|
||||
|
@ -219,60 +322,21 @@
|
|||
|
||||
const { t } = useI18n();
|
||||
|
||||
const defaultParams: Omit<Param, 'id'> = {
|
||||
required: false,
|
||||
name: '',
|
||||
type: 'string',
|
||||
value: '',
|
||||
min: undefined,
|
||||
max: undefined,
|
||||
contentType: RequestContentTypeEnum.TEXT,
|
||||
desc: '',
|
||||
encode: false,
|
||||
};
|
||||
const allType = [
|
||||
{
|
||||
label: 'string',
|
||||
value: 'string',
|
||||
},
|
||||
{
|
||||
label: 'integer',
|
||||
value: 'integer',
|
||||
},
|
||||
{
|
||||
label: 'number',
|
||||
value: 'number',
|
||||
},
|
||||
{
|
||||
label: 'array',
|
||||
value: 'array',
|
||||
},
|
||||
{
|
||||
label: 'json',
|
||||
value: 'json',
|
||||
},
|
||||
{
|
||||
label: 'file',
|
||||
value: 'file',
|
||||
},
|
||||
];
|
||||
const typeOptions = computed(() => {
|
||||
if (
|
||||
props.format === RequestBodyFormat.X_WWW_FORM_URLENCODED ||
|
||||
props.format === 'query' ||
|
||||
props.format === 'rest'
|
||||
) {
|
||||
return allType.filter((e) => e.value !== 'file' && e.value !== 'json');
|
||||
}
|
||||
return allType;
|
||||
});
|
||||
const tableStore = useTableStore();
|
||||
if (props.showSetting && props.tableKey) {
|
||||
await tableStore.initColumn(props.tableKey, props.columns);
|
||||
}
|
||||
|
||||
const { propsRes, propsEvent } = useTable(() => Promise.resolve([]), {
|
||||
tableKey: props.showSetting ? props.tableKey : undefined,
|
||||
scroll: props.scroll,
|
||||
heightUsed: props.heightUsed,
|
||||
columns: props.columns,
|
||||
selectable: true,
|
||||
draggable: { type: 'handle', width: 24 },
|
||||
selectable: props.selectable,
|
||||
draggable: props.draggable ? { type: 'handle', width: 24 } : undefined,
|
||||
showSetting: props.showSetting,
|
||||
disabled: props.disabled,
|
||||
showSelectorAll: props.showSelectorAll,
|
||||
});
|
||||
|
||||
watch(
|
||||
|
@ -282,16 +346,8 @@
|
|||
propsRes.value.data = val;
|
||||
} else {
|
||||
propsRes.value.data = props.params.concat({
|
||||
id: new Date().getTime(),
|
||||
required: false,
|
||||
name: '',
|
||||
type: 'string',
|
||||
value: '',
|
||||
min: undefined,
|
||||
max: undefined,
|
||||
contentType: RequestContentTypeEnum.TEXT,
|
||||
desc: '',
|
||||
encode: false,
|
||||
id: new Date().getTime(), // 默认给时间戳 id,若 props.defaultParamItem 有 id,则覆盖
|
||||
...props.defaultParamItem,
|
||||
});
|
||||
emit('change', propsRes.value.data, true);
|
||||
}
|
||||
|
@ -320,13 +376,15 @@
|
|||
* @param val 输入值
|
||||
* @param isForce 是否强制添加
|
||||
*/
|
||||
function addTableLine(val?: string | number, isForce?: boolean) {
|
||||
function addTableLine(val?: string | number | boolean | (string | number | boolean)[], isForce?: boolean) {
|
||||
const lastData = propsRes.value.data[propsRes.value.data.length - 1];
|
||||
const isNotChange = Object.keys(defaultParams).every((key) => lastData[key] === defaultParams[key as any]);
|
||||
const isNotChange = Object.keys(props.defaultParamItem).every(
|
||||
(key) => JSON.stringify(lastData[key]) === JSON.stringify(props.defaultParamItem[key])
|
||||
);
|
||||
if (isForce || (val !== '' && val !== undefined && !isNotChange)) {
|
||||
propsRes.value.data.push({
|
||||
id: new Date().getTime(),
|
||||
...defaultParams,
|
||||
...props.defaultParamItem,
|
||||
} as any);
|
||||
emit('change', propsRes.value.data);
|
||||
}
|
||||
|
@ -387,15 +445,18 @@
|
|||
|
||||
function handleTypeChange(
|
||||
val: string | number | boolean | Record<string, any> | (string | number | boolean | Record<string, any>)[],
|
||||
record: Param
|
||||
record: Partial<Param>
|
||||
) {
|
||||
addTableLine(val as string);
|
||||
if (val === 'file') {
|
||||
record.contentType = RequestContentTypeEnum.OCTET_STREAM;
|
||||
} else if (val === 'json') {
|
||||
record.contentType = RequestContentTypeEnum.JSON;
|
||||
} else {
|
||||
record.contentType = RequestContentTypeEnum.TEXT;
|
||||
// 根据参数类型自动推断 Content-Type 类型
|
||||
if (record.contentType) {
|
||||
if (val === 'file') {
|
||||
record.contentType = RequestContentTypeEnum.OCTET_STREAM;
|
||||
} else if (val === 'json') {
|
||||
record.contentType = RequestContentTypeEnum.JSON;
|
||||
} else {
|
||||
record.contentType = RequestContentTypeEnum.TEXT;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@ -424,9 +485,6 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
.param-input-switch:not(:hover).arco-switch-checked {
|
||||
background-color: rgb(var(--primary-3)) !important;
|
||||
}
|
||||
.content-type-trigger-content {
|
||||
@apply bg-white;
|
||||
|
||||
|
|
|
@ -8,20 +8,14 @@
|
|||
<a-radio value="digest">Digest Auth</a-radio>
|
||||
</a-radio-group>
|
||||
<a-form v-if="authForm.authType !== 'none'" ref="authFormRef" :model="authForm" layout="vertical">
|
||||
<a-form-item
|
||||
:label="t('apiTestDebug.account')"
|
||||
:rules="[{ required: true, message: t('apiTestDebug.accountRequired') }]"
|
||||
>
|
||||
<a-form-item :label="t('apiTestDebug.account')">
|
||||
<a-input
|
||||
v-model:model-value="authForm.account"
|
||||
:placeholder="t('apiTestDebug.commonPlaceholder')"
|
||||
class="w-[450px]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
:label="t('apiTestDebug.password')"
|
||||
:rules="[{ required: true, message: t('apiTestDebug.passwordRequired') }]"
|
||||
>
|
||||
<a-form-item :label="t('apiTestDebug.password')">
|
||||
<a-input-password
|
||||
v-model:model-value="authForm.password"
|
||||
autocomplete="new-password"
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
v-model:model-value="batchParamsCode"
|
||||
class="flex-1"
|
||||
theme="MS-text"
|
||||
height="calc(100% - 48px)"
|
||||
height="calc(100% - 12px)"
|
||||
:show-full-screen="false"
|
||||
>
|
||||
<template #title>
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
v-else-if="showParamTable"
|
||||
v-model:params="currentTableParams"
|
||||
:scroll="{ minWidth: 1160 }"
|
||||
:format="format"
|
||||
:columns="columns"
|
||||
:height-used="heightUsed"
|
||||
@change="handleParamTableChange"
|
||||
|
@ -33,7 +32,7 @@
|
|||
/>
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<a-switch v-model:model-value="innerParams.binarySend" class="mr-[8px]" size="small"></a-switch>
|
||||
<a-switch v-model:model-value="innerParams.binarySend" class="mr-[8px]" size="small" type="line"></a-switch>
|
||||
<span>{{ t('apiTestDebug.sendAsMainText') }}</span>
|
||||
<a-tooltip position="right">
|
||||
<template #content>
|
||||
|
@ -52,7 +51,7 @@
|
|||
v-model:model-value="currentBodyCode"
|
||||
class="flex-1"
|
||||
theme="vs-dark"
|
||||
height="calc(100% - 48px)"
|
||||
height="calc(100% - 12px)"
|
||||
:show-full-screen="false"
|
||||
:language="currentCodeLanguage"
|
||||
>
|
||||
|
@ -74,8 +73,7 @@
|
|||
import { useVModel } from '@vueuse/core';
|
||||
|
||||
import MsCodeEditor from '@/components/pure/ms-code-editor/index.vue';
|
||||
import { MsTableColumn } from '@/components/pure/ms-table/type';
|
||||
import paramTable from '../../../components/paramTable.vue';
|
||||
import paramTable, { type ParamTableColumn } from '../../../components/paramTable.vue';
|
||||
import batchAddKeyVal from './batchAddKeyVal.vue';
|
||||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
|
@ -107,7 +105,7 @@
|
|||
|
||||
const innerParams = useVModel(props, 'params', emit);
|
||||
|
||||
const columns: MsTableColumn = [
|
||||
const columns: ParamTableColumn[] = [
|
||||
{
|
||||
title: 'apiTestDebug.paramName',
|
||||
dataIndex: 'name',
|
||||
|
@ -117,6 +115,33 @@
|
|||
title: 'apiTestDebug.paramType',
|
||||
dataIndex: 'type',
|
||||
slotName: 'type',
|
||||
hasRequired: true,
|
||||
typeOptions: [
|
||||
{
|
||||
label: 'string',
|
||||
value: 'string',
|
||||
},
|
||||
{
|
||||
label: 'integer',
|
||||
value: 'integer',
|
||||
},
|
||||
{
|
||||
label: 'number',
|
||||
value: 'number',
|
||||
},
|
||||
{
|
||||
label: 'array',
|
||||
value: 'array',
|
||||
},
|
||||
{
|
||||
label: 'json',
|
||||
value: 'json',
|
||||
},
|
||||
{
|
||||
label: 'file',
|
||||
value: 'file',
|
||||
},
|
||||
],
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
|
@ -146,7 +171,7 @@
|
|||
title: '',
|
||||
slotName: 'operation',
|
||||
fixed: 'right',
|
||||
width: 80,
|
||||
width: 50,
|
||||
},
|
||||
];
|
||||
|
||||
|
|
|
@ -15,8 +15,7 @@
|
|||
<script setup lang="ts">
|
||||
import { useVModel } from '@vueuse/core';
|
||||
|
||||
import type { MsTableColumn } from '@/components/pure/ms-table/type';
|
||||
import paramTable from '../../../components/paramTable.vue';
|
||||
import paramTable, { ParamTableColumn } from '../../../components/paramTable.vue';
|
||||
import batchAddKeyVal from './batchAddKeyVal.vue';
|
||||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
|
@ -35,7 +34,7 @@
|
|||
|
||||
const innerParams = useVModel(props, 'params', emit);
|
||||
|
||||
const columns: MsTableColumn = [
|
||||
const columns: ParamTableColumn[] = [
|
||||
{
|
||||
title: 'apiTestDebug.paramName',
|
||||
dataIndex: 'name',
|
||||
|
|
|
@ -59,7 +59,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div ref="splitContainerRef" class="flex-1">
|
||||
<div ref="splitContainerRef" class="h-[calc(100%-125px)]">
|
||||
<MsSplitBox
|
||||
ref="splitBoxRef"
|
||||
v-model:size="splitBoxSize"
|
||||
|
@ -69,7 +69,7 @@
|
|||
@expand-change="handleExpandChange"
|
||||
>
|
||||
<template #first>
|
||||
<div :class="`h-full min-w-[700px] px-[24px] pb-[16px] ${activeLayout === 'horizontal' ? ' pr-[16px]' : ''}`">
|
||||
<div :class="`h-full min-w-[800px] px-[24px] pb-[16px] ${activeLayout === 'horizontal' ? ' pr-[16px]' : ''}`">
|
||||
<a-tabs v-model:active-key="activeDebug.activeTab" class="no-content">
|
||||
<a-tab-pane v-for="item of contentTabList" :key="item.value" :title="item.label" />
|
||||
</a-tabs>
|
||||
|
@ -102,6 +102,13 @@
|
|||
:second-box-height="secondBoxHeight"
|
||||
@change="handleActiveDebugChange"
|
||||
/>
|
||||
<precondition
|
||||
v-else-if="activeDebug.activeTab === RequestComposition.PREFIX"
|
||||
v-model:params="activeDebug.preconditions"
|
||||
:layout="activeLayout"
|
||||
:second-box-height="secondBoxHeight"
|
||||
@change="handleActiveDebugChange"
|
||||
/>
|
||||
<debugAuth
|
||||
v-else-if="activeDebug.activeTab === RequestComposition.AUTH"
|
||||
v-model:params="activeDebug.authParams"
|
||||
|
@ -159,6 +166,7 @@
|
|||
import debugAuth from './auth.vue';
|
||||
import debugBody, { BodyParams } from './body.vue';
|
||||
import debugHeader from './header.vue';
|
||||
import precondition from './precondition.vue';
|
||||
import debugQuery from './query.vue';
|
||||
import debugRest from './rest.vue';
|
||||
import debugSetting from './setting.vue';
|
||||
|
@ -201,6 +209,7 @@
|
|||
account: '',
|
||||
password: '',
|
||||
},
|
||||
preconditions: [],
|
||||
setting: {
|
||||
connectTimeout: 60000,
|
||||
responseTimeout: 60000,
|
||||
|
|
|
@ -0,0 +1,597 @@
|
|||
<template>
|
||||
<div class="mb-[8px] flex items-center justify-between">
|
||||
<a-dropdown @select="addPrecondition">
|
||||
<a-button type="outline">
|
||||
<template #icon>
|
||||
<icon-plus :size="14" />
|
||||
</template>
|
||||
{{ t('apiTestDebug.precondition') }}
|
||||
</a-button>
|
||||
<template #content>
|
||||
<a-doption value="script">{{ t('apiTestDebug.script') }}</a-doption>
|
||||
<a-doption value="sql">{{ t('apiTestDebug.sql') }}</a-doption>
|
||||
<a-doption value="waitTime">{{ t('apiTestDebug.waitTime') }}</a-doption>
|
||||
</template>
|
||||
</a-dropdown>
|
||||
<div class="flex items-center">
|
||||
<a-switch v-model:model-value="openGlobalPrecondition" size="small" type="line"></a-switch>
|
||||
<div class="ml-[8px] text-[var(--color-text-1)]">{{ t('apiTestDebug.openGlobalPrecondition') }}</div>
|
||||
<a-tooltip :content="t('apiTestDebug.openGlobalPreconditionTip')" position="top">
|
||||
<icon-question-circle
|
||||
class="ml-[4px] text-[var(--color-text-brand)] hover:text-[rgb(var(--primary-5))]"
|
||||
size="16"
|
||||
/>
|
||||
</a-tooltip>
|
||||
</div>
|
||||
</div>
|
||||
<div v-show="preconditions.length > 0" class="flex h-[calc(100%-110px)] gap-[8px]">
|
||||
<div class="h-full w-[20%] min-w-[220px]">
|
||||
<MsList
|
||||
v-model:active-item-key="activeItem.id"
|
||||
v-model:focus-item-key="focusItemKey"
|
||||
v-model:data="preconditions"
|
||||
mode="static"
|
||||
item-key-field="id"
|
||||
:item-border="false"
|
||||
class="h-full rounded-[var(--border-radius-small)] bg-[var(--color-text-n9)] p-[12px]"
|
||||
item-class="mb-[4px] bg-white !p-[4px_8px]"
|
||||
:item-more-actions="itemMoreActions"
|
||||
active-item-class="!bg-[rgb(var(--primary-1))] text-[rgb(var(--primary-5))]"
|
||||
:virtual-list-props="{ height: '100%', fixedSize: true }"
|
||||
draggable
|
||||
@item-click="handlePreconditionItemClick"
|
||||
@more-action-select="handlePreconditionMoreActionSelect"
|
||||
@more-actions-close="focusItemKey = ''"
|
||||
>
|
||||
<template #title="{ item, index }">
|
||||
<div class="flex items-center gap-[4px]">
|
||||
<div
|
||||
:class="`flex h-[16px] w-[16px] items-center justify-center rounded-full ${
|
||||
activeItem.id === item.id ? ' bg-white' : 'bg-[var(--color-text-n8)]'
|
||||
}`"
|
||||
>
|
||||
{{ index + 1 }}
|
||||
</div>
|
||||
<div>{{ typeMap[item.type] }}</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #itemRight="{ item }">
|
||||
<a-switch v-model:model-value="item.enable" size="small" type="line"></a-switch>
|
||||
</template>
|
||||
</MsList>
|
||||
</div>
|
||||
<div class="precondition-content">
|
||||
<!-- 前置条件-脚本操作 -->
|
||||
<template v-if="activeItem.type === 'script'">
|
||||
<a-radio-group v-model:model-value="activeItem.scriptType" size="small" class="mb-[16px]">
|
||||
<a-radio value="manual">{{ t('apiTestDebug.manual') }}</a-radio>
|
||||
<a-radio value="quote">{{ t('apiTestDebug.quote') }}</a-radio>
|
||||
</a-radio-group>
|
||||
<div
|
||||
v-if="activeItem.scriptType === 'manual'"
|
||||
class="relative rounded-[var(--border-radius-small)] bg-[var(--color-text-n9)] p-[12px]"
|
||||
>
|
||||
<div v-if="isShowEditScriptNameInput" class="absolute left-[12px] z-10 w-[calc(100%-24px)]">
|
||||
<a-input
|
||||
ref="scriptNameInputRef"
|
||||
v-model:model-value="activeItem.name"
|
||||
:placeholder="t('apiTestDebug.preconditionScriptNamePlaceholder')"
|
||||
:max-length="255"
|
||||
show-word-limit
|
||||
size="small"
|
||||
@press-enter="isShowEditScriptNameInput = false"
|
||||
@blur="isShowEditScriptNameInput = false"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center">
|
||||
<a-tooltip :content="activeItem.name">
|
||||
<div class="script-name-container">
|
||||
<div class="one-line-text mr-[4px] max-w-[110px] font-medium text-[var(--color-text-1)]">
|
||||
{{ activeItem.name }}
|
||||
</div>
|
||||
<MsIcon
|
||||
type="icon-icon_edit_outlined"
|
||||
class="edit-script-name-icon"
|
||||
@click="showEditScriptNameInput"
|
||||
/>
|
||||
</div>
|
||||
</a-tooltip>
|
||||
<a-popover class="h-auto" position="top">
|
||||
<div class="text-[rgb(var(--primary-5))]">{{ t('apiTestDebug.scriptEx') }}</div>
|
||||
<template #content>
|
||||
<div class="mb-[8px] flex items-center justify-between">
|
||||
<div class="text-[14px] font-medium text-[var(--color-text-1)]">
|
||||
{{ t('apiTestDebug.scriptEx') }}
|
||||
</div>
|
||||
<a-button
|
||||
type="outline"
|
||||
class="arco-btn-outline--secondary p-[0_8px]"
|
||||
size="mini"
|
||||
@click="copyScriptEx"
|
||||
>
|
||||
{{ t('common.copy') }}
|
||||
</a-button>
|
||||
</div>
|
||||
<div class="flex h-[412px]">
|
||||
<MsCodeEditor
|
||||
v-model:model-value="scriptEx"
|
||||
class="flex-1"
|
||||
theme="MS-text"
|
||||
width="500px"
|
||||
height="388px"
|
||||
:show-full-screen="false"
|
||||
:show-theme-change="false"
|
||||
read-only
|
||||
>
|
||||
</MsCodeEditor>
|
||||
</div>
|
||||
</template>
|
||||
</a-popover>
|
||||
</div>
|
||||
<div class="flex items-center gap-[8px]">
|
||||
<a-button type="outline" class="arco-btn-outline--secondary p-[0_8px]" size="mini">
|
||||
<template #icon>
|
||||
<MsIcon type="icon-icon_undo_outlined" class="text-var(--color-text-4)" size="12" />
|
||||
</template>
|
||||
{{ t('common.revoke') }}
|
||||
</a-button>
|
||||
<a-button type="outline" class="arco-btn-outline--secondary p-[0_8px]" size="mini" @click="clearScript">
|
||||
<template #icon>
|
||||
<MsIcon type="icon-icon_clear" class="text-var(--color-text-4)" size="12" />
|
||||
</template>
|
||||
{{ t('common.clear') }}
|
||||
</a-button>
|
||||
<a-button
|
||||
type="outline"
|
||||
class="arco-btn-outline--secondary p-[0_8px]"
|
||||
size="mini"
|
||||
@click="() => copyPrecondition(activeItem)"
|
||||
>
|
||||
{{ t('common.copy') }}
|
||||
</a-button>
|
||||
<a-button
|
||||
type="outline"
|
||||
class="arco-btn-outline--secondary p-[0_8px]"
|
||||
size="mini"
|
||||
@click="() => deletePrecondition(activeItem)"
|
||||
>
|
||||
{{ t('common.delete') }}
|
||||
</a-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="flex h-[calc(100%-47px)] flex-col">
|
||||
<div class="mb-[16px] flex w-full items-center bg-[var(--color-text-n9)] p-[12px]">
|
||||
<div class="text-[var(--color-text-2)]">
|
||||
{{ activeItem.quoteScript.name || '-' }}
|
||||
</div>
|
||||
<a-divider margin="8px" direction="vertical" />
|
||||
<MsButton type="text" class="font-medium">
|
||||
{{ t('apiTestDebug.quote') }}
|
||||
</MsButton>
|
||||
</div>
|
||||
<a-radio-group v-model:model-value="commonScriptShowType" size="small" type="button" class="mb-[8px] w-fit">
|
||||
<a-radio value="parameters">{{ t('apiTestDebug.parameters') }}</a-radio>
|
||||
<a-radio value="scriptContent">{{ t('apiTestDebug.scriptContent') }}</a-radio>
|
||||
</a-radio-group>
|
||||
<MsBaseTable v-show="commonScriptShowType === 'parameters'" v-bind="propsRes" v-on="propsEvent">
|
||||
<template #value="{ record }">
|
||||
<a-tooltip :content="t(record.required ? 'apiTestDebug.paramRequired' : 'apiTestDebug.paramNotRequired')">
|
||||
<div
|
||||
:class="[
|
||||
record.required ? '!text-[rgb(var(--danger-5))]' : '!text-[var(--color-text-brand)]',
|
||||
'!mr-[4px] !p-[4px]',
|
||||
]"
|
||||
>
|
||||
<div>*</div>
|
||||
</div>
|
||||
</a-tooltip>
|
||||
{{ record.type }}
|
||||
</template>
|
||||
</MsBaseTable>
|
||||
<div v-show="commonScriptShowType === 'scriptContent'" class="h-[calc(100%-76px)]">
|
||||
<MsCodeEditor
|
||||
v-model:model-value="activeItem.quoteScript.script"
|
||||
theme="MS-text"
|
||||
height="100%"
|
||||
:show-full-screen="false"
|
||||
:show-theme-change="false"
|
||||
read-only
|
||||
>
|
||||
</MsCodeEditor>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<!-- 前置条件-SQL操作 -->
|
||||
<template v-else-if="activeItem.type === 'sql'">
|
||||
<div class="mb-[16px]">
|
||||
<div class="mb-[8px] text-[var(--color-text-1)]">{{ t('common.desc') }}</div>
|
||||
<a-input
|
||||
v-model:model-value="activeItem.desc"
|
||||
:placeholder="t('apiTestDebug.commonPlaceholder')"
|
||||
:max-length="255"
|
||||
show-word-limit
|
||||
/>
|
||||
</div>
|
||||
<div class="mb-[16px] flex w-full items-center bg-[var(--color-text-n9)] p-[12px]">
|
||||
<div class="text-[var(--color-text-2)]">
|
||||
{{ activeItem.sqlSource.name || '-' }}
|
||||
</div>
|
||||
<a-divider margin="8px" direction="vertical" />
|
||||
<MsButton type="text" class="font-medium">
|
||||
{{ t('apiTestDebug.quoteSource') }}
|
||||
</MsButton>
|
||||
</div>
|
||||
<div class="mb-[8px] text-[var(--color-text-1)]">{{ t('apiTestDebug.sqlScript') }}</div>
|
||||
<div class="mb-[16px] h-[400px]">
|
||||
<MsCodeEditor
|
||||
v-model:model-value="activeItem.sqlSource.script"
|
||||
theme="MS-text"
|
||||
height="376px"
|
||||
:show-full-screen="false"
|
||||
:show-theme-change="false"
|
||||
read-only
|
||||
>
|
||||
</MsCodeEditor>
|
||||
</div>
|
||||
<div class="mb-[16px]">
|
||||
<div class="mb-[8px] flex items-center text-[var(--color-text-1)]">
|
||||
{{ t('apiTestDebug.storageType') }}
|
||||
<a-tooltip position="right">
|
||||
<icon-question-circle
|
||||
class="ml-[4px] text-[var(--color-text-brand)] hover:text-[rgb(var(--primary-5))]"
|
||||
size="16"
|
||||
/>
|
||||
<template #content>
|
||||
<div>{{ t('apiTestDebug.storageTypeTip1') }}</div>
|
||||
<div>{{ t('apiTestDebug.storageTypeTip2') }}</div>
|
||||
</template>
|
||||
</a-tooltip>
|
||||
</div>
|
||||
<a-radio-group
|
||||
v-model:model-value="activeItem.sqlSource.storageType"
|
||||
size="small"
|
||||
type="button"
|
||||
class="w-fit"
|
||||
>
|
||||
<a-radio value="column">{{ t('apiTestDebug.storageByCol') }}</a-radio>
|
||||
<a-radio value="result">{{ t('apiTestDebug.storageByResult') }}</a-radio>
|
||||
</a-radio-group>
|
||||
</div>
|
||||
<div v-if="activeItem.sqlSource.storageType === 'column'" class="mb-[16px]">
|
||||
<div class="mb-[8px] text-[var(--color-text-1)]">{{ t('apiTestDebug.storageByCol') }}</div>
|
||||
<a-input
|
||||
v-model:model-value="activeItem.sqlSource.storageByCol"
|
||||
:placeholder="t('apiTestDebug.storageByColPlaceholder', { a: '{id_1}', b: '{username_1}' })"
|
||||
/>
|
||||
</div>
|
||||
<div v-else class="mb-[16px]">
|
||||
<div class="mb-[8px] text-[var(--color-text-1)]">{{ t('apiTestDebug.storageByResult') }}</div>
|
||||
<a-input
|
||||
v-model:model-value="activeItem.sqlSource.storageByResult"
|
||||
:placeholder="t('apiTestDebug.storageByResultPlaceholder', { a: '${result}' })"
|
||||
/>
|
||||
</div>
|
||||
<div class="mb-[16px]">
|
||||
<div class="mb-[8px] text-[var(--color-text-1)]">{{ t('apiTestDebug.extractParameter') }}</div>
|
||||
<paramTable
|
||||
v-model:params="activeItem.sqlSource.params"
|
||||
:columns="sqlSourceColumns"
|
||||
:selectable="false"
|
||||
@change="handleParamTableChange"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<!-- 前置条件-等待时间 -->
|
||||
<div v-else>
|
||||
<div class="mb-[8px] flex items-center">
|
||||
{{ t('apiTestDebug.waitTime') }}
|
||||
<div class="text-[var(--color-text-4)]">(ms)</div>
|
||||
</div>
|
||||
<a-input-number v-model:model-value="activeItem.time" mode="button" :step="100" :min="0" class="w-[160px]" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useClipboard, useVModel } from '@vueuse/core';
|
||||
import { InputInstance, Message } from '@arco-design/web-vue';
|
||||
|
||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||
import MsCodeEditor from '@/components/pure/ms-code-editor/index.vue';
|
||||
import MsIcon from '@/components/pure/ms-icon-font/index.vue';
|
||||
import MsList from '@/components/pure/ms-list/index.vue';
|
||||
import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
|
||||
import type { MsTableColumn } from '@/components/pure/ms-table/type';
|
||||
import useTable from '@/components/pure/ms-table/useTable';
|
||||
import type { ActionsItem } from '@/components/pure/ms-table-more-action/types';
|
||||
import paramTable, { type ParamTableColumn } from '../../../components/paramTable.vue';
|
||||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
|
||||
const props = defineProps<{
|
||||
params: any[];
|
||||
layout: 'horizontal' | 'vertical';
|
||||
secondBoxHeight: number;
|
||||
}>();
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:params', params: any[]): void;
|
||||
(e: 'change'): void;
|
||||
}>();
|
||||
|
||||
const { t } = useI18n();
|
||||
// 是否开启全局前置条件
|
||||
const openGlobalPrecondition = ref(false);
|
||||
const preconditions = useVModel(props, 'params', emit);
|
||||
// 当前聚焦的前置条件
|
||||
const focusItemKey = ref<any>('');
|
||||
// 当前选中的前置条件
|
||||
const activeItem = ref(preconditions.value[0] || {});
|
||||
const typeMap = {
|
||||
script: t('apiTestDebug.script'),
|
||||
sql: t('apiTestDebug.sql'),
|
||||
waitTime: t('apiTestDebug.waitTime'),
|
||||
};
|
||||
const itemMoreActions: ActionsItem[] = [
|
||||
{
|
||||
label: 'common.copy',
|
||||
eventTag: 'copy',
|
||||
},
|
||||
{
|
||||
label: 'project.fileManagement.delete',
|
||||
eventTag: 'delete',
|
||||
},
|
||||
];
|
||||
const scriptEx = ref(`2023-12-04 11:19:28 INFO 9026fd6a 1-1 Thread started: 9026fd6a 1-1
|
||||
2023-12-04 11:19:28 ERROR 9026fd6a 1-1 Problem in JSR223 script JSR223Sampler, message: {}
|
||||
In file: inline evaluation of: prev.getResponseCode() import java.net.URI; import org.apache.http.client.method . . . '' Encountered "import" at line 2, column 1.
|
||||
in inline evaluation of: prev.getResponseCode() import java.net.URI; import org.apache.http.client.method . . . '' at line number 2
|
||||
javax.script.ScriptException '' at line number 2
|
||||
javax.script.ScriptException '' at line number 2
|
||||
javax.script.ScriptException '' at line number 2
|
||||
javax.script.ScriptException '' at line number 2
|
||||
javax.script.ScriptException '' at line number 2
|
||||
javax.script.ScriptException
|
||||
org.apache.http.client.method . . . '' at line number 2
|
||||
`);
|
||||
const { copy, isSupported } = useClipboard();
|
||||
|
||||
function copyScriptEx() {
|
||||
if (isSupported) {
|
||||
copy(scriptEx.value);
|
||||
Message.success(t('apiTestDebug.scriptExCopySuccess'));
|
||||
} else {
|
||||
Message.warning(t('apiTestDebug.copyNotSupport'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加前置条件
|
||||
* @param value script | sql | waitTime
|
||||
*/
|
||||
function addPrecondition(value: string | number | Record<string, any> | undefined) {
|
||||
const id = new Date().getTime();
|
||||
switch (value) {
|
||||
case 'script':
|
||||
preconditions.value.push({
|
||||
id,
|
||||
type: 'script',
|
||||
name: t('apiTestDebug.preconditionScriptName'),
|
||||
scriptType: 'manual',
|
||||
enable: true,
|
||||
script: '',
|
||||
quoteScript: {
|
||||
name: '',
|
||||
script: scriptEx,
|
||||
},
|
||||
});
|
||||
break;
|
||||
case 'sql':
|
||||
preconditions.value.push({
|
||||
id,
|
||||
type: 'sql',
|
||||
desc: '',
|
||||
enable: true,
|
||||
sqlSource: {
|
||||
name: '',
|
||||
script: scriptEx,
|
||||
storageType: 'column',
|
||||
params: [],
|
||||
},
|
||||
});
|
||||
break;
|
||||
case 'waitTime':
|
||||
preconditions.value.push({
|
||||
id,
|
||||
type: 'waitTime',
|
||||
enable: true,
|
||||
time: 1000,
|
||||
});
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
activeItem.value = preconditions.value[preconditions.value.length - 1];
|
||||
emit('change');
|
||||
}
|
||||
|
||||
function handlePreconditionItemClick(item: any) {
|
||||
activeItem.value = item;
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制前置条件
|
||||
* @param item 前置条件项
|
||||
*/
|
||||
function copyPrecondition(item: Record<string, any>) {
|
||||
const copyItem = {
|
||||
...item,
|
||||
id: new Date().getTime(),
|
||||
};
|
||||
preconditions.value.push(copyItem);
|
||||
activeItem.value = copyItem;
|
||||
emit('change');
|
||||
}
|
||||
|
||||
function deletePrecondition(item: Record<string, any>) {
|
||||
preconditions.value = preconditions.value.filter((precondition) => precondition.id !== item.id);
|
||||
if (activeItem.value.id === item.id) {
|
||||
[activeItem.value] = preconditions.value;
|
||||
}
|
||||
emit('change');
|
||||
}
|
||||
|
||||
/**
|
||||
* 前置条件列表项-选择更多操作项
|
||||
* @param event
|
||||
* @param item
|
||||
*/
|
||||
function handlePreconditionMoreActionSelect(event: ActionsItem, item: Record<string, any>) {
|
||||
if (event.eventTag === 'copy') {
|
||||
copyPrecondition(item);
|
||||
} else if (event.eventTag === 'delete') {
|
||||
deletePrecondition(item);
|
||||
}
|
||||
}
|
||||
|
||||
function clearScript() {
|
||||
activeItem.value.script = '';
|
||||
}
|
||||
|
||||
// 是否显示前置脚本名称编辑框
|
||||
const isShowEditScriptNameInput = ref(false);
|
||||
const scriptNameInputRef = ref<InputInstance>();
|
||||
|
||||
function showEditScriptNameInput() {
|
||||
isShowEditScriptNameInput.value = true;
|
||||
nextTick(() => {
|
||||
scriptNameInputRef.value?.focus();
|
||||
});
|
||||
}
|
||||
|
||||
const commonScriptShowType = ref<'parameters' | 'scriptContent'>('parameters');
|
||||
const heightUsed = ref<number | undefined>(undefined);
|
||||
const scroll = computed(() => (props.layout === 'horizontal' ? { x: '700px' } : { x: '100%' }));
|
||||
const columns: MsTableColumn = [
|
||||
{
|
||||
title: 'apiTestDebug.paramName',
|
||||
dataIndex: 'name',
|
||||
showTooltip: true,
|
||||
},
|
||||
{
|
||||
title: 'apiTestDebug.paramValue',
|
||||
dataIndex: 'value',
|
||||
slotName: 'value',
|
||||
},
|
||||
{
|
||||
title: 'apiTestDebug.desc',
|
||||
dataIndex: 'desc',
|
||||
showTooltip: true,
|
||||
},
|
||||
];
|
||||
const { propsRes, propsEvent } = useTable(() => Promise.resolve([]), {
|
||||
scroll: scroll.value,
|
||||
heightUsed: heightUsed.value,
|
||||
columns,
|
||||
});
|
||||
propsRes.value.data = [
|
||||
{
|
||||
id: new Date().getTime(),
|
||||
required: false,
|
||||
name: 'asdasd',
|
||||
type: 'string',
|
||||
value: '',
|
||||
desc: '',
|
||||
},
|
||||
{
|
||||
id: new Date().getTime(),
|
||||
required: true,
|
||||
name: '23d23d',
|
||||
type: 'string',
|
||||
value: '',
|
||||
desc: '',
|
||||
},
|
||||
] as any;
|
||||
watch(
|
||||
() => props.layout,
|
||||
(val) => {
|
||||
heightUsed.value = val === 'horizontal' ? 422 : 422 + props.secondBoxHeight;
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.secondBoxHeight,
|
||||
(val) => {
|
||||
if (props.layout === 'vertical') {
|
||||
heightUsed.value = 422 + val;
|
||||
}
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
}
|
||||
);
|
||||
|
||||
const sqlSourceColumns: ParamTableColumn[] = [
|
||||
{
|
||||
title: 'apiTestDebug.paramName',
|
||||
dataIndex: 'name',
|
||||
slotName: 'name',
|
||||
},
|
||||
{
|
||||
title: 'apiTestDebug.paramValue',
|
||||
dataIndex: 'value',
|
||||
slotName: 'value',
|
||||
isNormal: true,
|
||||
},
|
||||
{
|
||||
title: '',
|
||||
slotName: 'operation',
|
||||
width: 50,
|
||||
},
|
||||
];
|
||||
|
||||
function handleParamTableChange(resultArr: any[], isInit?: boolean) {
|
||||
activeItem.value.sqlSource.params = [...resultArr];
|
||||
if (!isInit) {
|
||||
emit('change');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.precondition-content {
|
||||
@apply flex-1 overflow-y-auto;
|
||||
.ms-scroll-bar();
|
||||
|
||||
padding: 16px;
|
||||
border: 1px solid rgb(var(--color-text-n8));
|
||||
border-radius: var(--border-radius-small);
|
||||
}
|
||||
.script-name-container {
|
||||
@apply flex items-center;
|
||||
|
||||
margin-right: 16px;
|
||||
&:hover {
|
||||
.edit-script-name-icon {
|
||||
@apply visible;
|
||||
}
|
||||
}
|
||||
.edit-script-name-icon {
|
||||
@apply invisible cursor-pointer;
|
||||
|
||||
color: rgb(var(--primary-5));
|
||||
}
|
||||
}
|
||||
:deep(.arco-table-th) {
|
||||
background-color: var(--color-text-n9);
|
||||
}
|
||||
:deep(.arco-table-cell) {
|
||||
padding: 16px 12px;
|
||||
}
|
||||
</style>
|
|
@ -16,7 +16,6 @@
|
|||
:columns="columns"
|
||||
:height-used="heightUsed"
|
||||
:scroll="{ minWidth: 1160 }"
|
||||
format="query"
|
||||
@change="handleParamTableChange"
|
||||
/>
|
||||
</template>
|
||||
|
@ -24,8 +23,7 @@
|
|||
<script setup lang="ts">
|
||||
import { useVModel } from '@vueuse/core';
|
||||
|
||||
import type { MsTableColumn } from '@/components/pure/ms-table/type';
|
||||
import paramTable from '../../../components/paramTable.vue';
|
||||
import paramTable, { type ParamTableColumn } from '../../../components/paramTable.vue';
|
||||
import batchAddKeyVal from './batchAddKeyVal.vue';
|
||||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
|
@ -44,7 +42,7 @@
|
|||
|
||||
const innerParams = useVModel(props, 'params', emit);
|
||||
|
||||
const columns: MsTableColumn = [
|
||||
const columns: ParamTableColumn[] = [
|
||||
{
|
||||
title: 'apiTestDebug.paramName',
|
||||
dataIndex: 'name',
|
||||
|
@ -54,6 +52,25 @@
|
|||
title: 'apiTestDebug.paramType',
|
||||
dataIndex: 'type',
|
||||
slotName: 'type',
|
||||
hasRequired: true,
|
||||
typeOptions: [
|
||||
{
|
||||
label: 'string',
|
||||
value: 'string',
|
||||
},
|
||||
{
|
||||
label: 'integer',
|
||||
value: 'integer',
|
||||
},
|
||||
{
|
||||
label: 'number',
|
||||
value: 'number',
|
||||
},
|
||||
{
|
||||
label: 'array',
|
||||
value: 'array',
|
||||
},
|
||||
],
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
|
@ -82,7 +99,8 @@
|
|||
title: '',
|
||||
slotName: 'operation',
|
||||
fixed: 'right',
|
||||
width: 50,
|
||||
format: 'query',
|
||||
width: 80,
|
||||
},
|
||||
];
|
||||
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
:columns="columns"
|
||||
:height-used="heightUsed"
|
||||
:scroll="{ minWidth: 1160 }"
|
||||
format="query"
|
||||
@change="handleParamTableChange"
|
||||
/>
|
||||
</template>
|
||||
|
@ -24,8 +23,7 @@
|
|||
<script setup lang="ts">
|
||||
import { useVModel } from '@vueuse/core';
|
||||
|
||||
import type { MsTableColumn } from '@/components/pure/ms-table/type';
|
||||
import paramTable from '../../../components/paramTable.vue';
|
||||
import paramTable, { type ParamTableColumn } from '../../../components/paramTable.vue';
|
||||
import batchAddKeyVal from './batchAddKeyVal.vue';
|
||||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
|
@ -44,7 +42,7 @@
|
|||
|
||||
const innerParams = useVModel(props, 'params', emit);
|
||||
|
||||
const columns: MsTableColumn = [
|
||||
const columns: ParamTableColumn[] = [
|
||||
{
|
||||
title: 'apiTestDebug.paramName',
|
||||
dataIndex: 'name',
|
||||
|
@ -54,6 +52,25 @@
|
|||
title: 'apiTestDebug.paramType',
|
||||
dataIndex: 'type',
|
||||
slotName: 'type',
|
||||
hasRequired: true,
|
||||
typeOptions: [
|
||||
{
|
||||
label: 'string',
|
||||
value: 'string',
|
||||
},
|
||||
{
|
||||
label: 'integer',
|
||||
value: 'integer',
|
||||
},
|
||||
{
|
||||
label: 'number',
|
||||
value: 'number',
|
||||
},
|
||||
{
|
||||
label: 'array',
|
||||
value: 'array',
|
||||
},
|
||||
],
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
|
@ -82,7 +99,8 @@
|
|||
title: '',
|
||||
slotName: 'operation',
|
||||
fixed: 'right',
|
||||
width: 50,
|
||||
format: 'query',
|
||||
width: 80,
|
||||
},
|
||||
];
|
||||
|
||||
|
|
|
@ -11,7 +11,13 @@
|
|||
<div class="text-[var(--color-text-brand)]">(ms)</div>
|
||||
</div>
|
||||
</template>
|
||||
<a-input-number v-model:model-value="settingForm.connectTimeout" mode="button" class="w-[160px]" />
|
||||
<a-input-number
|
||||
v-model:model-value="settingForm.connectTimeout"
|
||||
mode="button"
|
||||
:step="100"
|
||||
:min="0"
|
||||
class="w-[160px]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item>
|
||||
<template #label>
|
||||
|
@ -20,7 +26,13 @@
|
|||
<div class="text-[var(--color-text-brand)]">(ms)</div>
|
||||
</div>
|
||||
</template>
|
||||
<a-input-number v-model:model-value="settingForm.responseTimeout" mode="button" class="w-[160px]" />
|
||||
<a-input-number
|
||||
v-model:model-value="settingForm.responseTimeout"
|
||||
mode="button"
|
||||
:step="100"
|
||||
:min="0"
|
||||
class="w-[160px]"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item :label="t('apiTestDebug.certificateAlias')">
|
||||
<a-input
|
||||
|
|
|
@ -54,4 +54,31 @@ export default {
|
|||
'apiTestDebug.redirect': '重定向',
|
||||
'apiTestDebug.follow': '跟随',
|
||||
'apiTestDebug.auto': '自动',
|
||||
'apiTestDebug.precondition': '前置条件',
|
||||
'apiTestDebug.openGlobalPrecondition': '启用全局前置',
|
||||
'apiTestDebug.openGlobalPreconditionTip': '默认开启,关闭则运行该接口时不执行全局前置',
|
||||
'apiTestDebug.sql': 'SQL 操作',
|
||||
'apiTestDebug.sqlScript': 'SQL 脚本',
|
||||
'apiTestDebug.waitTime': '等待时间',
|
||||
'apiTestDebug.script': '脚本操作',
|
||||
'apiTestDebug.preconditionScriptName': '前置脚本名称',
|
||||
'apiTestDebug.preconditionScriptNamePlaceholder': '前置脚本名称',
|
||||
'apiTestDebug.manual': '手动录入',
|
||||
'apiTestDebug.quote': '引用公共脚本',
|
||||
'apiTestDebug.commonScriptList': '公共脚本列表',
|
||||
'apiTestDebug.scriptEx': '脚本案例',
|
||||
'apiTestDebug.copyNotSupport': '您的浏览器不支持自动复制,请您手动复制脚本案例',
|
||||
'apiTestDebug.scriptExCopySuccess': '脚本案例已复制',
|
||||
'apiTestDebug.parameters': '传递参数',
|
||||
'apiTestDebug.scriptContent': '脚本内容',
|
||||
'apiTestDebug.quoteSource': '引入数据源',
|
||||
'apiTestDebug.quoteSourcePlaceholder': '请选择数据源',
|
||||
'apiTestDebug.storageType': '存储方式',
|
||||
'apiTestDebug.storageTypeTip1': '按列存储:指定从数据库结果集中提取的列的名称;多个列可以使用“,”分隔',
|
||||
'apiTestDebug.storageTypeTip2': '按结果存储:把整个结果集保存为一个变量,而不是将每个列的值保存为单独的变量',
|
||||
'apiTestDebug.storageByCol': '按列存储',
|
||||
'apiTestDebug.storageByColPlaceholder': '如 {a} 改成 {b}',
|
||||
'apiTestDebug.storageByResult': '按结果存储',
|
||||
'apiTestDebug.storageByResultPlaceholder': '如 {a}',
|
||||
'apiTestDebug.extractParameter': '提取参数',
|
||||
};
|
||||
|
|
|
@ -92,7 +92,7 @@
|
|||
<div class="flex flex-row items-center justify-between">
|
||||
<div>
|
||||
<div v-if="showAppend" class="flex flex-row items-center gap-[4px]">
|
||||
<a-switch v-model:model-value="form.append" size="small" />
|
||||
<a-switch v-model:model-value="form.append" size="small" type="line" />
|
||||
<span class="text-[var(--color-text-1)]">{{ t('bugManagement.batchUpdate.update') }}</span>
|
||||
<a-tooltip position="top">
|
||||
<template #content>
|
||||
|
|
|
@ -65,7 +65,7 @@
|
|||
|
||||
<template #content>
|
||||
<a-doption>
|
||||
<a-switch class="mr-1" size="small" />{{ t('caseManagement.featureCase.addToPublic') }}
|
||||
<a-switch class="mr-1" size="small" type="line" />{{ t('caseManagement.featureCase.addToPublic') }}
|
||||
</a-doption>
|
||||
<a-doption @click="updateHandler('copy')">
|
||||
<MsIcon type="icon-icon_copy_filled" class="font-[16px]" />{{ t('common.copy') }}</a-doption
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
<div>
|
||||
<div class="itemTab">
|
||||
<span>{{ t('caseManagement.featureCase.detail') }}</span>
|
||||
<a-switch v-model="detailEnable" size="small" :disabled="true" />
|
||||
<a-switch v-model="detailEnable" size="small" :disabled="true" type="line" />
|
||||
</div>
|
||||
<a-divider orientation="center" class="non-sort"
|
||||
><span class="one-line-text text-xs text-[var(--color-text-4)]">{{
|
||||
|
@ -38,7 +38,7 @@
|
|||
>
|
||||
<div v-for="item of tabSettingList" :key="item.key" class="itemTab">
|
||||
<span>{{ t(item.title) }}</span>
|
||||
<a-switch v-model="item.enable" size="small" />
|
||||
<a-switch v-model="item.enable" size="small" type="line" />
|
||||
</div>
|
||||
</div>
|
||||
</MsDrawer>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
}}
|
||||
</div>
|
||||
<div class="ml-[16px] flex items-center">
|
||||
<a-switch v-model:model-value="onlyMine" size="small" class="mr-[8px]" />
|
||||
<a-switch v-model:model-value="onlyMine" size="small" class="mr-[8px]" type="line" />
|
||||
{{ t('caseManagement.caseReview.myReview') }}
|
||||
</div>
|
||||
</template>
|
||||
|
@ -228,7 +228,7 @@
|
|||
<div class="font-medium text-[var(--color-text-1)]">
|
||||
{{ t('caseManagement.caseReview.startReview') }}
|
||||
</div>
|
||||
<a-switch v-model:model-value="autoNext" class="mx-[8px]" size="small" />
|
||||
<a-switch v-model:model-value="autoNext" class="mx-[8px]" size="small" type="line" />
|
||||
<div class="text-[var(--color-text-4)]">{{ t('caseManagement.caseReview.autoNext') }}</div>
|
||||
<a-tooltip position="right">
|
||||
<template #content>
|
||||
|
|
|
@ -187,7 +187,7 @@
|
|||
<template #footer>
|
||||
<div class="flex items-center justify-end">
|
||||
<div v-if="dialogShowType === 'changeReviewer'" class="mr-auto flex items-center">
|
||||
<a-switch v-model:model-value="dialogForm.isAppend" size="small" class="mr-[4px]"></a-switch>
|
||||
<a-switch v-model:model-value="dialogForm.isAppend" size="small" class="mr-[4px]" type="line"></a-switch>
|
||||
{{ t('caseManagement.caseReview.append') }}
|
||||
<a-tooltip :content="t('caseManagement.caseReview.reviewResultTip')" position="right">
|
||||
<template #content>
|
||||
|
|
|
@ -376,7 +376,7 @@
|
|||
}
|
||||
|
||||
const caseAssociateVisible = ref<boolean>(false);
|
||||
const caseAssociateProject = ref('');
|
||||
const caseAssociateProject = ref(appStore.currentProjectId);
|
||||
const loading = ref(false);
|
||||
async function initReviewDetail() {
|
||||
try {
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
</template>
|
||||
<template #headerRight>
|
||||
<div class="mr-[16px] flex items-center">
|
||||
<a-switch v-model:model-value="onlyMine" size="small" class="mr-[8px]" />
|
||||
<a-switch v-model:model-value="onlyMine" size="small" class="mr-[8px]" type="line" />
|
||||
{{ t('caseManagement.caseReview.onlyMine') }}
|
||||
</div>
|
||||
<MsButton type="button" status="default" @click="associateDrawerVisible = true">
|
||||
|
@ -221,7 +221,7 @@
|
|||
|
||||
const caseTableRef = ref<InstanceType<typeof CaseTable>>();
|
||||
const associateDrawerVisible = ref(false);
|
||||
const associateDrawerProject = ref('');
|
||||
const associateDrawerProject = ref(appStore.currentProjectId);
|
||||
|
||||
// 关联用例
|
||||
async function writeAssociateCases(params: BaseAssociateCaseRequest & { reviewers: string[] }) {
|
||||
|
|
|
@ -1,417 +0,0 @@
|
|||
<template>
|
||||
<MsBaseTable v-bind="propsRes" :hoverable="false" v-on="propsEvent">
|
||||
<template #name="{ record }">
|
||||
<a-popover position="tl" :disabled="!record.name || record.name.trim() === ''" class="ms-params-input-popover">
|
||||
<template #content>
|
||||
<div class="param-popover-title">
|
||||
{{ t('ms.apiTestDebug.paramName') }}
|
||||
</div>
|
||||
<div class="param-popover-value">
|
||||
{{ record.name }}
|
||||
</div>
|
||||
</template>
|
||||
<a-input
|
||||
v-model:model-value="record.name"
|
||||
:placeholder="t('project.environmental.paramNamePlaceholder')"
|
||||
class="param-input"
|
||||
@input="(val) => addTableLine(val)"
|
||||
/>
|
||||
</a-popover>
|
||||
</template>
|
||||
<template #type="{ record }">
|
||||
<a-select v-model:model-value="record.type" class="param-input" @change="(val) => handleTypeChange(val)">
|
||||
<a-option v-for="element in typeOptions" :key="element.value" :value="element.value">{{
|
||||
t(element.label)
|
||||
}}</a-option>
|
||||
</a-select>
|
||||
</template>
|
||||
<template #value="{ record }">
|
||||
<MsParamsInput
|
||||
v-model:value="record.value"
|
||||
@change="addTableLine"
|
||||
@dblclick="quickInputParams(record)"
|
||||
@apply="handleParamSettingApply"
|
||||
/>
|
||||
</template>
|
||||
<template #desc="{ record }">
|
||||
<ParamDescInput
|
||||
v-model:desc="record.desc"
|
||||
@input="addTableLine"
|
||||
@dblclick="quickInputDesc(record)"
|
||||
@change="handleDescChange"
|
||||
/>
|
||||
</template>
|
||||
<template #operation="{ record, rowIndex }">
|
||||
<div class="flex flex-row items-center gap-[16px]">
|
||||
<a-switch v-if="rowIndex" v-model:model-value="record.enable" size="small" />
|
||||
<icon-minus-circle
|
||||
v-if="paramsLength > 1 && rowIndex !== paramsLength - 1"
|
||||
class="cursor-pointer text-[var(--color-text-4)]"
|
||||
size="20"
|
||||
@click="deleteParam(rowIndex)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<template #tag="{ record }">
|
||||
<ParamTagInput
|
||||
v-model:model-value="record.tag"
|
||||
@input="(val) => addTableLine(val)"
|
||||
@dblclick="quickInputDesc(record)"
|
||||
@change="handleDescChange"
|
||||
/>
|
||||
</template>
|
||||
</MsBaseTable>
|
||||
<a-modal
|
||||
v-model:visible="showQuickInputParam"
|
||||
:title="t('ms.paramsInput.value')"
|
||||
:ok-text="t('ms.apiTestDebug.apply')"
|
||||
class="ms-modal-form"
|
||||
body-class="!p-0"
|
||||
:width="680"
|
||||
title-align="start"
|
||||
@ok="applyQuickInputParam"
|
||||
@close="clearQuickInputParam"
|
||||
>
|
||||
<MsCodeEditor
|
||||
v-if="showQuickInputParam"
|
||||
v-model:model-value="quickInputParamValue"
|
||||
theme="MS-text"
|
||||
height="300px"
|
||||
:show-full-screen="false"
|
||||
>
|
||||
<template #title>
|
||||
<div class="flex justify-between">
|
||||
<div class="text-[var(--color-text-1)]">
|
||||
{{ t('ms.apiTestDebug.quickInputParamsTip') }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</MsCodeEditor>
|
||||
</a-modal>
|
||||
<a-modal
|
||||
v-model:visible="showQuickInputDesc"
|
||||
:title="t('ms.apiTestDebug.desc')"
|
||||
:ok-text="t('common.save')"
|
||||
:ok-button-props="{ disabled: !quickInputDescValue || quickInputDescValue.trim() === '' }"
|
||||
class="ms-modal-form"
|
||||
body-class="!p-0"
|
||||
:width="480"
|
||||
title-align="start"
|
||||
:auto-size="{ minRows: 2 }"
|
||||
@ok="applyQuickInputDesc"
|
||||
@close="clearQuickInputDesc"
|
||||
>
|
||||
<a-textarea
|
||||
v-model:model-value="quickInputDescValue"
|
||||
:placeholder="t('ms.apiTestDebug.descPlaceholder')"
|
||||
:max-length="255"
|
||||
show-word-limit
|
||||
></a-textarea>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script async setup lang="ts">
|
||||
import MsCodeEditor from '@/components/pure/ms-code-editor/index.vue';
|
||||
import MsBaseTable from '@/components/pure/ms-table/base-table.vue';
|
||||
import type { MsTableColumnData } from '@/components/pure/ms-table/type';
|
||||
import useTable from '@/components/pure/ms-table/useTable';
|
||||
import MsParamsInput from '@/components/business/ms-params-input/index.vue';
|
||||
import ParamDescInput from './ParamDescInput.vue';
|
||||
import ParamTagInput from './ParamTagInput.vue';
|
||||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
import { useTableStore } from '@/store';
|
||||
|
||||
import { TableKeyEnum } from '@/enums/tableEnum';
|
||||
|
||||
interface Param {
|
||||
id: number;
|
||||
name: string;
|
||||
type: string;
|
||||
value: string;
|
||||
desc: string;
|
||||
tag: string[];
|
||||
enable: boolean;
|
||||
}
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
params: Param[];
|
||||
scroll?: {
|
||||
x?: number | string;
|
||||
y?: number | string;
|
||||
maxHeight?: number | string;
|
||||
minWidth?: number | string;
|
||||
};
|
||||
disabled?: boolean; // 是否禁用
|
||||
showSetting?: boolean; // 是否显示列设置
|
||||
tableKey?: TableKeyEnum; // 表格key showSetting为true时必传
|
||||
columns: MsTableColumnData[]; // 表格列配置 showSetting为false时必传
|
||||
showSelectorAll?: boolean; // 是否显示全选
|
||||
heightUsed?: number;
|
||||
}>(),
|
||||
{
|
||||
disabled: false,
|
||||
showSetting: false,
|
||||
tableKey: undefined,
|
||||
showSelectorAll: false,
|
||||
heightUsed: 0,
|
||||
}
|
||||
);
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:params', value: Param[]): void;
|
||||
(e: 'change', data: Param[], isInit?: boolean): void;
|
||||
}>();
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const defaultParams: Omit<Param, 'id'> = {
|
||||
name: '',
|
||||
type: 'string',
|
||||
value: '',
|
||||
desc: '',
|
||||
tag: [],
|
||||
enable: true,
|
||||
};
|
||||
const allType = [
|
||||
{
|
||||
label: 'common.string',
|
||||
value: 'string',
|
||||
},
|
||||
{
|
||||
label: 'common.integer',
|
||||
value: 'integer',
|
||||
},
|
||||
{
|
||||
label: 'common.number',
|
||||
value: 'number',
|
||||
},
|
||||
{
|
||||
label: 'common.array',
|
||||
value: 'array',
|
||||
},
|
||||
{
|
||||
label: 'common.json',
|
||||
value: 'json',
|
||||
},
|
||||
{
|
||||
label: 'common.file',
|
||||
value: 'file',
|
||||
},
|
||||
];
|
||||
|
||||
const tableStore = useTableStore();
|
||||
|
||||
const typeOptions = computed(() => {
|
||||
return allType;
|
||||
});
|
||||
|
||||
if (props.showSetting && props.tableKey) {
|
||||
await tableStore.initColumn(props.tableKey, props.columns);
|
||||
}
|
||||
|
||||
const { propsRes, propsEvent } = useTable<Param>(undefined, {
|
||||
tableKey: props.showSetting ? props.tableKey : undefined,
|
||||
columns: props.columns,
|
||||
scroll: props.scroll,
|
||||
heightUsed: props.heightUsed,
|
||||
selectable: true,
|
||||
draggable: { type: 'handle', width: 24 },
|
||||
showSetting: props.showSetting,
|
||||
disabled: props.disabled,
|
||||
showSelectorAll: props.showSelectorAll,
|
||||
});
|
||||
|
||||
watch(
|
||||
() => props.params,
|
||||
(val) => {
|
||||
if (val.length > 0) {
|
||||
propsRes.value.data = val;
|
||||
} else {
|
||||
propsRes.value.data = props.params.concat({
|
||||
id: new Date().getTime(),
|
||||
name: '',
|
||||
type: 'string',
|
||||
value: '',
|
||||
desc: '',
|
||||
tag: [],
|
||||
enable: true,
|
||||
});
|
||||
emit('change', propsRes.value.data, true);
|
||||
}
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.heightUsed,
|
||||
(val) => {
|
||||
propsRes.value.heightUsed = val;
|
||||
}
|
||||
);
|
||||
|
||||
const paramsLength = computed(() => propsRes.value.data.length);
|
||||
|
||||
function deleteParam(rowIndex: number) {
|
||||
propsRes.value.data.splice(rowIndex, 1);
|
||||
emit('change', propsRes.value.data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 当表格输入框变化时,给参数表格添加一行数据行
|
||||
* @param val 输入值
|
||||
* @param isForce 是否强制添加
|
||||
*/
|
||||
function addTableLine(val?: string | number, isForce?: boolean) {
|
||||
const lastData = propsRes.value.data[propsRes.value.data.length - 1];
|
||||
const isNotChange = Object.keys(defaultParams).every((key) => {
|
||||
if (key === 'id') {
|
||||
return true;
|
||||
}
|
||||
if (key === 'tag') {
|
||||
return lastData[key].length === 0;
|
||||
}
|
||||
return lastData[key] === defaultParams[key as any];
|
||||
});
|
||||
if (isForce || (val !== '' && val !== undefined && !isNotChange)) {
|
||||
propsRes.value.data = [...propsRes.value.data, { id: new Date().getTime(), ...defaultParams }];
|
||||
emit('change', propsRes.value.data);
|
||||
}
|
||||
}
|
||||
|
||||
const showQuickInputParam = ref(false);
|
||||
const activeQuickInputRecord = ref<any>({});
|
||||
const quickInputParamValue = ref('');
|
||||
|
||||
function quickInputParams(record: any) {
|
||||
activeQuickInputRecord.value = record;
|
||||
showQuickInputParam.value = true;
|
||||
quickInputParamValue.value = record.value;
|
||||
}
|
||||
|
||||
function clearQuickInputParam() {
|
||||
activeQuickInputRecord.value = {};
|
||||
quickInputParamValue.value = '';
|
||||
}
|
||||
|
||||
function applyQuickInputParam() {
|
||||
activeQuickInputRecord.value.value = quickInputParamValue.value;
|
||||
showQuickInputParam.value = false;
|
||||
clearQuickInputParam();
|
||||
addTableLine(quickInputParamValue.value, true);
|
||||
emit('change', propsRes.value.data);
|
||||
}
|
||||
|
||||
function handleParamSettingApply(val: string | number) {
|
||||
addTableLine(val);
|
||||
}
|
||||
|
||||
const showQuickInputDesc = ref(false);
|
||||
const quickInputDescValue = ref('');
|
||||
|
||||
function quickInputDesc(record: any) {
|
||||
activeQuickInputRecord.value = record;
|
||||
showQuickInputDesc.value = true;
|
||||
quickInputDescValue.value = record.desc;
|
||||
}
|
||||
|
||||
function clearQuickInputDesc() {
|
||||
activeQuickInputRecord.value = {};
|
||||
quickInputDescValue.value = '';
|
||||
}
|
||||
|
||||
function applyQuickInputDesc() {
|
||||
activeQuickInputRecord.value.desc = quickInputDescValue.value;
|
||||
showQuickInputDesc.value = false;
|
||||
clearQuickInputDesc();
|
||||
addTableLine(quickInputDescValue.value, true);
|
||||
emit('change', propsRes.value.data);
|
||||
}
|
||||
|
||||
function handleDescChange() {
|
||||
emit('change', propsRes.value.data);
|
||||
}
|
||||
|
||||
function handleTypeChange(
|
||||
val: string | number | boolean | Record<string, any> | (string | number | boolean | Record<string, any>)[]
|
||||
) {
|
||||
addTableLine(val as string);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
:deep(.setting-icon) {
|
||||
margin-left: 0 !important;
|
||||
}
|
||||
:deep(.arco-table-th) {
|
||||
background-color: var(--color-text-n9);
|
||||
}
|
||||
:deep(.arco-table-cell-align-left) {
|
||||
padding: 16px 4px;
|
||||
}
|
||||
:deep(.arco-table-cell) {
|
||||
padding: 11px 4px;
|
||||
}
|
||||
: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);
|
||||
}
|
||||
}
|
||||
}
|
||||
.param-input-switch:not(:hover).arco-switch-checked {
|
||||
background-color: rgb(var(--primary-3)) !important;
|
||||
}
|
||||
.content-type-trigger-content {
|
||||
@apply bg-white;
|
||||
|
||||
padding: 8px;
|
||||
border-radius: var(--border-radius-small);
|
||||
box-shadow: 0 4px 10px -1px rgb(100 100 102 / 15%);
|
||||
}
|
||||
.param-input {
|
||||
.param-input-mock-icon {
|
||||
@apply invisible;
|
||||
}
|
||||
&:hover,
|
||||
&.arco-input-focus {
|
||||
.param-input-mock-icon {
|
||||
@apply visible cursor-pointer;
|
||||
&:hover {
|
||||
color: rgb(var(--primary-5));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.param-popover-title {
|
||||
@apply font-medium;
|
||||
|
||||
margin-bottom: 4px;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
line-height: 16px;
|
||||
color: var(--color-text-1);
|
||||
}
|
||||
.param-popover-subtitle {
|
||||
margin-bottom: 2px;
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
color: var(--color-text-4);
|
||||
}
|
||||
.param-popover-value {
|
||||
min-width: 100px;
|
||||
max-width: 280px;
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
color: var(--color-text-1);
|
||||
}
|
||||
</style>
|
|
@ -1,77 +0,0 @@
|
|||
<template>
|
||||
<a-popover position="tl" :disabled="!props.desc || props.desc.trim() === ''" class="ms-params-input-popover">
|
||||
<template #content>
|
||||
<div class="param-popover-title">
|
||||
{{ t('ms.apiTestDebug.desc') }}
|
||||
</div>
|
||||
<div class="param-popover-value">
|
||||
{{ props.desc }}
|
||||
</div>
|
||||
</template>
|
||||
<a-input
|
||||
ref="inputRef"
|
||||
v-model:model-value="innerValue"
|
||||
class="param-input"
|
||||
@input="(val) => emit('input', val)"
|
||||
@change="(val) => emit('change', val)"
|
||||
/>
|
||||
</a-popover>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useEventListener, useVModel } from '@vueuse/core';
|
||||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
|
||||
const props = defineProps<{
|
||||
desc: string;
|
||||
}>();
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:desc', val: string): void;
|
||||
(e: 'input', val: string): void;
|
||||
(e: 'change', val: string): void;
|
||||
(e: 'dblclick'): void;
|
||||
}>();
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const innerValue = useVModel(props, 'desc', emit);
|
||||
|
||||
const inputRef = ref<HTMLElement>();
|
||||
|
||||
onMounted(() => {
|
||||
useEventListener(inputRef.value, 'dblclick', () => {
|
||||
emit('dblclick');
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.param-input:not(.arco-input-focus) {
|
||||
&:not(:hover) {
|
||||
border-color: transparent;
|
||||
}
|
||||
}
|
||||
.param-popover-title {
|
||||
@apply font-medium;
|
||||
|
||||
margin-bottom: 4px;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
line-height: 16px;
|
||||
color: var(--color-text-1);
|
||||
}
|
||||
.param-popover-subtitle {
|
||||
margin-bottom: 2px;
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
color: var(--color-text-4);
|
||||
}
|
||||
.param-popover-value {
|
||||
min-width: 100px;
|
||||
max-width: 280px;
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
color: var(--color-text-1);
|
||||
}
|
||||
</style>
|
|
@ -1,74 +0,0 @@
|
|||
<template>
|
||||
<a-popover position="tl" class="ms-params-input-popover">
|
||||
<template #content>
|
||||
<div class="param-popover-title">
|
||||
{{ t('project.environmental.tag') }}
|
||||
</div>
|
||||
<div class="param-popover-value">
|
||||
<MsTagsGroup is-string-tag :tag-list="props.modelValue" :show-num="1" class="param-input" />
|
||||
</div>
|
||||
</template>
|
||||
<MsTagsInput ref="inputRef" v-model:model-value="innerValue" :max-tag-count="1" class="param-input" />
|
||||
</a-popover>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useEventListener, useVModel } from '@vueuse/core';
|
||||
|
||||
import MsTagsGroup from '@/components/pure/ms-tag/ms-tag-group.vue';
|
||||
import MsTagsInput from '@/components/pure/ms-tags-input/index.vue';
|
||||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: string[];
|
||||
}>();
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:modelValue', val: string[]): void;
|
||||
(e: 'input', val: string): void;
|
||||
(e: 'change', val: string): void;
|
||||
(e: 'dblclick'): void;
|
||||
}>();
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const innerValue = useVModel(props, 'modelValue', emit);
|
||||
|
||||
const inputRef = ref<HTMLElement>();
|
||||
|
||||
onMounted(() => {
|
||||
useEventListener(inputRef.value, 'dblclick', () => {
|
||||
emit('dblclick');
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.param-input:not(.arco-input-focus) {
|
||||
&:not(:hover) {
|
||||
border-color: transparent;
|
||||
}
|
||||
}
|
||||
.param-popover-title {
|
||||
@apply font-medium;
|
||||
|
||||
margin-bottom: 4px;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
line-height: 16px;
|
||||
color: var(--color-text-1);
|
||||
}
|
||||
.param-popover-subtitle {
|
||||
margin-bottom: 2px;
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
color: var(--color-text-4);
|
||||
}
|
||||
.param-popover-value {
|
||||
min-width: 100px;
|
||||
max-width: 280px;
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
color: var(--color-text-1);
|
||||
}
|
||||
</style>
|
|
@ -16,7 +16,7 @@
|
|||
</a-input>
|
||||
<batchAddKeyVal :params="innerParams" @apply="handleBatchParamApply" />
|
||||
</div>
|
||||
<AllParamsTable
|
||||
<paramsTable
|
||||
v-model:params="innerParams"
|
||||
:table-key="props.tableKey"
|
||||
:columns="columns"
|
||||
|
@ -28,8 +28,7 @@
|
|||
<script setup lang="ts">
|
||||
import { useVModel } from '@vueuse/core';
|
||||
|
||||
import { MsTableColumn } from '@/components/pure/ms-table/type';
|
||||
import AllParamsTable from './AllParamsTable.vue';
|
||||
import paramsTable, { type ParamTableColumn } from '@/views/api-test/components/paramTable.vue';
|
||||
import batchAddKeyVal from '@/views/api-test/debug/components/debug/batchAddKeyVal.vue';
|
||||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
|
@ -56,7 +55,7 @@
|
|||
|
||||
const innerParams = useVModel(props, 'params', emit);
|
||||
|
||||
const columns: MsTableColumn = [
|
||||
const columns: ParamTableColumn[] = [
|
||||
{
|
||||
title: 'project.environmental.paramName',
|
||||
dataIndex: 'name',
|
||||
|
@ -70,6 +69,34 @@
|
|||
slotName: 'type',
|
||||
showInTable: true,
|
||||
showDrag: true,
|
||||
typeOptions: [
|
||||
{
|
||||
label: t('common.string'),
|
||||
value: 'string',
|
||||
},
|
||||
{
|
||||
label: t('common.integer'),
|
||||
value: 'integer',
|
||||
},
|
||||
{
|
||||
label: t('common.number'),
|
||||
value: 'number',
|
||||
},
|
||||
{
|
||||
label: t('common.array'),
|
||||
value: 'array',
|
||||
},
|
||||
{
|
||||
label: t('common.json'),
|
||||
value: 'json',
|
||||
},
|
||||
{
|
||||
label: t('common.file'),
|
||||
value: 'file',
|
||||
},
|
||||
],
|
||||
titleSlotName: 'typeTitle',
|
||||
typeTitleTooltip: t('project.environmental.paramTypeTooltip'),
|
||||
},
|
||||
{
|
||||
title: 'project.environmental.paramValue',
|
||||
|
|
|
@ -1,21 +1,15 @@
|
|||
<template>
|
||||
<div class="mb-[8px] flex items-center justify-between">
|
||||
<div class="font-medium">{{ t('ms.apiTestDebug.header') }}</div>
|
||||
<div class="font-medium">{{ t('apiTestDebug.header') }}</div>
|
||||
<batchAddKeyVal :params="innerParams" @apply="handleBatchParamApply" />
|
||||
</div>
|
||||
<AllParamsTable
|
||||
v-model:params="innerParams"
|
||||
:show-setting="false"
|
||||
:columns="columns"
|
||||
@change="handleParamTableChange"
|
||||
/>
|
||||
<paramsTable v-model:params="innerParams" :show-setting="false" :columns="columns" @change="handleParamTableChange" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useVModel } from '@vueuse/core';
|
||||
|
||||
import type { MsTableColumn } from '@/components/pure/ms-table/type';
|
||||
import AllParamsTable from '../allParams/AllParamsTable.vue';
|
||||
import paramsTable, { type ParamTableColumn } from '@/views/api-test/components/paramTable.vue';
|
||||
import batchAddKeyVal from '@/views/api-test/debug/components/debug/batchAddKeyVal.vue';
|
||||
|
||||
import { useI18n } from '@/hooks/useI18n';
|
||||
|
@ -32,14 +26,14 @@
|
|||
|
||||
const innerParams = useVModel(props, 'params', emit);
|
||||
|
||||
const columns: MsTableColumn = [
|
||||
const columns: ParamTableColumn[] = [
|
||||
{
|
||||
title: 'ms.apiTestDebug.paramName',
|
||||
title: 'apiTestDebug.paramName',
|
||||
dataIndex: 'name',
|
||||
slotName: 'name',
|
||||
},
|
||||
{
|
||||
title: 'ms.apiTestDebug.desc',
|
||||
title: 'apiTestDebug.desc',
|
||||
dataIndex: 'desc',
|
||||
slotName: 'desc',
|
||||
},
|
||||
|
|
|
@ -182,6 +182,8 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { VueDraggable } from 'vue-draggable-plus';
|
||||
|
||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||
import MsIcon from '@/components/pure/ms-icon-font/index.vue';
|
||||
import MsSplitBox from '@/components/pure/ms-split-box/index.vue';
|
||||
|
@ -199,8 +201,6 @@
|
|||
import { PopVisible } from '@/models/setting/usergroup';
|
||||
import { EnvAuthScopeEnum, EnvAuthTypeEnum } from '@/enums/envEnum';
|
||||
|
||||
import { VueDraggable } from 'vue-draggable-plus';
|
||||
|
||||
const { t } = useI18n();
|
||||
const store = useProjectEnvStore();
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
:disabled="loading"
|
||||
size="small"
|
||||
class="mr-[4px]"
|
||||
type="line"
|
||||
/>
|
||||
<a-tooltip :content="t('project.fileManagement.uploadTipSingle')">
|
||||
<MsIcon type="icon-icon-maybe_outlined" class="mr-[8px] cursor-pointer hover:text-[rgb(var(--primary-5))]" />
|
||||
|
|
|
@ -174,7 +174,7 @@
|
|||
>
|
||||
<template #tabExtra>
|
||||
<div v-if="acceptType === 'jar'" class="flex items-center gap-[4px]">
|
||||
<a-switch size="small" :disabled="fileList.length === 0" @change="enableAllJar"></a-switch>
|
||||
<a-switch size="small" :disabled="fileList.length === 0" type="line" @change="enableAllJar"></a-switch>
|
||||
{{ t('project.fileManagement.enableAll') }}
|
||||
<a-tooltip :content="t('project.fileManagement.uploadTip')">
|
||||
<MsIcon type="icon-icon-maybe_outlined" class="cursor-pointer hover:text-[rgb(var(--primary-5))]" />
|
||||
|
@ -182,7 +182,7 @@
|
|||
</div>
|
||||
</template>
|
||||
<template #actions="{ item }">
|
||||
<a-switch v-if="acceptType === 'jar'" v-model:model-value="item.enable" size="small"></a-switch>
|
||||
<a-switch v-if="acceptType === 'jar'" v-model:model-value="item.enable" size="small" type="line"></a-switch>
|
||||
</template>
|
||||
</MsFileList>
|
||||
<template #footer>
|
||||
|
|
|
@ -88,6 +88,7 @@
|
|||
v-model:model-value="record.projectRobotConfigMap[dataIndex as string].enable"
|
||||
:before-change="(val) => handleChangeIntercept(!!val, record, dataIndex as string)"
|
||||
size="small"
|
||||
type="line"
|
||||
/>
|
||||
<a-popover position="right" :popup-container="isFullscreen ? '#mscard' : undefined">
|
||||
<div
|
||||
|
|
|
@ -67,6 +67,7 @@
|
|||
v-model:model-value="robot.enable"
|
||||
size="small"
|
||||
class="ml-auto"
|
||||
type="line"
|
||||
@change="handleEnableIntercept(robot)"
|
||||
/>
|
||||
</div>
|
||||
|
@ -240,7 +241,7 @@
|
|||
</a-form-item>
|
||||
</a-form>
|
||||
<template #footerLeft>
|
||||
<a-switch v-model:model-value="robotForm.enable" size="small" class="mr-[4px]"></a-switch>
|
||||
<a-switch v-model:model-value="robotForm.enable" size="small" class="mr-[4px]" type="line"></a-switch>
|
||||
{{ t('project.messageManagement.status') }}
|
||||
<a-tooltip position="tl" mini>
|
||||
<template #content>
|
||||
|
|
|
@ -80,9 +80,9 @@
|
|||
<template v-if="platformOption.length" #footerLeft>
|
||||
<div class="flex flex-row items-center gap-[4px]">
|
||||
<a-tooltip v-if="okDisabled" :content="t('project.menu.defect.enableAfterConfig')">
|
||||
<a-switch size="small" disabled />
|
||||
<a-switch size="small" type="line" disabled />
|
||||
</a-tooltip>
|
||||
<a-switch v-else v-model="form.SYNC_ENABLE" size="small" />
|
||||
<a-switch v-else v-model="form.SYNC_ENABLE" size="small" type="line" />
|
||||
<span class="text-[var(--color-text-1)]">
|
||||
{{ t('project.menu.status') }}
|
||||
</span>
|
||||
|
|
|
@ -37,9 +37,9 @@
|
|||
<template v-if="platformOption.length" #footerLeft>
|
||||
<div class="flex flex-row items-center gap-[4px]">
|
||||
<a-tooltip v-if="okDisabled" :content="t('project.menu.defect.enableAfterConfig')">
|
||||
<a-switch size="small" disabled />
|
||||
<a-switch size="small" type="line" disabled />
|
||||
</a-tooltip>
|
||||
<a-switch v-else v-model="form.SYNC_ENABLE" size="small" />
|
||||
<a-switch v-else v-model="form.SYNC_ENABLE" size="small" type="line" />
|
||||
<span class="text-[var(--color-text-1)]">
|
||||
{{ t('project.menu.status') }}
|
||||
</span>
|
||||
|
|
|
@ -226,6 +226,7 @@
|
|||
unchecked-value="false"
|
||||
:value="allValueMap['BUG_SYNC_SYNC_ENABLE']"
|
||||
size="small"
|
||||
type="line"
|
||||
@change="(v: boolean | string| number) => handleMenuStatusChange('BUG_SYNC_SYNC_ENABLE',v as boolean, MenuEnum.bugManagement)"
|
||||
/>
|
||||
</a-tooltip>
|
||||
|
@ -234,6 +235,7 @@
|
|||
checked-value="true"
|
||||
unchecked-value="false"
|
||||
size="small"
|
||||
type="line"
|
||||
@change="(v: boolean | string| number) => handleMenuStatusChange('BUG_SYNC_SYNC_ENABLE',v as boolean, MenuEnum.bugManagement)"
|
||||
/>
|
||||
<!-- 关联需求状态 -->
|
||||
|
@ -252,6 +254,7 @@
|
|||
unchecked-value="false"
|
||||
:value="allValueMap['CASE_RELATED_CASE_ENABLE']"
|
||||
size="small"
|
||||
type="line"
|
||||
@change="(v: boolean | string| number) => handleMenuStatusChange('CASE_RELATED_CASE_ENABLE',v as boolean, MenuEnum.caseManagement)"
|
||||
/>
|
||||
</a-tooltip>
|
||||
|
@ -260,6 +263,7 @@
|
|||
checked-value="true"
|
||||
unchecked-value="false"
|
||||
size="small"
|
||||
type="line"
|
||||
@change="(v: boolean | string| number) => handleMenuStatusChange('CASE_RELATED_CASE_ENABLE',v as boolean, MenuEnum.caseManagement)"
|
||||
/>
|
||||
<!-- 其他配置项 -->
|
||||
|
@ -270,6 +274,7 @@
|
|||
checked-value="true"
|
||||
unchecked-value="false"
|
||||
size="small"
|
||||
type="line"
|
||||
@change="(v: boolean | string| number) => handleMenuStatusChange(record.type,v as boolean,MenuEnum.workstation)"
|
||||
/>
|
||||
<!-- 用例 公共用例 Switch-->
|
||||
|
@ -279,6 +284,7 @@
|
|||
checked-value="true"
|
||||
unchecked-value="false"
|
||||
size="small"
|
||||
type="line"
|
||||
@change="(v: boolean | string| number) => handleMenuStatusChange(record.type,v as boolean,MenuEnum.caseManagement)"
|
||||
/>
|
||||
<!-- 用例 重新提审 Switch-->
|
||||
|
@ -288,6 +294,7 @@
|
|||
checked-value="true"
|
||||
unchecked-value="false"
|
||||
size="small"
|
||||
type="line"
|
||||
@change="(v: boolean | string| number) => handleMenuStatusChange(record.type,v as boolean,MenuEnum.caseManagement)"
|
||||
/>
|
||||
<!-- 接口测试 接口定义URL可重复 Switch-->
|
||||
|
@ -297,6 +304,7 @@
|
|||
checked-value="true"
|
||||
unchecked-value="false"
|
||||
size="small"
|
||||
type="line"
|
||||
@change="(v: boolean | string| number) => handleMenuStatusChange(record.type,v as boolean,MenuEnum.apiTest)"
|
||||
/>
|
||||
<!-- 接口测试 用例同步 Switch-->
|
||||
|
@ -306,6 +314,7 @@
|
|||
checked-value="true"
|
||||
unchecked-value="false"
|
||||
size="small"
|
||||
type="line"
|
||||
@change="(v: boolean | string| number) => handleMenuStatusChange(record.type,v as boolean,MenuEnum.apiTest)"
|
||||
/>
|
||||
<!-- 性能测试 脚本审核 Switch-->
|
||||
|
@ -315,6 +324,7 @@
|
|||
checked-value="true"
|
||||
unchecked-value="false"
|
||||
size="small"
|
||||
type="line"
|
||||
@change="(v: boolean | string| number) => handleMenuStatusChange('PERFORMANCE_TEST_SCRIPT_REVIEWER_ENABLE',v as boolean,MenuEnum.loadTest)"
|
||||
/>
|
||||
</template>
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
v-model:model-value="projectVersionStatus"
|
||||
size="small"
|
||||
:before-change="(val) => openProjectVersion(val)"
|
||||
type="line"
|
||||
>
|
||||
</a-switch>
|
||||
<span class="ml-[4px] font-medium">{{ t('project.projectVersion.version') }}</span>
|
||||
|
@ -144,6 +145,7 @@
|
|||
v-model:model-value="record.status"
|
||||
size="small"
|
||||
:before-change="(val) => handleStatusChange(val, record)"
|
||||
type="line"
|
||||
></a-switch>
|
||||
</template>
|
||||
<template #latest="{ record }">
|
||||
|
@ -152,6 +154,7 @@
|
|||
:disabled="record.latest"
|
||||
:before-change="() => handleUseLatestVersionChange(record)"
|
||||
size="small"
|
||||
type="line"
|
||||
/>
|
||||
</template>
|
||||
<template #action="{ record }">
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
v-model="record.enableDefault"
|
||||
:disabled="record.enableDefault || isEnableOrdTemplate"
|
||||
size="small"
|
||||
type="line"
|
||||
@change="(value) => changeDefault(value, record)"
|
||||
/>
|
||||
</template>
|
||||
|
|
|
@ -72,7 +72,7 @@
|
|||
<template #footer>
|
||||
<div class="flex flex-row justify-between">
|
||||
<div class="flex flex-row items-center gap-[4px]">
|
||||
<a-switch v-model="form.enable" size="small" />
|
||||
<a-switch v-model="form.enable" size="small" type="line" />
|
||||
<span>{{ t('system.organization.status') }}</span>
|
||||
<a-tooltip :content="t('system.project.createTip')" position="top">
|
||||
<MsIcon type="icon-icon-maybe_outlined" class="text-[var(--color-text-4)]" />
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<template #footer>
|
||||
<div class="flex justify-between">
|
||||
<div class="flex flex-row items-center justify-center">
|
||||
<a-switch v-model="isEnable" :disabled="isDisabled" size="small" />
|
||||
<a-switch v-model="isEnable" :disabled="isDisabled" size="small" type="line" />
|
||||
<a-tooltip>
|
||||
<template #content>
|
||||
<div class="text-sm">{{ t('organization.service.statusEnableTip') }}</div>
|
||||
|
|
|
@ -86,10 +86,17 @@
|
|||
v-model="item.enable"
|
||||
size="small"
|
||||
:disabled="true"
|
||||
type="line"
|
||||
@change="(v) => changeStatus(v, item.id)"
|
||||
/></span>
|
||||
</a-tooltip>
|
||||
<a-switch v-else v-model="item.enable" size="small" @change="(v) => changeStatus(v, item.id)" />
|
||||
<a-switch
|
||||
v-else
|
||||
v-model="item.enable"
|
||||
size="small"
|
||||
type="line"
|
||||
@change="(v) => changeStatus(v, item.id)"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -97,6 +97,7 @@
|
|||
* @description 系统管理-模版-模版管理-创建模板-添加字段到模板抽屉
|
||||
*/
|
||||
import { ref } from 'vue';
|
||||
import { VueDraggable } from 'vue-draggable-plus';
|
||||
|
||||
import MsButton from '@/components/pure/ms-button/index.vue';
|
||||
import MsDrawer from '@/components/pure/ms-drawer/index.vue';
|
||||
|
@ -106,8 +107,6 @@
|
|||
|
||||
import type { DefinedFieldItem } from '@/models/setting/template';
|
||||
|
||||
import { VueDraggable } from 'vue-draggable-plus';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const showAddDrawer = ref<boolean>(false);
|
||||
|
|
|
@ -58,7 +58,7 @@
|
|||
:label="t('system.orgTemplate.allowMultiMember')"
|
||||
asterisk-position="end"
|
||||
>
|
||||
<a-switch v-model="isMultipleSelectMember" size="small" :disabled="isEdit" />
|
||||
<a-switch v-model="isMultipleSelectMember" size="small" :disabled="isEdit" type="line" />
|
||||
</a-form-item>
|
||||
<!-- 选项选择器 -->
|
||||
<a-form-item
|
||||
|
|
|
@ -180,11 +180,11 @@
|
|||
></a-input>
|
||||
</a-form-item>
|
||||
<a-form-item :label="t('system.config.email.ssl')" field="ssl" asterisk-position="end">
|
||||
<a-switch v-model:model-value="emailConfigForm.ssl" />
|
||||
<a-switch v-model:model-value="emailConfigForm.ssl" type="line" />
|
||||
<MsFormItemSub :text="t('system.config.email.sslTip')" :show-fill-icon="false" />
|
||||
</a-form-item>
|
||||
<a-form-item :label="t('system.config.email.tsl')" field="tsl" asterisk-position="end">
|
||||
<a-switch v-model:model-value="emailConfigForm.tsl" />
|
||||
<a-switch v-model:model-value="emailConfigForm.tsl" type="line" />
|
||||
<MsFormItemSub :text="t('system.config.email.tslTip')" :show-fill-icon="false" />
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
|
|
|
@ -74,7 +74,7 @@
|
|||
<template #footer>
|
||||
<div class="flex flex-row justify-between">
|
||||
<div class="flex flex-row items-center gap-[4px]">
|
||||
<a-switch v-model="form.enable" size="small" />
|
||||
<a-switch v-model="form.enable" size="small" type="line" />
|
||||
<span>{{ t('system.organization.status') }}</span>
|
||||
<a-tooltip :content="t('system.project.createTip')" position="top">
|
||||
<MsIcon type="icon-icon-maybe_outlined" class="text-[var(--color-text-4)]" />
|
||||
|
|
|
@ -73,7 +73,7 @@
|
|||
<template #footer>
|
||||
<div class="flex justify-between">
|
||||
<div class="flex flex-row items-center justify-center">
|
||||
<a-switch v-model="form.enable" size="small" />
|
||||
<a-switch v-model="form.enable" size="small" type="line" />
|
||||
<a-tooltip>
|
||||
<template #content>
|
||||
<div class="text-sm">{{ t('system.plugin.statusEnableTip') }}</div>
|
||||
|
|
Loading…
Reference in New Issue