diff --git a/frontend/src/api/modules/case-management/featureCase.ts b/frontend/src/api/modules/case-management/featureCase.ts index 2a94fab6ec..0d4554946b 100644 --- a/frontend/src/api/modules/case-management/featureCase.ts +++ b/frontend/src/api/modules/case-management/featureCase.ts @@ -1,3 +1,5 @@ +import { CommentItem } from '@/components/business/ms-comment/types'; + import MSR from '@/api/http/index'; import { AddDemandUrl, @@ -22,6 +24,7 @@ import { DetailCaseUrl, DownloadFileUrl, FollowerCaseUrl, + GetAssociatedDrawerCaseUrl, GetAssociatedFilePageUrl, GetAssociationPublicCaseModuleCountUrl, GetAssociationPublicCasePageUrl, @@ -44,6 +47,7 @@ import { GetTrashCaseModuleTreeUrl, MoveCaseModuleTreeUrl, PreviewFileUrl, + publicAssociatedCaseUrl, RecoverRecycleCaseListUrl, RestoreCaseListUrl, TransferFileUrl, @@ -61,7 +65,6 @@ import type { BatchMoveOrCopyType, CaseManagementTable, CaseModuleQueryParams, - CommentItem, CreateOrUpdate, CreateOrUpdateDemand, CreateOrUpdateModule, @@ -297,6 +300,10 @@ export function getPublicLinkCaseModulesCounts(data: TableQueryParams) { export function getPublicLinkModuleTree(data: TableQueryParams) { return MSR.post({ url: `${GetAssociationPublicModuleTreeUrl}`, data }); } +// 关联用例 +export function associationPublicCase(data: TableQueryParams) { + return MSR.post({ url: `${publicAssociatedCaseUrl}`, data }); +} // 获取前后置用例 export function getDependOnCase(data: TableQueryParams) { @@ -314,4 +321,8 @@ export function addPrepositionRelation(data: TableQueryParams) { export function cancelPreOrPostCase(id: string) { return MSR.get({ url: `${cancelPreAndPostCaseUrl}/${id}` }); } +// 获取抽屉详情已关联用例列表 +export function getAssociatedCasePage(data: TableQueryParams) { + return MSR.post>({ url: `${GetAssociatedDrawerCaseUrl}`, data }); +} export default {}; diff --git a/frontend/src/api/requrls/case-management/featureCase.ts b/frontend/src/api/requrls/case-management/featureCase.ts index 428a2a7d76..f7e0b4d627 100644 --- a/frontend/src/api/requrls/case-management/featureCase.ts +++ b/frontend/src/api/requrls/case-management/featureCase.ts @@ -116,3 +116,7 @@ export const GetDependOnRelationUrl = '/functional/case/relationship/relate/page export const AddDependOnRelationUrl = '/functional/case/relationship/add'; // 取消关联前后置关系 export const cancelPreAndPostCaseUrl = '/functional/case/relationship/delete'; +// 关联用例 +export const publicAssociatedCaseUrl = '/functional/case/test/associate/case'; +// 获取关联用例已关联列表 +export const GetAssociatedDrawerCaseUrl = '/functional/case/test/has/associate/case/page'; diff --git a/frontend/src/components/pure/ms-code-editor/index.vue b/frontend/src/components/pure/ms-code-editor/index.vue index 46e37b638e..7a646a0968 100644 --- a/frontend/src/components/pure/ms-code-editor/index.vue +++ b/frontend/src/components/pure/ms-code-editor/index.vue @@ -41,6 +41,7 @@ setup(props, { emit }) { const { t } = useI18n(); let editor: monaco.editor.IStandaloneCodeEditor; + const codeEditBox = ref(); const fullRef = ref(); const currentTheme = ref(props.theme); @@ -83,8 +84,6 @@ emit('update:modelValue', value); emit('change', value); }); - - emit('editorMounted', editor); }; const setEditBoxBg = () => { @@ -101,6 +100,26 @@ const { isFullscreen, toggle } = useFullscreen(fullRef); + // 插入内容 + const insertContent = (text: string) => { + if (editor) { + const position = editor.getPosition(); + if (position) { + editor.executeEdits('', [ + { + range: new monaco.Range(position?.lineNumber, position?.column, position?.lineNumber, position?.column), + text, + }, + ]); + editor.setPosition({ + lineNumber: position?.lineNumber, + column: position.column + text.length, + }); + } + editor.focus(); + } + }; + watch( () => props.modelValue, (newValue) => { @@ -137,7 +156,17 @@ setEditBoxBg(); }); - return { codeEditBox, fullRef, isFullscreen, currentTheme, themeOptions, toggle, t, handleThemeChange }; + return { + codeEditBox, + fullRef, + isFullscreen, + currentTheme, + themeOptions, + toggle, + t, + handleThemeChange, + insertContent, + }; }, }); diff --git a/frontend/src/enums/tableEnum.ts b/frontend/src/enums/tableEnum.ts index e657398bbc..01d87db0c3 100644 --- a/frontend/src/enums/tableEnum.ts +++ b/frontend/src/enums/tableEnum.ts @@ -29,12 +29,13 @@ export enum TableKeyEnum { FILE_MANAGEMENT_CASE_RECYCLE = 'fileManagementCaseRecycle', FILE_MANAGEMENT_VERSION = 'fileManagementVersion', PROJECT_MANAGEMENT_MENU_FALSE_ALERT = 'projectManagementMenuFalseAlert', + PROJECT_MANAGEMENT_COMMON_SCRIPT_DETAIL = 'projectManagementCommonScriptDetail', + PROJECT_MANAGEMENT_COMMON_SCRIPT_CHANGE_HISTORY = 'projectManagementCommonScriptChangeHistory', ORGANIZATION_TEMPLATE_DEFECT_TABLE = 'organizationTemplateManagementDefect', CASE_MANAGEMENT_TABLE = 'caseManagement', CASE_MANAGEMENT_DETAIL_TABLE = 'caseManagementDetailTable', CASE_MANAGEMENT_ASSOCIATED_TABLE = 'caseManagementAssociatedFileTable', BUG_MANAGEMENT = 'bugManagement', - CASE_MANAGEMENT_DEMAND = 'caseManagementDemand', CASE_MANAGEMENT_REVIEW = 'caseManagementReview', CASE_MANAGEMENT_REVIEW_CASE = 'caseManagementReviewCase', CASE_MANAGEMENT_TAB_DEFECT = 'caseManagementTabDefect', diff --git a/frontend/src/views/case-management/caseManagementFeature/components/tabContent/tabBug/tabDefect.vue b/frontend/src/views/case-management/caseManagementFeature/components/tabContent/tabBug/tabDefect.vue index 38850abded..6ecdd2bb7b 100644 --- a/frontend/src/views/case-management/caseManagementFeature/components/tabContent/tabBug/tabDefect.vue +++ b/frontend/src/views/case-management/caseManagementFeature/components/tabContent/tabBug/tabDefect.vue @@ -16,7 +16,7 @@ {{ t('caseManagement.featureCase.createDefect') }}
{{ t('caseManagement.featureCase.testPlanLinkList') }}
-
+
{{ t('caseManagement.featureCase.directLink') @@ -117,7 +117,6 @@ width: 200, showInTable: true, showTooltip: true, - ellipsis: true, showDrag: false, }, { @@ -167,7 +166,6 @@ setLoadListParams: setLinkListParams, } = useTable(getBugList, { columns, - tableKey: TableKeyEnum.CASE_MANAGEMENT_TAB_DEFECT, scroll: { x: '100%' }, heightUsed: 340, enableDrag: true, @@ -231,7 +229,6 @@ setLoadListParams: setTestPlanListParams, } = useTable(getBugList, { columns: testPlanColumns, - tableKey: TableKeyEnum.CASE_MANAGEMENT_TAB_DEFECT_TEST_PLAN, scroll: { x: '100%' }, heightUsed: 340, enableDrag: true, diff --git a/frontend/src/views/case-management/caseManagementFeature/components/tabContent/tabCase/tabCaseTable.vue b/frontend/src/views/case-management/caseManagementFeature/components/tabContent/tabCase/tabCaseTable.vue index 239d336b86..9588fd3b7b 100644 --- a/frontend/src/views/case-management/caseManagementFeature/components/tabContent/tabCase/tabCaseTable.vue +++ b/frontend/src/views/case-management/caseManagementFeature/components/tabContent/tabCase/tabCaseTable.vue @@ -14,6 +14,8 @@ :placeholder="t('caseManagement.featureCase.searchByNameAndId')" allow-clear class="mx-[8px] w-[240px]" + @search="searchCase" + @press-enter="searchCase" >
@@ -56,12 +58,12 @@ import useTable from '@/components/pure/ms-table/useTable'; import MsCaseAssociate from '@/components/business/ms-case-associate/index.vue'; - import { getAssociatedIds } from '@/api/modules/case-management/caseReview'; import { + associationPublicCase, + getAssociatedCasePage, getPublicLinkCaseList, getPublicLinkCaseModulesCounts, getPublicLinkModuleTree, - getRecycleListRequest, } from '@/api/modules/case-management/featureCase'; import { postTabletList } from '@/api/modules/project-management/menuManagement'; import { useI18n } from '@/hooks/useI18n'; @@ -70,6 +72,8 @@ import type { TableQueryParams } from '@/models/common'; import { TableKeyEnum } from '@/enums/tableEnum'; + import Message from '@arco-design/web-vue/es/message'; + const appStore = useAppStore(); const { t } = useI18n(); @@ -149,7 +153,7 @@ }, ]; - const { propsRes, propsEvent, loadList, setLoadListParams } = useTable(getRecycleListRequest, { + const { propsRes, propsEvent, loadList, setLoadListParams, setKeyword } = useTable(getAssociatedCasePage, { columns, tableKey: TableKeyEnum.CASE_MANAGEMENT_TAB_DEPENDENCY_PRE_CASE, scroll: { x: '100%' }, @@ -166,14 +170,6 @@ const associatedIds = ref([]); - async function getLinkedIds() { - // try { - // associatedIds.value = await getAssociatedIds('1111'); - // } catch (error) { - // console.log(error); - // } - } - const currentSelectCase = ref(''); const countParams = ref({}); @@ -181,23 +177,10 @@ const modulesTreeParams = ref({}); const getTableParams = ref({}); - function getParams() { - switch (currentSelectCase.value) { - case 'API': - modulesTreeParams.value = { protocol: 'HTTP' }; - countParams.value = { sourceId: props.caseId, protocol: 'HTTP' }; - getTableParams.value = { sourceId: props.caseId, protocol: 'HTTP' }; - break; - default: - break; - } - } function handleSelect(value: string | number | Record | undefined) { currentSelectCase.value = value as string; innerVisible.value = true; - getLinkedIds(); - // getParams(); } function cancelLink(record: any) {} @@ -216,8 +199,17 @@ const confirmLoading = ref(false); - function saveHandler(params: TableQueryParams) { - console.log(params); + async function saveHandler(params: TableQueryParams) { + try { + confirmLoading.value = true; + await associationPublicCase(params); + Message.success(t('caseManagement.featureCase.AssociatedSuccess')); + innerVisible.value = false; + } catch (error) { + console.log(error); + } finally { + confirmLoading.value = false; + } } const moduleMaps: Record = { @@ -245,7 +237,7 @@ ], }; - onMounted(async () => { + async function getEnabledModules() { const result = await postTabletList({ projectId: currentProjectId.value }); const caseArr = result.filter((item) => Object.keys(moduleMaps).includes(item.module)); caseArr.forEach((item: any) => { @@ -253,7 +245,26 @@ caseTypeOptions.value.push(...currentModule); }); currentSelectCase.value = caseTypeOptions.value[0].value; - getParams(); + } + + function getFetch() { + setLoadListParams({ + keyword: keyword.value, + sourceId: props.caseId, + projectId: currentProjectId.value, + sourceType: currentSelectCase.value, + }); + loadList(); + } + + async function searchCase() { + setKeyword(keyword.value); + await loadList(); + } + + onMounted(async () => { + getEnabledModules(); + getFetch(); }); diff --git a/frontend/src/views/case-management/caseManagementFeature/components/tabContent/tabCaseReview.vue b/frontend/src/views/case-management/caseManagementFeature/components/tabContent/tabCaseReview.vue index ac1f9f6a14..bfd13d3187 100644 --- a/frontend/src/views/case-management/caseManagementFeature/components/tabContent/tabCaseReview.vue +++ b/frontend/src/views/case-management/caseManagementFeature/components/tabContent/tabCaseReview.vue @@ -12,11 +12,19 @@ >
- @@ -24,12 +19,11 @@ import { ref } from 'vue'; import MsComment from '@/components/business/ms-comment/comment'; + import { CommentItem, CommentParams } from '@/components/business/ms-comment/types'; import { getCommentList } from '@/api/modules/case-management/featureCase'; import { useI18n } from '@/hooks/useI18n'; - import type { CommentItem } from '@/models/caseManagement/featureCase'; - const { t } = useI18n(); const props = defineProps<{ @@ -59,6 +53,9 @@ // 删除评论 function handleDelete() {} + // 更新评论 + function handleUpdate() {} + onBeforeMount(() => { initCommentList(); }); diff --git a/frontend/src/views/case-management/caseManagementFeature/components/tabContent/tabDemand/associatedDemandTable.vue b/frontend/src/views/case-management/caseManagementFeature/components/tabContent/tabDemand/associatedDemandTable.vue index 5c2aae561f..bb8551546c 100644 --- a/frontend/src/views/case-management/caseManagementFeature/components/tabContent/tabDemand/associatedDemandTable.vue +++ b/frontend/src/views/case-management/caseManagementFeature/components/tabContent/tabDemand/associatedDemandTable.vue @@ -38,7 +38,6 @@ import { useAppStore } from '@/store'; import type { DemandItem } from '@/models/caseManagement/featureCase'; - import { TableKeyEnum } from '@/enums/tableEnum'; const appStore = useAppStore(); const pageConfig = computed(() => appStore.pageConfig); @@ -99,7 +98,6 @@ ]; const { propsRes, propsEvent, loadList, setLoadListParams } = useTable(getDemandList, { - tableKey: TableKeyEnum.CASE_MANAGEMENT_DEMAND, columns, rowKey: 'id', scroll: { x: '100%' }, @@ -120,6 +118,7 @@ defineExpose({ initData, }); + const tableRef = ref | null>(null); watch( diff --git a/frontend/src/views/case-management/caseManagementFeature/components/tabContent/tabDemand/demand.vue b/frontend/src/views/case-management/caseManagementFeature/components/tabContent/tabDemand/demand.vue index 3939fb6c02..b8c356b781 100644 --- a/frontend/src/views/case-management/caseManagementFeature/components/tabContent/tabDemand/demand.vue +++ b/frontend/src/views/case-management/caseManagementFeature/components/tabContent/tabDemand/demand.vue @@ -216,7 +216,7 @@ const initData = async () => { setLoadListParams({ keyword: platformKeyword.value }); - loadList(); + // loadList(); }; const searchHandler = () => { @@ -224,12 +224,9 @@ resetSelector(); }; - onMounted(() => { - initData(); - }); - onMounted(() => { resetSelector(); + initData(); }); diff --git a/frontend/src/views/case-management/caseManagementFeature/components/tabContent/tabDemand/platformDemandDrawer.vue b/frontend/src/views/case-management/caseManagementFeature/components/tabContent/tabDemand/platformDemandDrawer.vue index 756b7895a5..88c658d7c7 100644 --- a/frontend/src/views/case-management/caseManagementFeature/components/tabContent/tabDemand/platformDemandDrawer.vue +++ b/frontend/src/views/case-management/caseManagementFeature/components/tabContent/tabDemand/platformDemandDrawer.vue @@ -43,8 +43,6 @@ import { getDemandList } from '@/api/modules/case-management/featureCase'; import { useI18n } from '@/hooks/useI18n'; - import { TableKeyEnum } from '@/enums/tableEnum'; - const { t } = useI18n(); const columns: MsTableColumn = [ @@ -88,7 +86,6 @@ ]; const { propsRes, propsEvent, loadList, setLoadListParams, resetSelector } = useTable(getDemandList, { - tableKey: TableKeyEnum.CASE_MANAGEMENT_DEMAND, columns, rowKey: 'id', scroll: { x: '100%' }, diff --git a/frontend/src/views/case-management/caseManagementFeature/components/tabContent/tabDependency/tabDependency.vue b/frontend/src/views/case-management/caseManagementFeature/components/tabContent/tabDependency/tabDependency.vue index a73fe6f969..f0eca57d34 100644 --- a/frontend/src/views/case-management/caseManagementFeature/components/tabContent/tabDependency/tabDependency.vue +++ b/frontend/src/views/case-management/caseManagementFeature/components/tabContent/tabDependency/tabDependency.vue @@ -138,7 +138,7 @@ selectable: false, noDisable: true, showSetting: false, - enableDrag: true, + enableDrag: false, }); const cancelLoading = ref(false); diff --git a/frontend/src/views/case-management/caseManagementFeature/locale/en-US.ts b/frontend/src/views/case-management/caseManagementFeature/locale/en-US.ts index 063c00b112..a5b766fa6a 100644 --- a/frontend/src/views/case-management/caseManagementFeature/locale/en-US.ts +++ b/frontend/src/views/case-management/caseManagementFeature/locale/en-US.ts @@ -246,4 +246,5 @@ export default { 'caseManagement.featureCase.quicklyCreateDefectSuccess': 'Quick bug creation success', 'caseManagement.featureCase.cancelDependencyTip': 'Confirm cancel dependencies?', 'caseManagement.featureCase.cancelDependencyContent': 'Cancel after impact test plan related statistics', + 'caseManagement.featureCase.AssociatedSuccess': 'Associated with success', }; diff --git a/frontend/src/views/case-management/caseManagementFeature/locale/zh-CN.ts b/frontend/src/views/case-management/caseManagementFeature/locale/zh-CN.ts index d4a945f572..a33048a95b 100644 --- a/frontend/src/views/case-management/caseManagementFeature/locale/zh-CN.ts +++ b/frontend/src/views/case-management/caseManagementFeature/locale/zh-CN.ts @@ -235,10 +235,11 @@ export default { 'caseManagement.featureCase.CheckFailure': '校验失败', 'caseManagement.featureCase.CheckSuccess': '校验成功', 'caseManagement.featureCase.tableNoData': '暂无数据', - 'caseManagement.featureCase.noAssociated': '暂无可关联缺陷,请', + 'caseManagement.featureCase.noAssociatedDefect': '暂无可关联缺陷,请', 'caseManagement.featureCase.fileIsUpdated': '当前文件已更新', 'caseManagement.featureCase.selectTransferDirectory': '请选择转存目录', 'caseManagement.featureCase.quicklyCreateDefectSuccess': '快速创建缺陷成功', 'caseManagement.featureCase.cancelDependencyTip': '确认取消依赖关系吗?', 'caseManagement.featureCase.cancelDependencyContent': '取消后,影响测试计划相关统计', + 'caseManagement.featureCase.AssociatedSuccess': '关联成功', }; diff --git a/frontend/src/views/project-management/commonScript/components/addScriptDrawer.vue b/frontend/src/views/project-management/commonScript/components/addScriptDrawer.vue index 7ddbd712c9..ffae64534f 100644 --- a/frontend/src/views/project-management/commonScript/components/addScriptDrawer.vue +++ b/frontend/src/views/project-management/commonScript/components/addScriptDrawer.vue @@ -46,19 +46,7 @@ {{ t('project.commonScript.scriptTest') }} - -
- -
+ @@ -66,7 +54,6 @@ diff --git a/frontend/src/views/project-management/commonScript/components/scriptDefined.vue b/frontend/src/views/project-management/commonScript/components/scriptDefined.vue index f8af6ceeee..087828de14 100644 --- a/frontend/src/views/project-management/commonScript/components/scriptDefined.vue +++ b/frontend/src/views/project-management/commonScript/components/scriptDefined.vue @@ -1,5 +1,5 @@ diff --git a/frontend/src/views/project-management/commonScript/index.vue b/frontend/src/views/project-management/commonScript/index.vue index 99289e564f..ec9e8b47e0 100644 --- a/frontend/src/views/project-management/commonScript/index.vue +++ b/frontend/src/views/project-management/commonScript/index.vue @@ -12,7 +12,11 @@ @@ -70,6 +75,7 @@ import { ActionsItem } from '@/components/pure/ms-table-more-action/types'; import MsTag from '@/components/pure/ms-tag/ms-tag.vue'; import AddScriptDrawer from './components/addScriptDrawer.vue'; + import ScriptDetailDrawer from './components/scriptDetailDrawer.vue'; import { getDependOnCase } from '@/api/modules/case-management/featureCase'; import { useI18n } from '@/hooks/useI18n'; @@ -218,6 +224,12 @@ const showScriptDrawer = ref(false); + const showDetailDrawer = ref(false); + // 脚本详情 + function showDetail(record: any) { + showDetailDrawer.value = true; + } + function addCommonScript() { showScriptDrawer.value = true; } diff --git a/frontend/src/views/project-management/commonScript/locale/en-US.ts b/frontend/src/views/project-management/commonScript/locale/en-US.ts index 2f5da3ab2d..07aad32849 100644 --- a/frontend/src/views/project-management/commonScript/locale/en-US.ts +++ b/frontend/src/views/project-management/commonScript/locale/en-US.ts @@ -29,6 +29,16 @@ export default { 'project.commonScript.formatting': 'formatting', 'project.commonScript.undo': 'cancel', 'project.commonScript.clear': 'clear', + 'project.commonScript.testSuccess': 'Test successfully', + 'project.commonScript.ParameterNames': 'Parameter names', + 'project.commonScript.isRequired': 'Required', + 'project.commonScript.ParameterValue': 'Parameter Value', + 'project.commonScript.changeSerialNumber': 'Change Number', + 'project.commonScript.actionType': 'action Type', + 'project.commonScript.actionUser': 'operator', + 'project.commonScript.recover': 'recover', + 'project.commonScript.detail': 'detail', + 'project.commonScript.changeHistory': 'Change history', 'code_segment': { importApiTest: 'Import from API definition', newApiTest: 'New API test[JSON]', diff --git a/frontend/src/views/project-management/commonScript/locale/zh-CN.ts b/frontend/src/views/project-management/commonScript/locale/zh-CN.ts index 02ef2ca116..95331dcd35 100644 --- a/frontend/src/views/project-management/commonScript/locale/zh-CN.ts +++ b/frontend/src/views/project-management/commonScript/locale/zh-CN.ts @@ -15,7 +15,7 @@ export default { 'project.commonScript.testsPass': '测试通过', 'project.commonScript.draft': '草稿', 'project.commonScript.publicScriptName': '公共脚本名称', - 'project.commonScript.publicScriptNameNotEmpty': '公共脚本名称', + 'project.commonScript.publicScriptNameNotEmpty': '公共脚本名称不能为空', 'project.commonScript.pleaseEnterScriptName': '请输入脚本名称', 'project.commonScript.scriptEnabled': '脚本状态', 'project.commonScript.enterContentAddTags': '输入内容后回车可直接添加标签', @@ -28,6 +28,16 @@ export default { 'project.commonScript.formatting': '格式化', 'project.commonScript.undo': '撤销', 'project.commonScript.clear': '清空', + 'project.commonScript.testSuccess': '测试成功', + 'project.commonScript.ParameterNames': '参数名称', + 'project.commonScript.isRequired': '是否必填', + 'project.commonScript.ParameterValue': '参数值', + 'project.commonScript.changeSerialNumber': '变更序号', + 'project.commonScript.actionType': '类型', + 'project.commonScript.actionUser': '操作人', + 'project.commonScript.recover': '恢复', + 'project.commonScript.detail': '详情', + 'project.commonScript.changeHistory': '变更历史', 'project': { code_segment: { importApiTest: '从API定义导入', diff --git a/frontend/src/views/project-management/commonScript/utils.ts b/frontend/src/views/project-management/commonScript/utils.ts index 867c07a201..c5e0abe17e 100644 --- a/frontend/src/views/project-management/commonScript/utils.ts +++ b/frontend/src/views/project-management/commonScript/utils.ts @@ -4,6 +4,8 @@ import type { CommonScriptMenu } from '@/models/projectManagement/commonScript'; const { t } = useI18n(); +export type Languages = 'groovy' | 'python' | 'beanshell' | 'nashornScript' | 'rhinoScript' | 'javascript'; + export const SCRIPT_MENU: CommonScriptMenu[] = [ { title: t('project.code_segment.importApiTest'), @@ -47,9 +49,479 @@ export const SCRIPT_MENU: CommonScriptMenu[] = [ }, { title: t('project.processor.terminationTest'), - value: 'terminal_function', - command: 'terminal_function', + value: 'ctx.getEngine().stopThreadNow(ctx.getThread().getThreadName());', }, ]; +// 处理groovyCode 请求头 +function getGroovyHeaders(requestHeaders) { + let headers = '['; + let index = 1; + // for (const [k, v] of requestHeaders) { + // if (index !== 1) { + // headers += ','; + // } + // // 拼装 + // headers += `'${k}':'${v}'`; + // index++; + // } + requestHeaders.forEach(([k, v]) => { + if (index !== 1) { + headers += ','; + } + headers += `'${k}':'${v}'`; + index++; + }); + headers += ']'; + return headers; +} +// 解析请求url +function getRequestPath(requestArgs, requestPath) { + if (requestArgs.size > 0) { + requestPath += '?'; + let index = 1; + requestArgs.forEach(([k, v]) => { + if (index !== 1) { + requestPath += '&'; + } + requestPath = `${requestPath + k}=${v}`; + index++; + }); + } + return requestPath; +} +// 处理mockPath +function getMockPath(domain, port, socket) { + if (domain === socket || !port) { + return ''; + } + const str = `${domain}:${port}`; + // 获取socket之后的路径 + return socket.substring(str.length); +} + +// 处理请求参数 +function replaceRestParams(path, restMap) { + if (!path) { + return path; + } + let arr = path.match(/{([\w]+)}/g); + if (Array.isArray(arr) && arr.length > 0) { + arr = Array.from(new Set(arr)); + arr.forEach((str) => { + try { + const temp = str.substr(1); + const param = temp.substring(0, temp.length - 1); + if (str && restMap.has(param)) { + path = path.replace(new RegExp(str, 'g'), restMap.get(param)); + } + } catch (e) { + // nothing + } + }); + } + return path; +} + +// 返回最终groovyCode 代码模板片段 +function _groovyCodeTemplate(obj) { + const { requestUrl, requestMethod, headers, body } = obj; + const params = `[ + 'url': '${requestUrl}', + 'method': '${requestMethod}', // POST/GET + 'headers': ${headers}, // 请求headers 例:{'Content-type':'application/json'} + 'data': ${body} // 参数 + ]`; + return `import groovy.json.JsonOutput +import groovy.json.JsonSlurper + +def params = ${params} +def headers = params['headers'] +// json数据 +def data = params['data'] +def conn = new URL(params['url']).openConnection() +conn.setRequestMethod(params['method']) +if (headers) { + headers.each { + k,v -> conn.setRequestProperty(k, v); + } +} +if (data) { + // 输出请求参数 + log.info(data) + conn.doOutput = true + def writer = new OutputStreamWriter(conn.outputStream) + writer.write(data) + writer.flush() + writer.close() +} +log.info(conn.content.text) +`; +} + +// 处理groovyCode语言 +function groovyCode(requestObj) { + const { + requestHeaders = new Map(), + requestBody = '', + domain = '', + port = '', + requestMethod = '', + host = '', + protocol = '', + requestArguments = new Map(), + requestRest = new Map(), + requestBodyKvs = new Map(), + bodyType, + } = requestObj; + + let { requestPath = '' } = requestObj; + let requestUrl = ''; + if (requestMethod.toLowerCase() === 'get' && requestBodyKvs) { + // 如果是get方法要将kv值加入argument中 + requestBodyKvs.forEach(([k, v]) => { + requestArguments.set(k, v); + }); + } + requestPath = getRequestPath(requestArguments, requestPath); + const path = getMockPath(domain, port, host); + requestPath = path + replaceRestParams(requestPath, requestRest); + if (protocol && host && requestPath) { + requestUrl = `${protocol}://${domain}${port ? `:${port}` : ''}${requestPath}`; + } + let body = JSON.stringify(requestBody); + if (requestMethod === 'POST' && bodyType === 'kvs') { + body = '"'; + + requestBodyKvs.forEach(([k, v]) => { + if (body !== '"') { + body += '&'; + } + body += `${k}=${v}`; + }); + body += '"'; + } + + if (bodyType && bodyType.toUpperCase() === 'RAW') { + requestHeaders.set('Content-type', 'text/plain'); + } + const headers = getGroovyHeaders(requestHeaders); + const obj = { requestUrl, requestMethod, headers, body }; + return _groovyCodeTemplate(obj); +} + +// 获取请求头 +function getHeaders(requestHeaders) { + let headers = '{'; + let index = 1; + requestHeaders.forEach(([k, v]) => { + if (index !== 1) { + headers += ','; + } + // 拼装 + headers += `'${k}':'${v}'`; + index++; + }); + headers += '}'; + return headers; +} +// 获取pythonCode 模板 +function _pythonCodeTemplate(obj) { + const { requestBody, requestBodyKvs, bodyType, requestPath, requestMethod, connType, domain, port } = obj; + let { headers } = obj; + let reqBody = obj.requestBody; + if (requestMethod.toLowerCase() === 'post' && obj.bodyType === 'kvs' && obj.requestBodyKvs) { + reqBody = 'urllib.urlencode({'; + requestBodyKvs.forEach(([k, v]) => { + reqBody += `'${k}':'${v}'`; + }); + reqBody += `})`; + if (headers === '{}') { + headers = "{'Content-type': 'application/x-www-form-urlencoded', 'Accept': 'text/plain'}"; + } + } + + const host = domain + (port ? `:${port}` : ''); + + return `import httplib,urllib +params = ${reqBody} #例 {'username':'test'} +headers = ${headers} #例 {'Content-Type':'application/json'} 或 {'Content-type': 'application/x-www-form-urlencoded', 'Accept': 'text/plain'} +host = '${host}' +path = '${requestPath}' +method = '${requestMethod}' # POST/GET + +conn = httplib.${connType}(host) +conn.request(method, path, params, headers) +res = conn.getresponse() +data = unicode(res.read(), 'utf-8') +log.info(data) +`; +} + +// 处理pythonCode语言 +function pythonCode(requestObj) { + const { + requestHeaders = new Map(), + requestMethod = '', + host = '', + domain = '', + port = '', + protocol = 'http', + requestArguments = new Map(), + requestBodyKvs = new Map(), + bodyType, + requestRest = new Map(), + } = requestObj; + let { requestBody = '', requestPath = '/' } = requestObj; + let connType = 'HTTPConnection'; + if (protocol === 'https') { + connType = 'HTTPSConnection'; + } + const headers = getHeaders(requestHeaders); + requestBody = requestBody ? JSON.stringify(requestBody) : '{}'; + if (requestMethod.toLowerCase() === 'get' && requestBodyKvs) { + requestBodyKvs.forEach(([k, v]) => { + requestArguments.set(k, v); + }); + } + requestPath = getRequestPath(requestArguments, requestPath); + const path = getMockPath(domain, port, host); + requestPath = path + replaceRestParams(requestPath, requestRest); + const obj = { requestBody, headers, requestPath, requestMethod, requestBodyKvs, bodyType, connType, domain, port }; + return _pythonCodeTemplate(obj); +} + +// 获取javaBeanshell代码模版 +function _beanshellTemplate(obj) { + const { + requestHeaders = new Map(), + requestBodyKvs = new Map(), + bodyType = '', + requestMethod = 'GET', + protocol = 'http', + requestArguments = new Map(), + domain = '', + host = '', + port = '', + requestRest = new Map(), + } = obj; + let { requestPath = '/', requestBody = '' } = obj; + + const path = getMockPath(domain, port, host); + requestPath = path + replaceRestParams(requestPath, requestRest); + let uri = `new URIBuilder() + .setScheme("${protocol}") + .setHost("${domain}") + .setPath("${requestPath}") + `; + // http 请求类型 + const method = requestMethod.toLowerCase().replace(/^\S/, (s) => s.toUpperCase()); + const httpMethodCode = `Http${method} request = new Http${method}(uri);`; + // 设置参数 + requestArguments.forEach(([k, v]) => { + uri += `.setParameter("${k}", "${v}")`; + }); + if (method === 'Get' && requestBodyKvs) { + requestBodyKvs.forEach(([k, v]) => { + uri += `.setParameter("${k}", "${v}")`; + }); + } + + let postKvsParam = ''; + if (method === 'Post') { + // 设置post参数 + requestBodyKvs.forEach(([k, v]) => { + postKvsParam += `nameValueList.add(new BasicNameValuePair("${k}", "${v}"));\r\n`; + }); + if (postKvsParam !== '') { + postKvsParam = `List nameValueList = new ArrayList();\r\n${postKvsParam}`; + } + } + + if (port) { + uri += `.setPort(${port}) // int类型端口 + `; + uri += ` .build();`; + } else { + uri += `// .setPort(${port}) // int类型端口 + `; + uri += ` .build();`; + } + // 设置请求头 + let setHeader = ''; + requestHeaders.forEach(([k, v]) => { + setHeader = `${setHeader}request.setHeader("${k}", "${v}");\n`; + }); + try { + requestBody = JSON.stringify(requestBody); + if (!requestBody || requestBody === 'null') { + requestBody = ''; + } + } catch (e) { + requestBody = ''; + } + let postMethodCode = ''; + if (requestMethod === 'POST') { + if (bodyType === 'kvs') { + postMethodCode = `${postKvsParam}\r\n request.setEntity(new UrlEncodedFormEntity(nameValueList, "UTF-8"));`; + } else { + postMethodCode = `request.setEntity(new StringEntity(StringEscapeUtils.unescapeJava(payload)));`; + } + } + + return `import java.net.URI; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.*; +import org.apache.commons.text.StringEscapeUtils; +import org.apache.http.client.utils.URIBuilder; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.util.EntityUtils; +import org.apache.http.entity.StringEntity; + +import java.util.*; +import org.apache.http.NameValuePair; +import org.apache.http.message.BasicNameValuePair; +import org.apache.http.client.entity.UrlEncodedFormEntity; + +// 创建Httpclient对象 +CloseableHttpClient httpclient = HttpClients.createDefault(); +// 参数 +String payload = ${requestBody}; +// 定义请求的参数 +URI uri = ${uri} +// 创建http请求 +${httpMethodCode} +${setHeader} +${postMethodCode} +log.info(uri.toString()); +//response 对象 +CloseableHttpResponse response = null; + +response = httpclient.execute(request); +// 判断返回状态是否为200 +if (response.getStatusLine().getStatusCode() == 200) { + String content = EntityUtils.toString(response.getEntity(), "UTF-8"); + log.info(content); +}`; +} + +// 处理java语言 +function javaCode(requestObj) { + return _beanshellTemplate(requestObj); +} + +// 获取js语言代码模版 +function _jsTemplate(obj) { + const { + requestHeaders = new Map(), + requestMethod = 'GET', + protocol = 'http', + requestArguments = new Map(), + host = '', + domain = '', + port = '', + requestBodyKvs = new Map(), + bodyType = '', + requestRest = new Map(), + } = obj; + let url = ''; + let { requestBody = '', requestPath = '/' } = obj; + requestPath = replaceRestParams(requestPath, requestRest); + if (protocol && domain && port) { + const path = getMockPath(domain, port, host); + requestPath = path + requestPath; + url = `${protocol}://${domain}${port ? `:${port}` : ''}${requestPath}`; + } else if (protocol && domain) { + url = `${protocol}://${domain}${requestPath}`; + } + if (requestMethod.toLowerCase() === 'get' && requestBodyKvs) { + // 如果是get方法要将kv值加入argument中 + requestBodyKvs.forEach(([k, v]) => { + requestArguments.set(k, v); + }); + } + url = getRequestPath(requestArguments, url); + try { + requestBody = JSON.stringify(requestBody); + } catch (e) { + requestBody = ''; + } + + let connStr = ''; + if (bodyType && bodyType.toUpperCase() === 'RAW') { + requestHeaders.set('Content-type', 'text/plain'); + } + requestHeaders.forEach(([k, v]) => { + connStr += `conn.setRequestProperty("${k}","${v}");\n`; + }); + + if (requestMethod === 'POST' && bodyType === 'kvs') { + requestBody = '"'; + requestBodyKvs.forEach(([k, v]) => { + if (requestBody !== '"') { + requestBody += '&'; + } + requestBody += `${k}=${v}`; + }); + requestBody += '"'; + } + let postParamExecCode = ''; + if (requestBody && requestBody !== '' && requestBody !== '""') { + postParamExecCode = ` +var opt = new java.io.DataOutputStream(conn.getOutputStream()); +var t = (new java.lang.String(parameterData)).getBytes("utf-8"); +opt.write(t); +opt.flush(); +opt.close(); + `; + } + + return `var urlStr = "${url}"; // 请求地址 +var requestMethod = "${requestMethod}"; // 请求类型 +var parameterData = ${requestBody}; // 请求参数 +var url = new java.net.URL(urlStr); +var conn = url.openConnection(); +conn.setRequestMethod(requestMethod); +conn.setDoOutput(true); +${connStr}conn.connect(); +${postParamExecCode} +var res = ""; +var rspCode = conn.getResponseCode(); +if (rspCode == 200) { +var ipt = conn.getInputStream(); +var reader = new java.io.BufferedReader(new java.io.InputStreamReader(ipt, "UTF-8")); +var lines; +while((lines = reader.readLine()) !== null) { + res += lines; +} +} +log.info(res); + `; +} + +// 处理js语言 +function jsCode(requestObj) { + return _jsTemplate(requestObj); +} + +export function getCodeTemplate(language: Languages, requestObj: any) { + switch (language) { + case 'groovy': + return groovyCode(requestObj); + case 'python': + return pythonCode(requestObj); + case 'beanshell': + return javaCode(requestObj); + case 'nashornScript': + return jsCode(requestObj); + case 'rhinoScript': + return jsCode(requestObj); + case 'javascript': + return jsCode(requestObj); + default: + return ''; + } +} + export default {};