diff --git a/frontend/src/components/business/ms-params-input/index.vue b/frontend/src/components/business/ms-params-input/index.vue index 2eb89625ed..2ee50870fd 100644 --- a/frontend/src/components/business/ms-params-input/index.vue +++ b/frontend/src/components/business/ms-params-input/index.vue @@ -332,6 +332,7 @@ emit('dblclick'); }); const autoCompleteInput = (autoCompleteRef.value?.inputRef as any)?.$el.querySelector('.arco-input'); + // 设置输入框聚焦状态,聚焦时不显示参数预览的 popover useEventListener(autoCompleteInput, 'focus', () => { isFocusAutoComplete.value = true; popoverVisible.value = false; @@ -515,7 +516,7 @@ if (currentParamsFuncInputGroup.value.length > 0 && !Number.isNaN(paramForm.value.funcParam1)) { // 如果添加的函数还有入参 resultStr = `${resultStr}(${[paramForm.value.funcParam1, paramForm.value.funcParam2] - .filter((e) => !Number.isNaN(e)) + .filter((e) => e !== '' && !Number.isNaN(e)) .join(',')})`; } } @@ -579,6 +580,10 @@ .ms-params-input:not(.arco-input-focus) { border-color: transparent; &:not(:hover) { + .arco-input::placeholder { + @apply invisible; + } + border-color: transparent; } } diff --git a/frontend/src/components/pure/ms-code-editor/index.vue b/frontend/src/components/pure/ms-code-editor/index.vue index ee1057f552..46e37b638e 100644 --- a/frontend/src/components/pure/ms-code-editor/index.vue +++ b/frontend/src/components/pure/ms-code-editor/index.vue @@ -4,6 +4,15 @@ {{ title }} +
+ +
@@ -22,7 +31,7 @@ import './userWorker'; import MsCodeEditorTheme from './themes'; - import { CustomTheme, editorProps } from './types'; + import { CustomTheme, editorProps, Theme } from './types'; import * as monaco from 'monaco-editor/esm/vs/editor/editor.api'; export default defineComponent({ @@ -34,12 +43,34 @@ let editor: monaco.editor.IStandaloneCodeEditor; const codeEditBox = ref(); const fullRef = ref(); + const currentTheme = ref(props.theme); + const themeOptions = [ + { label: 'vs', value: 'vs' }, + { label: 'vs-dark', value: 'vs-dark' }, + { label: 'hc-black', value: 'hc-black' }, + ].concat( + Object.keys(MsCodeEditorTheme).map((item) => ({ + label: item, + value: item, + })) + ); + + watch( + () => props.theme, + (val) => { + currentTheme.value = val; + } + ); + + function handleThemeChange(val: Theme) { + monaco.editor.setTheme(val); + } const init = () => { // 注册自定义主题 - if (MsCodeEditorTheme[props.theme as CustomTheme]) { - monaco.editor.defineTheme(props.theme, MsCodeEditorTheme[props.theme as CustomTheme]); - } + Object.keys(MsCodeEditorTheme).forEach((e) => { + monaco.editor.defineTheme(e, MsCodeEditorTheme[e as CustomTheme]); + }); editor = monaco.editor.create(codeEditBox.value, { value: props.modelValue, automaticLayout: true, @@ -90,12 +121,12 @@ { deep: true } ); - // watch( - // () => props.language, - // (newValue) => { - // monaco.editor.setModelLanguage(editor.getModel()!, newValue); - // } - // ); + watch( + () => props.language, + (newValue) => { + monaco.editor.setModelLanguage(editor.getModel()!, newValue); + } + ); onBeforeUnmount(() => { editor.dispose(); @@ -106,7 +137,7 @@ setEditBoxBg(); }); - return { codeEditBox, fullRef, isFullscreen, toggle, t }; + return { codeEditBox, fullRef, isFullscreen, currentTheme, themeOptions, toggle, t, handleThemeChange }; }, }); diff --git a/frontend/src/components/pure/ms-code-editor/types.ts b/frontend/src/components/pure/ms-code-editor/types.ts index 9f76321f5a..4e0a4904f1 100644 --- a/frontend/src/components/pure/ms-code-editor/types.ts +++ b/frontend/src/components/pure/ms-code-editor/types.ts @@ -87,4 +87,8 @@ export const editorProps = { type: Boolean as PropType, default: true, }, + showThemeChange: { + type: Boolean as PropType, + default: true, + }, }; diff --git a/frontend/src/components/pure/ms-editable-tab/index.vue b/frontend/src/components/pure/ms-editable-tab/index.vue index 3babbbfef6..2784ecdf77 100644 --- a/frontend/src/components/pure/ms-editable-tab/index.vue +++ b/frontend/src/components/pure/ms-editable-tab/index.vue @@ -44,9 +44,20 @@ - - - + + + + + @@ -72,12 +83,13 @@ tabs: TabItem[]; activeTab: string | number; moreActionList?: ActionsItem[]; + limit?: number; // 最多可打开的tab数量 }>(); const emit = defineEmits<{ (e: 'update:activeTab', activeTab: string | number): void; (e: 'add'): void; (e: 'close', item: TabItem): void; - (e: 'click', item: TabItem): void; + (e: 'change', item: TabItem): void; }>(); const { t } = useI18n(); @@ -119,6 +131,13 @@ } }; + watch( + () => props.activeTab, + (val) => { + emit('change', props.tabs.find((item) => item.id === val) as TabItem); + } + ); + watch(props.tabs, () => { nextTick(() => { scrollToActiveTab(); @@ -141,6 +160,7 @@ } function handleTabClick(item: TabItem) { + emit('change', item); innerActiveTab.value = item.id; nextTick(() => { tabNav.value?.querySelector('.tab.active')?.scrollIntoView({ behavior: 'smooth', block: 'center' }); diff --git a/frontend/src/components/pure/ms-editable-tab/locale/en-US.ts b/frontend/src/components/pure/ms-editable-tab/locale/en-US.ts index b704aecec8..ef818f51a6 100644 --- a/frontend/src/components/pure/ms-editable-tab/locale/en-US.ts +++ b/frontend/src/components/pure/ms-editable-tab/locale/en-US.ts @@ -1,4 +1,5 @@ export default { 'ms.editableTab.arrivedLeft': 'Already reached the far left~', 'ms.editableTab.arrivedRight': 'Already reached the far right~', + 'ms.editableTab.limitTip': 'Up to {max} tabs can currently be open', }; diff --git a/frontend/src/components/pure/ms-editable-tab/locale/zh-CN.ts b/frontend/src/components/pure/ms-editable-tab/locale/zh-CN.ts index 48afa0421c..c6309fb71a 100644 --- a/frontend/src/components/pure/ms-editable-tab/locale/zh-CN.ts +++ b/frontend/src/components/pure/ms-editable-tab/locale/zh-CN.ts @@ -1,4 +1,5 @@ export default { 'ms.editableTab.arrivedLeft': '到最左侧啦~', 'ms.editableTab.arrivedRight': '到最右侧啦~', + 'ms.editableTab.limitTip': '当前最多可打开 {max} 个标签页', }; diff --git a/frontend/src/components/pure/ms-split-box/index.vue b/frontend/src/components/pure/ms-split-box/index.vue index ae5ab7dab7..9222a5833e 100644 --- a/frontend/src/components/pure/ms-split-box/index.vue +++ b/frontend/src/components/pure/ms-split-box/index.vue @@ -162,7 +162,7 @@ .ms-scroll-bar(); } .ms-split-box--left { - width: calc(v-bind(innerSize) - 4px); + width: calc(v-bind(innerSize) - 2px); } .expand-icon { @apply relative z-20 flex cursor-pointer justify-center; @@ -185,7 +185,7 @@ border-radius: 0 var(--border-radius-small) var(--border-radius-small) 0; } .horizontal-expand-line { - padding: 0 1px; + padding-left: 2px; height: 100%; .expand-color-line { width: 1px; diff --git a/frontend/src/components/pure/ms-table/useTable.ts b/frontend/src/components/pure/ms-table/useTable.ts index bea416a269..e05b1c0951 100644 --- a/frontend/src/components/pure/ms-table/useTable.ts +++ b/frontend/src/components/pure/ms-table/useTable.ts @@ -392,22 +392,22 @@ export default function useTableProps( }); watchEffect(() => { - if (props?.heightUsed) { - const { heightUsed, showPagination, selectedKeys, msPagination } = propsRes.value; - let hasFooterAction = false; - if (showPagination) { - const { pageSize, total } = msPagination as Pagination; - /* - * 是否有底部操作栏 包括 批量操作 和 分页器 - * 1. 有分页器,且总条数大于每页条数 - * 2. 有选中项 - */ - hasFooterAction = total > pageSize || selectedKeys.size > 0; - } + const { heightUsed, showPagination, selectedKeys, msPagination } = propsRes.value; + let hasFooterAction = false; + if (showPagination) { + const { pageSize, total } = msPagination as Pagination; + /* + * 是否有底部操作栏 包括 批量操作 和 分页器 + * 1. 有分页器,且总条数大于每页条数 + * 2. 有选中项 + */ + hasFooterAction = total > pageSize || selectedKeys.size > 0; + } + propsRes.value.showFooterActionWrap = hasFooterAction; + if (props?.heightUsed) { const currentY = appStore.innerHeight - (heightUsed || defaultHeightUsed) + (hasFooterAction ? 0 : footerActionWrapHeight); - propsRes.value.showFooterActionWrap = hasFooterAction; propsRes.value.scroll = { ...propsRes.value.scroll, y: currentY }; } }); diff --git a/frontend/src/enums/apiEnum.ts b/frontend/src/enums/apiEnum.ts index 6556a252ab..1dc4b92865 100644 --- a/frontend/src/enums/apiEnum.ts +++ b/frontend/src/enums/apiEnum.ts @@ -1,3 +1,4 @@ +// 接口请求方法 export enum RequestMethods { GET = 'GET', POST = 'POST', @@ -8,7 +9,7 @@ export enum RequestMethods { HEAD = 'HEAD', CONNECT = 'CONNECT', } - +// 接口组成部分 export enum RequestComposition { HEADER = 'HEADER', BODY = 'BODY', @@ -20,3 +21,25 @@ export enum RequestComposition { AUTH = 'AUTH', SETTING = 'SETTING', } +// 接口请求体格式 +export enum RequestBodyFormat { + NONE = 'none', + FORM_DATA = 'form-data', + X_WWW_FORM_URLENCODED = 'x-www-form-urlencoded', + JSON = 'json', + XML = 'xml', + RAW = 'raw', + BINARY = 'binary', +} +// 接口响应体格式 +export enum RequestContentTypeEnum { + JSON = 'application/json', + TEXT = 'application/text', + OGG = 'application/ogg', + PDF = 'application/pdf', + JAVASCRIPT = 'application/javascript', + OCTET_STREAM = 'application/octet-stream', + VND_API_JSON = 'application/vnd.api+json', + ATOM_XML = 'application/atom+xml', + ECMASCRIPT = 'application/ecmascript', +} diff --git a/frontend/src/views/api-test/debug/components/debug/paramDescInput.vue b/frontend/src/views/api-test/components/paramDescInput.vue similarity index 84% rename from frontend/src/views/api-test/debug/components/debug/paramDescInput.vue rename to frontend/src/views/api-test/components/paramDescInput.vue index 50ebd398a8..d6c5fc970c 100644 --- a/frontend/src/views/api-test/debug/components/debug/paramDescInput.vue +++ b/frontend/src/views/api-test/components/paramDescInput.vue @@ -8,7 +8,13 @@ {{ props.desc }}
- + @@ -21,8 +27,9 @@ desc: string; }>(); const emit = defineEmits<{ - (e: 'update:value', val: string): void; + (e: 'update:desc', val: string): void; (e: 'input', val: string): void; + (e: 'change', val: string): void; (e: 'dblclick'): void; }>(); diff --git a/frontend/src/views/api-test/components/paramTable.vue b/frontend/src/views/api-test/components/paramTable.vue new file mode 100644 index 0000000000..120da42709 --- /dev/null +++ b/frontend/src/views/api-test/components/paramTable.vue @@ -0,0 +1,466 @@ + + + + + diff --git a/frontend/src/views/api-test/debug/components/debug/batchAddKeyVal.vue b/frontend/src/views/api-test/debug/components/debug/batchAddKeyVal.vue new file mode 100644 index 0000000000..d496e219de --- /dev/null +++ b/frontend/src/views/api-test/debug/components/debug/batchAddKeyVal.vue @@ -0,0 +1,103 @@ + + + + + diff --git a/frontend/src/views/api-test/debug/components/debug/body.vue b/frontend/src/views/api-test/debug/components/debug/body.vue new file mode 100644 index 0000000000..c134375ec2 --- /dev/null +++ b/frontend/src/views/api-test/debug/components/debug/body.vue @@ -0,0 +1,222 @@ + + + + + diff --git a/frontend/src/views/api-test/debug/components/debug/header.vue b/frontend/src/views/api-test/debug/components/debug/header.vue index 4920020966..8923a7d136 100644 --- a/frontend/src/views/api-test/debug/components/debug/header.vue +++ b/frontend/src/views/api-test/debug/components/debug/header.vue @@ -1,131 +1,23 @@ - + diff --git a/frontend/src/views/api-test/debug/components/debug/index.vue b/frontend/src/views/api-test/debug/components/debug/index.vue index 2d2db8f492..de871527a4 100644 --- a/frontend/src/views/api-test/debug/components/debug/index.vue +++ b/frontend/src/views/api-test/debug/components/debug/index.vue @@ -6,28 +6,40 @@ :more-action-list="moreActionList" @add="addDebugTab" @close="closeDebugTab" - @click="setActiveDebug" + @change="setActiveDebug" >
- - - - - - - - - +
+ + + + + + + + + + +
{{ t('ms.apiTestDebug.serverExec') }} @@ -57,12 +69,25 @@ @expand-change="handleExpandChange" > diff --git a/frontend/src/views/api-test/debug/locale/en-US.ts b/frontend/src/views/api-test/debug/locale/en-US.ts index 9ad5ee3a59..ee62a4301d 100644 --- a/frontend/src/views/api-test/debug/locale/en-US.ts +++ b/frontend/src/views/api-test/debug/locale/en-US.ts @@ -1,6 +1,6 @@ export default { - 'ms.apiTestDebug.createDebug': 'New debug', 'ms.apiTestDebug.newApi': 'New request', + 'ms.apiTestDebug.importApi': 'Import request', 'ms.apiTestDebug.urlPlaceholder': 'Please enter the full URL including http or https', 'ms.apiTestDebug.serverExec': 'Server execution', 'ms.apiTestDebug.localExec': 'Local execution', diff --git a/frontend/src/views/api-test/debug/locale/zh-CN.ts b/frontend/src/views/api-test/debug/locale/zh-CN.ts index 2c9fa95d28..387fdc03e8 100644 --- a/frontend/src/views/api-test/debug/locale/zh-CN.ts +++ b/frontend/src/views/api-test/debug/locale/zh-CN.ts @@ -1,6 +1,6 @@ export default { - 'ms.apiTestDebug.createDebug': '新建调试', 'ms.apiTestDebug.newApi': '新建请求', + 'ms.apiTestDebug.importApi': '导入请求', 'ms.apiTestDebug.urlPlaceholder': '请输入包含 http 或 https 的完整URL', 'ms.apiTestDebug.serverExec': '服务端执行', 'ms.apiTestDebug.localExec': '本地执行', @@ -18,13 +18,23 @@ export default { 'ms.apiTestDebug.horizontal': '左右布局', 'ms.apiTestDebug.paramName': '参数名称', 'ms.apiTestDebug.paramNamePlaceholder': '请输入参数名称', + 'ms.apiTestDebug.paramRequired': '必填', + 'ms.apiTestDebug.paramNotRequired': '非必填', + 'ms.apiTestDebug.paramType': '类型', 'ms.apiTestDebug.paramValue': '参数值', 'ms.apiTestDebug.paramValuePlaceholder': '以{at}开始,双击可快速输入', + 'ms.apiTestDebug.paramLengthRange': '长度区间', + 'ms.apiTestDebug.paramMin': '最小值', + 'ms.apiTestDebug.paramMax': '最大值', 'ms.apiTestDebug.paramValuePreview': '参数预览', 'ms.apiTestDebug.desc': '描述', + 'ms.apiTestDebug.encode': '编码', + 'ms.apiTestDebug.encodeTip1': '开启:使用编码', + 'ms.apiTestDebug.encodeTip2': '关闭:不使用编码', 'ms.apiTestDebug.apply': '应用', 'ms.apiTestDebug.batchAddParamsTip': '书写格式:参数名:参数值;如 nama:natural', 'ms.apiTestDebug.batchAddParamsTip2': '注: 多条记录以换行分隔,批量添加里的参数名重复,默认以最后一条数据为最新数据', 'ms.apiTestDebug.quickInputParamsTip': '支持Mock/JMeter/Json/Text/String等', 'ms.apiTestDebug.descPlaceholder': '请输入内容', + 'ms.apiTestDebug.noneBody': '请求没有 Body', };