Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
MeterSphere
metersphere
提交
cbc9c421
M
metersphere
项目概览
MeterSphere
/
metersphere
上一次同步 3 年多
通知
25
Star
1
Fork
1
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
M
metersphere
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
cbc9c421
编写于
11月 24, 2020
作者:
F
fit2-zhao
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
feat(接口定义): TCP 协议基础完成
上级
84e99e1b
变更
45
隐藏空白更改
内联
并排
Showing
45 changed file
with
2469 addition
and
98 deletion
+2469
-98
backend/src/main/java/io/metersphere/api/controller/ApiDefinitionController.java
...o/metersphere/api/controller/ApiDefinitionController.java
+8
-0
backend/src/main/java/io/metersphere/api/dto/ApiTestImportRequest.java
...ain/java/io/metersphere/api/dto/ApiTestImportRequest.java
+2
-0
backend/src/main/java/io/metersphere/api/dto/definition/parse/ApiDefinitionImport.java
...rsphere/api/dto/definition/parse/ApiDefinitionImport.java
+13
-0
backend/src/main/java/io/metersphere/api/dto/definition/parse/postman/PostmanCollection.java
...e/api/dto/definition/parse/postman/PostmanCollection.java
+13
-0
backend/src/main/java/io/metersphere/api/dto/definition/parse/postman/PostmanCollectionInfo.java
...i/dto/definition/parse/postman/PostmanCollectionInfo.java
+13
-0
backend/src/main/java/io/metersphere/api/dto/definition/parse/postman/PostmanItem.java
...rsphere/api/dto/definition/parse/postman/PostmanItem.java
+12
-0
backend/src/main/java/io/metersphere/api/dto/definition/parse/postman/PostmanKeyValue.java
...ere/api/dto/definition/parse/postman/PostmanKeyValue.java
+18
-0
backend/src/main/java/io/metersphere/api/dto/definition/parse/postman/PostmanRequest.java
...here/api/dto/definition/parse/postman/PostmanRequest.java
+18
-0
backend/src/main/java/io/metersphere/api/dto/definition/parse/postman/PostmanUrl.java
...ersphere/api/dto/definition/parse/postman/PostmanUrl.java
+14
-0
backend/src/main/java/io/metersphere/api/dto/definition/parse/swagger/SwaggerApi.java
...ersphere/api/dto/definition/parse/swagger/SwaggerApi.java
+18
-0
backend/src/main/java/io/metersphere/api/dto/definition/parse/swagger/SwaggerInfo.java
...rsphere/api/dto/definition/parse/swagger/SwaggerInfo.java
+11
-0
backend/src/main/java/io/metersphere/api/dto/definition/parse/swagger/SwaggerParameter.java
...re/api/dto/definition/parse/swagger/SwaggerParameter.java
+13
-0
backend/src/main/java/io/metersphere/api/dto/definition/parse/swagger/SwaggerRequest.java
...here/api/dto/definition/parse/swagger/SwaggerRequest.java
+16
-0
backend/src/main/java/io/metersphere/api/dto/definition/parse/swagger/SwaggerTag.java
...ersphere/api/dto/definition/parse/swagger/SwaggerTag.java
+9
-0
backend/src/main/java/io/metersphere/api/parse/ApiImportParser.java
...c/main/java/io/metersphere/api/parse/ApiImportParser.java
+3
-0
backend/src/main/java/io/metersphere/api/parse/MsParser.java
backend/src/main/java/io/metersphere/api/parse/MsParser.java
+8
-0
backend/src/main/java/io/metersphere/api/parse/PostmanParser.java
...src/main/java/io/metersphere/api/parse/PostmanParser.java
+72
-1
backend/src/main/java/io/metersphere/api/parse/Swagger2Parser.java
...rc/main/java/io/metersphere/api/parse/Swagger2Parser.java
+55
-1
backend/src/main/java/io/metersphere/api/service/ApiDefinitionService.java
...java/io/metersphere/api/service/ApiDefinitionService.java
+65
-4
frontend/src/business/components/api/definition/ApiDefinition.vue
.../src/business/components/api/definition/ApiDefinition.vue
+17
-2
frontend/src/business/components/api/definition/components/ApiCaseList.vue
...ness/components/api/definition/components/ApiCaseList.vue
+2
-2
frontend/src/business/components/api/definition/components/ApiConfig.vue
...siness/components/api/definition/components/ApiConfig.vue
+46
-27
frontend/src/business/components/api/definition/components/ApiModule.vue
...siness/components/api/definition/components/ApiModule.vue
+41
-3
frontend/src/business/components/api/definition/components/complete/AddCompleteHttpApi.vue
...api/definition/components/complete/AddCompleteHttpApi.vue
+1
-1
frontend/src/business/components/api/definition/components/complete/ApiTcpRequestForm.vue
.../api/definition/components/complete/ApiTcpRequestForm.vue
+311
-0
frontend/src/business/components/api/definition/components/complete/BasisApi.vue
...omponents/api/definition/components/complete/BasisApi.vue
+118
-0
frontend/src/business/components/api/definition/components/debug/DebugHttpPage.vue
...ponents/api/definition/components/debug/DebugHttpPage.vue
+1
-1
frontend/src/business/components/api/definition/components/environment/ApiEnvironmentConfig.vue
...efinition/components/environment/ApiEnvironmentConfig.vue
+157
-0
frontend/src/business/components/api/definition/components/environment/ApiHostTable.vue
...ts/api/definition/components/environment/ApiHostTable.vue
+160
-0
frontend/src/business/components/api/definition/components/environment/ApiScenarioVariables.vue
...efinition/components/environment/ApiScenarioVariables.vue
+111
-0
frontend/src/business/components/api/definition/components/environment/EnvironmentCommonConfig.vue
...nition/components/environment/EnvironmentCommonConfig.vue
+63
-0
frontend/src/business/components/api/definition/components/environment/EnvironmentEdit.vue
...api/definition/components/environment/EnvironmentEdit.vue
+166
-0
frontend/src/business/components/api/definition/components/environment/EnvironmentHttpConfig.vue
...finition/components/environment/EnvironmentHttpConfig.vue
+86
-0
frontend/src/business/components/api/definition/components/import/ApiImport.vue
...components/api/definition/components/import/ApiImport.vue
+353
-0
frontend/src/business/components/api/definition/components/jmeter/components/sampler/tcp-sampler/index.js
...components/jmeter/components/sampler/tcp-sampler/index.js
+18
-19
frontend/src/business/components/api/definition/components/request/database/DatabaseConfig.vue
...definition/components/request/database/DatabaseConfig.vue
+80
-0
frontend/src/business/components/api/definition/components/request/database/DatabaseConfigList.vue
...nition/components/request/database/DatabaseConfigList.vue
+83
-0
frontend/src/business/components/api/definition/components/request/database/DatabaseFrom.vue
...i/definition/components/request/database/DatabaseFrom.vue
+145
-0
frontend/src/business/components/api/definition/components/request/http/ApiHttpRequestForm.vue
...definition/components/request/http/ApiHttpRequestForm.vue
+11
-11
frontend/src/business/components/api/definition/components/request/http/ApiRequestForm.vue
...api/definition/components/request/http/ApiRequestForm.vue
+1
-20
frontend/src/business/components/api/definition/components/request/tcp/TcpConfig.vue
...nents/api/definition/components/request/tcp/TcpConfig.vue
+109
-0
frontend/src/business/components/api/definition/components/runtest/RunTestHttpPage.vue
...nts/api/definition/components/runtest/RunTestHttpPage.vue
+2
-3
frontend/src/i18n/en-US.js
frontend/src/i18n/en-US.js
+1
-0
frontend/src/i18n/zh-CN.js
frontend/src/i18n/zh-CN.js
+4
-2
frontend/src/i18n/zh-TW.js
frontend/src/i18n/zh-TW.js
+1
-1
未找到文件。
backend/src/main/java/io/metersphere/api/controller/ApiDefinitionController.java
浏览文件 @
cbc9c421
...
...
@@ -3,6 +3,7 @@ package io.metersphere.api.controller;
import
com.github.pagehelper.Page
;
import
com.github.pagehelper.PageHelper
;
import
io.metersphere.api.dto.APIReportResult
;
import
io.metersphere.api.dto.ApiTestImportRequest
;
import
io.metersphere.api.dto.definition.ApiDefinitionRequest
;
import
io.metersphere.api.dto.definition.ApiDefinitionResult
;
import
io.metersphere.api.dto.definition.RunDefinitionRequest
;
...
...
@@ -81,4 +82,11 @@ public class ApiDefinitionController {
return
apiDefinitionService
.
getDbResult
(
testId
);
}
@PostMapping
(
value
=
"/import"
,
consumes
=
{
"multipart/form-data"
})
@RequiresRoles
(
value
=
{
RoleConstants
.
TEST_USER
,
RoleConstants
.
TEST_MANAGER
},
logical
=
Logical
.
OR
)
public
String
testCaseImport
(
@RequestPart
(
value
=
"file"
,
required
=
false
)
MultipartFile
file
,
@RequestPart
(
"request"
)
ApiTestImportRequest
request
)
{
return
apiDefinitionService
.
apiTestImport
(
file
,
request
);
}
}
backend/src/main/java/io/metersphere/api/dto/ApiTestImportRequest.java
浏览文件 @
cbc9c421
...
...
@@ -7,6 +7,8 @@ import lombok.Setter;
@Getter
public
class
ApiTestImportRequest
{
private
String
name
;
private
String
moduleId
;
private
String
modulePath
;
private
String
environmentId
;
private
String
projectId
;
private
String
platform
;
...
...
backend/src/main/java/io/metersphere/api/dto/definition/parse/ApiDefinitionImport.java
0 → 100644
浏览文件 @
cbc9c421
package
io.metersphere.api.dto.definition.parse
;
import
io.metersphere.api.dto.definition.ApiDefinitionResult
;
import
lombok.Data
;
import
java.util.List
;
@Data
public
class
ApiDefinitionImport
{
private
String
projectName
;
private
String
protocol
;
private
List
<
ApiDefinitionResult
>
data
;
}
backend/src/main/java/io/metersphere/api/dto/definition/parse/postman/PostmanCollection.java
0 → 100644
浏览文件 @
cbc9c421
package
io.metersphere.api.dto.definition.parse.postman
;
import
lombok.Data
;
import
java.util.List
;
@Data
public
class
PostmanCollection
{
private
PostmanCollectionInfo
info
;
private
List
<
PostmanItem
>
item
;
private
List
<
PostmanKeyValue
>
variable
;
}
backend/src/main/java/io/metersphere/api/dto/definition/parse/postman/PostmanCollectionInfo.java
0 → 100644
浏览文件 @
cbc9c421
package
io.metersphere.api.dto.definition.parse.postman
;
import
com.alibaba.fastjson.annotation.JSONField
;
import
lombok.Data
;
@Data
public
class
PostmanCollectionInfo
{
@JSONField
(
name
=
"_postman_id"
)
private
String
postmanId
;
private
String
name
;
private
String
schema
;
}
backend/src/main/java/io/metersphere/api/dto/definition/parse/postman/PostmanItem.java
0 → 100644
浏览文件 @
cbc9c421
package
io.metersphere.api.dto.definition.parse.postman
;
import
lombok.Data
;
import
java.util.List
;
@Data
public
class
PostmanItem
{
private
String
name
;
private
PostmanRequest
request
;
private
List
<
PostmanItem
>
item
;
}
backend/src/main/java/io/metersphere/api/dto/definition/parse/postman/PostmanKeyValue.java
0 → 100644
浏览文件 @
cbc9c421
package
io.metersphere.api.dto.definition.parse.postman
;
import
lombok.Data
;
@Data
public
class
PostmanKeyValue
{
private
String
key
;
private
String
value
;
private
String
type
;
public
PostmanKeyValue
()
{
}
public
PostmanKeyValue
(
String
key
,
String
value
)
{
this
.
key
=
key
;
this
.
value
=
value
;
}
}
backend/src/main/java/io/metersphere/api/dto/definition/parse/postman/PostmanRequest.java
0 → 100644
浏览文件 @
cbc9c421
package
io.metersphere.api.dto.definition.parse.postman
;
import
com.alibaba.fastjson.JSONObject
;
import
lombok.Data
;
import
java.util.List
;
@Data
public
class
PostmanRequest
{
private
String
method
;
private
String
schema
;
private
List
<
PostmanKeyValue
>
header
;
private
JSONObject
body
;
private
JSONObject
auth
;
private
PostmanUrl
url
;
private
String
description
;
}
backend/src/main/java/io/metersphere/api/dto/definition/parse/postman/PostmanUrl.java
0 → 100644
浏览文件 @
cbc9c421
package
io.metersphere.api.dto.definition.parse.postman
;
import
lombok.Data
;
import
java.util.List
;
@Data
public
class
PostmanUrl
{
private
String
raw
;
private
String
protocol
;
private
String
port
;
private
List
<
PostmanKeyValue
>
query
;
}
backend/src/main/java/io/metersphere/api/dto/definition/parse/swagger/SwaggerApi.java
0 → 100644
浏览文件 @
cbc9c421
package
io.metersphere.api.dto.definition.parse.swagger
;
import
com.alibaba.fastjson.JSONObject
;
import
lombok.Data
;
import
java.util.List
;
@Data
public
class
SwaggerApi
{
private
String
swagger
;
private
SwaggerInfo
info
;
private
String
host
;
private
String
basePath
;
private
List
<
String
>
schemes
;
private
List
<
SwaggerTag
>
tags
;
private
JSONObject
paths
;
private
JSONObject
definitions
;
}
backend/src/main/java/io/metersphere/api/dto/definition/parse/swagger/SwaggerInfo.java
0 → 100644
浏览文件 @
cbc9c421
package
io.metersphere.api.dto.definition.parse.swagger
;
import
lombok.Data
;
@Data
public
class
SwaggerInfo
{
private
String
version
;
private
String
title
;
private
String
description
;
private
String
termsOfService
;
}
backend/src/main/java/io/metersphere/api/dto/definition/parse/swagger/SwaggerParameter.java
0 → 100644
浏览文件 @
cbc9c421
package
io.metersphere.api.dto.definition.parse.swagger
;
import
lombok.Data
;
@Data
public
class
SwaggerParameter
{
private
String
name
;
private
String
in
;
private
String
description
;
private
Boolean
required
;
private
String
type
;
private
String
format
;
}
backend/src/main/java/io/metersphere/api/dto/definition/parse/swagger/SwaggerRequest.java
0 → 100644
浏览文件 @
cbc9c421
package
io.metersphere.api.dto.definition.parse.swagger
;
import
lombok.Data
;
import
java.util.List
;
@Data
public
class
SwaggerRequest
{
private
List
<
String
>
tags
;
private
String
summary
;
private
String
description
;
private
String
operationId
;
private
List
<
String
>
consumes
;
private
List
<
String
>
produces
;
private
List
<
SwaggerParameter
>
parameters
;
}
backend/src/main/java/io/metersphere/api/dto/definition/parse/swagger/SwaggerTag.java
0 → 100644
浏览文件 @
cbc9c421
package
io.metersphere.api.dto.definition.parse.swagger
;
import
lombok.Data
;
@Data
public
class
SwaggerTag
{
private
String
name
;
private
String
description
;
}
backend/src/main/java/io/metersphere/api/parse/ApiImportParser.java
浏览文件 @
cbc9c421
package
io.metersphere.api.parse
;
import
io.metersphere.api.dto.ApiTestImportRequest
;
import
io.metersphere.api.dto.definition.parse.ApiDefinitionImport
;
import
io.metersphere.api.dto.parse.ApiImport
;
import
java.io.InputStream
;
public
interface
ApiImportParser
{
ApiImport
parse
(
InputStream
source
,
ApiTestImportRequest
request
);
ApiDefinitionImport
parseApi
(
InputStream
source
,
ApiTestImportRequest
request
);
}
backend/src/main/java/io/metersphere/api/parse/MsParser.java
浏览文件 @
cbc9c421
...
...
@@ -5,6 +5,7 @@ import com.alibaba.fastjson.JSONArray;
import
com.alibaba.fastjson.JSONObject
;
import
com.alibaba.fastjson.parser.Feature
;
import
io.metersphere.api.dto.ApiTestImportRequest
;
import
io.metersphere.api.dto.definition.parse.ApiDefinitionImport
;
import
io.metersphere.api.dto.parse.ApiImport
;
import
io.metersphere.api.dto.scenario.request.RequestType
;
import
io.metersphere.commons.constants.MsRequestBodyType
;
...
...
@@ -22,6 +23,13 @@ public class MsParser extends ApiImportAbstractParser {
return
apiImport
;
}
@Override
public
ApiDefinitionImport
parseApi
(
InputStream
source
,
ApiTestImportRequest
request
)
{
String
testStr
=
getApiTestStr
(
source
);
ApiDefinitionImport
apiImport
=
JSON
.
parseObject
(
testStr
,
ApiDefinitionImport
.
class
);
return
apiImport
;
}
private
String
parsePluginFormat
(
String
testStr
)
{
JSONObject
testObject
=
JSONObject
.
parseObject
(
testStr
,
Feature
.
OrderedField
);
if
(
testObject
.
get
(
"scenarios"
)
!=
null
)
{
...
...
backend/src/main/java/io/metersphere/api/parse/PostmanParser.java
浏览文件 @
cbc9c421
...
...
@@ -3,6 +3,11 @@ package io.metersphere.api.parse;
import
com.alibaba.fastjson.JSON
;
import
com.alibaba.fastjson.JSONObject
;
import
io.metersphere.api.dto.ApiTestImportRequest
;
import
io.metersphere.api.dto.definition.ApiDefinitionResult
;
import
io.metersphere.api.dto.definition.parse.ApiDefinitionImport
;
import
io.metersphere.api.dto.definition.request.MsTestElement
;
import
io.metersphere.api.dto.definition.request.configurations.MsHeaderManager
;
import
io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy
;
import
io.metersphere.api.dto.parse.ApiImport
;
import
io.metersphere.api.dto.parse.postman.*
;
import
io.metersphere.api.dto.scenario.Body
;
...
...
@@ -10,12 +15,17 @@ import io.metersphere.api.dto.scenario.KeyValue;
import
io.metersphere.api.dto.scenario.Scenario
;
import
io.metersphere.api.dto.scenario.request.HttpRequest
;
import
io.metersphere.api.dto.scenario.request.Request
;
import
io.metersphere.api.dto.scenario.request.RequestType
;
import
io.metersphere.commons.constants.MsRequestBodyType
;
import
io.metersphere.commons.constants.PostmanRequestBodyMode
;
import
org.apache.commons.lang3.StringUtils
;
import
org.apache.jorphan.collections.HashTree
;
import
java.io.InputStream
;
import
java.util.*
;
import
java.util.ArrayList
;
import
java.util.LinkedList
;
import
java.util.List
;
import
java.util.UUID
;
public
class
PostmanParser
extends
ApiImportAbstractParser
{
...
...
@@ -38,6 +48,67 @@ public class PostmanParser extends ApiImportAbstractParser {
return
apiImport
;
}
@Override
public
ApiDefinitionImport
parseApi
(
InputStream
source
,
ApiTestImportRequest
request
)
{
String
testStr
=
getApiTestStr
(
source
);
PostmanCollection
postmanCollection
=
JSON
.
parseObject
(
testStr
,
PostmanCollection
.
class
);
List
<
PostmanKeyValue
>
variables
=
postmanCollection
.
getVariable
();
ApiDefinitionImport
apiImport
=
new
ApiDefinitionImport
();
List
<
ApiDefinitionResult
>
requests
=
new
ArrayList
<>();
parseItem
(
postmanCollection
.
getItem
(),
variables
,
requests
);
apiImport
.
setData
(
requests
);
return
apiImport
;
}
private
void
parseItem
(
List
<
PostmanItem
>
items
,
List
<
PostmanKeyValue
>
variables
,
List
<
ApiDefinitionResult
>
scenarios
)
{
for
(
PostmanItem
item
:
items
)
{
List
<
PostmanItem
>
childItems
=
item
.
getItem
();
if
(
childItems
!=
null
)
{
parseItem
(
childItems
,
variables
,
scenarios
);
}
else
{
ApiDefinitionResult
request
=
parsePostman
(
item
);
if
(
request
!=
null
)
{
scenarios
.
add
(
request
);
}
}
}
}
private
ApiDefinitionResult
parsePostman
(
PostmanItem
requestItem
)
{
PostmanRequest
requestDesc
=
requestItem
.
getRequest
();
if
(
requestDesc
==
null
)
{
return
null
;
}
PostmanUrl
url
=
requestDesc
.
getUrl
();
ApiDefinitionResult
request
=
new
ApiDefinitionResult
();
request
.
setName
(
requestItem
.
getName
());
request
.
setPath
(
url
.
getRaw
());
request
.
setMethod
(
requestDesc
.
getMethod
());
request
.
setProtocol
(
RequestType
.
HTTP
);
MsHTTPSamplerProxy
requestElement
=
new
MsHTTPSamplerProxy
();
requestElement
.
setName
(
requestItem
.
getName
()
+
"Postman MHTTPSamplerProxy"
);
requestElement
.
setBody
(
parseBody
(
requestDesc
));
requestElement
.
setArguments
(
parseKeyValue
(
url
.
getQuery
()));
requestElement
.
setProtocol
(
RequestType
.
HTTP
);
requestElement
.
setPath
(
url
.
getRaw
());
requestElement
.
setMethod
(
requestDesc
.
getMethod
());
requestElement
.
setId
(
UUID
.
randomUUID
().
toString
());
requestElement
.
setRest
(
new
ArrayList
<
KeyValue
>());
MsHeaderManager
headerManager
=
new
MsHeaderManager
();
headerManager
.
setId
(
UUID
.
randomUUID
().
toString
());
headerManager
.
setName
(
requestItem
.
getName
()
+
"Postman MsHeaderManager"
);
headerManager
.
setHeaders
(
parseKeyValue
(
requestDesc
.
getHeader
()));
HashTree
tree
=
new
HashTree
();
tree
.
add
(
headerManager
);
LinkedList
<
MsTestElement
>
list
=
new
LinkedList
<>();
list
.
add
(
headerManager
);
requestElement
.
setHashTree
(
list
);
request
.
setRequest
(
JSON
.
toJSONString
(
requestElement
));
return
request
;
}
private
List
<
KeyValue
>
parseKeyValue
(
List
<
PostmanKeyValue
>
postmanKeyValues
)
{
if
(
postmanKeyValues
==
null
)
{
return
null
;
...
...
backend/src/main/java/io/metersphere/api/parse/Swagger2Parser.java
浏览文件 @
cbc9c421
package
io.metersphere.api.parse
;
import
com.alibaba.fastjson.JSON
;
import
com.alibaba.fastjson.JSONArray
;
import
com.alibaba.fastjson.JSONObject
;
import
io.metersphere.api.dto.ApiTestImportRequest
;
import
io.metersphere.api.dto.definition.ApiDefinitionResult
;
import
io.metersphere.api.dto.definition.parse.ApiDefinitionImport
;
import
io.metersphere.api.dto.definition.request.MsTestElement
;
import
io.metersphere.api.dto.definition.request.configurations.MsHeaderManager
;
import
io.metersphere.api.dto.definition.request.sampler.MsHTTPSamplerProxy
;
import
io.metersphere.api.dto.parse.ApiImport
;
import
io.metersphere.api.dto.scenario.Body
;
import
io.metersphere.api.dto.scenario.KeyValue
;
import
io.metersphere.api.dto.scenario.Scenario
;
import
io.metersphere.api.dto.scenario.request.HttpRequest
;
import
io.metersphere.api.dto.scenario.request.Request
;
import
io.metersphere.api.dto.scenario.request.RequestType
;
import
io.metersphere.commons.constants.MsRequestBodyType
;
import
io.metersphere.commons.constants.SwaggerParameterType
;
import
io.swagger.models.*
;
...
...
@@ -19,6 +26,7 @@ import io.swagger.models.properties.Property;
import
io.swagger.models.properties.RefProperty
;
import
io.swagger.parser.SwaggerParser
;
import
org.apache.commons.lang3.StringUtils
;
import
org.apache.jorphan.collections.HashTree
;
import
java.io.InputStream
;
import
java.util.*
;
...
...
@@ -39,6 +47,52 @@ public class Swagger2Parser extends ApiImportAbstractParser {
return
apiImport
;
}
@Override
public
ApiDefinitionImport
parseApi
(
InputStream
source
,
ApiTestImportRequest
request
)
{
ApiImport
apiImport
=
this
.
parse
(
source
,
request
);
ApiDefinitionImport
definitionImport
=
new
ApiDefinitionImport
();
definitionImport
.
setData
(
parseSwagger
(
apiImport
));
return
definitionImport
;
}
private
List
<
ApiDefinitionResult
>
parseSwagger
(
ApiImport
apiImport
)
{
List
<
ApiDefinitionResult
>
results
=
new
LinkedList
<>();
apiImport
.
getScenarios
().
forEach
(
item
->
{
item
.
getRequests
().
forEach
(
childItem
->
{
if
(
childItem
instanceof
HttpRequest
)
{
HttpRequest
res
=
(
HttpRequest
)
childItem
;
ApiDefinitionResult
request
=
new
ApiDefinitionResult
();
request
.
setName
(
res
.
getName
());
request
.
setPath
(
res
.
getPath
());
request
.
setMethod
(
res
.
getMethod
());
request
.
setProtocol
(
RequestType
.
HTTP
);
MsHTTPSamplerProxy
requestElement
=
new
MsHTTPSamplerProxy
();
requestElement
.
setName
(
res
.
getName
()
+
"Postman MHTTPSamplerProxy"
);
requestElement
.
setBody
(
res
.
getBody
());
requestElement
.
setArguments
(
res
.
getParameters
());
requestElement
.
setProtocol
(
RequestType
.
HTTP
);
requestElement
.
setPath
(
res
.
getPath
());
requestElement
.
setMethod
(
res
.
getMethod
());
requestElement
.
setId
(
UUID
.
randomUUID
().
toString
());
requestElement
.
setRest
(
new
ArrayList
<
KeyValue
>());
MsHeaderManager
headerManager
=
new
MsHeaderManager
();
headerManager
.
setId
(
UUID
.
randomUUID
().
toString
());
headerManager
.
setName
(
res
.
getName
()
+
"Postman MsHeaderManager"
);
headerManager
.
setHeaders
(
res
.
getHeaders
());
HashTree
tree
=
new
HashTree
();
tree
.
add
(
headerManager
);
LinkedList
<
MsTestElement
>
list
=
new
LinkedList
<>();
list
.
add
(
headerManager
);
requestElement
.
setHashTree
(
list
);
request
.
setRequest
(
JSON
.
toJSONString
(
requestElement
));
results
.
add
(
request
);
}
});
});
return
results
;
}
private
List
<
Scenario
>
parseRequests
(
Swagger
swagger
)
{
Map
<
String
,
Path
>
paths
=
swagger
.
getPaths
();
Set
<
String
>
pathNames
=
paths
.
keySet
();
...
...
@@ -141,7 +195,7 @@ public class Swagger2Parser extends ApiImportAbstractParser {
Model
model
=
definitions
.
get
(
simpleRef
);
HashSet
<
String
>
refSet
=
new
HashSet
<>();
refSet
.
add
(
simpleRef
);
if
(
model
!=
null
)
{
if
(
model
!=
null
)
{
JSONObject
bodyParameters
=
getBodyJSONObjectParameters
(
model
.
getProperties
(),
definitions
,
refSet
);
body
.
setRaw
(
bodyParameters
.
toJSONString
());
}
...
...
backend/src/main/java/io/metersphere/api/service/ApiDefinitionService.java
浏览文件 @
cbc9c421
...
...
@@ -3,10 +3,14 @@ package io.metersphere.api.service;
import
com.alibaba.fastjson.JSON
;
import
com.alibaba.fastjson.JSONObject
;
import
io.metersphere.api.dto.APIReportResult
;
import
io.metersphere.api.dto.ApiTestImportRequest
;
import
io.metersphere.api.dto.definition.*
;
import
io.metersphere.api.dto.definition.parse.ApiDefinitionImport
;
import
io.metersphere.api.dto.scenario.request.RequestType
;
import
io.metersphere.api.jmeter.JMeterService
;
import
io.metersphere.api.jmeter.TestResult
;
import
io.metersphere.api.parse.ApiImportParser
;
import
io.metersphere.api.parse.ApiImportParserFactory
;
import
io.metersphere.base.domain.*
;
import
io.metersphere.base.mapper.ApiDefinitionExecResultMapper
;
import
io.metersphere.base.mapper.ApiDefinitionMapper
;
...
...
@@ -29,10 +33,7 @@ import sun.security.util.Cache;
import
javax.annotation.Resource
;
import
java.io.*
;
import
java.util.ArrayList
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Objects
;
import
java.util.*
;
import
java.util.function.Function
;
import
java.util.stream.Collectors
;
...
...
@@ -206,6 +207,39 @@ public class ApiDefinitionService {
return
test
;
}
private
ApiDefinition
createTest
(
ApiDefinitionResult
request
)
{
SaveApiDefinitionRequest
saveReq
=
new
SaveApiDefinitionRequest
();
saveReq
.
setId
(
UUID
.
randomUUID
().
toString
());
saveReq
.
setName
(
request
.
getName
());
saveReq
.
setProtocol
(
request
.
getProtocol
());
saveReq
.
setProjectId
(
request
.
getProjectId
());
saveReq
.
setPath
(
request
.
getPath
());
checkNameExist
(
saveReq
);
final
ApiDefinition
test
=
new
ApiDefinition
();
test
.
setId
(
request
.
getId
());
test
.
setName
(
request
.
getName
());
test
.
setProtocol
(
request
.
getProtocol
());
test
.
setMethod
(
request
.
getMethod
());
test
.
setPath
(
request
.
getPath
());
test
.
setModuleId
(
request
.
getModuleId
());
test
.
setProjectId
(
request
.
getProjectId
());
test
.
setRequest
(
request
.
getRequest
());
test
.
setCreateTime
(
System
.
currentTimeMillis
());
test
.
setUpdateTime
(
System
.
currentTimeMillis
());
test
.
setStatus
(
APITestStatus
.
Underway
.
name
());
test
.
setModulePath
(
request
.
getModulePath
());
test
.
setResponse
(
request
.
getResponse
());
test
.
setEnvironmentId
(
request
.
getEnvironmentId
());
if
(
request
.
getUserId
()
==
null
)
{
test
.
setUserId
(
Objects
.
requireNonNull
(
SessionUtils
.
getUser
()).
getId
());
}
else
{
test
.
setUserId
(
request
.
getUserId
());
}
test
.
setDescription
(
request
.
getDescription
());
apiDefinitionMapper
.
insert
(
test
);
return
test
;
}
private
void
deleteFileByTestId
(
String
apiId
)
{
ApiTestFileExample
apiTestFileExample
=
new
ApiTestFileExample
();
apiTestFileExample
.
createCriteria
().
andTestIdEqualTo
(
apiId
);
...
...
@@ -276,4 +310,31 @@ public class ApiDefinitionService {
reportResult
.
setContent
(
result
.
getContent
());
return
reportResult
;
}
public
String
apiTestImport
(
MultipartFile
file
,
ApiTestImportRequest
request
)
{
ApiImportParser
apiImportParser
=
ApiImportParserFactory
.
getApiImportParser
(
request
.
getPlatform
());
ApiDefinitionImport
apiImport
=
null
;
try
{
apiImport
=
Objects
.
requireNonNull
(
apiImportParser
).
parseApi
(
file
==
null
?
null
:
file
.
getInputStream
(),
request
);
}
catch
(
Exception
e
)
{
LogUtil
.
error
(
e
.
getMessage
(),
e
);
MSException
.
throwException
(
Translator
.
get
(
"parse_data_error"
));
}
importApiTest
(
request
,
apiImport
);
return
"SUCCESS"
;
}
private
void
importApiTest
(
ApiTestImportRequest
importRequest
,
ApiDefinitionImport
apiImport
)
{
apiImport
.
getData
().
forEach
(
item
->
{
item
.
setProjectId
(
importRequest
.
getProjectId
());
item
.
setModuleId
(
importRequest
.
getModuleId
());
item
.
setModulePath
(
importRequest
.
getModulePath
());
item
.
setEnvironmentId
(
importRequest
.
getEnvironmentId
());
item
.
setId
(
UUID
.
randomUUID
().
toString
());
item
.
setUserId
(
null
);
createTest
(
item
);
});
}
}
frontend/src/business/components/api/definition/ApiDefinition.vue
浏览文件 @
cbc9c421
...
...
@@ -3,7 +3,7 @@
<ms-aside-container>
<ms-node-tree
@
selectModule=
"selectModule"
@
getApiModuleTree=
"initTree"
@
changeProject=
"changeProject"
@
changeProtocol=
"changeProtocol"
@
refresh=
"refresh"
@
saveAsEdit=
"editApi"
/>
@
refresh=
"refresh"
@
saveAsEdit=
"editApi"
@
debug=
"debug"
@
exportAPI=
"exportAPI"
/>
</ms-aside-container>
<ms-main-container>
...
...
@@ -69,7 +69,7 @@
import
MsApiConfig
from
"
./components/ApiConfig
"
;
import
MsDebugHttpPage
from
"
./components/debug/DebugHttpPage
"
;
import
MsRunTestHttpPage
from
"
./components/runtest/RunTestHttpPage
"
;
import
{
getCurrentUser
,
getUUID
}
from
"
../../../..
/common/js/utils
"
;
import
{
downloadFile
,
getCurrentUser
,
getUUID
}
from
"
@
/common/js/utils
"
;
export
default
{
name
:
"
TestCase
"
,
...
...
@@ -103,6 +103,11 @@
}],
}
},
watch
:
{
currentProtocol
()
{
this
.
handleCommand
(
"
closeAll
"
);
}
},
methods
:
{
handleCommand
(
e
)
{
if
(
e
===
"
add
"
)
{
...
...
@@ -154,6 +159,9 @@
this
.
apiDefaultTab
=
newTabName
;
}
},
debug
()
{
this
.
handleTabsEdit
(
this
.
$t
(
'
api_test.definition.request.fast_debug
'
),
"
debug
"
);
},
editApi
(
row
)
{
this
.
currentApi
=
row
;
this
.
handleTabsEdit
(
row
.
name
,
"
add
"
);
...
...
@@ -168,6 +176,13 @@
selectModule
(
data
)
{
this
.
currentModule
=
data
;
},
exportAPI
()
{
if
(
!
this
.
$refs
.
apiList
[
0
].
tableData
)
{
return
;
}
let
obj
=
{
projectName
:
this
.
currentProject
.
name
,
protocol
:
this
.
currentProtocol
,
data
:
this
.
$refs
.
apiList
[
0
].
tableData
}
downloadFile
(
"
导出API.json
"
,
JSON
.
stringify
(
obj
));
},
refresh
(
data
)
{
this
.
$refs
.
apiList
[
0
].
initApiTable
(
data
);
},
...
...
frontend/src/business/components/api/definition/components/ApiCaseList.vue
浏览文件 @
cbc9c421
...
...
@@ -168,10 +168,10 @@
<
script
>
import
MsTag
from
"
../../../common/components/MsTag
"
;
import
MsTipButton
from
"
../../../common/components/MsTipButton
"
;
import
MsApiRequestForm
from
"
./request/ApiRequestForm
"
;
import
MsApiRequestForm
from
"
./request/
http/
ApiRequestForm
"
;
import
{
downloadFile
,
getUUID
}
from
"
@/common/js/utils
"
;
import
{
parseEnvironment
}
from
"
../model/EnvironmentModel
"
;
import
ApiEnvironmentConfig
from
"
.
./../test/components
/ApiEnvironmentConfig
"
;
import
ApiEnvironmentConfig
from
"
.
/environment
/ApiEnvironmentConfig
"
;
import
{
PRIORITY
,
RESULT_MAP
}
from
"
../model/JsonData
"
;
import
MsApiAssertions
from
"
./assertion/ApiAssertions
"
;
import
MsRun
from
"
./Run
"
;
...
...
frontend/src/business/components/api/definition/components/ApiConfig.vue
浏览文件 @
cbc9c421
...
...
@@ -5,26 +5,33 @@
<ms-add-complete-http-api
@
runTest=
"runTest"
@
saveApi=
"saveApi"
:request=
"request"
:headers=
"headers"
:response=
"response"
:basisData=
"currentApi"
:moduleOptions=
"moduleOptions"
:currentProject=
"currentProject"
v-if=
"currentProtocol === 'HTTP'"
/>
<!-- TCP -->
<ms-api-tcp-request-form
:request=
"request"
:currentProject=
"currentProject"
:basisData=
"currentApi"
:moduleOptions=
"moduleOptions"
:maintainerOptions=
"maintainerOptions"
v-if=
"currentProtocol === 'TCP'"
/>
</div>
</
template
>
<
script
>
import
MsAddCompleteHttpApi
from
"
./complete/AddCompleteHttpApi
"
;
import
MsApiTcpRequestForm
from
"
./complete/ApiTcpRequestForm
"
;
import
{
ResponseFactory
,
Body
}
from
"
../model/ApiTestModel
"
;
import
{
getUUID
}
from
"
@/common/js/utils
"
;
import
{
createComponent
,
Request
}
from
"
./jmeter/components
"
;
import
Sampler
from
"
./jmeter/components/sampler/sampler
"
;
import
HeaderManager
from
"
./jmeter/components/configurations/header-manager
"
;
import
{
WORKSPACE_ID
}
from
'
@/common/js/constants
'
;
export
default
{
name
:
"
ApiConfig
"
,
components
:
{
MsAddCompleteHttpApi
},
components
:
{
MsAddCompleteHttpApi
,
MsApiTcpRequestForm
},
data
()
{
return
{
reqUrl
:
""
,
request
:
Sampler
,
config
:
{},
response
:
{},
headers
:
[],
maintainerOptions
:
[],
}
},
props
:
{
...
...
@@ -34,6 +41,7 @@
currentProtocol
:
String
,
},
created
()
{
this
.
getMaintainerOptions
();
switch
(
this
.
currentProtocol
)
{
case
Request
.
TYPES
.
SQL
:
this
.
request
=
createComponent
(
"
SQL
"
);
...
...
@@ -70,6 +78,13 @@
this
.
$emit
(
'
runTest
'
,
data
);
});
},
getMaintainerOptions
()
{
let
workspaceId
=
localStorage
.
getItem
(
WORKSPACE_ID
);
this
.
$post
(
'
/user/ws/member/tester/list
'
,
{
workspaceId
:
workspaceId
},
response
=>
{
this
.
maintainerOptions
=
response
.
data
;
});
},
createHttp
()
{
if
(
this
.
currentApi
.
request
!=
undefined
&&
this
.
currentApi
.
request
!=
null
)
{
this
.
request
=
JSON
.
parse
(
this
.
currentApi
.
request
);
...
...
@@ -103,32 +118,36 @@
data
.
bodyUploadIds
=
[];
let
request
=
data
.
request
;
if
(
request
.
body
)
{
request
.
body
.
kvs
.
forEach
(
param
=>
{
if
(
param
.
files
)
{
param
.
files
.
forEach
(
item
=>
{
if
(
item
.
file
)
{
let
fileId
=
getUUID
().
substring
(
0
,
8
);
item
.
name
=
item
.
file
.
name
;
item
.
id
=
fileId
;
data
.
bodyUploadIds
.
push
(
fileId
);
bodyUploadFiles
.
push
(
item
.
file
);
}
});
}
});
request
.
body
.
binary
.
forEach
(
param
=>
{
if
(
param
.
files
)
{
param
.
files
.
forEach
(
item
=>
{
if
(
item
.
file
)
{
let
fileId
=
getUUID
().
substring
(
0
,
8
);
item
.
name
=
item
.
file
.
name
;
item
.
id
=
fileId
;
data
.
bodyUploadIds
.
push
(
fileId
);
bodyUploadFiles
.
push
(
item
.
file
);
}
});
}
});
if
(
request
.
body
.
kvs
)
{
request
.
body
.
kvs
.
forEach
(
param
=>
{
if
(
param
.
files
)
{
param
.
files
.
forEach
(
item
=>
{
if
(
item
.
file
)
{
let
fileId
=
getUUID
().
substring
(
0
,
8
);
item
.
name
=
item
.
file
.
name
;
item
.
id
=
fileId
;
data
.
bodyUploadIds
.
push
(
fileId
);
bodyUploadFiles
.
push
(
item
.
file
);
}
});
}
});
}
if
(
request
.
body
.
binary
)
{
request
.
body
.
binary
.
forEach
(
param
=>
{
if
(
param
.
files
)
{
param
.
files
.
forEach
(
item
=>
{
if
(
item
.
file
)
{
let
fileId
=
getUUID
().
substring
(
0
,
8
);
item
.
name
=
item
.
file
.
name
;
item
.
id
=
fileId
;
data
.
bodyUploadIds
.
push
(
fileId
);
bodyUploadFiles
.
push
(
item
.
file
);
}
});
}
});
}
}
return
bodyUploadFiles
;
},
...
...
frontend/src/business/components/api/definition/components/ApiModule.vue
浏览文件 @
cbc9c421
...
...
@@ -18,7 +18,20 @@
<el-input
style=
"width: 175px; padding-left: 3px"
:placeholder=
"$t('test_track.module.search')"
v-model=
"filterText"
size=
"small"
>
<template
v-slot:append
>
<el-button
icon=
"el-icon-folder-add"
@
click=
"addApi"
></el-button>
<!--
<el-button
icon=
"el-icon-folder-add"
@
click=
"addApi"
></el-button>
-->
<el-dropdown
size=
"small"
split-button
type=
"primary"
class=
"ms-api-buttion"
@
click=
"handleCommand('add')"
@
command=
"handleCommand"
>
<el-button
icon=
"el-icon-folder-add"
@
click=
"addApi"
></el-button>
<el-dropdown-menu
slot=
"dropdown"
>
<el-dropdown-item
command=
"add-api"
>
{{
$t
(
'
api_test.definition.request.title
'
)
}}
</el-dropdown-item>
<!--
<el-dropdown-item
command=
"add-module"
>
{{
$t
(
'
api_test.definition.request.add_module
'
)
}}
</el-dropdown-item>
-->
<el-dropdown-item
command=
"debug"
>
{{
$t
(
'
api_test.definition.request.fast_debug
'
)
}}
</el-dropdown-item>
<el-dropdown-item
command=
"import"
>
{{
$t
(
'
api_test.api_import.label
'
)
}}
</el-dropdown-item>
<el-dropdown-item
command=
"export"
>
{{
$t
(
'
report.export
'
)
}}
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</
template
>
</el-input>
...
...
@@ -81,6 +94,7 @@
</el-tree>
<ms-add-basis-http-api
:current-protocol=
"value"
ref=
"httpApi"
></ms-add-basis-http-api>
<api-import
ref=
"apiImport"
@
refresh=
"refresh"
/>
</div>
...
...
@@ -90,12 +104,14 @@
import
MsAddBasisHttpApi
from
"
./basis/AddBasisApi
"
;
import
SelectMenu
from
"
../../../track/common/SelectMenu
"
;
import
{
OPTIONS
,
DEFAULT_DATA
}
from
"
../model/JsonData
"
;
import
ApiImport
from
"
./import/ApiImport
"
;
export
default
{
name
:
'
MsApiModule
'
,
components
:
{
MsAddBasisHttpApi
,
SelectMenu
SelectMenu
,
ApiImport
},
data
()
{
return
{
...
...
@@ -140,6 +156,24 @@
}
},
handleCommand
(
e
)
{
switch
(
e
)
{
case
"
debug
"
:
this
.
$emit
(
'
debug
'
);
break
;
case
"
add-api
"
:
this
.
addApi
();
break
;
case
"
add-module
"
:
break
;
case
"
import
"
:
this
.
$refs
.
apiImport
.
open
(
this
.
currentModule
);
break
;
default
:
this
.
$emit
(
'
exportAPI
'
);
break
;
}
},
buildNodePath
(
node
,
option
,
moduleOptions
)
{
//递归构建节点路径
option
.
id
=
node
.
id
;
...
...
@@ -382,7 +416,7 @@
return
data
.
name
.
indexOf
(
value
)
!==
-
1
;
},
addApi
()
{
this
.
$refs
.
httpApi
.
open
(
this
.
currentModule
,
this
.
currentProject
.
id
);
this
.
$refs
.
httpApi
.
open
(
this
.
currentModule
);
},
// 项目相关方法
changeProject
(
project
)
{
...
...
@@ -460,4 +494,8 @@
/
deep
/
.el-tree-node__content
{
height
:
33px
;
}
.ms-api-buttion
{
width
:
30px
;
}
</
style
>
frontend/src/business/components/api/definition/components/complete/AddCompleteHttpApi.vue
浏览文件 @
cbc9c421
...
...
@@ -74,7 +74,7 @@
</
template
>
<
script
>
import
MsApiRequestForm
from
"
../request/ApiRequestForm
"
;
import
MsApiRequestForm
from
"
../request/
http/
ApiRequestForm
"
;
import
MsResponseText
from
"
../response/ResponseText
"
;
import
{
WORKSPACE_ID
}
from
'
../../../../../../common/js/constants
'
;
import
{
REQ_METHOD
,
API_STATUS
}
from
"
../../model/JsonData
"
;
...
...
frontend/src/business/components/api/definition/components/complete/ApiTcpRequestForm.vue
0 → 100644
浏览文件 @
cbc9c421
<
template
xmlns:el-col=
"http://www.w3.org/1999/html"
>
<!-- 操作按钮 -->
<div
style=
"background-color: white;"
>
<el-row>
<el-col>
<!--操作按钮-->
<div
style=
"float: right;margin-right: 20px;margin-top: 20px"
>
<el-button
type=
"primary"
size=
"small"
@
click=
"validateApi"
>
{{
$t
(
'
commons.save
'
)
}}
</el-button>
<el-button
type=
"primary"
size=
"small"
@
click=
"runTest"
>
{{
$t
(
'
commons.test
'
)
}}
</el-button>
</div>
</el-col>
</el-row>
<!-- 基础信息 -->
<p
class=
"tip"
>
{{
$t
(
'
test_track.plan_view.base_info
'
)
}}
</p>
<br/>
<el-row>
<el-col>
<ms-basis-api
:moduleOptions=
"moduleOptions"
:basisData=
"basisData"
ref=
"basicForm"
@
callback=
"saveApi"
/>
</el-col>
</el-row>
<!-- 请求参数 -->
<p
class=
"tip"
>
{{
$t
(
'
api_test.definition.request.req_param
'
)
}}
</p>
<el-row>
<el-col
:span=
"21"
style=
"padding-bottom: 50px"
>
<el-form
class=
"tcp"
:model=
"request"
:rules=
"rules"
ref=
"request"
label-width=
"auto"
:disabled=
"isReadOnly"
>
<el-form-item/>
<!--
<el-form-item
:label=
"$t('api_test.request.name')"
prop=
"name"
>
<el-input
v-model=
"request.name"
size=
"small"
maxlength=
"300"
show-word-limit
/>
</el-form-item>
-->
<el-form-item
label=
"TCPClient"
prop=
"classname"
>
<el-select
v-model=
"request.classname"
style=
"width: 100%"
size=
"small"
>
<el-option
v-for=
"c in classes"
:key=
"c"
:label=
"c"
:value=
"c"
/>
</el-select>
</el-form-item>
<el-row
:gutter=
"10"
>
<el-col
:span=
"16"
>
<el-form-item
:label=
"$t('api_test.request.tcp.server')"
prop=
"server"
>
<el-input
v-model=
"request.server"
maxlength=
"300"
show-word-limit
size=
"small"
/>
</el-form-item>
</el-col>
<el-col
:span=
"8"
>
<el-form-item
:label=
"$t('api_test.request.tcp.port')"
prop=
"port"
label-width=
"60px"
>
<el-input-number
v-model=
"request.port"
controls-position=
"right"
:min=
"0"
:max=
"65535"
size=
"small"
/>
</el-form-item>
</el-col>
</el-row>
<el-row
:gutter=
"10"
>
<el-col
:span=
"6"
>
<el-form-item
:label=
"$t('api_test.request.tcp.connect')"
prop=
"ctimeout"
>
<el-input-number
v-model=
"request.ctimeout"
controls-position=
"right"
:min=
"0"
size=
"small"
/>
</el-form-item>
</el-col>
<el-col
:span=
"6"
>
<el-form-item
:label=
"$t('api_test.request.tcp.response')"
prop=
"timeout"
>
<el-input-number
v-model=
"request.timeout"
controls-position=
"right"
:min=
"0"
size=
"small"
/>
</el-form-item>
</el-col>
<el-col
:span=
"6"
>
<el-form-item
:label=
"$t('api_test.request.tcp.so_linger')"
prop=
"soLinger"
>
<el-input
v-model=
"request.soLinger"
size=
"small"
/>
</el-form-item>
</el-col>
<el-col
:span=
"6"
>
<el-form-item
:label=
"$t('api_test.request.tcp.eol_byte')"
prop=
"eolByte"
>
<el-input
v-model=
"request.eolByte"
size=
"small"
/>
</el-form-item>
</el-col>
</el-row>
<el-row
:gutter=
"10"
>
<el-col
:span=
"6"
>
<el-form-item
:label=
"$t('api_test.request.refer_to_environment')"
>
<el-switch
v-model=
"request.useEnvironment"
@
change=
"useEnvironmentChange"
>
</el-switch>
</el-form-item>
</el-col>
<el-col
:span=
"6"
>
<el-form-item
:label=
"$t('api_test.request.tcp.re_use_connection')"
>
<el-checkbox
v-model=
"request.reUseConnection"
/>
</el-form-item>
</el-col>
<el-col
:span=
"6"
>
<el-form-item
:label=
"$t('api_test.request.tcp.close_connection')"
>
<el-checkbox
v-model=
"request.closeConnection"
/>
</el-form-item>
</el-col>
<el-col
:span=
"6"
>
<el-form-item
:label=
"$t('api_test.request.tcp.no_delay')"
>
<el-checkbox
v-model=
"request.nodelay"
/>
</el-form-item>
</el-col>
</el-row>
<el-row
:gutter=
"10"
>
<el-col
:span=
"12"
>
<el-form-item
:label=
"$t('api_test.request.tcp.username')"
prop=
"username"
>
<el-input
v-model=
"request.username"
maxlength=
"100"
show-word-limit
size=
"small"
/>
</el-form-item>
</el-col>
<el-col
:span=
"12"
>
<el-form-item
:label=
"$t('api_test.request.tcp.password')"
prop=
"password"
>
<el-input
v-model=
"request.password"
maxlength=
"30"
show-word-limit
show-password
autocomplete=
"new-password"
size=
"small"
/>
</el-form-item>
</el-col>
</el-row>
<el-form-item
:label=
"$t('api_test.request.tcp.request')"
prop=
"request"
>
<div
class=
"send-request"
>
<ms-code-edit
mode=
"text"
:read-only=
"isReadOnly"
:data.sync=
"request.request"
:modes=
"['text', 'json', 'xml', 'html']"
theme=
"eclipse"
/>
</div>
</el-form-item>
</el-form>
<div
v-for=
"row in request.hashTree"
:key=
"row.id"
v-loading=
"isReloadData"
style=
"margin-left: 30px"
>
<!-- 前置脚本 -->
<ms-jsr233-processor
v-if=
"row.label ==='JSR223 PreProcessor'"
@
remove=
"remove"
:is-read-only=
"false"
:title=
"$t('api_test.definition.request.pre_script')"
style-type=
"warning"
:jsr223-processor=
"row"
/>
<!--后置脚本-->
<ms-jsr233-processor
v-if=
"row.label ==='JSR223 PostProcessor'"
@
remove=
"remove"
:is-read-only=
"false"
:title=
"$t('api_test.definition.request.post_script')"
style-type=
"success"
:jsr223-processor=
"row"
/>
<!--断言规则-->
<ms-api-assertions
v-if=
"row.type==='Assertions'"
@
remove=
"remove"
:is-read-only=
"isReadOnly"
:assertions=
"row"
/>
<!--提取规则-->
<ms-api-extract
:is-read-only=
"isReadOnly"
@
remove=
"remove"
v-if=
"row.type==='Extract'"
:extract=
"row"
/>
</div>
</el-col>
<el-col
:span=
"3"
class=
"ms-left-cell"
>
<el-button
class=
"ms-left-buttion"
size=
"small"
type=
"warning"
@
click=
"addPre"
plain
>
+
{{
$t
(
'
api_test.definition.request.pre_script
'
)
}}
</el-button>
<br/>
<el-button
class=
"ms-left-buttion"
size=
"small"
type=
"success"
@
click=
"addPost"
plain
>
+
{{
$t
(
'
api_test.definition.request.post_script
'
)
}}
</el-button>
<br/>
<el-button
class=
"ms-left-buttion"
size=
"small"
type=
"danger"
@
click=
"addAssertions"
plain
>
+
{{
$t
(
'
api_test.definition.request.assertions_rule
'
)
}}
</el-button>
<br/>
<el-button
class=
"ms-left-buttion"
size=
"small"
type=
"info"
@
click=
"addExtract"
plain
>
+
{{
$t
(
'
api_test.definition.request.extract_param
'
)
}}
</el-button>
</el-col>
</el-row>
</div>
</
template
>
<
script
>
import
MsApiAssertions
from
"
../assertion/ApiAssertions
"
;
import
MsApiExtract
from
"
../extract/ApiExtract
"
;
import
MsJsr233Processor
from
"
../processor/Jsr233Processor
"
;
import
MsCodeEdit
from
"
@/business/components/common/components/MsCodeEdit
"
;
import
TCPSampler
from
"
../jmeter/components/sampler/tcp-sampler
"
;
import
{
createComponent
}
from
"
../jmeter/components
"
;
import
{
Assertions
,
Extract
}
from
"
../../model/ApiTestModel
"
;
import
{
API_STATUS
}
from
"
../../model/JsonData
"
;
import
MsBasisApi
from
"
./BasisApi
"
;
export
default
{
name
:
"
MsApiTcpRequestForm
"
,
components
:
{
MsCodeEdit
,
MsJsr233Processor
,
MsApiExtract
,
MsApiAssertions
,
MsBasisApi
},
props
:
{
request
:
{},
basisData
:
{},
currentProject
:
{},
maintainerOptions
:
Array
,
moduleOptions
:
Array
,
isReadOnly
:
{
type
:
Boolean
,
default
:
false
}
},
data
()
{
return
{
activeName
:
"
assertions
"
,
classes
:
TCPSampler
.
CLASSES
,
rules
:
{
name
:
[
{
required
:
true
,
message
:
this
.
$t
(
'
test_track.case.input_name
'
),
trigger
:
'
blur
'
},
{
max
:
50
,
message
:
this
.
$t
(
'
test_track.length_less_than
'
)
+
'
50
'
,
trigger
:
'
blur
'
}
],
},
isReloadData
:
false
,
options
:
API_STATUS
,
}
},
methods
:
{
useEnvironmentChange
(
value
)
{
if
(
value
&&
!
this
.
request
.
environment
)
{
this
.
$error
(
this
.
$t
(
'
api_test.request.please_add_environment_to_scenario
'
),
2000
);
this
.
request
.
useEnvironment
=
false
;
}
this
.
$refs
[
"
request
"
].
clearValidate
();
},
addPre
()
{
let
jsr223PreProcessor
=
createComponent
(
"
JSR223PreProcessor
"
);
this
.
request
.
hashTree
.
push
(
jsr223PreProcessor
);
this
.
reload
();
},
addPost
()
{
let
jsr223PostProcessor
=
createComponent
(
"
JSR223PostProcessor
"
);
this
.
request
.
hashTree
.
push
(
jsr223PostProcessor
);
this
.
reload
();
},
addAssertions
()
{
let
assertions
=
new
Assertions
();
this
.
request
.
hashTree
.
push
(
assertions
);
this
.
reload
();
},
addExtract
()
{
let
jsonPostProcessor
=
new
Extract
();
this
.
request
.
hashTree
.
push
(
jsonPostProcessor
);
this
.
reload
();
},
remove
(
row
)
{
let
index
=
this
.
request
.
hashTree
.
indexOf
(
row
);
this
.
request
.
hashTree
.
splice
(
index
,
1
);
this
.
reload
();
},
reload
()
{
this
.
isReloadData
=
true
this
.
$nextTick
(()
=>
{
this
.
isReloadData
=
false
})
},
setParameter
()
{
this
.
request
.
modulePath
=
this
.
getPath
(
this
.
basisData
.
moduleId
);
this
.
request
.
useEnvironment
=
undefined
;
},
getPath
(
id
)
{
if
(
id
===
null
)
{
return
null
;
}
let
path
=
this
.
moduleOptions
.
filter
(
function
(
item
)
{
return
item
.
id
===
id
?
item
.
path
:
""
;
});
return
path
[
0
].
path
;
},
validateApi
()
{
this
.
basisData
.
method
=
"
TCP
"
;
if
(
this
.
currentProject
===
null
)
{
this
.
$error
(
this
.
$t
(
'
api_test.select_project
'
),
2000
);
return
;
}
this
.
$refs
[
'
basicForm
'
].
validate
();
},
saveApi
()
{
this
.
$emit
(
'
saveApi
'
,
this
.
request
);
},
runTest
()
{
alert
(
444
);
}
},
}
</
script
>
<
style
scoped
>
.tcp
>>>
.el-input-number
{
width
:
100%
;
}
.send-request
{
padding
:
0px
0
;
height
:
300px
;
border
:
1px
#DCDFE6
solid
;
border-radius
:
4px
;
width
:
100%
;
}
.ms-left-cell
{
margin-top
:
40px
;
}
.ms-left-buttion
{
margin
:
6px
0px
8px
30px
;
}
.ms-query
{
background
:
#7F7F7F
;
color
:
white
;
height
:
18px
;
border-radius
:
42%
;
}
.ms-header
{
background
:
#783887
;
color
:
white
;
height
:
18px
;
border-radius
:
42%
;
}
/
deep
/
.el-form-item
{
margin-bottom
:
15px
;
}
.tip
{
padding
:
3px
5px
;
font-size
:
16px
;
border-radius
:
4px
;
border-left
:
4px
solid
#783887
;
margin
:
0px
20px
0px
;
}
</
style
>
frontend/src/business/components/api/definition/components/complete/BasisApi.vue
0 → 100644
浏览文件 @
cbc9c421
<
template
>
<el-form
:model=
"basicForm"
label-position=
"right"
label-width=
"80px"
size=
"small"
:rules=
"rule"
ref=
"basicForm"
style=
"margin-right: 20px"
>
<!-- 基础信息 -->
<el-row>
<el-col
:span=
"12"
>
<el-form-item
:label=
"$t('commons.name')"
prop=
"name"
>
<el-input
class=
"ms-http-input"
size=
"small"
v-model=
"basicForm.name"
/>
</el-form-item>
</el-col>
<el-col
:span=
"12"
>
<el-form-item
:label=
"$t('test_track.module.module')"
prop=
"moduleId"
>
<el-select
class=
"ms-http-input"
size=
"small"
v-model=
"basicForm.moduleId"
style=
"width: 100%"
>
<el-option
v-for=
"item in moduleOptions"
:key=
"item.id"
:label=
"item.path"
:value=
"item.id"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col
:span=
"12"
>
<el-form-item
:label=
"$t('commons.status')"
prop=
"status"
>
<el-select
class=
"ms-http-input"
size=
"small"
v-model=
"basicForm.status"
style=
"width: 100%"
>
<el-option
v-for=
"item in options"
:key=
"item.id"
:label=
"item.label"
:value=
"item.id"
/>
</el-select>
</el-form-item>
</el-col>
<el-col
:span=
"12"
>
<el-form-item
:label=
"$t('api_test.definition.request.responsible')"
prop=
"userId"
>
<el-select
v-model=
"basicForm.userId"
:placeholder=
"$t('api_test.definition.request.responsible')"
filterable
size=
"small"
class=
"ms-http-input"
style=
"width: 100%"
>
<el-option
v-for=
"item in maintainerOptions"
:key=
"item.id"
:label=
"item.id + ' (' + item.name + ')'"
:value=
"item.id"
>
</el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col>
<el-form-item
:label=
"$t('commons.description')"
prop=
"description"
>
<el-input
class=
"ms-http-textarea"
v-model=
"basicForm.description"
type=
"textarea"
:autosize=
"
{ minRows: 2, maxRows: 10}"
:rows="2" size="small"/>
</el-form-item>
</el-col>
</el-row>
</el-form>
</
template
>
<
script
>
import
{
API_STATUS
}
from
"
../../model/JsonData
"
;
import
{
WORKSPACE_ID
}
from
'
../../../../../../common/js/constants
'
;
export
default
{
name
:
"
MsBasisApi
"
,
components
:
{},
props
:
{
currentProtocol
:
{
type
:
String
,
default
:
"
HTTP
"
},
moduleOptions
:
Array
,
basisData
:
{},
},
created
()
{
this
.
getMaintainerOptions
();
this
.
basicForm
=
this
.
basisData
;
},
data
()
{
return
{
basicForm
:
{},
httpVisible
:
false
,
currentModule
:
{},
projectId
:
""
,
maintainerOptions
:
[],
rule
:
{
name
:
[
{
required
:
true
,
message
:
this
.
$t
(
'
test_track.case.input_name
'
),
trigger
:
'
blur
'
},
{
max
:
50
,
message
:
this
.
$t
(
'
test_track.length_less_than
'
)
+
'
50
'
,
trigger
:
'
blur
'
}
],
userId
:
[{
required
:
true
,
message
:
this
.
$t
(
'
test_track.case.input_maintainer
'
),
trigger
:
'
change
'
}],
moduleId
:
[{
required
:
true
,
message
:
this
.
$t
(
'
test_track.case.input_module
'
),
trigger
:
'
change
'
}],
status
:
[{
required
:
true
,
message
:
this
.
$t
(
'
commons.please_select
'
),
trigger
:
'
change
'
}],
},
value
:
API_STATUS
[
0
].
id
,
options
:
API_STATUS
,
}
},
methods
:
{
getMaintainerOptions
()
{
let
workspaceId
=
localStorage
.
getItem
(
WORKSPACE_ID
);
this
.
$post
(
'
/user/ws/member/tester/list
'
,
{
workspaceId
:
workspaceId
},
response
=>
{
this
.
maintainerOptions
=
response
.
data
;
});
},
validate
()
{
this
.
$refs
[
'
basicForm
'
].
validate
((
valid
)
=>
{
if
(
valid
)
{
this
.
$emit
(
'
callback
'
);
}
})
}
}
}
</
script
>
<
style
scoped
>
</
style
>
frontend/src/business/components/api/definition/components/debug/DebugHttpPage.vue
浏览文件 @
cbc9c421
...
...
@@ -40,7 +40,7 @@
</
template
>
<
script
>
import
MsApiRequestForm
from
"
../request/ApiRequestForm
"
;
import
MsApiRequestForm
from
"
../request/
http/
ApiRequestForm
"
;
import
MsResponseResult
from
"
../response/ResponseResult
"
;
import
MsRequestMetric
from
"
../response/RequestMetric
"
;
import
{
getUUID
,
getCurrentUser
}
from
"
@/common/js/utils
"
;
...
...
frontend/src/business/components/api/definition/components/environment/ApiEnvironmentConfig.vue
0 → 100644
浏览文件 @
cbc9c421
<
template
>
<el-dialog
:close-on-click-modal=
"false"
:title=
"$t('api_test.environment.environment_config')"
:visible.sync=
"visible"
class=
"environment-dialog"
width=
"60%"
@
close=
"close"
append-to-body
ref=
"environmentConfig"
>
<el-container
v-loading=
"result.loading"
>
<ms-aside-item
:enable-aside-hidden=
"false"
:title=
"$t('api_test.environment.environment_list')"
:data=
"environments"
:item-operators=
"environmentOperators"
:add-fuc=
"addEnvironment"
:delete-fuc=
"deleteEnvironment"
@
itemSelected=
"environmentSelected"
ref=
"environmentItems"
/>
<environment-edit
:environment=
"currentEnvironment"
ref=
"environmentEdit"
@
close=
"close"
/>
</el-container>
</el-dialog>
</
template
>
<
script
>
import
MsApiCollapse
from
"
../collapse/ApiCollapse
"
;
import
MsApiCollapseItem
from
"
../collapse/ApiCollapseItem
"
;
import
draggable
from
'
vuedraggable
'
;
import
MsContainer
from
"
../../../../common/components/MsContainer
"
;
import
MsAsideContainer
from
"
../../../../common/components/MsAsideContainer
"
;
import
MsMainContainer
from
"
../../../../common/components/MsMainContainer
"
;
import
MsAsideItem
from
"
../../../../common/components/MsAsideItem
"
;
import
EnvironmentEdit
from
"
./EnvironmentEdit
"
;
import
{
deepClone
,
listenGoBack
,
removeGoBackListener
}
from
"
@/common/js/utils
"
;
import
{
Environment
,
parseEnvironment
}
from
"
../../model/EnvironmentModel
"
;
export
default
{
name
:
"
ApiEnvironmentConfig
"
,
components
:
{
EnvironmentEdit
,
MsAsideItem
,
MsMainContainer
,
MsAsideContainer
,
MsContainer
,
MsApiCollapseItem
,
MsApiCollapse
,
draggable
},
data
()
{
return
{
result
:
{},
visible
:
false
,
projectId
:
''
,
environments
:
[],
currentEnvironment
:
new
Environment
(),
environmentOperators
:
[
{
icon
:
'
el-icon-document-copy
'
,
func
:
this
.
copyEnvironment
},
{
icon
:
'
el-icon-delete
'
,
func
:
this
.
deleteEnvironment
}
]
}
},
methods
:
{
open
:
function
(
projectId
)
{
this
.
visible
=
true
;
this
.
projectId
=
projectId
;
this
.
getEnvironments
();
listenGoBack
(
this
.
close
);
},
deleteEnvironment
(
environment
,
index
)
{
if
(
environment
.
id
)
{
this
.
result
=
this
.
$get
(
'
/api/environment/delete/
'
+
environment
.
id
,
()
=>
{
this
.
$success
(
this
.
$t
(
'
commons.delete_success
'
));
this
.
getEnvironments
();
});
}
else
{
this
.
environments
.
splice
(
index
,
1
);
}
},
copyEnvironment
(
environment
)
{
this
.
currentEnvironment
=
environment
;
if
(
!
environment
.
id
)
{
this
.
$warning
(
this
.
$t
(
'
commons.please_save
'
));
return
;
}
let
newEnvironment
=
{};
newEnvironment
=
new
Environment
(
environment
);
newEnvironment
.
id
=
null
;
newEnvironment
.
name
=
this
.
getNoRepeatName
(
newEnvironment
.
name
);
if
(
!
this
.
validateEnvironment
(
newEnvironment
))
{
return
;
}
this
.
$refs
.
environmentEdit
.
_save
(
newEnvironment
);
this
.
environments
.
push
(
newEnvironment
);
this
.
$refs
.
environmentItems
.
itemSelected
(
this
.
environments
.
length
-
1
,
newEnvironment
);
},
validateEnvironment
(
environment
)
{
if
(
!
this
.
$refs
.
environmentEdit
.
validate
())
{
this
.
$error
(
this
.
$t
(
'
commons.formatErr
'
));
return
false
;
}
return
true
;
},
getNoRepeatName
(
name
)
{
for
(
let
i
in
this
.
environments
)
{
if
(
this
.
environments
[
i
].
name
===
name
)
{
return
this
.
getNoRepeatName
(
name
+
'
copy
'
);
}
}
return
name
;
},
addEnvironment
()
{
let
newEnvironment
=
new
Environment
({
projectId
:
this
.
projectId
});
this
.
environments
.
push
(
newEnvironment
);
this
.
$refs
.
environmentItems
.
itemSelected
(
this
.
environments
.
length
-
1
,
newEnvironment
);
},
environmentSelected
(
environment
)
{
this
.
getEnvironment
(
environment
);
},
getEnvironments
()
{
if
(
this
.
projectId
)
{
this
.
result
=
this
.
$get
(
'
/api/environment/list/
'
+
this
.
projectId
,
response
=>
{
this
.
environments
=
response
.
data
;
if
(
this
.
environments
.
length
>
0
)
{
this
.
$refs
.
environmentItems
.
itemSelected
(
0
,
this
.
environments
[
0
]);
}
else
{
let
item
=
new
Environment
({
projectId
:
this
.
projectId
});
this
.
environments
.
push
(
item
);
this
.
$refs
.
environmentItems
.
itemSelected
(
0
,
item
);
}
});
}
},
getEnvironment
(
environment
)
{
parseEnvironment
(
environment
);
this
.
currentEnvironment
=
environment
;
},
close
()
{
this
.
$emit
(
'
close
'
);
this
.
visible
=
false
;
this
.
$refs
.
environmentEdit
.
clearValidate
();
removeGoBackListener
(
this
.
close
);
}
}
}
</
script
>
<
style
scoped
>
.environment-dialog
>>>
.el-dialog__body
{
padding-top
:
20px
;
}
.el-container
{
position
:
relative
;
}
.ms-aside-container
{
height
:
100%
;
position
:
absolute
;
}
</
style
>
frontend/src/business/components/api/definition/components/environment/ApiHostTable.vue
0 → 100644
浏览文件 @
cbc9c421
<
template
>
<div
class=
"ms-border"
>
<el-table
:data=
"hostTable"
style=
"width: 100%"
@
cell-dblclick=
"dblHostTable"
class=
"ht-tb"
>
<el-table-column
prop=
"ip"
label=
"IP"
>
<template
slot-scope=
"scope"
>
<el-input
v-if=
"scope.row.status"
v-model=
"scope.row.ip"
></el-input>
<span
v-else
>
{{
scope
.
row
.
ip
}}
</span>
</
template
>
</el-table-column>
<el-table-column
prop=
"domain"
:label=
"$t('load_test.domain')"
>
<
template
slot-scope=
"scope"
>
<el-input
v-if=
"scope.row.status"
v-model=
"scope.row.domain"
></el-input>
<span
v-else
>
{{
scope
.
row
.
domain
}}
</span>
</
template
>
</el-table-column>
<el-table-column
prop=
"annotation"
:label=
"$t('commons.annotation')"
>
<
template
slot-scope=
"scope"
>
<el-input
v-if=
"scope.row.status"
v-model=
"scope.row.annotation"
></el-input>
<span
v-else
>
{{
scope
.
row
.
annotation
}}
</span>
</
template
>
</el-table-column>
<el-table-column
:label=
"$t('commons.operating')"
width=
"100"
>
<
template
v-slot:default=
"scope"
>
<span>
<el-button
size=
"mini"
p=
"$t('commons.remove')"
icon=
"el-icon-close"
circle
@
click=
"remove(scope.row)"
class=
"ht-btn-remove"
/>
<el-button
size=
"mini"
p=
"$t('commons.save')"
icon=
"el-icon-check"
circle
@
click=
"confirm(scope.row)"
class=
"ht-btn-confirm"
/>
</span>
</
template
>
</el-table-column>
</el-table>
<el-button
class=
"ht-btn-add"
size=
"mini"
p=
"$t('commons.add')"
icon=
"el-icon-circle-plus-outline"
@
click=
"add"
>
添加
</el-button>
</div>
</template>
<
script
>
import
MsApiVariableInput
from
"
../ApiVariableInput
"
;
import
MsTableOperatorButton
from
"
../../../../common/components/MsTableOperatorButton
"
;
export
default
{
name
:
"
MsApiHostTable
"
,
components
:
{
MsApiVariableInput
,
MsTableOperatorButton
},
props
:
{
hostTable
:
Array
,
},
data
()
{
return
{
currentPage
:
1
,
pageSize
:
5
,
total
:
0
,
}
},
created
()
{
this
.
init
();
},
methods
:
{
remove
:
function
(
row
)
{
this
.
hostTable
.
splice
(
this
.
hostTable
.
indexOf
(
row
),
1
);
},
change
:
function
()
{
this
.
$emit
(
'
change
'
,
this
.
hostTable
);
},
add
:
function
(
r
)
{
let
row
=
{
ip
:
''
,
domain
:
''
,
status
:
'
edit
'
,
annotation
:
''
,
uuid
:
this
.
uuid
(),
}
// 获取上一行的数据
for
(
let
i
=
this
.
hostTable
.
length
-
1
;
i
>=
0
;
i
--
)
{
if
(
this
.
hostTable
[
i
].
status
===
''
)
{
row
.
ip
=
this
.
hostTable
[
i
].
ip
;
row
.
domain
=
this
.
hostTable
[
i
].
domain
;
row
.
annotation
=
this
.
hostTable
[
i
].
annotation
;
break
;
}
}
this
.
hostTable
.
push
(
row
);
},
confirm
:
function
(
row
)
{
this
.
validateIp
(
row
.
ip
)
&&
this
.
validateDomain
(
row
.
domain
)
?
row
.
status
=
''
:
row
.
status
;
this
.
$emit
(
'
change
'
,
this
.
hostTable
);
if
(
row
.
status
===
""
)
{
return
true
;
}
return
false
;
},
init
:
function
()
{
if
(
this
.
hostTable
===
undefined
||
this
.
hostTable
.
length
===
0
)
{
let
row
=
{
ip
:
''
,
domain
:
''
,
status
:
'
edit
'
,
annotation
:
''
,
uuid
:
this
.
uuid
()
}
this
.
hostTable
.
push
(
row
);
}
},
validateIp
(
ip
)
{
let
regexp
=
/^
((
2
(
5
[
0-5
]
|
[
0-4
]\d))
|
[
0-1
]?\d{1,2})(\.((
2
(
5
[
0-5
]
|
[
0-4
]\d))
|
[
0-1
]?\d{1,2})){3}
$/
;
if
(
regexp
.
test
(
ip
)
==
false
)
{
this
.
$warning
(
this
.
$t
(
'
load_test.input_ip
'
));
return
false
;
}
return
true
;
},
validateDomain
(
domain
)
{
let
strRegex
=
"
^(?=^.{3,255}$)(http(s)?:
\\
/
\\
/)?(www
\\
.)?[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(
\\
.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+(:
\\
d+)*(
\\
/
\\
w+
\\
.
\\
w+)*$
"
;
const
re
=
new
RegExp
(
strRegex
);
if
(
re
.
test
(
domain
)
&&
domain
.
length
<
67
)
{
return
true
;
}
this
.
$warning
(
this
.
$t
(
'
load_test.input_domain
'
));
return
false
;
},
dblHostTable
:
function
(
row
)
{
row
.
status
=
'
edit
'
;
},
uuid
:
function
()
{
return
(((
1
+
Math
.
random
())
*
0x100000
)
|
0
).
toString
(
16
).
substring
(
1
);
},
}
}
</
script
>
<
style
scoped
>
.ht-btn-remove
{
color
:
white
;
background-color
:
#DCDFE6
;
}
.ht-btn-confirm
{
color
:
white
;
background-color
:
#1483F6
;
}
.ht-btn-add
{
border
:
0px
;
margin-top
:
10px
;
color
:
#1483F6
;
background-color
:
white
;
}
.ht-tb
{
background-color
:
white
;
border
:
0px
;
}
</
style
>
frontend/src/business/components/api/definition/components/environment/ApiScenarioVariables.vue
0 → 100644
浏览文件 @
cbc9c421
<
template
>
<div>
<span
class=
"kv-description"
v-if=
"description"
>
{{
description
}}
</span>
<div
class=
"kv-row"
v-for=
"(item, index) in items"
:key=
"index"
>
<el-row
type=
"flex"
:gutter=
"20"
justify=
"space-between"
align=
"middle"
>
<el-col
class=
"kv-checkbox"
>
<input
type=
"checkbox"
v-if=
"!isDisable(index)"
@
change=
"change"
:value=
"item.uuid"
v-model=
"item.enable"
:disabled=
"isDisable(index) || isReadOnly"
/>
</el-col>
<el-col>
<ms-api-variable-input
:show-copy=
"showCopy"
:show-variable=
"showVariable"
:is-read-only=
"isReadOnly"
v-model=
"item.name"
size=
"small"
maxlength=
"200"
@
change=
"change"
:placeholder=
"$t('api_test.variable_name')"
show-word-limit
/>
</el-col>
<el-col>
<el-input
:disabled=
"isReadOnly"
v-model=
"item.value"
size=
"small"
@
change=
"change"
:placeholder=
"$t('api_test.value')"
show-word-limit
/>
</el-col>
<el-col
class=
"kv-delete"
>
<el-button
size=
"mini"
class=
"el-icon-delete-solid"
circle
@
click=
"remove(index)"
:disabled=
"isDisable(index) || isReadOnly"
/>
</el-col>
</el-row>
</div>
</div>
</
template
>
<
script
>
import
{
KeyValue
}
from
"
../../model/ApiTestModel
"
;
import
MsApiVariableInput
from
"
../ApiVariableInput
"
;
export
default
{
name
:
"
MsApiScenarioVariables
"
,
components
:
{
MsApiVariableInput
},
props
:
{
description
:
String
,
items
:
Array
,
isReadOnly
:
{
type
:
Boolean
,
default
:
false
},
showVariable
:
{
type
:
Boolean
,
default
:
true
},
showCopy
:
{
type
:
Boolean
,
default
:
true
},
},
data
()
{
return
{
}
},
methods
:
{
remove
:
function
(
index
)
{
this
.
items
.
splice
(
index
,
1
);
this
.
$emit
(
'
change
'
,
this
.
items
);
},
change
:
function
()
{
let
isNeedCreate
=
true
;
let
removeIndex
=
-
1
;
this
.
items
.
forEach
((
item
,
index
)
=>
{
if
(
!
item
.
name
&&
!
item
.
value
)
{
// 多余的空行
if
(
index
!==
this
.
items
.
length
-
1
)
{
removeIndex
=
index
;
}
// 没有空行,需要创建空行
isNeedCreate
=
false
;
}
});
if
(
isNeedCreate
)
{
this
.
items
.
push
(
new
KeyValue
({
enable
:
true
}));
}
this
.
$emit
(
'
change
'
,
this
.
items
);
// TODO 检查key重复
},
isDisable
:
function
(
index
)
{
return
this
.
items
.
length
-
1
===
index
;
}
},
created
()
{
if
(
this
.
items
.
length
===
0
)
{
this
.
items
.
push
(
new
KeyValue
({
enable
:
true
}));
}
}
}
</
script
>
<
style
scoped
>
.kv-description
{
font-size
:
13px
;
}
.kv-checkbox
{
width
:
20px
;
margin-right
:
10px
;
}
.kv-row
{
margin-top
:
10px
;
}
.kv-delete
{
width
:
60px
;
}
</
style
>
frontend/src/business/components/api/definition/components/environment/EnvironmentCommonConfig.vue
0 → 100644
浏览文件 @
cbc9c421
<
template
>
<div>
<el-form
:model=
"commonConfig"
:rules=
"rules"
ref=
"commonConfig"
>
<span>
{{
$t
(
'
api_test.environment.globalVariable
'
)
}}
</span>
<ms-api-scenario-variables
:show-copy=
"false"
:items=
"commonConfig.variables"
/>
<el-form-item>
<el-switch
v-model=
"commonConfig.enableHost"
active-text=
"Hosts"
/>
</el-form-item>
<ms-api-host-table
v-if=
"commonConfig.enableHost"
:hostTable=
"commonConfig.hosts"
ref=
"refHostTable"
/>
</el-form>
</div>
</
template
>
<
script
>
import
{
CommonConfig
,
Environment
}
from
"
../../model/EnvironmentModel
"
;
import
MsApiScenarioVariables
from
"
./ApiScenarioVariables
"
;
import
MsApiHostTable
from
"
./ApiHostTable
"
;
export
default
{
name
:
"
MsEnvironmentCommonConfig
"
,
components
:
{
MsApiHostTable
,
MsApiScenarioVariables
},
props
:
{
commonConfig
:
new
CommonConfig
(),
},
data
()
{
return
{
rules
:
{
},
}
},
methods
:
{
validate
()
{
let
isValidate
=
false
;
this
.
$refs
[
'
commonConfig
'
].
validate
((
valid
)
=>
{
if
(
valid
)
{
// 校验host列表
let
valHost
=
true
;
if
(
this
.
commonConfig
.
enableHost
)
{
for
(
let
i
=
0
;
i
<
this
.
commonConfig
.
hosts
.
length
;
i
++
)
{
valHost
=
this
.
$refs
[
'
refHostTable
'
].
confirm
(
this
.
commonConfig
.
hosts
[
i
]);
}
}
if
(
valHost
)
{
isValidate
=
true
;
}
else
{
isValidate
=
false
;
}
}
else
{
isValidate
=
false
;
}
});
return
isValidate
;
}
}
}
</
script
>
<
style
scoped
>
</
style
>
frontend/src/business/components/api/definition/components/environment/EnvironmentEdit.vue
0 → 100644
浏览文件 @
cbc9c421
<
template
>
<el-main
v-loading=
"result.loading"
>
<el-form
:model=
"environment"
:rules=
"rules"
ref=
"environment"
>
<span>
{{
$t
(
'
api_test.environment.name
'
)
}}
</span>
<el-form-item
prop=
"name"
>
<el-input
v-model=
"environment.name"
:placeholder=
"this.$t('commons.input_name')"
clearable
/>
</el-form-item>
<el-tabs
v-model=
"activeName"
>
<el-tab-pane
:label=
"$t('api_test.environment.common_config')"
name=
"common"
>
<ms-environment-common-config
:common-config=
"environment.config.commonConfig"
ref=
"commonConfig"
/>
</el-tab-pane>
<el-tab-pane
:label=
"$t('api_test.environment.http_config')"
name=
"http"
>
<ms-environment-http-config
:http-config=
"environment.config.httpConfig"
ref=
"httpConfig"
/>
</el-tab-pane>
<el-tab-pane
:label=
"$t('api_test.environment.database_config')"
name=
"sql"
>
<ms-database-config
:configs=
"environment.config.databaseConfigs"
/>
</el-tab-pane>
<el-tab-pane
:label=
"$t('api_test.environment.tcp_config')"
name=
"tcp"
>
<ms-tcp-config
:config=
"environment.config.tcpConfig"
/>
</el-tab-pane>
</el-tabs>
<div
class=
"environment-footer"
>
<ms-dialog-footer
@
cancel=
"cancel"
@
confirm=
"save()"
/>
</div>
</el-form>
</el-main>
</
template
>
<
script
>
import
MsApiScenarioVariables
from
"
./ApiScenarioVariables
"
;
import
MsApiKeyValue
from
"
../ApiKeyValue
"
;
import
MsDialogFooter
from
"
../../../../common/components/MsDialogFooter
"
;
import
{
REQUEST_HEADERS
}
from
"
@/common/js/constants
"
;
import
{
Environment
}
from
"
../../model/EnvironmentModel
"
;
import
MsApiHostTable
from
"
./ApiHostTable
"
;
import
MsDatabaseConfig
from
"
../request/database/DatabaseConfig
"
;
import
MsEnvironmentHttpConfig
from
"
./EnvironmentHttpConfig
"
;
import
MsEnvironmentCommonConfig
from
"
./EnvironmentCommonConfig
"
;
import
MsTcpConfig
from
"
../request/tcp/TcpConfig
"
;
export
default
{
name
:
"
EnvironmentEdit
"
,
components
:
{
MsTcpConfig
,
MsEnvironmentCommonConfig
,
MsEnvironmentHttpConfig
,
MsDatabaseConfig
,
MsApiHostTable
,
MsDialogFooter
,
MsApiKeyValue
,
MsApiScenarioVariables
},
props
:
{
environment
:
new
Environment
(),
},
data
()
{
return
{
result
:
{},
envEnable
:
false
,
rules
:
{
name
:
[
{
required
:
true
,
message
:
this
.
$t
(
'
commons.input_name
'
),
trigger
:
'
blur
'
},
{
max
:
64
,
message
:
this
.
$t
(
'
commons.input_limit
'
,
[
1
,
64
]),
trigger
:
'
blur
'
}
],
},
headerSuggestions
:
REQUEST_HEADERS
,
activeName
:
'
common
'
}
},
watch
:
{
environment
:
function
(
o
)
{
this
.
envEnable
=
o
.
enable
;
}
},
methods
:
{
save
()
{
this
.
$refs
[
'
environment
'
].
validate
((
valid
)
=>
{
if
(
valid
&&
this
.
$refs
.
commonConfig
.
validate
()
&&
this
.
$refs
.
httpConfig
.
validate
())
{
this
.
_save
(
this
.
environment
);
}
});
},
validate
()
{
let
isValidate
=
false
;
this
.
$refs
[
'
environment
'
].
validate
((
valid
)
=>
{
if
(
valid
&&
this
.
$refs
.
commonConfig
.
validate
()
&&
this
.
$refs
.
httpConfig
.
validate
())
{
isValidate
=
true
;
}
else
{
isValidate
=
false
;
}
});
return
isValidate
;
},
_save
(
environment
)
{
let
param
=
this
.
buildParam
(
environment
);
let
url
=
'
/api/environment/add
'
;
if
(
param
.
id
)
{
url
=
'
/api/environment/update
'
;
}
this
.
result
=
this
.
$post
(
url
,
param
,
response
=>
{
if
(
!
param
.
id
)
{
environment
.
id
=
response
.
data
;
}
this
.
$success
(
this
.
$t
(
'
commons.save_success
'
));
});
},
buildParam
:
function
(
environment
)
{
let
param
=
{};
Object
.
assign
(
param
,
environment
);
let
hosts
=
param
.
config
.
commonConfig
.
hosts
;
if
(
hosts
!=
undefined
)
{
let
validHosts
=
[];
// 去除掉未确认的host
hosts
.
forEach
(
host
=>
{
if
(
host
.
status
===
''
)
{
validHosts
.
push
(
host
);
}
});
param
.
config
.
commonConfig
.
hosts
=
validHosts
;
}
param
.
config
=
JSON
.
stringify
(
param
.
config
);
return
param
;
},
cancel
()
{
this
.
$emit
(
'
close
'
);
},
clearValidate
()
{
this
.
$refs
[
"
environment
"
].
clearValidate
();
},
},
}
</
script
>
<
style
scoped
>
.el-main
{
border
:
solid
1px
#EBEEF5
;
margin-left
:
200px
;
min-height
:
400px
;
max-height
:
700px
;
}
.el-row
{
margin-bottom
:
15px
;
}
.environment-footer
{
margin-top
:
15px
;
float
:
right
;
}
span
{
display
:
block
;
margin-bottom
:
15px
;
}
span
:not
(
:first-child
)
{
margin-top
:
15px
;
}
</
style
>
frontend/src/business/components/api/definition/components/environment/EnvironmentHttpConfig.vue
0 → 100644
浏览文件 @
cbc9c421
<
template
>
<el-form
:model=
"httpConfig"
:rules=
"rules"
ref=
"httpConfig"
>
<span>
{{
$t
(
'
api_test.environment.socket
'
)
}}
</span>
<el-form-item
prop=
"socket"
>
<el-input
v-model=
"httpConfig.socket"
:placeholder=
"$t('api_test.request.url_description')"
clearable
>
<template
v-slot:prepend
>
<el-select
v-model=
"httpConfig.protocol"
class=
"request-protocol-select"
>
<el-option
label=
"http://"
value=
"http"
/>
<el-option
label=
"https://"
value=
"https"
/>
</el-select>
</
template
>
</el-input>
</el-form-item>
<span>
{{$t('api_test.request.headers')}}
</span>
<ms-api-key-value
:items=
"httpConfig.headers"
:isShowEnable=
"true"
:suggestions=
"headerSuggestions"
/>
</el-form>
</template>
<
script
>
import
{
HttpConfig
}
from
"
../../model/EnvironmentModel
"
;
import
MsApiKeyValue
from
"
../ApiKeyValue
"
;
import
{
REQUEST_HEADERS
}
from
"
../../../../../../common/js/constants
"
;
export
default
{
name
:
"
MsEnvironmentHttpConfig
"
,
components
:
{
MsApiKeyValue
},
props
:
{
httpConfig
:
new
HttpConfig
(),
},
data
()
{
let
socketValidator
=
(
rule
,
value
,
callback
)
=>
{
if
(
!
this
.
validateSocket
(
value
))
{
callback
(
new
Error
(
this
.
$t
(
'
commons.formatErr
'
)));
return
false
;
}
else
{
callback
();
return
true
;
}
}
return
{
headerSuggestions
:
REQUEST_HEADERS
,
rules
:
{
socket
:
[{
required
:
false
,
validator
:
socketValidator
,
trigger
:
'
blur
'
}],
},
}
},
methods
:
{
validateSocket
(
socket
)
{
if
(
!
socket
)
return
true
;
let
urlStr
=
this
.
httpConfig
.
protocol
+
'
://
'
+
socket
;
let
url
=
{};
try
{
url
=
new
URL
(
urlStr
);
}
catch
(
e
)
{
return
false
;
}
this
.
httpConfig
.
domain
=
decodeURIComponent
(
url
.
hostname
);
this
.
httpConfig
.
port
=
url
.
port
;
let
path
=
url
.
pathname
===
'
/
'
?
''
:
url
.
pathname
;
if
(
url
.
port
)
{
this
.
httpConfig
.
socket
=
this
.
httpConfig
.
domain
+
'
:
'
+
url
.
port
+
path
;
}
else
{
this
.
httpConfig
.
socket
=
this
.
httpConfig
.
domain
+
path
;
}
return
true
;
},
validate
()
{
let
isValidate
=
false
;
this
.
$refs
[
'
httpConfig
'
].
validate
((
valid
)
=>
{
isValidate
=
valid
;
});
return
isValidate
;
}
}
}
</
script
>
<
style
scoped
>
.request-protocol-select
{
width
:
90px
;
}
</
style
>
frontend/src/business/components/api/definition/components/import/ApiImport.vue
0 → 100644
浏览文件 @
cbc9c421
<
template
>
<el-dialog
:close-on-click-modal=
"false"
:title=
"$t('api_test.api_import.title')"
:visible.sync=
"visible"
class=
"api-import"
v-loading=
"result.loading"
@
close=
"close"
>
<div
class=
"header-bar"
>
<div>
{{
$t
(
'
api_test.api_import.data_format
'
)
}}
</div>
<el-radio-group
v-model=
"selectedPlatformValue"
>
<el-radio
v-for=
"(item, index) in platforms"
:key=
"index"
:label=
"item.value"
>
{{
item
.
name
}}
</el-radio>
</el-radio-group>
<div
class=
"operate-button"
>
<el-button
class=
"save-button"
type=
"primary"
plain
@
click=
"save"
>
{{
$t
(
'
commons.save
'
)
}}
</el-button>
<el-button
class=
"cancel-button"
type=
"warning"
plain
@
click=
"visible = false"
>
{{
$t
(
'
commons.cancel
'
)
}}
</el-button>
</div>
</div>
<el-form
:model=
"formData"
:rules=
"rules"
label-width=
"100px"
v-loading=
"result.loading"
ref=
"form"
>
<el-row>
<el-col
:span=
"11"
>
<el-form-item
:label=
"$t('commons.name')"
prop=
"name"
>
<el-input
size=
"small"
class=
"name-input"
v-model=
"formData.name"
clearable
show-word-limit
/>
</el-form-item>
<el-form-item
:label=
"$t('commons.project')"
prop=
"projectId"
>
<el-select
size=
"small"
v-model=
"formData.projectId"
class=
"project-select"
clearable
>
<el-option
v-for=
"(project, index) in projects"
:key=
"index"
:label=
"project.name"
:value=
"project.id"
/>
</el-select>
</el-form-item>
<el-form-item
v-if=
"useEnvironment || selectedPlatformValue == 'Swagger2'"
:label=
"$t('api_test.environment.environment_config')"
prop=
"environmentId"
>
<el-select
v-if=
"showEnvironmentSelect"
size=
"small"
v-model=
"formData.environmentId"
class=
"environment-select"
clearable
>
<el-option
v-for=
"(environment, index) in environments"
:key=
"index"
:label=
"environment.name"
:value=
"environment.id"
/>
<el-button
class=
"environment-button"
size=
"mini"
type=
"primary"
@
click=
"openEnvironmentConfig"
>
{{
$t
(
'
api_test.environment.environment_config
'
)
}}
</el-button>
<template
v-slot:empty
>
<div
class=
"empty-environment"
>
<el-button
:disabled=
"formData.projectId == ''"
class=
"environment-button"
size=
"mini"
type=
"primary"
@
click=
"openEnvironmentConfig"
>
{{
$t
(
'
api_test.environment.environment_config
'
)
}}
</el-button>
</div>
</
template
>
</el-select>
</el-form-item>
<el-form-item
v-if=
"selectedPlatformValue != 'Swagger2'"
prop=
"useEnvironment"
>
<el-checkbox
v-model=
"useEnvironment"
>
{{$t('api_test.environment.config_environment')}}
</el-checkbox>
</el-form-item>
<el-form-item
:label=
"'Swagger URL'"
prop=
"wgerUrl"
v-if=
"selectedPlatformValue == 'Swagger2' && swaggerUrlEable"
>
<el-input
size=
"small"
v-model=
"formData.swaggerUrl"
clearable
show-word-limit
/>
</el-form-item>
<el-form-item
v-if=
"selectedPlatformValue == 'Swagger2'"
>
<el-switch
v-model=
"swaggerUrlEable"
:active-text=
"$t('api_test.api_import.swagger_url_import')"
>
</el-switch>
</el-form-item>
</el-col>
<el-col
:span=
"1"
v-if=
"selectedPlatformValue != 'Swagger2' || (selectedPlatformValue == 'Swagger2' && !swaggerUrlEable)"
>
<el-divider
direction=
"vertical"
/>
</el-col>
<el-col
:span=
"12"
v-if=
"selectedPlatformValue != 'Swagger2' || (selectedPlatformValue == 'Swagger2' && !swaggerUrlEable)"
>
<el-upload
class=
"api-upload"
drag
action=
""
:http-request=
"upload"
:limit=
"1"
:beforeUpload=
"uploadValidate"
:on-remove=
"handleRemove"
:file-list=
"fileList"
:on-exceed=
"handleExceed"
multiple
>
<i
class=
"el-icon-upload"
></i>
<div
class=
"el-upload__text"
v-html=
"$t('load_test.upload_tips')"
></div>
<div
class=
"el-upload__tip"
slot=
"tip"
>
{{$t('api_test.api_import.file_size_limit')}}
</div>
</el-upload>
</el-col>
</el-row>
</el-form>
<div
class=
"format-tip"
>
<div>
<span>
{{$t('api_test.api_import.tip')}}:{{selectedPlatform.tip}}
</span>
</div>
<div>
<span>
{{$t('api_test.api_import.export_tip')}}:{{selectedPlatform.exportTip}}
</span>
</div>
</div>
<api-environment-config
ref=
"environmentConfig"
@
close=
"getEnvironments"
/>
</el-dialog>
</template>
<
script
>
import
MsDialogFooter
from
"
../../../../common/components/MsDialogFooter
"
;
import
ApiEnvironmentConfig
from
"
../environment/ApiEnvironmentConfig
"
;
import
{
listenGoBack
,
removeGoBackListener
}
from
"
@/common/js/utils
"
;
export
default
{
name
:
"
ApiImport
"
,
components
:
{
ApiEnvironmentConfig
,
MsDialogFooter
},
data
()
{
return
{
visible
:
false
,
swaggerUrlEable
:
false
,
showEnvironmentSelect
:
true
,
platforms
:
[
{
name
:
'
Metersphere
'
,
value
:
'
Metersphere
'
,
tip
:
this
.
$t
(
'
api_test.api_import.ms_tip
'
),
exportTip
:
this
.
$t
(
'
api_test.api_import.ms_export_tip
'
),
suffixes
:
new
Set
([
'
json
'
])
},
{
name
:
'
Postman
'
,
value
:
'
Postman
'
,
tip
:
this
.
$t
(
'
api_test.api_import.postman_tip
'
),
exportTip
:
this
.
$t
(
'
api_test.api_import.post_export_tip
'
),
suffixes
:
new
Set
([
'
json
'
])
},
{
name
:
'
Swagger
'
,
value
:
'
Swagger2
'
,
tip
:
this
.
$t
(
'
api_test.api_import.swagger_tip
'
),
exportTip
:
this
.
$t
(
'
api_test.api_import.swagger_export_tip
'
),
suffixes
:
new
Set
([
'
json
'
])
}
],
selectedPlatform
:
{},
selectedPlatformValue
:
'
Metersphere
'
,
result
:
{},
projects
:
[],
environments
:
[],
useEnvironment
:
false
,
formData
:
{
name
:
''
,
environmentId
:
''
,
projectId
:
''
,
file
:
undefined
,
swaggerUrl
:
''
},
currentModule
:
{},
rules
:
{
name
:
[
{
required
:
true
,
message
:
this
.
$t
(
'
commons.input_name
'
),
trigger
:
'
blur
'
},
{
max
:
60
,
message
:
this
.
$t
(
'
commons.input_limit
'
,
[
1
,
60
]),
trigger
:
'
blur
'
}
],
environmentId
:
[
{
required
:
true
,
message
:
this
.
$t
(
'
api_test.environment.select_environment
'
),
trigger
:
'
blur
'
},
],
projectId
:
[
{
required
:
true
,
message
:
this
.
$t
(
'
api_test.select_project
'
),
trigger
:
'
blur
'
},
]
},
fileList
:
[]
}
},
activated
()
{
this
.
selectedPlatform
=
this
.
platforms
[
0
];
this
.
getProjects
();
},
watch
:
{
selectedPlatformValue
()
{
for
(
let
i
in
this
.
platforms
)
{
if
(
this
.
platforms
[
i
].
value
===
this
.
selectedPlatformValue
)
{
this
.
selectedPlatform
=
this
.
platforms
[
i
];
break
;
}
}
},
'
formData.projectId
'
()
{
this
.
getEnvironments
();
}
},
methods
:
{
open
(
module
)
{
this
.
currentModule
=
module
;
this
.
visible
=
true
;
listenGoBack
(
this
.
close
);
},
upload
(
file
)
{
this
.
formData
.
file
=
file
.
file
;
},
handleExceed
(
files
,
fileList
)
{
this
.
$warning
(
this
.
$t
(
'
test_track.case.import.upload_limit_count
'
));
},
handleRemove
(
file
,
fileList
)
{
this
.
formData
.
file
=
undefined
;
},
uploadValidate
(
file
,
fileList
)
{
let
suffix
=
file
.
name
.
substring
(
file
.
name
.
lastIndexOf
(
'
.
'
)
+
1
);
if
(
!
this
.
selectedPlatform
.
suffixes
.
has
(
suffix
))
{
this
.
$warning
(
this
.
$t
(
'
api_test.api_import.suffixFormatErr
'
));
return
false
;
}
if
(
file
.
size
/
1024
/
1024
>
20
)
{
this
.
$warning
(
this
.
$t
(
'
test_track.case.import.upload_limit_size
'
));
return
false
;
}
return
true
;
},
getEnvironments
()
{
if
(
this
.
formData
.
projectId
)
{
this
.
$get
(
'
/api/environment/list/
'
+
this
.
formData
.
projectId
,
response
=>
{
this
.
environments
=
response
.
data
;
let
hasEnvironmentId
=
false
;
this
.
environments
.
forEach
(
env
=>
{
if
(
env
.
id
===
this
.
formData
.
environmentId
)
{
hasEnvironmentId
=
true
;
}
});
if
(
!
hasEnvironmentId
)
{
this
.
formData
.
environmentId
=
''
;
}
});
}
else
{
this
.
environments
=
[];
this
.
formData
.
environmentId
=
''
;
}
},
getProjects
()
{
this
.
result
=
this
.
$get
(
"
/project/listAll
"
,
response
=>
{
this
.
projects
=
response
.
data
;
})
},
openEnvironmentConfig
()
{
if
(
!
this
.
formData
.
projectId
)
{
this
.
$error
(
this
.
$t
(
'
api_test.select_project
'
));
return
;
}
this
.
showEnvironmentSelect
=
false
;
this
.
$refs
.
environmentConfig
.
open
(
this
.
formData
.
projectId
);
this
.
showEnvironmentSelect
=
true
;
},
save
()
{
this
.
$refs
.
form
.
validate
(
valid
=>
{
if
(
valid
)
{
let
param
=
{};
Object
.
assign
(
param
,
this
.
formData
);
param
.
platform
=
this
.
selectedPlatformValue
;
param
.
useEnvironment
=
this
.
useEnvironment
;
param
.
moduleId
=
this
.
currentModule
.
id
;
param
.
modulePath
=
this
.
currentModule
.
path
;
if
((
this
.
selectedPlatformValue
!=
'
Swagger2
'
||
(
this
.
selectedPlatformValue
==
'
Swagger2
'
&&
!
this
.
swaggerUrlEable
))
&&
!
this
.
formData
.
file
)
{
this
.
$warning
(
this
.
$t
(
'
commons.please_upload
'
));
return
;
}
if
(
!
this
.
swaggerUrlEable
)
{
param
.
swaggerUrl
=
undefined
;
}
this
.
result
=
this
.
$fileUpload
(
'
/api/definition/import
'
,
param
.
file
,
null
,
param
,
response
=>
{
let
res
=
response
.
data
;
this
.
$success
(
this
.
$t
(
'
test_track.case.import.success
'
));
this
.
visible
=
false
;
this
.
$emit
(
'
refresh
'
);
});
}
else
{
return
false
;
}
});
},
close
()
{
this
.
formData
=
{
name
:
''
,
environmentId
:
''
,
projectId
:
''
,
file
:
undefined
,
swaggerUrl
:
''
};
this
.
fileList
=
[];
removeGoBackListener
(
this
.
close
);
this
.
visible
=
false
;
}
}
}
</
script
>
<
style
scoped
>
.format-tip
{
background
:
#EDEDED
;
}
.api-upload
{
text-align
:
center
;
margin
:
auto
0
;
}
.api-upload
>>>
.el-upload
{
width
:
100%
;
max-width
:
350px
;
}
.api-upload
>>>
.el-upload-dragger
{
width
:
100%
;
}
.el-radio-group
{
margin
:
10px
0
;
}
.header-bar
,
.format-tip
,
.el-form
{
border
:
solid
#E1E1E1
1px
;
margin
:
10px
0
;
padding
:
10px
;
border-radius
:
3px
;
}
.header-bar
{
padding
:
10px
30px
;
}
.api-import
>>>
.el-dialog__body
{
padding
:
15px
25px
;
}
.operate-button
{
float
:
right
;
}
.save-button
{
margin-left
:
10px
;
}
.environment-button
{
margin-left
:
20px
;
padding
:
7px
;
}
.empty-environment
{
padding
:
10px
0px
;
}
.el-form
{
padding
:
30px
10px
;
}
.el-divider
{
height
:
200px
;
}
.name-input
{
max-width
:
195px
;
}
.dialog-footer
{
float
:
right
;
}
</
style
>
frontend/src/business/components/api/definition/components/jmeter/components/sampler/tcp-sampler/index.js
浏览文件 @
cbc9c421
...
...
@@ -12,27 +12,26 @@ const DEFAULT_OPTIONS = {
};
export
default
class
TCPSampler
extends
Sampler
{
static
CLASSES
=
[
"
TCPClientImpl
"
,
"
BinaryTCPClientImpl
"
,
"
LengthPrefixedBinaryTCPClientImpl
"
]
constructor
(
options
=
DEFAULT_OPTIONS
)
{
super
(
options
);
this
.
classname
=
this
.
initStringProp
(
"
TCPSampler.classname
"
,
"
TCPClientImpl
"
)
this
.
server
=
this
.
initStringProp
(
"
TCPSampler.server
"
)
this
.
port
=
this
.
initStringProp
(
"
TCPSampler.port
"
)
this
.
connectTimeout
=
this
.
initStringProp
(
"
TCPSampler.ctimeout
"
)
this
.
responseTimeout
=
this
.
initStringProp
(
"
TCPSampler.timeout
"
)
this
.
reUseConnection
=
this
.
initBoolProp
(
"
TCPSampler.reUseConnection
"
,
true
)
this
.
closeConnection
=
this
.
initBoolProp
(
"
TCPSampler.closeConnection
"
,
false
)
this
.
nodelay
=
this
.
initBoolProp
(
"
TCPSampler.nodelay
"
,
false
)
this
.
soLinger
=
this
.
initStringProp
(
"
TCPSampler.soLinger
"
)
this
.
eolByte
=
this
.
initStringProp
(
"
TCPSampler.EolByte
"
)
this
.
request
=
this
.
initStringProp
(
"
TCPSampler.request
"
)
this
.
username
=
this
.
initStringProp
(
"
ConfigTestElement.username
"
)
this
.
password
=
this
.
initStringProp
(
"
ConfigTestElement.password
"
)
this
.
type
=
"
TCPSampler
"
;
this
.
classname
=
options
.
classname
||
TCPSampler
.
CLASSES
[
0
];
this
.
server
=
options
.
server
;
this
.
port
=
options
.
port
;
this
.
ctimeout
=
options
.
ctimeout
;
// Connect
this
.
timeout
=
options
.
timeout
;
// Response
this
.
reUseConnection
=
options
.
reUseConnection
===
undefined
?
true
:
options
.
reUseConnection
;
this
.
nodelay
=
options
.
nodelay
===
undefined
?
false
:
options
.
nodelay
;
this
.
closeConnection
=
options
.
closeConnection
===
undefined
?
false
:
options
.
closeConnection
;
this
.
soLinger
=
options
.
soLinger
;
this
.
eolByte
=
options
.
eolByte
;
this
.
username
=
options
.
username
;
this
.
password
=
options
.
password
;
this
.
hashTree
=
[];
}
}
...
...
frontend/src/business/components/api/definition/components/request/database/DatabaseConfig.vue
0 → 100644
浏览文件 @
cbc9c421
<
template
>
<div>
<ms-database-from
:config=
"currentConfig"
:callback=
"saveConfig"
ref=
"databaseFrom"
:is-read-only=
"isReadOnly"
/>
<ms-database-config-list
@
rowSelect=
"rowSelect"
v-if=
"configs.length > 0"
:table-data=
"configs"
/>
</div>
</
template
>
<
script
>
import
MsDatabaseConfigList
from
"
./DatabaseConfigList
"
;
import
{
DatabaseConfig
}
from
"
../../../model/ApiTestModel
"
;
import
MsDatabaseFrom
from
"
./DatabaseFrom
"
;
import
{
getUUID
}
from
"
@/common/js/utils
"
;
export
default
{
name
:
"
MsDatabaseConfig
"
,
components
:
{
MsDatabaseFrom
,
MsDatabaseConfigList
},
props
:
{
configs
:
Array
,
isReadOnly
:
{
type
:
Boolean
,
default
:
false
},
},
data
()
{
return
{
drivers
:
DatabaseConfig
.
DRIVER_CLASS
,
currentConfig
:
new
DatabaseConfig
()
}
},
watch
:
{
configs
()
{
this
.
currentConfig
=
new
DatabaseConfig
();
}
},
methods
:
{
saveConfig
(
config
)
{
for
(
let
item
of
this
.
configs
)
{
if
(
item
.
name
===
config
.
name
&&
item
.
id
!==
config
.
id
)
{
this
.
$warning
(
this
.
$t
(
'
commons.already_exists
'
));
return
;
}
}
if
(
config
.
id
)
{
this
.
updateConfig
(
config
);
}
else
{
this
.
addConfig
(
config
);
}
},
addConfig
(
config
)
{
config
.
id
=
getUUID
();
let
item
=
{};
Object
.
assign
(
item
,
config
);
this
.
configs
.
push
(
item
);
this
.
currentConfig
=
new
DatabaseConfig
();
},
updateConfig
(
config
)
{
Object
.
assign
(
this
.
currentConfig
,
config
);
this
.
currentConfig
=
new
DatabaseConfig
();
},
rowSelect
(
config
)
{
this
.
currentConfig
=
config
;
}
}
}
</
script
>
<
style
scoped
>
.addButton
{
float
:
right
;
}
.database-from
{
padding
:
10px
;
border
:
#DCDFE6
solid
1px
;
margin
:
5px
0
;
border-radius
:
5px
;
}
</
style
>
frontend/src/business/components/api/definition/components/request/database/DatabaseConfigList.vue
0 → 100644
浏览文件 @
cbc9c421
<
template
>
<div
class=
"database-config-list"
>
<el-table
border
:data=
"tableData"
class=
"adjust-table table-content"
highlight-current-row
@
row-click=
"handleView"
>
<el-table-column
prop=
"name"
:label=
"$t('api_test.request.sql.dataSource')"
show-overflow-tooltip
/>
<el-table-column
prop=
"driver"
:label=
"$t('api_test.request.sql.database_driver')"
show-overflow-tooltip
/>
<el-table-column
prop=
"dbUrl"
:label=
"$t('api_test.request.sql.database_url')"
show-overflow-tooltip
/>
<el-table-column
prop=
"username"
:label=
"$t('api_test.request.sql.username')"
show-overflow-tooltip
/>
<el-table-column
prop=
"poolMax"
:label=
"$t('api_test.request.sql.pool_max')"
show-overflow-tooltip
/>
<el-table-column
prop=
"timeout"
:label=
"$t('api_test.request.sql.query_timeout')"
show-overflow-tooltip
/>
<el-table-column
:label=
"$t('commons.operating')"
min-width=
"100"
>
<template
v-slot:default=
"scope"
>
<ms-table-operator-button
:is-tester-permission=
"true"
:tip=
"$t('commons.copy')"
icon=
"el-icon-document-copy"
type=
"success"
@
exec=
"handleCopy(scope.$index, scope.row)"
/>
<ms-table-operator-button
:isTesterPermission=
"true"
:tip=
"$t('commons.delete')"
icon=
"el-icon-delete"
type=
"danger"
@
exec=
"handleDelete(scope.$index)"
/>
</
template
>
</el-table-column>
</el-table>
</div>
</template>
<
script
>
import
{
DatabaseConfig
}
from
"
../../../model/ApiTestModel
"
;
import
MsTableOperator
from
"
../../../../../common/components/MsTableOperator
"
;
import
MsTableOperatorButton
from
"
../../../../../common/components/MsTableOperatorButton
"
;
import
{
getUUID
}
from
"
../../../../../../../common/js/utils
"
;
export
default
{
name
:
"
MsDatabaseConfigList
"
,
components
:
{
MsTableOperatorButton
,
MsTableOperator
},
props
:
{
tableData
:
Array
,
isReadOnly
:
{
type
:
Boolean
,
default
:
false
}
},
data
()
{
return
{
drivers
:
DatabaseConfig
.
DRIVER_CLASS
,
result
:
{},
}
},
methods
:
{
handleView
(
row
)
{
this
.
$emit
(
'
rowSelect
'
,
row
);
},
handleDelete
(
index
)
{
this
.
tableData
.
splice
(
index
,
1
);
},
handleCopy
(
index
,
config
)
{
let
copy
=
{};
Object
.
assign
(
copy
,
config
);
copy
.
id
=
getUUID
();
copy
.
name
=
this
.
getNoRepeatName
(
copy
.
name
);
this
.
tableData
.
splice
(
index
+
1
,
0
,
copy
);
},
getNoRepeatName
(
name
)
{
for
(
let
i
in
this
.
tableData
)
{
if
(
this
.
tableData
[
i
].
name
===
name
)
{
return
this
.
getNoRepeatName
(
name
+
'
copy
'
);
}
}
return
name
;
},
}
}
</
script
>
<
style
scoped
>
.addButton
{
float
:
right
;
}
</
style
>
frontend/src/business/components/api/definition/components/request/database/DatabaseFrom.vue
0 → 100644
浏览文件 @
cbc9c421
<
template
>
<div
class=
"database-from"
v-loading=
"result.loading"
>
<el-form
:model=
"currentConfig"
:rules=
"rules"
label-width=
"150px"
size=
"small"
:disabled=
"isReadOnly"
ref=
"databaseFrom"
>
<el-form-item
:label=
"$t('api_test.request.sql.dataSource')"
prop=
"name"
>
<el-input
v-model=
"currentConfig.name"
maxlength=
"300"
show-word-limit
:placeholder=
"$t('commons.input_content')"
/>
</el-form-item>
<el-form-item
:label=
"$t('api_test.request.sql.database_url')"
prop=
"dbUrl"
>
<el-input
v-model=
"currentConfig.dbUrl"
maxlength=
"500"
show-word-limit
:placeholder=
"$t('commons.input_content')"
/>
</el-form-item>
<el-form-item
:label=
"$t('api_test.request.sql.database_driver')"
prop=
"driver"
>
<el-select
v-model=
"currentConfig.driver"
class=
"select-100"
clearable
>
<el-option
v-for=
"p in drivers"
:key=
"p"
:label=
"p"
:value=
"p"
/>
</el-select>
</el-form-item>
<el-form-item
:label=
"$t('api_test.request.sql.username')"
prop=
"username"
>
<el-input
v-model=
"currentConfig.username"
maxlength=
"300"
show-word-limit
:placeholder=
"$t('commons.input_content')"
/>
</el-form-item>
<el-form-item
:label=
"$t('api_test.request.sql.password')"
prop=
"password"
>
<el-input
v-model=
"currentConfig.password"
type=
"password"
autocomplete=
"new-password"
maxlength=
"200"
:placeholder=
"$t('commons.input_content')"
/>
</el-form-item>
<el-form-item
:label=
"$t('api_test.request.sql.pool_max')"
prop=
"poolMax"
>
<el-input-number
size=
"small"
:disabled=
"isReadOnly"
v-model=
"currentConfig.poolMax"
:placeholder=
"$t('commons.please_select')"
:max=
"1000*10000000"
:min=
"0"
/>
</el-form-item>
<el-form-item
:label=
"$t('api_test.request.sql.timeout')"
prop=
"timeout"
>
<el-input-number
size=
"small"
:disabled=
"isReadOnly"
v-model=
"currentConfig.timeout"
:placeholder=
"$t('commons.millisecond')"
:max=
"1000*10000000"
:min=
"0"
/>
</el-form-item>
<el-form-item>
<div
class=
"buttons"
>
<el-button
type=
"primary"
v-show=
"currentConfig.id"
size=
"small"
@
click=
"validate()"
>
{{
$t
(
'
commons.validate
'
)
}}
</el-button>
<el-button
type=
"primary"
v-show=
"currentConfig.id"
size=
"small"
@
click=
"save('update')"
>
{{
$t
(
'
commons.update
'
)
}}
</el-button>
<el-button
type=
"primary"
size=
"small"
@
click=
"save('add')"
>
{{
$t
(
'
commons.add
'
)
}}
</el-button>
</div>
</el-form-item>
</el-form>
</div>
</
template
>
<
script
>
import
{
DatabaseConfig
}
from
"
../../../model/ApiTestModel
"
;
export
default
{
name
:
"
MsDatabaseFrom
"
,
components
:
{},
props
:
{
isReadOnly
:
{
type
:
Boolean
,
default
:
false
},
config
:
{
type
:
Object
,
default
()
{
return
new
DatabaseConfig
();
}
},
callback
:
{
type
:
Function
},
},
watch
:
{
config
()
{
Object
.
assign
(
this
.
currentConfig
,
this
.
config
);
}
},
mounted
()
{
Object
.
assign
(
this
.
currentConfig
,
this
.
config
);
},
data
()
{
return
{
drivers
:
DatabaseConfig
.
DRIVER_CLASS
,
result
:
{},
currentConfig
:
new
DatabaseConfig
(),
rules
:
{
name
:
[
{
required
:
true
,
message
:
this
.
$t
(
'
commons.input_name
'
),
trigger
:
'
blur
'
},
{
max
:
300
,
message
:
this
.
$t
(
'
commons.input_limit
'
,
[
0
,
300
]),
trigger
:
'
blur
'
}
],
driver
:
[
{
required
:
true
,
message
:
this
.
$t
(
'
commons.cannot_be_null
'
),
trigger
:
'
blur
'
},
],
password
:
[
{
max
:
200
,
message
:
this
.
$t
(
'
commons.input_limit
'
,
[
0
,
200
]),
trigger
:
'
blur
'
}
],
dbUrl
:
[
{
required
:
true
,
message
:
this
.
$t
(
'
commons.cannot_be_null
'
),
trigger
:
'
blur
'
},
{
max
:
500
,
message
:
this
.
$t
(
'
commons.input_limit
'
,
[
0
,
500
]),
trigger
:
'
blur
'
}
],
username
:
[
{
required
:
true
,
message
:
this
.
$t
(
'
commons.cannot_be_null
'
),
trigger
:
'
blur
'
},
{
max
:
200
,
message
:
this
.
$t
(
'
commons.input_limit
'
,
[
0
,
200
]),
trigger
:
'
blur
'
}
],
poolMax
:
[
{
required
:
true
,
message
:
this
.
$t
(
'
commons.cannot_be_null
'
),
trigger
:
'
blur
'
},
],
timeout
:
[
{
required
:
true
,
message
:
this
.
$t
(
'
commons.cannot_be_null
'
),
trigger
:
'
blur
'
},
]
}
}
},
methods
:
{
save
(
type
)
{
this
.
$refs
[
'
databaseFrom
'
].
validate
((
valid
)
=>
{
if
(
valid
)
{
if
(
this
.
callback
)
{
if
(
type
===
'
add
'
)
{
this
.
currentConfig
.
id
=
undefined
;
}
this
.
callback
(
this
.
currentConfig
);
}
}
else
{
return
false
;
}
});
},
validate
()
{
this
.
result
=
this
.
$post
(
'
/api/database/validate
'
,
this
.
currentConfig
,
()
=>
{
this
.
$success
(
this
.
$t
(
'
commons.connection_successful
'
));
})
}
}
}
</
script
>
<
style
scoped
>
.buttons
{
float
:
right
;
}
</
style
>
frontend/src/business/components/api/definition/components/request/ApiHttpRequestForm.vue
→
frontend/src/business/components/api/definition/components/request/
http/
ApiHttpRequestForm.vue
浏览文件 @
cbc9c421
...
...
@@ -87,18 +87,18 @@
</
template
>
<
script
>
import
MsApiKeyValue
from
"
../ApiKeyValue
"
;
import
MsApiBody
from
"
../body/ApiBody
"
;
import
MsApiAuthConfig
from
"
../auth/ApiAuthConfig
"
;
import
ApiRequestMethodSelect
from
"
../collapse/ApiRequestMethodSelect
"
;
import
MsApiKeyValue
from
"
../
../
ApiKeyValue
"
;
import
MsApiBody
from
"
../
../
body/ApiBody
"
;
import
MsApiAuthConfig
from
"
../
../
auth/ApiAuthConfig
"
;
import
ApiRequestMethodSelect
from
"
../
../
collapse/ApiRequestMethodSelect
"
;
import
{
REQUEST_HEADERS
}
from
"
@/common/js/constants
"
;
import
MsApiVariable
from
"
../ApiVariable
"
;
import
MsJsr233Processor
from
"
../processor/Jsr233Processor
"
;
import
MsApiAdvancedConfig
from
"
../ApiAdvancedConfig
"
;
import
{
createComponent
}
from
"
../jmeter/components
"
;
import
MsApiAssertions
from
"
../assertion/ApiAssertions
"
;
import
MsApiExtract
from
"
../extract/ApiExtract
"
;
import
{
Assertions
,
Extract
}
from
"
../../model/ApiTestModel
"
;
import
MsApiVariable
from
"
../
../
ApiVariable
"
;
import
MsJsr233Processor
from
"
../
../
processor/Jsr233Processor
"
;
import
MsApiAdvancedConfig
from
"
../
../
ApiAdvancedConfig
"
;
import
{
createComponent
}
from
"
../
../
jmeter/components
"
;
import
MsApiAssertions
from
"
../
../
assertion/ApiAssertions
"
;
import
MsApiExtract
from
"
../
../
extract/ApiExtract
"
;
import
{
Assertions
,
Extract
}
from
"
../../
../
model/ApiTestModel
"
;
export
default
{
name
:
"
MsApiHttpRequestForm
"
,
...
...
frontend/src/business/components/api/definition/components/request/ApiRequestForm.vue
→
frontend/src/business/components/api/definition/components/request/
http/
ApiRequestForm.vue
浏览文件 @
cbc9c421
...
...
@@ -6,11 +6,6 @@
<
script
>
import
MsApiHttpRequestForm
from
"
./ApiHttpRequestForm
"
;
import
{
Request
}
from
"
../jmeter/components
"
;
// import MsApiTcpRequestForm from "./ApiTcpRequestForm";
// import MsApiDubboRequestForm from "./ApiDubboRequestForm";
// import MsApiSqlRequestForm from "./ApiSqlRequestForm";
export
default
{
name
:
"
MsApiRequestForm
"
,
...
...
@@ -29,21 +24,7 @@
},
computed
:
{
component
({
request
:
{
type
}})
{
let
name
;
switch
(
type
)
{
case
Request
.
TYPES
.
DUBBO
:
name
=
"
MsApiDubboRequestForm
"
;
break
;
case
Request
.
TYPES
.
SQL
:
name
=
"
MsApiSqlRequestForm
"
;
break
;
case
Request
.
TYPES
.
TCP
:
name
=
"
MsApiTcpRequestForm
"
;
break
;
default
:
name
=
"
MsApiHttpRequestForm
"
;
}
return
name
;
return
"
MsApiHttpRequestForm
"
;
}
}
}
...
...
frontend/src/business/components/api/definition/components/request/tcp/TcpConfig.vue
0 → 100644
浏览文件 @
cbc9c421
<
template
>
<el-form
class=
"tcp"
:model=
"config"
:rules=
"rules"
ref=
"config"
label-width=
"120px"
:disabled=
"isReadOnly"
size=
"small"
>
<el-form-item
label=
"TCPClient"
prop=
"classname"
>
<el-select
v-model=
"config.classname"
style=
"width: 100%"
>
<el-option
v-for=
"c in classes"
:key=
"c"
:label=
"c"
:value=
"c"
/>
</el-select>
</el-form-item>
<el-row
:gutter=
"10"
>
<el-col
:span=
"16"
>
<el-form-item
:label=
"$t('api_test.request.tcp.server')"
prop=
"server"
>
<el-input
v-model=
"config.server"
maxlength=
"300"
show-word-limit
/>
</el-form-item>
</el-col>
<el-col
:span=
"8"
>
<el-form-item
:label=
"$t('api_test.request.tcp.port')"
prop=
"port"
label-width=
"60px"
>
<el-input-number
v-model=
"config.port"
controls-position=
"right"
:min=
"0"
:max=
"65535"
:controls=
"false"
/>
</el-form-item>
</el-col>
</el-row>
<el-row
:gutter=
"10"
>
<el-col
:span=
"12"
>
<el-form-item
:label=
"$t('api_test.request.tcp.connect')"
prop=
"ctimeout"
>
<el-input-number
v-model=
"config.ctimeout"
controls-position=
"right"
:min=
"0"
:step=
"1000"
:controls=
"false"
/>
</el-form-item>
</el-col>
<el-col
:span=
"12"
>
<el-form-item
:label=
"$t('api_test.request.tcp.response')"
prop=
"timeout"
>
<el-input-number
v-model=
"config.timeout"
controls-position=
"right"
:min=
"0"
:step=
"1000"
:controls=
"false"
/>
</el-form-item>
</el-col>
</el-row>
<el-row
:gutter=
"10"
>
<el-col
:span=
"12"
>
<el-form-item
:label=
"$t('api_test.request.tcp.so_linger')"
prop=
"soLinger"
>
<el-input
v-model=
"config.soLinger"
/>
</el-form-item>
</el-col>
<el-col
:span=
"12"
>
<el-form-item
:label=
"$t('api_test.request.tcp.eol_byte')"
prop=
"eolByte"
>
<el-input
v-model=
"config.eolByte"
/>
</el-form-item>
</el-col>
</el-row>
<el-row
:gutter=
"10"
>
<el-col
:span=
"8"
>
<el-form-item
:label=
"$t('api_test.request.tcp.re_use_connection')"
>
<el-checkbox
v-model=
"config.reUseConnection"
/>
</el-form-item>
</el-col>
<el-col
:span=
"8"
>
<el-form-item
:label=
"$t('api_test.request.tcp.close_connection')"
>
<el-checkbox
v-model=
"config.closeConnection"
/>
</el-form-item>
</el-col>
<el-col
:span=
"8"
>
<el-form-item
:label=
"$t('api_test.request.tcp.no_delay')"
>
<el-checkbox
v-model=
"config.nodelay"
/>
</el-form-item>
</el-col>
</el-row>
<el-row
:gutter=
"10"
>
<el-col
:span=
"12"
>
<el-form-item
:label=
"$t('api_test.request.tcp.username')"
prop=
"username"
>
<el-input
v-model=
"config.username"
maxlength=
"100"
show-word-limit
/>
</el-form-item>
</el-col>
<el-col
:span=
"12"
>
<el-form-item
:label=
"$t('api_test.request.tcp.password')"
prop=
"password"
>
<el-input
v-model=
"config.password"
maxlength=
"30"
show-word-limit
show-password
autocomplete=
"new-password"
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
</
template
>
<
script
>
import
{
TCPConfig
}
from
"
../../../model/ApiTestModel
"
;
export
default
{
name
:
"
MsTcpConfig
"
,
props
:
{
config
:
TCPConfig
,
isReadOnly
:
{
type
:
Boolean
,
default
:
false
},
},
data
()
{
return
{
classes
:
TCPConfig
.
CLASSES
,
rules
:
{}
}
},
}
</
script
>
<
style
scoped
>
.tcp
>>>
.el-input-number
{
width
:
100%
;
}
</
style
>
frontend/src/business/components/api/definition/components/runtest/RunTestHttpPage.vue
浏览文件 @
cbc9c421
...
...
@@ -86,14 +86,13 @@
</template>
<
script
>
import
MsApiRequestForm
from
"
../request/ApiRequestForm
"
;
import
MsApiRequestForm
from
"
../request/
http/
ApiRequestForm
"
;
import
{
downloadFile
,
getUUID
}
from
"
@/common/js/utils
"
;
import
MsApiCaseList
from
"
../ApiCaseList
"
;
import
MsContainer
from
"
../../../../common/components/MsContainer
"
;
import
MsBottomContainer
from
"
../BottomContainer
"
;
import
{
RequestFactory
,
Scenario
}
from
"
../../model/ApiTestModel
"
;
import
{
parseEnvironment
}
from
"
../../model/EnvironmentModel
"
;
import
ApiEnvironmentConfig
from
"
../
../../test/components
/ApiEnvironmentConfig
"
;
import
ApiEnvironmentConfig
from
"
../
environment
/ApiEnvironmentConfig
"
;
import
MsRequestResultTail
from
"
../response/RequestResultTail
"
;
import
MsRun
from
"
../Run
"
;
...
...
frontend/src/i18n/en-US.js
浏览文件 @
cbc9c421
...
...
@@ -525,6 +525,7 @@ export default {
pre_script
:
"
Prescript
"
,
post_script
:
"
Postscript
"
,
extract_param
:
"
Extract parameters
"
,
add_module
:
"
Add module
"
,
}
},
...
...
frontend/src/i18n/zh-CN.js
浏览文件 @
cbc9c421
...
...
@@ -525,7 +525,9 @@ export default {
auth_config_info
:
"
请求需要进行权限校验
"
,
pre_script
:
"
前置脚本
"
,
post_script
:
"
后置脚本
"
,
extract_param
:
"
提取参数
"
,
extract_param
:
"
提取参数
"
,
add_module
:
"
创建模块
"
,
}
},
environment
:
{
...
...
@@ -704,7 +706,7 @@ export default {
close_connection
:
"
关闭连接
"
,
so_linger
:
"
SO LINGER
"
,
eol_byte
:
"
行尾(EOL)字节值
"
,
request
:
"
要发送的
文本
"
,
request
:
"
发送
文本
"
,
username
:
"
用户名
"
,
password
:
"
密码
"
,
login
:
"
登录设置
"
,
...
...
frontend/src/i18n/zh-TW.js
浏览文件 @
cbc9c421
...
...
@@ -526,7 +526,7 @@ export default {
pre_script
:
"
前置腳本
"
,
post_script
:
"
後置腳本
"
,
extract_param
:
"
提取參數
"
,
add_module
:
"
創建模塊
"
,
}
},
environment
:
{
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录