feat(接口定义): 重新绘制接口定义页面

重新绘制接口定义页面
This commit is contained in:
song-tianyang 2022-03-15 19:11:31 +08:00 committed by 刘瑞斌
parent 87bd354475
commit 2ff5769c32
46 changed files with 4910 additions and 483 deletions

View File

@ -7,6 +7,7 @@ import io.metersphere.api.dto.ApiTestImportRequest;
import io.metersphere.api.dto.automation.ApiScenarioRequest;
import io.metersphere.api.dto.automation.ReferenceDTO;
import io.metersphere.api.dto.definition.*;
import io.metersphere.api.dto.definition.information.ApiDetailedInformationDTO;
import io.metersphere.api.dto.definition.parse.ApiDefinitionImport;
import io.metersphere.api.dto.definition.request.assertions.document.DocumentElement;
import io.metersphere.api.dto.scenario.Body;
@ -177,6 +178,12 @@ public class ApiDefinitionController {
return apiDefinitionService.getById(id);
}
@GetMapping("/get/apiDetail/{id}")
@RequiresPermissions("PROJECT_API_DEFINITION:READ")
public ApiDetailedInformationDTO getApiDetail(@PathVariable String id) {
return apiDefinitionService.getApiDetail(id);
}
@PostMapping(value = "/run/debug", consumes = {"multipart/form-data"})
@MsAuditLog(module = OperLogModule.API_DEFINITION, type = OperLogConstants.DEBUG, title = "#request.name", project = "#request.projectId")
public MsExecResponseDTO runDebug(@RequestPart("request") RunDefinitionRequest request, @RequestPart(value = "files", required = false) List<MultipartFile> bodyFiles) {

View File

@ -65,7 +65,7 @@ public class ShareInfoController {
model.setId(id);
model.setName(id);
}
ApiDocumentInfoDTO returnDTO = shareInfoService.conversionModelToDTO(model,userIdMap);
ApiDocumentInfoDTO returnDTO = apiDefinitionService.conversionModelToDTO(model,userIdMap);
returnList.add(returnDTO);
}
}
@ -78,7 +78,7 @@ public class ShareInfoController {
ApiDocumentInfoDTO returnDTO = new ApiDocumentInfoDTO();
try {
Map<String, User> userIdMap = userService.queryName();
returnDTO = shareInfoService.conversionModelToDTO(apiModel,userIdMap);
returnDTO = apiDefinitionService.conversionModelToDTO(apiModel,userIdMap);
} catch (Exception e) {
LogUtil.error(e);
}

View File

@ -0,0 +1,13 @@
package io.metersphere.api.dto.definition.information;
import io.metersphere.api.dto.definition.ApiDefinitionResult;
import io.metersphere.api.dto.share.ApiDocumentInfoDTO;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class ApiDetailedInformationDTO {
private ApiDefinitionResult apiDefinition;
private ApiDocumentInfoDTO apiInfo;
}

View File

@ -17,6 +17,7 @@ public class ApiDocumentInfoDTO {
private String uri;
private String name;
private String status;
private String protocol;
private String tags;
private String modules;

View File

@ -1,6 +1,7 @@
package io.metersphere.api.service;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
@ -10,6 +11,7 @@ import io.metersphere.api.dto.automation.ApiScenarioRequest;
import io.metersphere.api.dto.automation.ReferenceDTO;
import io.metersphere.api.dto.datacount.ApiDataCountResult;
import io.metersphere.api.dto.definition.*;
import io.metersphere.api.dto.definition.information.ApiDetailedInformationDTO;
import io.metersphere.api.dto.definition.parse.ApiDefinitionImport;
import io.metersphere.api.dto.definition.parse.ApiDefinitionImportParserFactory;
import io.metersphere.api.dto.definition.parse.Swagger3Parser;
@ -19,6 +21,7 @@ import io.metersphere.api.dto.definition.request.sampler.MsTCPSampler;
import io.metersphere.api.dto.mockconfig.MockConfigImportDTO;
import io.metersphere.api.dto.scenario.Scenario;
import io.metersphere.api.dto.scenario.request.RequestType;
import io.metersphere.api.dto.share.ApiDocumentInfoDTO;
import io.metersphere.api.dto.swaggerurl.SwaggerTaskResult;
import io.metersphere.api.dto.swaggerurl.SwaggerUrlRequest;
import io.metersphere.api.exec.api.ApiExecuteService;
@ -29,6 +32,7 @@ import io.metersphere.base.mapper.*;
import io.metersphere.base.mapper.ext.*;
import io.metersphere.commons.constants.*;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.json.JSONSchemaGenerator;
import io.metersphere.commons.json.JSONSchemaToDocumentUtils;
import io.metersphere.commons.json.JSONToDocumentUtils;
import io.metersphere.commons.utils.*;
@ -121,6 +125,8 @@ public class ApiDefinitionService {
@Resource
private ApiDefinitionFollowMapper apiDefinitionFollowMapper;
@Resource
private UserService userService;
@Resource
@Lazy
private TestPlanService testPlanService;
@Resource
@ -2033,4 +2039,345 @@ public class ApiDefinitionService {
}
}
public ApiDetailedInformationDTO getApiDetail(String id) {
ApiDetailedInformationDTO informationDTO = new ApiDetailedInformationDTO();
ApiDefinitionResult result = this.getById(id);
ApiDocumentInfoDTO returnDTO = new ApiDocumentInfoDTO();
try {
Map<String, User> userIdMap = userService.queryName();
ApiDefinitionWithBLOBs definition = apiDefinitionMapper.selectByPrimaryKey(id);
returnDTO = this.conversionModelToDTO(definition,userIdMap);
} catch (Exception e) {
LogUtil.error(e);
}
informationDTO.setApiDefinition(result);
informationDTO.setApiInfo(returnDTO);
return informationDTO;
}
public ApiDocumentInfoDTO conversionModelToDTO(ApiDefinitionWithBLOBs apiModel, Map<String,User> userIdMap) {
ApiDocumentInfoDTO apiInfoDTO = new ApiDocumentInfoDTO();
JSONArray previewJsonArray = new JSONArray();
if (apiModel != null) {
apiInfoDTO.setId(apiModel.getId());
apiInfoDTO.setName(apiModel.getName());
apiInfoDTO.setMethod(apiModel.getMethod());
apiInfoDTO.setUri(apiModel.getPath());
apiInfoDTO.setStatus(apiModel.getStatus());
apiInfoDTO.setProtocol(apiModel.getProtocol());
if(StringUtils.isNotEmpty(apiModel.getTags())){
JSONArray tagsArr = JSONArray.parseArray(apiModel.getTags());
List<String> tagList = new ArrayList<>();
for(int i = 0;i < tagsArr.size();i ++){
tagList.add(tagsArr.getString(i));
}
if(!tagList.isEmpty()){
apiInfoDTO.setTags(StringUtils.join(tagList,","));
}
}
apiInfoDTO.setResponsibler(userIdMap.get(apiModel.getUserId()) == null? apiModel.getUserId() : userIdMap.get(apiModel.getUserId()).getName());
apiInfoDTO.setCreateUser(userIdMap.get(apiModel.getCreateUser()) == null? apiModel.getCreateUser() : userIdMap.get(apiModel.getCreateUser()).getName());
apiInfoDTO.setDesc(apiModel.getDescription());
ApiModuleService apiModuleService = CommonBeanFactory.getBean(ApiModuleService.class);
apiInfoDTO.setModules(apiModuleService.getModuleNameById(apiModel.getModuleId()));
if (apiModel.getRequest() != null) {
JSONObject requestObj = this.genJSONObject(apiModel.getRequest());
if (requestObj != null) {
if (requestObj.containsKey("headers")) {
JSONArray requestHeadDataArr = new JSONArray();
//head赋值
JSONArray headArr = requestObj.getJSONArray("headers");
for (int index = 0; index < headArr.size(); index++) {
JSONObject headObj = headArr.getJSONObject(index);
if (headObj != null && headObj.containsKey("name") && headObj.containsKey("value")) {
requestHeadDataArr.add(headObj);
}
}
apiInfoDTO.setRequestHead(requestHeadDataArr.toJSONString());
}
//url参数赋值
JSONArray urlParamArr = new JSONArray();
if (requestObj.containsKey("arguments")) {
try {
JSONArray headArr = requestObj.getJSONArray("arguments");
for (int index = 0; index < headArr.size(); index++) {
JSONObject headObj = headArr.getJSONObject(index);
if (headObj.containsKey("name") && headObj.containsKey("value")) {
urlParamArr.add(headObj);
}
}
} catch (Exception e) {
}
}
//rest参数设置
JSONArray restParamArr = new JSONArray();
if (requestObj.containsKey("rest")) {
try {
//urlParam -- rest赋值
JSONArray headArr = requestObj.getJSONArray("rest");
for (int index = 0; index < headArr.size(); index++) {
JSONObject headObj = headArr.getJSONObject(index);
if (headObj.containsKey("name")) {
restParamArr.add(headObj);
}
}
} catch (Exception e) {
}
}
apiInfoDTO.setUrlParams(urlParamArr.toJSONString());
apiInfoDTO.setRestParams(restParamArr.toJSONString());
//请求体参数类型
if (requestObj.containsKey("body")) {
try {
JSONObject bodyObj = requestObj.getJSONObject("body");
if (bodyObj.containsKey("type")) {
String type = bodyObj.getString("type");
if (StringUtils.equals(type, "WWW_FORM")) {
apiInfoDTO.setRequestBodyParamType("x-www-from-urlencoded");
} else if (StringUtils.equals(type, "Form Data")) {
apiInfoDTO.setRequestBodyParamType("form-data");
} else {
apiInfoDTO.setRequestBodyParamType(type);
}
if (StringUtils.equals(type, "JSON")) {
//判断是否是JsonSchema
boolean isJsonSchema = false;
if (bodyObj.containsKey("format")) {
String foramtValue = String.valueOf(bodyObj.get("format"));
if (StringUtils.equals("JSON-SCHEMA", foramtValue)) {
isJsonSchema = true;
}
}
if (isJsonSchema) {
apiInfoDTO.setRequestBodyParamType("JSON-SCHEMA");
apiInfoDTO.setJsonSchemaBody(bodyObj);
if (bodyObj.containsKey("jsonSchema")) {
JSONObject jsonSchemaObj = bodyObj.getJSONObject("jsonSchema");
apiInfoDTO.setRequestPreviewData(JSON.parse(JSONSchemaGenerator.getJson(jsonSchemaObj.toJSONString())));
}
} else {
if (bodyObj.containsKey("raw")) {
String raw = bodyObj.getString("raw");
apiInfoDTO.setRequestBodyStrutureData(raw);
//转化jsonObje 或者 jsonArray
this.setPreviewData(previewJsonArray, raw);
}
}
} else if (StringUtils.equalsAny(type, "XML", "Raw")) {
if (bodyObj.containsKey("raw")) {
String raw = bodyObj.getString("raw");
apiInfoDTO.setRequestBodyStrutureData(raw);
this.setPreviewData(previewJsonArray, raw);
}
} else if (StringUtils.equalsAny(type, "Form Data", "WWW_FORM")) {
if (bodyObj.containsKey("kvs")) {
JSONArray bodyParamArr = new JSONArray();
JSONArray kvsArr = bodyObj.getJSONArray("kvs");
Map<String, String> previewObjMap = new LinkedHashMap<>();
for (int i = 0; i < kvsArr.size(); i++) {
JSONObject kv = kvsArr.getJSONObject(i);
if (kv.containsKey("name")) {
String value = "";
if (kv.containsKey("value")) {
value = String.valueOf(kv.get("value"));
}
bodyParamArr.add(kv);
previewObjMap.put(String.valueOf(kv.get("name")), value);
}
}
this.setPreviewData(previewJsonArray, JSONObject.toJSONString(previewObjMap));
apiInfoDTO.setRequestBodyFormData(bodyParamArr.toJSONString());
}
} else if (StringUtils.equals(type, "BINARY")) {
if (bodyObj.containsKey("binary")) {
List<Map<String, String>> bodyParamList = new ArrayList<>();
JSONArray kvsArr = bodyObj.getJSONArray("binary");
Map<String, String> previewObjMap = new LinkedHashMap<>();
for (int i = 0; i < kvsArr.size(); i++) {
JSONObject kv = kvsArr.getJSONObject(i);
if (kv.containsKey("description") && kv.containsKey("files")) {
Map<String, String> bodyMap = new HashMap<>();
String name = kv.getString("description");
JSONArray fileArr = kv.getJSONArray("files");
String value = "";
for (int j = 0; j < fileArr.size(); j++) {
JSONObject fileObj = fileArr.getJSONObject(j);
if (fileObj.containsKey("name")) {
value += fileObj.getString("name") + " ;";
}
}
bodyMap.put("name", name);
bodyMap.put("value", value);
bodyMap.put("contentType", "File");
bodyParamList.add(bodyMap);
previewObjMap.put(String.valueOf(name), String.valueOf(value));
}
}
this.setPreviewData(previewJsonArray, JSONObject.toJSONString(previewObjMap));
apiInfoDTO.setRequestBodyFormData(JSONArray.toJSONString(bodyParamList));
}
}
}
} catch (Exception e) {
}
}
}
}
//赋值响应头
if (apiModel.getResponse() != null) {
JSONObject responseJsonObj = this.genJSONObject(apiModel.getResponse());
if (responseJsonObj != null && responseJsonObj.containsKey("headers")) {
try {
JSONArray responseHeadDataArr = new JSONArray();
JSONArray headArr = responseJsonObj.getJSONArray("headers");
for (int index = 0; index < headArr.size(); index++) {
JSONObject headObj = headArr.getJSONObject(index);
if (headObj.containsKey("name") && headObj.containsKey("value")) {
responseHeadDataArr.add(headObj);
}
}
apiInfoDTO.setResponseHead(responseHeadDataArr.toJSONString());
} catch (Exception e) {
}
}
// 赋值响应体
if (responseJsonObj != null && responseJsonObj.containsKey("body")) {
try {
JSONObject bodyObj = responseJsonObj.getJSONObject("body");
if (bodyObj.containsKey("type")) {
String type = bodyObj.getString("type");
if (StringUtils.equals(type, "WWW_FORM")) {
apiInfoDTO.setResponseBodyParamType("x-www-from-urlencoded");
} else if (StringUtils.equals(type, "Form Data")) {
apiInfoDTO.setResponseBodyParamType("form-data");
} else {
apiInfoDTO.setResponseBodyParamType(type);
}
if (StringUtils.equalsAny(type, "JSON", "XML", "Raw")) {
//判断是否是JsonSchema
boolean isJsonSchema = false;
if (bodyObj.containsKey("format")) {
String foramtValue = String.valueOf(bodyObj.get("format"));
if (StringUtils.equals("JSON-SCHEMA", foramtValue)) {
isJsonSchema = true;
}
}
if (isJsonSchema) {
// apiInfoDTO.setRequestBodyParamType("JSON-SCHEMA");
apiInfoDTO.setResponseBodyParamType("JSON-SCHEMA");
apiInfoDTO.setJsonSchemaResponseBody(bodyObj);
// apiInfoDTO.setJsonSchemaBody(bodyObj);
} else {
if (bodyObj.containsKey("raw")) {
String raw = bodyObj.getString("raw");
apiInfoDTO.setResponseBodyStrutureData(raw);
//转化jsonObje 或者 jsonArray
this.setPreviewData(previewJsonArray, raw);
}
}
} else if (StringUtils.equalsAny(type, "Form Data", "WWW_FORM")) {
if (bodyObj.containsKey("kvs")) {
JSONArray bodyParamArr = new JSONArray();
JSONArray kvsArr = bodyObj.getJSONArray("kvs");
for (int i = 0; i < kvsArr.size(); i++) {
JSONObject kv = kvsArr.getJSONObject(i);
if (kv.containsKey("name")) {
bodyParamArr.add(kv);
}
}
apiInfoDTO.setResponseBodyFormData(bodyParamArr.toJSONString());
}
} else if (StringUtils.equals(type, "BINARY")) {
if (bodyObj.containsKey("binary")) {
List<Map<String, String>> bodyParamList = new ArrayList<>();
JSONArray kvsArr = bodyObj.getJSONArray("kvs");
for (int i = 0; i < kvsArr.size(); i++) {
JSONObject kv = kvsArr.getJSONObject(i);
if (kv.containsKey("description") && kv.containsKey("files")) {
Map<String, String> bodyMap = new HashMap<>();
String name = kv.getString("description");
JSONArray fileArr = kv.getJSONArray("files");
String value = "";
for (int j = 0; j < fileArr.size(); j++) {
JSONObject fileObj = fileArr.getJSONObject(j);
if (fileObj.containsKey("name")) {
value += fileObj.getString("name") + " ;";
}
}
bodyMap.put("name", name);
bodyMap.put("value", value);
bodyParamList.add(bodyMap);
}
}
apiInfoDTO.setResponseBodyFormData(JSONArray.toJSONString(bodyParamList));
}
}
}
} catch (Exception e) {
}
}
// 赋值响应码
if (responseJsonObj != null && responseJsonObj.containsKey("statusCode")) {
try {
JSONArray responseStatusDataArr = new JSONArray();
JSONArray statusArr = responseJsonObj.getJSONArray("statusCode");
for (int index = 0; index < statusArr.size(); index++) {
JSONObject statusObj = statusArr.getJSONObject(index);
if (statusObj.containsKey("name") && statusObj.containsKey("value")) {
responseStatusDataArr.add(statusObj);
}
}
apiInfoDTO.setResponseCode(responseStatusDataArr.toJSONString());
} catch (Exception e) {
}
}
}
}
if (!previewJsonArray.isEmpty()) {
apiInfoDTO.setRequestPreviewData(previewJsonArray);
}
apiInfoDTO.setSelectedFlag(true);
return apiInfoDTO;
}
private void setPreviewData(JSONArray previewArray, String data) {
try {
JSONObject previewObj = JSONObject.parseObject(data);
previewArray.add(previewObj);
} catch (Exception e) {
}
try {
previewArray = JSONArray.parseArray(data);
} catch (Exception e) {
}
}
private JSONObject genJSONObject(String request) {
JSONObject returnObj = null;
try {
returnObj = JSONObject.parseObject(request);
} catch (Exception e) {
}
return returnObj;
}
}

View File

@ -110,331 +110,6 @@ public class ShareInfoService {
return true;
}
public ApiDocumentInfoDTO conversionModelToDTO(ApiDefinitionWithBLOBs apiModel, Map<String,User> userIdMap) {
ApiDocumentInfoDTO apiInfoDTO = new ApiDocumentInfoDTO();
JSONArray previewJsonArray = new JSONArray();
if (apiModel != null) {
apiInfoDTO.setId(apiModel.getId());
apiInfoDTO.setName(apiModel.getName());
apiInfoDTO.setMethod(apiModel.getMethod());
apiInfoDTO.setUri(apiModel.getPath());
apiInfoDTO.setStatus(apiModel.getStatus());
if(StringUtils.isNotEmpty(apiModel.getTags())){
JSONArray tagsArr = JSONArray.parseArray(apiModel.getTags());
List<String> tagList = new ArrayList<>();
for(int i = 0;i < tagsArr.size();i ++){
tagList.add(tagsArr.getString(i));
}
if(!tagList.isEmpty()){
apiInfoDTO.setTags(StringUtils.join(tagList,","));
}
}
apiInfoDTO.setResponsibler(userIdMap.get(apiModel.getUserId()) == null? apiModel.getUserId() : userIdMap.get(apiModel.getUserId()).getName());
apiInfoDTO.setCreateUser(userIdMap.get(apiModel.getCreateUser()) == null? apiModel.getCreateUser() : userIdMap.get(apiModel.getCreateUser()).getName());
apiInfoDTO.setDesc(apiModel.getDescription());
ApiModuleService apiModuleService = CommonBeanFactory.getBean(ApiModuleService.class);
apiInfoDTO.setModules(apiModuleService.getModuleNameById(apiModel.getModuleId()));
if (apiModel.getRequest() != null) {
JSONObject requestObj = this.genJSONObject(apiModel.getRequest());
if (requestObj != null) {
if (requestObj.containsKey("headers")) {
JSONArray requestHeadDataArr = new JSONArray();
//head赋值
JSONArray headArr = requestObj.getJSONArray("headers");
for (int index = 0; index < headArr.size(); index++) {
JSONObject headObj = headArr.getJSONObject(index);
if (headObj != null && headObj.containsKey("name") && headObj.containsKey("value")) {
requestHeadDataArr.add(headObj);
}
}
apiInfoDTO.setRequestHead(requestHeadDataArr.toJSONString());
}
//url参数赋值
JSONArray urlParamArr = new JSONArray();
if (requestObj.containsKey("arguments")) {
try {
JSONArray headArr = requestObj.getJSONArray("arguments");
for (int index = 0; index < headArr.size(); index++) {
JSONObject headObj = headArr.getJSONObject(index);
if (headObj.containsKey("name") && headObj.containsKey("value")) {
urlParamArr.add(headObj);
}
}
} catch (Exception e) {
}
}
//rest参数设置
JSONArray restParamArr = new JSONArray();
if (requestObj.containsKey("rest")) {
try {
//urlParam -- rest赋值
JSONArray headArr = requestObj.getJSONArray("rest");
for (int index = 0; index < headArr.size(); index++) {
JSONObject headObj = headArr.getJSONObject(index);
if (headObj.containsKey("name")) {
restParamArr.add(headObj);
}
}
} catch (Exception e) {
}
}
apiInfoDTO.setUrlParams(urlParamArr.toJSONString());
apiInfoDTO.setRestParams(restParamArr.toJSONString());
//请求体参数类型
if (requestObj.containsKey("body")) {
try {
JSONObject bodyObj = requestObj.getJSONObject("body");
if (bodyObj.containsKey("type")) {
String type = bodyObj.getString("type");
if (StringUtils.equals(type, "WWW_FORM")) {
apiInfoDTO.setRequestBodyParamType("x-www-from-urlencoded");
} else if (StringUtils.equals(type, "Form Data")) {
apiInfoDTO.setRequestBodyParamType("form-data");
} else {
apiInfoDTO.setRequestBodyParamType(type);
}
if (StringUtils.equals(type, "JSON")) {
//判断是否是JsonSchema
boolean isJsonSchema = false;
if (bodyObj.containsKey("format")) {
String foramtValue = String.valueOf(bodyObj.get("format"));
if (StringUtils.equals("JSON-SCHEMA", foramtValue)) {
isJsonSchema = true;
}
}
if (isJsonSchema) {
apiInfoDTO.setRequestBodyParamType("JSON-SCHEMA");
apiInfoDTO.setJsonSchemaBody(bodyObj);
if (bodyObj.containsKey("jsonSchema")) {
JSONObject jsonSchemaObj = bodyObj.getJSONObject("jsonSchema");
apiInfoDTO.setRequestPreviewData(JSON.parse(JSONSchemaGenerator.getJson(jsonSchemaObj.toJSONString())));
}
} else {
if (bodyObj.containsKey("raw")) {
String raw = bodyObj.getString("raw");
apiInfoDTO.setRequestBodyStrutureData(raw);
//转化jsonObje 或者 jsonArray
this.setPreviewData(previewJsonArray, raw);
}
}
} else if (StringUtils.equalsAny(type, "XML", "Raw")) {
if (bodyObj.containsKey("raw")) {
String raw = bodyObj.getString("raw");
apiInfoDTO.setRequestBodyStrutureData(raw);
this.setPreviewData(previewJsonArray, raw);
}
} else if (StringUtils.equalsAny(type, "Form Data", "WWW_FORM")) {
if (bodyObj.containsKey("kvs")) {
JSONArray bodyParamArr = new JSONArray();
JSONArray kvsArr = bodyObj.getJSONArray("kvs");
Map<String, String> previewObjMap = new LinkedHashMap<>();
for (int i = 0; i < kvsArr.size(); i++) {
JSONObject kv = kvsArr.getJSONObject(i);
if (kv.containsKey("name")) {
String value = "";
if (kv.containsKey("value")) {
value = String.valueOf(kv.get("value"));
}
bodyParamArr.add(kv);
previewObjMap.put(String.valueOf(kv.get("name")), value);
}
}
this.setPreviewData(previewJsonArray, JSONObject.toJSONString(previewObjMap));
apiInfoDTO.setRequestBodyFormData(bodyParamArr.toJSONString());
}
} else if (StringUtils.equals(type, "BINARY")) {
if (bodyObj.containsKey("binary")) {
List<Map<String, String>> bodyParamList = new ArrayList<>();
JSONArray kvsArr = bodyObj.getJSONArray("binary");
Map<String, String> previewObjMap = new LinkedHashMap<>();
for (int i = 0; i < kvsArr.size(); i++) {
JSONObject kv = kvsArr.getJSONObject(i);
if (kv.containsKey("description") && kv.containsKey("files")) {
Map<String, String> bodyMap = new HashMap<>();
String name = kv.getString("description");
JSONArray fileArr = kv.getJSONArray("files");
String value = "";
for (int j = 0; j < fileArr.size(); j++) {
JSONObject fileObj = fileArr.getJSONObject(j);
if (fileObj.containsKey("name")) {
value += fileObj.getString("name") + " ;";
}
}
bodyMap.put("name", name);
bodyMap.put("value", value);
bodyMap.put("contentType", "File");
bodyParamList.add(bodyMap);
previewObjMap.put(String.valueOf(name), String.valueOf(value));
}
}
this.setPreviewData(previewJsonArray, JSONObject.toJSONString(previewObjMap));
apiInfoDTO.setRequestBodyFormData(JSONArray.toJSONString(bodyParamList));
}
}
}
} catch (Exception e) {
}
}
}
}
//赋值响应头
if (apiModel.getResponse() != null) {
JSONObject responseJsonObj = this.genJSONObject(apiModel.getResponse());
if (responseJsonObj != null && responseJsonObj.containsKey("headers")) {
try {
JSONArray responseHeadDataArr = new JSONArray();
JSONArray headArr = responseJsonObj.getJSONArray("headers");
for (int index = 0; index < headArr.size(); index++) {
JSONObject headObj = headArr.getJSONObject(index);
if (headObj.containsKey("name") && headObj.containsKey("value")) {
responseHeadDataArr.add(headObj);
}
}
apiInfoDTO.setResponseHead(responseHeadDataArr.toJSONString());
} catch (Exception e) {
}
}
// 赋值响应体
if (responseJsonObj != null && responseJsonObj.containsKey("body")) {
try {
JSONObject bodyObj = responseJsonObj.getJSONObject("body");
if (bodyObj.containsKey("type")) {
String type = bodyObj.getString("type");
if (StringUtils.equals(type, "WWW_FORM")) {
apiInfoDTO.setResponseBodyParamType("x-www-from-urlencoded");
} else if (StringUtils.equals(type, "Form Data")) {
apiInfoDTO.setResponseBodyParamType("form-data");
} else {
apiInfoDTO.setResponseBodyParamType(type);
}
if (StringUtils.equalsAny(type, "JSON", "XML", "Raw")) {
//判断是否是JsonSchema
boolean isJsonSchema = false;
if (bodyObj.containsKey("format")) {
String foramtValue = String.valueOf(bodyObj.get("format"));
if (StringUtils.equals("JSON-SCHEMA", foramtValue)) {
isJsonSchema = true;
}
}
if (isJsonSchema) {
// apiInfoDTO.setRequestBodyParamType("JSON-SCHEMA");
apiInfoDTO.setResponseBodyParamType("JSON-SCHEMA");
apiInfoDTO.setJsonSchemaResponseBody(bodyObj);
// apiInfoDTO.setJsonSchemaBody(bodyObj);
} else {
if (bodyObj.containsKey("raw")) {
String raw = bodyObj.getString("raw");
apiInfoDTO.setResponseBodyStrutureData(raw);
//转化jsonObje 或者 jsonArray
this.setPreviewData(previewJsonArray, raw);
}
}
// if (bodyObj.containsKey("raw")) {
// String raw = bodyObj.getString("raw");
// apiInfoDTO.setResponseBodyStrutureData(raw);
// }
} else if (StringUtils.equalsAny(type, "Form Data", "WWW_FORM")) {
if (bodyObj.containsKey("kvs")) {
JSONArray bodyParamArr = new JSONArray();
JSONArray kvsArr = bodyObj.getJSONArray("kvs");
for (int i = 0; i < kvsArr.size(); i++) {
JSONObject kv = kvsArr.getJSONObject(i);
if (kv.containsKey("name")) {
bodyParamArr.add(kv);
}
}
apiInfoDTO.setResponseBodyFormData(bodyParamArr.toJSONString());
}
} else if (StringUtils.equals(type, "BINARY")) {
if (bodyObj.containsKey("binary")) {
List<Map<String, String>> bodyParamList = new ArrayList<>();
JSONArray kvsArr = bodyObj.getJSONArray("kvs");
for (int i = 0; i < kvsArr.size(); i++) {
JSONObject kv = kvsArr.getJSONObject(i);
if (kv.containsKey("description") && kv.containsKey("files")) {
Map<String, String> bodyMap = new HashMap<>();
String name = kv.getString("description");
JSONArray fileArr = kv.getJSONArray("files");
String value = "";
for (int j = 0; j < fileArr.size(); j++) {
JSONObject fileObj = fileArr.getJSONObject(j);
if (fileObj.containsKey("name")) {
value += fileObj.getString("name") + " ;";
}
}
bodyMap.put("name", name);
bodyMap.put("value", value);
bodyParamList.add(bodyMap);
}
}
apiInfoDTO.setResponseBodyFormData(JSONArray.toJSONString(bodyParamList));
}
}
}
} catch (Exception e) {
}
}
// 赋值响应码
if (responseJsonObj != null && responseJsonObj.containsKey("statusCode")) {
try {
JSONArray responseStatusDataArr = new JSONArray();
JSONArray statusArr = responseJsonObj.getJSONArray("statusCode");
for (int index = 0; index < statusArr.size(); index++) {
JSONObject statusObj = statusArr.getJSONObject(index);
if (statusObj.containsKey("name") && statusObj.containsKey("value")) {
responseStatusDataArr.add(statusObj);
}
}
apiInfoDTO.setResponseCode(responseStatusDataArr.toJSONString());
} catch (Exception e) {
}
}
}
}
if (!previewJsonArray.isEmpty()) {
apiInfoDTO.setRequestPreviewData(previewJsonArray);
}
apiInfoDTO.setSelectedFlag(true);
return apiInfoDTO;
}
private JSONObject genJSONObject(String request) {
JSONObject returnObj = null;
try {
returnObj = JSONObject.parseObject(request);
} catch (Exception e) {
}
return returnObj;
}
private void setPreviewData(JSONArray previewArray, String data) {
try {
JSONObject previewObj = JSONObject.parseObject(data);
previewArray.add(previewObj);
} catch (Exception e) {
}
try {
previewArray = JSONArray.parseArray(data);
} catch (Exception e) {
}
}
/**
* 生成 api接口文档分享信息

View File

@ -1,12 +1,16 @@
package io.metersphere.api.service;
import com.alibaba.fastjson.JSONArray;
import io.metersphere.api.dto.automation.TcpTreeTableDataStruct;
import io.metersphere.api.dto.automation.parse.TcpTreeTableDataParser;
import io.metersphere.api.dto.definition.SaveApiDefinitionRequest;
import io.metersphere.api.dto.definition.request.sampler.MsTCPSampler;
import io.metersphere.api.dto.scenario.KeyValue;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.plugin.core.MsTestElement;
import io.metersphere.utils.LoggerUtil;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@ -52,7 +56,11 @@ public class TcpApiParamService {
if (testElement instanceof MsTCPSampler) {
tcpSampler = (MsTCPSampler) testElement;
String reportType = tcpSampler.getReportType();
if (StringUtils.isNotEmpty(reportType)) {
if (CollectionUtils.isNotEmpty(tcpSampler.getEsbDataStruct())) {
EsbApiParamService esbApiParamService = CommonBeanFactory.getBean(EsbApiParamService.class);
List<KeyValue> keyValueList = esbApiParamService.genKeyValueListByDataStruct(tcpSampler, JSONArray.toJSONString(tcpSampler.getEsbDataStruct()));
tcpSampler.setParameters(keyValueList);
}else if (StringUtils.isNotEmpty(reportType)) {
switch (reportType) {
case "raw":
tcpSampler.setRequest(tcpSampler.getRawDataStruct());

View File

@ -495,6 +495,9 @@ export default {
if (projectData && projectData.apiQuickMenu === 'api') {
this.handleTabAdd("ADD");
} else {
let newApi = {
};
this.handleTabsEdit(this.$t('api_test.definition.request.fast_debug'), "debug");
}
})

View File

@ -0,0 +1,974 @@
<template>
<div>
<ms-environment-select
:project-id="projectId"
:is-read-only="false"
:useEnvironment='useEnvironment'
@setEnvironment="setEnvironment"
class="ms-api-button"
ref="environmentSelect"/>
<el-tabs v-model="apiDefaultTab" @edit="closeConfirm" class="api-base-view-tab" @tab-click="addTab">
<el-tab-pane name="trash" :label="$t('commons.trash')" v-show="trashEnable">
<api-test-base-container>
<ms-api-module
slot="aside"
:show-operator="true"
@nodeSelectEvent="nodeChange"
@protocolChange="handleProtocolChange"
@refreshTable="refresh"
@exportAPI="exportAPI"
@debug="debug"
@saveAsEdit="editApi"
@setModuleOptions="setModuleOptions"
@setNodeTree="setNodeTree"
@enableTrash="enableTrash"
@schedule="handleTabsEdit($t('api_test.api_import.timing_synchronization'), 'SCHEDULE')"
:type="'edit'"
page-source="definition"
:total='total'
:current-version="currentVersion"
ref="nodeTree"/>
<div slot="mainContainer">
<ms-tab-button
v-if="this.trashTabInfo.type === 'list'"
:active-dom.sync="trashActiveDom"
:left-tip="$t('api_test.definition.api_title')"
:right-tip="$t('api_test.definition.case_title')"
:middle-button-enable="false"
left-content="API"
right-content="CASE"
>
<template v-slot:version>
<version-select v-xpack :project-id="projectId" :version-id="trashVersion"
@changeVersion="changeVersion"/>
</template>
<!-- 列表集合 -->
<ms-api-list
v-if="trashActiveDom==='left'"
@runTest="runTest"
@refreshTree="refreshTree"
@getTrashApi="getTrashApi"
:module-tree="nodeTree"
:module-options="moduleOptions"
:current-protocol="currentProtocol"
:current-version="currentVersion"
:visible="visible"
:currentRow="currentRow"
:select-node-ids="selectNodeIds"
:trash-enable="true"
:queryDataType="queryDataType"
:selectDataRange="selectDataRange"
:is-read-only="isReadOnly"
@changeSelectDataRangeAll="changeSelectDataRangeAll"
@editApi="editApi"
@handleCase="handleCase"
@showExecResult="showExecResult"
@refreshTable="refresh"
:init-api-table-opretion="initApiTableOpretion"
@updateInitApiTableOpretion="updateInitApiTableOpretion"
ref="trashApiList"/>
<!--测试用例列表-->
<api-case-simple-list
v-if="trashActiveDom==='right'"
:current-protocol="currentProtocol"
:current-version="currentVersion"
:visible="visible"
:currentRow="currentRow"
:select-node-ids="selectNodeIds"
:trash-enable="true"
:queryDataType="queryDataType"
:is-read-only="isReadOnly"
@changeSelectDataRangeAll="changeSelectDataRangeAll"
@handleCase="handleCase"
@refreshTable="refresh"
@showExecResult="showExecResult"
ref="trashCaseList"/>
</ms-tab-button>
</div>
</api-test-base-container>
</el-tab-pane>
<el-tab-pane name="default" :label="$t('api_test.definition.api_title')">
<api-test-base-container>
<ms-api-module
slot="aside"
:show-operator="true"
@nodeSelectEvent="nodeChange"
@protocolChange="handleProtocolChange"
@refreshTable="refresh"
@exportAPI="exportAPI"
@debug="debug"
@saveAsEdit="editApi"
@setModuleOptions="setModuleOptions"
@setNodeTree="setNodeTree"
@enableTrash="enableTrash"
@schedule="handleTabsEdit($t('api_test.api_import.timing_synchronization'), 'SCHEDULE')"
:type="'edit'"
page-source="definition"
:total='total'
:current-version="currentVersion"
ref="nodeTree"/>
<div slot="mainContainer">
<ms-tab-button
:active-dom.sync="activeDom"
:left-tip="$t('api_test.definition.api_title')"
:right-tip="$t('api_test.definition.doc_title')"
:middle-tip="$t('api_test.definition.case_title')"
left-content="API"
middle-content="CASE"
:right-content="$t('api_test.definition.doc_title')"
:right-button-enable="currentProtocol === 'HTTP' "
>
<template v-slot:version>
<version-select v-xpack :project-id="projectId" @changeVersion="changeVersion"/>
</template>
<ms-api-list
v-if="activeDom==='left'"
@getTrashApi="getTrashApi"
:module-tree="nodeTree"
:module-options="moduleOptions"
:current-protocol="currentProtocol"
:current-version="currentVersion"
:visible="visible"
:currentRow="currentRow"
:select-node-ids="selectNodeIds"
:trash-enable="false"
:queryDataType="queryDataType"
:selectDataRange="selectDataRange"
:is-read-only="isReadOnly"
@runTest="runTest"
@handleTestCase="handleTestCase"
@refreshTree="refreshTree"
@changeSelectDataRangeAll="changeSelectDataRangeAll"
@editApi="editApi"
@showApi="showApi"
@copyApi="copyApi"
@handleCase="handleCase"
@showExecResult="showExecResult"
@refreshTable="refresh"
:init-api-table-opretion="initApiTableOpretion"
@updateInitApiTableOpretion="updateInitApiTableOpretion"
ref="apiDefList"/>
<!--测试用例列表-->
<api-case-simple-list
v-if="activeDom==='middle'"
:current-protocol="currentProtocol"
:current-version="currentVersion"
:visible="visible"
:currentRow="currentRow"
:select-node-ids="selectNodeIds"
:trash-enable="false"
:queryDataType="queryDataType"
:is-read-only="isReadOnly"
@changeSelectDataRangeAll="changeSelectDataRangeAll"
@handleCase="handleCase"
@refreshTable="refresh"
@showExecResult="showExecResult"
ref="caseList"/>
<api-documents-page
class="api-doc-page"
v-if="activeDom==='right' && currentProtocol==='HTTP'"
:project-id="projectId"
:trash-enable="trashEnable"
:version-id="currentVersion"
:module-ids="selectNodeIds"
ref="documentsPage"/>
</ms-tab-button>
</div>
</api-test-base-container>
</el-tab-pane>
<el-tab-pane v-for="(item) in apiTabs"
:key="item.name"
:label="item.title"
:closable="item.closable"
:name="item.name">
<template v-slot:version>
<version-select v-xpack :project-id="projectId" @changeVersion="changeVersion"/>
</template>
<!-- 列表集合 -->
<!-- 添加/编辑测试窗口-->
<div v-if="item.type=== 'ADD' ||item.type=== 'Case' ||item.type === 'TEST'||item.type === 'debug'"
class="ms-api-div">
<api-info-container :api-id="item.api.id" :current-api="item.api" :project-id="projectId"
:module-options="moduleOptions" :current-protocol="currentProtocol"
@saveApi="saveApi" @updateApiStatus="updateApiStatus" @saveApiAndCase="saveApiAndCase" @saveCaseCallback="saveCaseCallback"
:operation-type="item.api.operationType"></api-info-container>
</div>
<!-- 定时任务 -->
<div v-if="item.type=== 'SCHEDULE'" class="ms-api-div">
<api-schedule :param="param" :module-options="nodeTree" ref="apiSchedules"/>
</div>
</el-tab-pane>
<el-tab-pane name="add" v-if="hasPermission('PROJECT_API_DEFINITION:READ+CREATE_API')">
<template v-slot:label>
<el-dropdown @command="handleCommand">
<el-button type="primary" plain icon="el-icon-plus" size="mini"/>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="debug" v-permission="['PROJECT_API_DEFINITION:READ+DEBUG']">
{{ $t('api_test.definition.request.fast_debug') }}
</el-dropdown-item>
<el-dropdown-item command="ADD" v-permission="['PROJECT_API_DEFINITION:READ+CREATE_API']">
{{ $t('api_test.definition.request.title') }}
</el-dropdown-item>
<el-dropdown-item command="CLOSE_ALL">{{ $t('api_test.definition.request.close_all_label') }}
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</template>
</el-tab-pane>
</el-tabs>
</div>
</template>
<script>
import MsApiModule from "@/business/components/api/definition/components/module/ApiModule";
import ApiTestBaseContainer from "@/business/components/common/layout/ApiTestBaseContainer";
import {getCurrentProjectID, getCurrentUser, getCurrentUserId, getUUID, hasPermission} from "@/common/js/utils";
import MsContainer from "@/business/components/common/components/MsContainer";
import MsApiList from "@/business/components/api/definition/components/list/ApiList";
import MsTabButton from "@/business/components/common/components/MsTabButton";
import VersionSelect from "@/business/components/xpack/version/VersionSelect";
import MsEditCompleteContainer from "@/business/components/api/definition/components/EditCompleteContainer";
import ApiInfoContainer from "@/business/components/api/definition/components/apiinfo/ApiInfoContainer";
import ApiCaseSimpleList from "@/business/components/api/definition/components/list/ApiCaseSimpleList";
import MsEnvironmentSelect from "@/business/components/api/definition/components/case/MsEnvironmentSelect";
import MsDebugHttpPage from "./components/debug/DebugHttpPage";
import MsDebugJdbcPage from "./components/debug/DebugJdbcPage";
import MsDebugTcpPage from "./components/debug/DebugTcpPage";
import MsDebugDubboPage from "./components/debug/DebugDubboPage";
import MsRunTestHttpPage from "./components/runtest/RunTestHTTPPage";
import MsRunTestTcpPage from "./components/runtest/RunTestTCPPage";
import MsRunTestSqlPage from "./components/runtest/RunTestSQLPage";
import MsRunTestDubboPage from "./components/runtest/RunTestDubboPage";
import {createComponent} from "@/business/components/api/definition/components/jmeter/components";
export default {
name: "ApiDefinitionBaseView",
components: {
MsApiModule, ApiTestBaseContainer, MsContainer, MsApiList, MsTabButton, VersionSelect, MsEditCompleteContainer,
MsDebugHttpPage, MsDebugJdbcPage, MsDebugTcpPage, MsDebugDubboPage,
MsRunTestHttpPage, MsRunTestTcpPage, MsRunTestSqlPage, MsRunTestDubboPage,
ApiInfoContainer, ApiCaseSimpleList, MsEnvironmentSelect
},
props: {
visible: {
type: Boolean,
default: false,
},
currentRow: {
type: Object,
}
},
data() {
return {
redirectID: '',
total: 0,
renderComponent: true,
selectDataRange: 'all',
showCasePage: true,
apiDefaultTab: 'default',
currentProtocol: 'HTTP',
currentModule: null,
selectNodeIds: [],
currentApi: {},
moduleOptions: [],
trashEnable: false,
apiTabs: [],
trashTabInfo: {
title: this.$t('api_test.definition.api_title'),
name: 'default',
type: "list",
closable: false
},
activeDom: "left",
trashActiveDom: "left",
syncTabs: [],
nodeTree: [],
currentModulePath: "",
//API
initApiTableOpretion: 'init',
param: {},
useEnvironment: String,
activeTab: "api",
currentVersion: null,
trashVersion: null,
project: null,
};
},
activated() {
},
watch: {
currentProtocol() {
if (this.activeDom === 'right') {
this.activeDom = 'left';
}
this.handleCommand("CLOSE_ALL");
},
selectNodeIds() {
this.apiDefaultTab = "default";
},
redirectID() {
this.renderComponent = false;
this.$nextTick(() => {
// DOM my-component
this.renderComponent = true;
});
},
'$route'(to, from) { // ctrl s
if (to.path.indexOf('/api/definition') === -1) {
if (this.$refs && this.$refs.apiConfig) {
this.$refs.apiConfig.forEach(item => {
item.removeListener();
});
}
}
},
},
created() {
this.initBaseData();
},
mounted() {
},
computed: {
queryDataType: function () {
let routeParam = this.$route.params.dataType;
let redirectIDParam = this.$route.params.redirectID;
this.changeRedirectParam(redirectIDParam);
return routeParam;
},
isReadOnly() {
return false;
},
projectId() {
return getCurrentProjectID();
},
},
methods: {
initBaseData() {
this.$get('/project/get/' + this.projectId, res => {
let projectData = res.data;
if (projectData) {
this.project = projectData;
}
})
},
setEnvironment(data) {
if (data) {
this.useEnvironment = data.id;
this.$store.state.useEnvironment = data.id;
this.addEnv(data.id);
}
},
addEnv(envId) {
this.$post('/api/definition/env/create', {userId: getCurrentUserId(), envId: envId}, response => {
});
},
getTrashApi() {
this.$get("/api/module/trashCount/" + this.projectId + "/" + this.currentProtocol, response => {
this.total = response.data;
});
},
updateApiStatus(operationType, apiName) {
for (let index in this.apiTabs) {
let tab = this.apiTabs[index];
if (tab.name === this.apiDefaultTab) {
tab.api.operationType = operationType;
if (operationType === 'edit') {
tab.title = this.$t('api_test.definition.request.edit_api') + "-" + apiName;
} else {
tab.title = this.$t('api_test.definition.request.show_api') + "-" + apiName;
}
break;
}
}
},
getEnv() {
this.$get("/api/definition/env/get/" + getCurrentUserId() + "/" + getCurrentProjectID(), response => {
let env = response.data;
if (env) {
this.$store.state.useEnvironment = env.envId;
this.useEnvironment = env.envId;
} else {
this.$store.state.useEnvironment = "";
this.useEnvironment = "";
}
});
},
hasPermission,
getPath(id, arr) {
if (id === null) {
return null;
}
if (arr) {
arr.forEach(item => {
if (item.id === id) {
this.currentModulePath = item.path;
}
if (item.children && item.children.length > 0) {
this.getPath(id, item.children);
}
});
}
},
changeRedirectParam(redirectIDParam) {
this.redirectID = redirectIDParam;
},
createApiStruct() {
let request = {};
let method = this.currentProtocol;
let response = {};
if (this.currentProtocol === 'HTTP') {
method = "GET";
request = createComponent("HTTPSamplerProxy");
if (!request.path) {
request.path = "";
}
response.type = "HTTP";
response.headers = [];
response.statusCode = [];
response.body = {
"binary": [],
"json": false,
"kV": false,
"kvs": [],
"oldKV": true,
"type": "KeyValue",
"valid": false,
"xml": false
};
} else if (this.currentProtocol === 'TCP') {
request = createComponent("TCPSampler");
} else if (this.currentProtocol === 'JDBC' || this.currentProtocol === 'SQL') {
request = createComponent("JDBCSampler");
} else if (this.currentProtocol === 'DUBBO') {
request = createComponent("DubboSampler");
}
let newApi = {
id: getUUID(),
operationType: 'debug',
protocol: this.currentProtocol,
environmentId: "",
path: "",
method: method,
request: request,
response: response,
};
return newApi;
},
addTab(tab) {
if (tab.name === 'add') {
if (this.project && this.project.apiQuick === 'api') {
this.handleTabAdd("ADD");
} else {
let newApiStruct = this.createApiStruct();
this.handleTabsEdit(this.$t('api_test.definition.request.fast_debug'), "debug", newApiStruct);
}
} else if (tab.name === 'trash') {
if (this.$refs.trashApiList) {
this.$refs.trashApiList.initTable();
}
if (this.$refs.trashCaseList) {
this.$refs.trashCaseList.initTable();
}
} else if (tab.name === 'default') {
this.refresh();
}
if (this.$refs.apiConfig) {
this.$refs.apiConfig.forEach(item => {
if (item) {
item.removeListener();
}
}); // tab ctrl + s
let tabs = this.apiTabs;
let index = tabs.findIndex(item => item.name === tab.name); // tabindex
if (index !== -1 && this.$refs.apiConfig[index - 1]) {
this.$refs.apiConfig[index - 1].addListener(); // tab ctrl + s index-1tab
}
}
},
handleCommand(e) {
switch (e) {
case "ADD":
this.handleTabAdd(e);
break;
case "TEST":
this.handleTabsEdit(this.$t("commons.api"), e);
break;
case "CLOSE_ALL":
this.handleTabClose();
break;
default:
this.handleTabsEdit(this.$t('api_test.definition.request.fast_debug'), "debug");
break;
}
},
handleApiAndCaseTabAdd(e, api) {
if (!this.projectId) {
this.$warning(this.$t('commons.check_project_tip'));
return;
}
this.currentModulePath = "";
if (this.nodeTree && this.nodeTree.length > 0) {
api.moduleId = this.nodeTree[0].id;
this.getPath(this.nodeTree[0].id, this.moduleOptions);
api.modulePath = this.currentModulePath;
}
if (this.selectNodeIds && this.selectNodeIds.length > 0) {
api.moduleId = this.selectNodeIds[0];
this.getPath(this.selectNodeIds[0], this.moduleOptions);
api.modulePath = this.currentModulePath;
}
this.handleTabsEdit(this.$t('test_track.case.create_case'), e, api);
},
handleTabAdd(e) {
if (!this.projectId) {
this.$warning(this.$t('commons.check_project_tip'));
return;
}
let request = {};
let method = this.currentProtocol;
let response = {};
if (this.currentProtocol === 'HTTP') {
method = "GET";
request = createComponent("HTTPSamplerProxy");
if (!request.path) {
request.path = "";
}
response.type = "HTTP";
response.headers = [];
response.statusCode = [];
response.body = {
"binary": [],
"json": false,
"kV": false,
"kvs": [],
"oldKV": true,
"type": "KeyValue",
"valid": false,
"xml": false
};
} else if (this.currentProtocol === 'TCP') {
request = createComponent("TCPSampler");
} else if (this.currentProtocol === 'JDBC' || this.currentProtocol === 'SQL') {
request = createComponent("JDBCSampler");
} else if (this.currentProtocol === 'DUBBO') {
request = createComponent("DubboSampler");
}
let api = {
status: "Underway",
method: method,
userId: getCurrentUser().id,
url: "",
id: getUUID(),
protocol: this.currentProtocol,
environmentId: "",
remark: "",
operationType: "create",
moduleId: 'default-module',
modulePath: "/" + this.$t("commons.module_title"),
request: request,
response: response
};
this.currentModulePath = "";
if (this.nodeTree && this.nodeTree.length > 0) {
api.moduleId = this.nodeTree[0].id;
this.getPath(this.nodeTree[0].id, this.moduleOptions);
api.modulePath = this.currentModulePath;
}
if (this.selectNodeIds && this.selectNodeIds.length > 0) {
api.moduleId = this.selectNodeIds[0];
this.getPath(this.selectNodeIds[0], this.moduleOptions);
api.modulePath = this.currentModulePath;
}
this.handleTabsEdit(this.$t('api_test.definition.request.title'), e, api);
},
handleTabClose() {
let message = "";
let tab = this.apiTabs;
delete tab[0];
tab.forEach(t => {
if (t.type === 'ADD' && t.api && this.$store.state.apiMap.has(t.api.id) && (this.$store.state.apiMap.get(t.api.id).get("responseChange") === true || this.$store.state.apiMap.get(t.api.id).get("requestChange") === true ||
this.$store.state.apiMap.get(t.api.id).get("fromChange") === true)) {
message += t.api.name + "";
}
});
if (message !== "") {
this.$alert(this.$t('commons.api') + " [ " + message.substr(0, message.length - 1) + " ] " + this.$t('commons.confirm_info'), '', {
confirmButtonText: this.$t('commons.confirm'),
cancelButtonText: this.$t('commons.cancel'),
callback: (action) => {
if (action === 'confirm') {
this.$store.state.apiMap.clear();
this.apiTabs = [];
}
}
});
} else {
this.apiTabs = [];
}
this.apiDefaultTab = "default";
},
closeConfirm(targetName) {
let tab = this.apiTabs;
tab.forEach(t => {
if (t.name === targetName) {
if (t.api && this.$store.state.apiMap.size > 0 && this.$store.state.apiMap.has(t.api.id)) {
if (this.$store.state.apiMap.get(t.api.id).get("responseChange") === true || this.$store.state.apiMap.get(t.api.id).get("requestChange") === true ||
this.$store.state.apiMap.get(t.api.id).get("fromChange") === true) {
this.$alert(this.$t('commons.api') + " [ " + t.api.name + " ] " + this.$t('commons.confirm_info'), '', {
confirmButtonText: this.$t('commons.confirm'),
cancelButtonText: this.$t('commons.cancel'),
callback: (action) => {
if (action === 'confirm') {
this.$store.state.apiMap.delete(t.api.id);
this.handleTabRemove(targetName);
}
}
});
}
} else {
this.handleTabRemove(targetName);
}
}
});
},
handleTabRemove(targetName) {
let tabs = this.apiTabs;
let activeName = this.apiDefaultTab;
if (activeName === targetName) {
tabs.forEach((tab, index) => {
if (tab.name === targetName) {
let nextTab = tabs[index + 1] || tabs[index - 1];
if (nextTab) {
activeName = nextTab.name;
} else {
activeName = "default";
}
}
});
}
this.apiDefaultTab = activeName;
this.apiTabs = tabs.filter(tab => tab.name !== targetName);
this.refresh();
},
//
createRootModel() {
this.$refs.nodeTree.createRootModel();
},
handleMockTabsConfig(targetName, action, param) {
if (!this.projectId) {
this.$warning(this.$t('commons.check_project_tip'));
return;
}
if (targetName === undefined || targetName === null) {
targetName = this.$t('api_test.definition.request.title');
}
let newTabName = getUUID();
this.apiTabs.push({
title: targetName,
name: newTabName,
closable: true,
type: action,
mock: param,
});
this.apiDefaultTab = newTabName;
},
handleTabsEdit(targetName, action, api) {
if (action === "debug" && !api) {
api = this.createApiStruct();
}
if (!this.projectId) {
this.$warning(this.$t('commons.check_project_tip'));
return;
}
if (targetName === undefined || targetName === null) {
targetName = this.$t('api_test.definition.request.title');
}
let newTabName = getUUID();
if(action === "Case"){
newTabName = api.id;
}
this.apiTabs.push({
title: targetName,
name: newTabName,
closable: true,
type: action,
api: api,
});
if (action === "ADD") {
this.activeTab = "api";
}
this.apiDefaultTab = newTabName;
},
debug(id) {
this.handleTabsEdit(this.$t('api_test.definition.request.fast_debug'), "debug", id);
},
init() {
let routeTestCase = this.$route.params.apiDefinition;
if (routeTestCase) {
this.editApi(routeTestCase);
}
let dataRange = this.$route.params.dataSelectRange;
let dataType = this.$route.params.dataType;
if (dataRange) {
let selectParamArr = dataRange.split("edit:");
if (selectParamArr.length === 2) {
let scenarioId = selectParamArr[1];
if (dataType === 'api') {
this.$get('/api/definition/get/' + scenarioId, (response) => {
this.editApi(response.data);
});
}
}
}
},
showApi(row) {
this.editApi(row, true);
},
editApi(row, isShowApi) {
const index = this.apiTabs.find(p => p.api && p.api.id === row.id);
if (!index) {
let name = "";
if (row.isCopy) {
name = "copy" + "_" + row.name;
row.name = "copy" + "_" + row.name;
} else {
if (row.name) {
if (isShowApi) {
name = this.$t('api_test.definition.request.show_api') + "-" + row.name;
} else {
name = this.$t('api_test.definition.request.edit_api') + "-" + row.name;
}
} else {
name = this.$t('api_test.definition.request.title');
}
}
this.activeTab = "api";
if (row !== null && row.tags !== 'null' && row.tags !== '' && row.tags !== undefined) {
if (Object.prototype.toString.call(row.tags).match(/\[object (\w+)\]/)[1].toLowerCase() !== 'object'
&& Object.prototype.toString.call(row.tags).match(/\[object (\w+)\]/)[1].toLowerCase() !== 'array') {
row.tags = JSON.parse(row.tags);
}
}
if (isShowApi) {
row.operationType = "show";
} else {
row.operationType = "edit";
}
this.handleTabsEdit(name, "ADD", row);
} else {
this.apiDefaultTab = index.name;
}
},
copyApi(row) {
let name = "";
if (row.isCopy) {
name = "copy" + "_" + row.name;
row.name = "copy" + "_" + row.name;
}
this.activeTab = "api";
if (row !== null && row.tags !== 'null' && row.tags !== '' && row.tags !== undefined) {
if (Object.prototype.toString.call(row.tags).match(/\[object (\w+)\]/)[1].toLowerCase() !== 'object'
&& Object.prototype.toString.call(row.tags).match(/\[object (\w+)\]/)[1].toLowerCase() !== 'array') {
row.tags = JSON.parse(row.tags);
}
}
this.handleTabsEdit(name, "ADD", row);
},
handleCase(api) {
this.currentApi = api;
this.showCasePage = false;
},
apiCaseClose() {
this.showCasePage = true;
},
exportAPI(type, nodeTree) {
if (this.activeDom !== 'left') {
this.$warning('用例列表暂不支持导出,请切换成接口列表');
return;
}
this.$refs.apiDefList[0].exportApi(type, nodeTree);
},
refreshModule() {
this.$refs.nodeTree.list();
},
refresh(data) {
if (this.$refs.caseList && this.$refs.caseList[0]) {
this.$refs.caseList[0].initTable();
}
if (this.$refs.trashApiList) {
this.$refs.trashApiList.initTable();
}
if (this.$refs.trashCaseList) {
this.$refs.trashCaseList.initTable();
}
if (this.$refs.nodeTree) {
this.$refs.nodeTree.list();
}
if (this.$refs.apiDefList) {
if (this.$refs.apiDefList[0]) {
this.$refs.apiDefList[0].initTable();
} else {
this.$refs.apiDefList.initTable();
}
}
if (this.$refs.documentsPage && this.$refs.documentsPage[0]) {
this.$refs.documentsPage[0].initApiDocSimpleList();
}
//this.$refs.nodeTree.list();
},
refreshTree() {
this.$refs.nodeTree.list();
},
setTabTitle(data) {
for (let index in this.apiTabs) {
let tab = this.apiTabs[index];
if (tab.name === this.apiDefaultTab) {
tab.api.operationType = "show";
tab.api.request = JSON.stringify(data.request);
tab.api.response = JSON.stringify(data.response);
tab.api.method = data.method;
tab.title = this.$t('api_test.definition.request.show_api') + "-" + data.name;
break;
}
}
},
runTest(data) {
this.activeTab = "test";
this.handleTabsEdit(this.$t("commons.api"), "TEST", data);
this.setTabTitle(data);
},
handleTestCase(row) {
this.activeTab = "testCase";
let name = "";
if (row.name) {
name = this.$t('api_test.definition.request.edit_api') + "-" + row.name;
} else {
name = this.$t('api_test.definition.request.title');
}
if (row !== null && row.tags !== 'null' && row.tags !== '' && row.tags !== undefined) {
if (Object.prototype.toString.call(row.tags).match(/\[object (\w+)\]/)[1].toLowerCase() !== 'object'
&& Object.prototype.toString.call(row.tags).match(/\[object (\w+)\]/)[1].toLowerCase() !== 'array') {
row.tags = JSON.parse(row.tags);
}
}
this.handleTabsEdit(name, "TEST", row);
},
mockConfig(data) {
let targetName = this.$t("commons.mock") + "-" + data.apiName;
this.handleMockTabsConfig(targetName, "MOCK", data);
},
saveApi(data) {
this.setTabTitle(data);
},
showExecResult(row) {
this.debug(row);
},
nodeChange(node, nodeIds, pNodes) {
this.initApiTableOpretion = "selectNodeIds";
this.selectNodeIds = nodeIds;
},
handleProtocolChange(protocol) {
this.initApiTableOpretion = "currentProtocol";
this.currentProtocol = protocol;
},
setModuleOptions(data) {
this.moduleOptions = data;
},
setNodeTree(data) {
this.nodeTree = data;
},
changeSelectDataRangeAll(tableType) {
this.$route.params.dataSelectRange = 'all';
},
enableTrash(data) {
this.initApiTableOpretion = "trashEnable";
this.trashEnable = data;
this.trashVersion = this.currentVersion
if (data) {
this.apiDefaultTab = "trash";
} else {
this.apiDefaultTab = "default";
}
},
updateInitApiTableOpretion(param) {
this.initApiTableOpretion = param;
},
changeVersion(currentVersion) {
this.trashVersion = null;
this.currentVersion = currentVersion || null;
},
saveApiAndCase(apiStruct) {
apiStruct.operationType = "addApiAndCase";
apiStruct.id = getUUID();
this.handleApiAndCaseTabAdd("Case", apiStruct);
},
saveCaseCallback(apiStruct){
this.closeConfirm(apiStruct.id);
}
}
};
</script>
<style scoped>
.ms-api-div {
overflow-y: auto;
height: calc(100vh - 125px)
}
/deep/ .el-main {
overflow: hidden;
}
/deep/ .api-base-view-tab > .el-tabs__header {
width: calc(100% - 230px);
margin: 0px 5px 0px 5px
}
/deep/ .api-base-view-tab > .el-tabs__nav-scroll {
width: calc(100% - 10px);
}
/deep/ .el-card {
border-top: none;
}
/deep/ .api-component {
margin-top: 10px;
}
.ms-api-button {
position: absolute;
top: 86px;
right: 10px;
padding: 0;
background: 0 0;
border: none;
outline: 0;
cursor: pointer;
margin-right: 10px;
font-size: 16px;
z-index: 1;
}
/deep/ .el-table__empty-block {
width: 100%;
min-width: 100%;
max-width: 100%;
padding-right: 100%;
}
.version-select {
padding-left: 10px;
}
</style>

View File

@ -0,0 +1,314 @@
<template>
<div v-if="operationType === 'edit' || operationType === 'create'|| operationType === 'debug'">
<api-definition-edit v-loading="loading" :api="currentApi" :module-options="moduleOptions"
:protocol="protocol" :project-id="projectId" :is-edit="operationType !== 'debug'"
@saveApiAndCase="saveApiAndCase" @saveApi="saveApi"/>
</div>
<div v-else-if="operationType === 'addApiAndCase'">
<api-case-edit v-loading="loading" :api="currentApi" :module-options="moduleOptions"
:protocol="protocol" :project-id="projectId" :is-edit="operationType !== 'debug'"
@saveApi="saveApiBeforeCase"/>
</div>
<div v-else>
<api-definition-information v-show="apiInfo && apiInfo.id" v-loading="loading"
:api-id="apiId"
:project-id="projectId" :current-protocol="protocol"
:current-api="currentApi" :api-info="apiInfo"
@editApi="editApi"
/>
</div>
</template>
<script>
import ApiTestBaseContainer from "@/business/components/common/layout/ApiTestBaseContainer";
import ApiInformation from "@/business/components/api/definition/components/document/components/ApiInformation";
import ApiDefinitionEdit from "@/business/components/api/definition/components/apiinfo/edit/ApiDefinitionEdit";
import ApiDefinitionInformation
from "@/business/components/api/definition/components/apiinfo/information/ApiDefinitionInformation";
import {getUUID} from "@/common/js/utils";
import ApiBaseInfo from "@/business/components/api/definition/components/apiinfo/edit/ApiBaseInfo";
import ApiTestInfo from "@/business/components/api/definition/components/apiinfo/edit/ApiTestInfo";
import {TYPE_TO_C} from "@/business/components/api/automation/scenario/Setting";
import ApiCaseEdit from "@/business/components/api/definition/components/apiinfo/edit/ApiCaseEdit";
export default {
name: "ApiInfoContainer",
components: {
ApiTestInfo,
ApiBaseInfo,
ApiDefinitionInformation,
ApiTestBaseContainer,
ApiInformation,
ApiDefinitionEdit,
ApiCaseEdit
},
props: {
isEdit: Boolean,
operationType: String,
apiId: String,
projectId: String,
currentApi: {},
currentProtocol: String,
moduleOptions: [],
},
data() {
return {
apiInfo: {},
api: {},
loading: true,
protocol: "",
apiIsEditing: false,
}
},
created() {
this.initData();
},
watch: {
operationType() {
this.initData();
}
},
methods: {
editApi() {
this.$emit("updateApiStatus", "edit", this.api.name);
},
initData() {
this.loading = true;
if (this.operationType === "debug" || this.operationType === "create") {
this.protocol = this.currentApi.protocol;
this.loading = false;
} else if (this.operationType === 'addApiAndCase') {
this.protocol = this.currentApi.protocol;
this.loading = false;
} else if (this.apiId) {
this.$get("/api/definition/get/apiDetail/" + this.apiId, response => {
if (response.data) {
if (response.data.apiInfo) {
this.apiInfo = response.data.apiInfo;
}
if (response.data.apiDefinition) {
this.api = response.data.apiDefinition;
this.protocol = this.api.protocol;
}
}
this.loading = false;
}, () => {
this.loading = false;
});
} else {
this.loading = false;
}
},
saveApi(apiStruct) {
let bodyFiles = this.getBodyUploadFiles(apiStruct);
apiStruct.requestId = apiStruct.request.id;
if (apiStruct.request) {
//
if (apiStruct.request.authManager) {
apiStruct.request.authManager.clazzName = TYPE_TO_C.get("AuthManager");
}
this.sort(apiStruct.request.hashTree);
}
this.setParameter(apiStruct);
let reqUrl = "/api/definition/update";
if (apiStruct.operationType === 'create') {
reqUrl = "/api/definition/create";
}
this.loading = true;
this.$fileUpload(reqUrl, null, bodyFiles, apiStruct, (response) => {
this.$success(this.$t('commons.save_success'));
this.currentApi.isCopy = false;
// apiidref_id id
apiStruct.id = response.data.id;
apiStruct.remark = response.data.remark;
this.loading = false;
if (!this.apiId) {
this.apiId = apiStruct.id;
}
this.$nextTick(() => {
this.$emit('saveApi', apiStruct);
});
}, () => {
this.loading = false;
});
},
saveApiAndCase(apiStruct) {
this.$emit("saveApiAndCase", apiStruct);
},
sort(stepArray) {
if (stepArray) {
for (let i in stepArray) {
if (!stepArray[i].clazzName) {
stepArray[i].clazzName = TYPE_TO_C.get(stepArray[i].type);
}
if (stepArray[i].type === "Assertions" && !stepArray[i].document) {
stepArray[i].document = {
type: "JSON",
data: {xmlFollowAPI: false, jsonFollowAPI: false, json: [], xml: []}
};
}
if (stepArray[i].hashTree && stepArray[i].hashTree.length > 0) {
this.sort(stepArray[i].hashTree);
}
}
}
},
saveApiBeforeCase(api) {
let apiData = JSON.parse(JSON.stringify(api));
let apiCase = JSON.parse(JSON.stringify(api));
apiData.moduleId = module;
apiData.modulePath = "/" + this.$t('commons.module_title');
this.setParameter(apiData);
let bodyFiles = this.getBodyUploadFiles(apiData);
apiData.response = null;
this.loading = true;
this.$fileUpload("/api/definition/create", null, bodyFiles, apiData, () => {
apiCase.apiDefinitionId = apiData.id;
apiCase.id = getUUID();
apiCase.name = apiData.name;
apiCase.priority = this.currentApi.priority;
apiCase.tags = apiData.tags;
apiCase.description = apiData.description;
this.saveCase(apiCase, api);
}, () => {
this.loading = false;
});
},
saveCase(newCase, api) {
let tmp = newCase;
tmp.request.body = newCase.request.body;
let bodyFiles = this.getBodyUploadFiles(tmp);
tmp.projectId = this.projectId;
tmp.active = true;
tmp.request.id = getUUID();
tmp.id = tmp.request.id;
tmp.request.path = this.api.path;
tmp.versionId = this.api.versionId;
if (tmp.request.protocol !== "dubbo://" && tmp.request.protocol !== "DUBBO") {
tmp.request.method = this.api.method;
}
if (tmp.request.esbDataStruct != null) {
tmp.esbDataStruct = JSON.stringify(tmp.request.esbDataStruct);
}
if (tmp.request.backEsbDataStruct != null) {
tmp.backEsbDataStruct = JSON.stringify(tmp.request.backEsbDataStruct);
}
if (tmp.tags instanceof Array) {
tmp.tags = JSON.stringify(tmp.tags);
} else if (!tmp.tags || tmp.tags === "") {
tmp.tags = "[]";
}
if (tmp.request) {
tmp.request.clazzName = TYPE_TO_C.get(tmp.request.type);
if (tmp.request.authManager) {
tmp.request.authManager.clazzName = TYPE_TO_C.get(tmp.request.authManager.type);
}
this.sort(tmp.request.hashTree);
}
if (tmp.response) {
tmp.response = JSON.stringify(tmp.response);
}
let url = "/api/testcase/create";
this.result = this.$fileUpload(url, null, bodyFiles, tmp, (response) => {
this.$success(this.$t('commons.save_success'));
this.$emit("saveCaseCallback", api);
this.loading = false;
}, (error) => {
this.loading = false;
});
},
setParameter(apiStruct) {
apiStruct.name = this.currentApi.name;
apiStruct.moduleId = this.currentApi.moduleId;
apiStruct.userId = this.currentApi.userId;
apiStruct.status = this.currentApi.status;
apiStruct.tags = this.currentApi.tags;
apiStruct.description = this.currentApi.description;
if (!apiStruct.isCopy) {
apiStruct.isCopy = false;
}
if (apiStruct.request) {
if (apiStruct.protocol !== "DUBBO") {
apiStruct.request.method = apiStruct.method;
}
apiStruct.request.path = apiStruct.path;
apiStruct.request.useEnvironment = undefined;
}
if (!apiStruct.follows) {
apiStruct.follows = [];
}
if (apiStruct.tags instanceof Array) {
apiStruct.tags = JSON.stringify(apiStruct.tags);
}
if (!apiStruct.method) {
apiStruct.method = this.currentProtocol;
}
apiStruct.projectId = this.projectId;
apiStruct.request.name = this.currentApi.name;
apiStruct.protocol = this.currentProtocol;
if (this.currentProtocol === "DUBBO" || this.currentProtocol === "dubbo://") {
apiStruct.request.protocol = "dubbo://";
} else {
apiStruct.request.protocol = this.currentProtocol;
}
if (apiStruct.isCopy) {
apiStruct.id = this.apiId;
} else {
if (apiStruct.id) {
apiStruct.request.id = apiStruct.id;
} else {
apiStruct.id = apiStruct.request.id;
}
}
if (this.currentProtocol !== 'HTTP') {
apiStruct.response = null;
}
},
getBodyUploadFiles(data) {
let bodyUploadFiles = [];
data.bodyUploadIds = [];
let request = data.request;
if (request.body) {
if (request.body.kvs) {
request.body.kvs.forEach(param => {
if (param.files) {
param.files.forEach(item => {
if (item.file) {
item.name = item.file.name;
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;
},
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,166 @@
<template>
<!-- 基础信息 -->
<div class="base-info">
<el-card class="box-card" style="border: 0px">
<div slot="header" class="clearfix">
<span>{{ $t('test_track.plan_view.base_info') }}</span>
</div>
<div>
<el-form :model="api" :rules="rule" ref="httpForm" label-width="80px" label-position="left">
<!--模块-->
<el-row>
<el-col>
<el-form-item :label="$t('test_track.module.module')" prop="moduleId">
<ms-select-tree size="small" :data="moduleOptions" :defaultKey="api.moduleId" @getValue="setModule" :disabled="true"
:obj="moduleObj" clearable checkStrictly/>
</el-form-item>
</el-col>
</el-row>
<!--名称-->
<el-row>
<el-col>
<el-form-item :label="$t('commons.name')" prop="name">
<el-input class="ms-http-input" size="small" v-model="api.name"/>
</el-form-item>
</el-col>
</el-row>
<!--责任人-->
<el-row>
<el-col>
<el-form-item :label="$t('api_test.definition.request.responsible')" prop="userId">
<el-select v-model="api.userId"
:placeholder="$t('api_test.definition.request.responsible')" filterable size="small"
class="ms-http-select">
<el-option
v-for="item in maintainerOptions"
:key="item.id"
:label="item.name + ' (' + item.id + ')'"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<!--状态-->
<el-row>
<el-col>
<el-form-item :label="$t('commons.status')" prop="status">
<el-select class="ms-http-select" size="small" v-model="api.status">
<el-option v-for="item in options" :key="item.id" :label="$t(item.label)" :value="item.id"/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<!--用例等级-->
<el-row>
<el-form-item :label="$t('api_test.automation.case_level')" prop="priority">
<el-select size="mini" v-model="api.priority" class="ms-api-select">
<el-option v-for="grd in priorities" :key="grd.id" :label="grd.name" :value="grd.id"/>
</el-select>
</el-form-item>
</el-row>
<!--标签-->
<el-row>
<el-col>
<el-form-item :label="$t('commons.tag')" prop="tag" class="not-unique-form-item">
<ms-input-tag :currentScenario="api" ref="tag" v-model="api.tags"/>
</el-form-item>
</el-col>
</el-row>
<!--描述-->
<el-row>
<el-col>
<el-form-item :label="$t('commons.description')" prop="description" class="not-unique-form-item">
<el-input class="ms-http-textarea"
v-model="api.description"
type="textarea"
:autosize="{ minRows: 1, maxRows: 10}"
:rows="1" size="small"/>
</el-form-item>
</el-col>
</el-row>
</el-form>
</div>
</el-card>
</div>
</template>
<script>
import {getCurrentProjectID} from "@/common/js/utils";
import {API_STATUS, PRIORITY, REQ_METHOD} from "@/business/components/api/definition/model/JsonData";
import MsSelectTree from "@/business/components/common/select-tree/SelectTree";
import MsInputTag from "@/business/components/api/automation/scenario/MsInputTag";
export default {
name: "ApiBaseCaseInfo",
components: {MsSelectTree, MsInputTag},
props: {
api: {},
moduleOptions: [],
isCase: Boolean,
currentProtocol: String,
},
data() {
let validateURL = (rule, value, callback) => {
if (!this.httpForm.path.startsWith("/") || this.httpForm.path.match(/\s/) != null) {
callback(this.$t('api_test.definition.request.path_valid_info'));
}
callback();
};
return {
rule: {
name: [
{required: true, message: this.$t('test_track.case.input_name'), trigger: 'blur'},
{max: 100, message: this.$t('test_track.length_less_than') + '100', trigger: 'blur'}
],
path: [{required: true, message: this.$t('api_test.definition.request.path_info'), trigger: 'blur'}, {
validator: validateURL,
trigger: 'blur'
}],
priority: [{required: true, message: this.$t('test_track.case.input_priority'), trigger: 'change'}],
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'}],
},
maintainerOptions: [],
reqOptions: REQ_METHOD,
options: API_STATUS,
priorities: PRIORITY,
moduleObj: {
id: 'id',
label: 'name',
},
}
},
created() {
this.getMaintainerOptions();
},
methods: {
getMaintainerOptions() {
this.$post('/user/project/member/tester/list', {projectId: getCurrentProjectID()}, response => {
this.maintainerOptions = response.data;
});
},
setModule(id, data) {
this.api.moduleId = id;
this.api.modulePath = data.path;
},
validateForm(){
let validateResult = false;
this.$refs['httpForm'].validate((valid) => {
validateResult = valid;
});
return validateResult;
}
}
}
</script>
<style scoped>
/deep/ .not-unique-form-item > .el-form-item__label {
width: 62px !important;
margin-left: 8px;
}
</style>

View File

@ -0,0 +1,155 @@
<template>
<!-- 基础信息 -->
<div class="base-info">
<el-card class="box-card" style="border: 0px">
<div slot="header" class="clearfix">
<span>{{ $t('test_track.plan_view.base_info') }}</span>
</div>
<div>
<el-form :model="api" :rules="rule" ref="httpForm" label-width="70px" label-position="left">
<!--名称-->
<el-row>
<el-col>
<el-form-item :label="$t('commons.name')" prop="name">
<el-input class="ms-http-input" size="small" v-model="api.name"/>
</el-form-item>
</el-col>
</el-row>
<!--模块-->
<el-row>
<el-col>
<el-form-item :label="$t('test_track.module.module')" prop="moduleId">
<ms-select-tree size="small" :data="moduleOptions" :defaultKey="api.moduleId" @getValue="setModule"
:obj="moduleObj" clearable checkStrictly/>
</el-form-item>
</el-col>
</el-row>
<!--责任人-->
<el-row>
<el-col>
<el-form-item :label="$t('api_test.definition.request.responsible')" prop="userId">
<el-select v-model="api.userId"
:placeholder="$t('api_test.definition.request.responsible')" filterable size="small"
class="ms-http-select">
<el-option
v-for="item in maintainerOptions"
:key="item.id"
:label="item.name + ' (' + item.id + ')'"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<!--状态-->
<el-row>
<el-col>
<el-form-item :label="$t('commons.status')" prop="status">
<el-select class="ms-http-select" size="small" v-model="api.status">
<el-option v-for="item in options" :key="item.id" :label="$t(item.label)" :value="item.id"/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<!--标签-->
<el-row>
<el-col>
<el-form-item :label="$t('commons.tag')" prop="tag" class="not-unique-form-item">
<ms-input-tag :currentScenario="api" ref="tag" v-model="api.tags"/>
</el-form-item>
</el-col>
</el-row>
<!--描述-->
<el-row>
<el-col>
<el-form-item :label="$t('commons.description')" prop="description" class="not-unique-form-item">
<el-input class="ms-http-textarea"
v-model="api.description"
type="textarea"
:autosize="{ minRows: 1, maxRows: 10}"
:rows="1" size="small"/>
</el-form-item>
</el-col>
</el-row>
</el-form>
</div>
</el-card>
</div>
</template>
<script>
import {getCurrentProjectID} from "@/common/js/utils";
import {API_STATUS, REQ_METHOD} from "@/business/components/api/definition/model/JsonData";
import MsSelectTree from "@/business/components/common/select-tree/SelectTree";
import MsInputTag from "@/business/components/api/automation/scenario/MsInputTag";
export default {
name: "ApiBaseInfo",
components: {MsSelectTree, MsInputTag},
props: {
api: {},
moduleOptions: [],
isCase: Boolean,
currentProtocol: String,
},
data() {
let validateURL = (rule, value, callback) => {
if (!this.httpForm.path.startsWith("/") || this.httpForm.path.match(/\s/) != null) {
callback(this.$t('api_test.definition.request.path_valid_info'));
}
callback();
};
return {
rule: {
name: [
{required: true, message: this.$t('test_track.case.input_name'), trigger: 'blur'},
{max: 100, message: this.$t('test_track.length_less_than') + '100', trigger: 'blur'}
],
path: [{required: true, message: this.$t('api_test.definition.request.path_info'), trigger: 'blur'}, {
validator: validateURL,
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'}],
},
maintainerOptions: [],
reqOptions: REQ_METHOD,
options: API_STATUS,
moduleObj: {
id: 'id',
label: 'name',
},
}
},
created() {
this.getMaintainerOptions();
},
methods: {
getMaintainerOptions() {
this.$post('/user/project/member/tester/list', {projectId: getCurrentProjectID()}, response => {
this.maintainerOptions = response.data;
});
},
setModule(id, data) {
this.api.moduleId = id;
this.api.modulePath = data.path;
},
validateForm(){
let validateResult = false;
this.$refs['httpForm'].validate((valid) => {
validateResult = valid;
});
return validateResult;
}
}
}
</script>
<style scoped>
/deep/ .not-unique-form-item > .el-form-item__label {
width: 62px !important;
margin-left: 8px;
}
</style>

View File

@ -0,0 +1,49 @@
<template>
<api-test-base-container :show-aside="isEdit">
<template v-slot:aside>
<api-base-case-info :api="api" :module-options="moduleOptions" ref="apiBaseInfo"/>
</template>
<template v-slot:mainContainer>
<api-test-info :project-id="projectId" :current-protocol="protocol" :api="api" :is-edit="isEdit"
@saveApiAndCase="saveApiAndCase"
@saveApi="saveApi"></api-test-info>
</template>
</api-test-base-container>
</template>
<script>
import ApiTestBaseContainer from "@/business/components/common/layout/ApiTestBaseContainer";
import ApiBaseInfo from "@/business/components/api/definition/components/apiinfo/edit/ApiBaseInfo";
import ApiTestInfo from "@/business/components/api/definition/components/apiinfo/edit/ApiTestInfo";
import ApiBaseCaseInfo from "@/business/components/api/definition/components/apiinfo/edit/ApiBaseCaseInfo";
export default {
name: "ApiCaseEdit",
components: {
ApiBaseCaseInfo,
ApiTestBaseContainer, ApiBaseInfo, ApiTestInfo
},
props: {
api: {},
moduleOptions: [],
projectId: String,
protocol: String,
isEdit:Boolean,
},
methods: {
saveApi(apiStruct) {
let baseInfoCheck = this.$refs.apiBaseInfo.validateForm();
if(baseInfoCheck){
this.$emit("saveApi", apiStruct);
}
},
saveApiAndCase(apiStruct){
this.$emit("saveApiAndCase",apiStruct);
}
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,48 @@
<template>
<api-test-base-container :show-aside="isEdit">
<template v-slot:aside>
<api-base-info :api="api" :module-options="moduleOptions" :current-protocol="protocol" ref="apiBaseInfo"></api-base-info>
</template>
<template v-slot:mainContainer>
<api-test-info :project-id="projectId" :current-protocol="protocol" :api="api" :is-edit="isEdit"
@saveApiAndCase="saveApiAndCase"
@saveApi="saveApi"></api-test-info>
</template>
</api-test-base-container>
</template>
<script>
import ApiTestBaseContainer from "@/business/components/common/layout/ApiTestBaseContainer";
import ApiBaseInfo from "@/business/components/api/definition/components/apiinfo/edit/ApiBaseInfo";
import ApiTestInfo from "@/business/components/api/definition/components/apiinfo/edit/ApiTestInfo";
export default {
name: "ApiDefinitionEdit",
components: {
ApiTestBaseContainer, ApiBaseInfo, ApiTestInfo
},
props: {
api: {},
moduleOptions: [],
projectId: String,
protocol: String,
isEdit:Boolean,
isLoading:Boolean,
},
methods: {
saveApi(apiStruct) {
let baseInfoCheck = this.$refs.apiBaseInfo.validateForm();
if(baseInfoCheck){
this.$emit("saveApi", apiStruct);
}
},
saveApiAndCase(apiStruct){
this.$emit("saveApiAndCase",apiStruct);
}
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,229 @@
<template>
<div style="margin:5px 5px 5px 5px">
<http-base-info
:syncTabs="syncTabs"
:currentProtocol="currentProtocol"
:api-data="api"
:project-id="projectId"
:is-edit="isEdit"
@refresh="refresh"
@saveApiAndCase="saveApiAndCase"
ref="httpTestPage"
v-if="currentProtocol==='HTTP'">
<template v-slot:rightHeader>
<div v-show="isEdit" class="ms-opt-btn">
<el-button type="primary" size="small" @click="saveApi" title="ctrl + s"
v-permission="['PROJECT_API_DEFINITION:READ+EDIT_API']">{{ $t('commons.save') }}
</el-button>
</div>
</template>
</http-base-info>
<tcp-base-info
:syncTabs="syncTabs"
:currentProtocol="currentProtocol"
:api-data="api"
:project-id="projectId"
:is-edit="isEdit"
@refresh="refresh"
@saveApiAndCase="saveApiAndCase"
ref="tcpTestPage"
v-else-if="currentProtocol==='TCP'"
>
<template v-slot:rightHeader>
<div v-show="isEdit" class="ms-opt-btn">
<el-button type="primary" size="small" @click="saveApi" title="ctrl + s"
v-permission="['PROJECT_API_DEFINITION:READ+EDIT_API']">{{ $t('commons.save') }}
</el-button>
</div>
</template>
</tcp-base-info>
<sql-base-info
:syncTabs="syncTabs"
:currentProtocol="currentProtocol"
:api-data="api"
:project-id="projectId"
:is-edit="isEdit"
@refresh="refresh"
@saveApiAndCase="saveApiAndCase"
ref="sqlTestPage"
v-else-if="currentProtocol==='SQL'"
>
<template v-slot:rightHeader>
<div v-show="isEdit" class="ms-opt-btn">
<el-button type="primary" size="small" @click="saveApi" title="ctrl + s"
v-permission="['PROJECT_API_DEFINITION:READ+EDIT_API']">{{ $t('commons.save') }}
</el-button>
</div>
</template>
</sql-base-info>
<dubbo-base-info
:syncTabs="syncTabs"
:currentProtocol="currentProtocol"
:api-data="api"
:project-id="projectId"
:is-edit="isEdit"
ref="dubboTestPage"
@saveApiAndCase="saveApiAndCase"
@refresh="refresh"
v-else-if="currentProtocol==='DUBBO'"
>
<template v-slot:rightHeader>
<div v-show="isEdit" class="ms-opt-btn">
<el-button type="primary" size="small" @click="saveApi" title="ctrl + s"
v-permission="['PROJECT_API_DEFINITION:READ+EDIT_API']">{{ $t('commons.save') }}
</el-button>
</div>
</template>
</dubbo-base-info>
</div>
</template>
<script>
import HttpBaseInfo from "@/business/components/api/definition/components/apiinfo/edit/compnents/HttpBaseInfo";
import TcpBaseInfo from "@/business/components/api/definition/components/apiinfo/edit/compnents/TcpBaseInfo";
import SqlBaseInfo from "@/business/components/api/definition/components/apiinfo/edit/compnents/SqlBaseInfo";
import DubboBaseInfo from "@/business/components/api/definition/components/apiinfo/edit/compnents/DubboBaseInfo";
import {TYPE_TO_C} from "@/business/components/api/automation/scenario/Setting";
import _ from 'lodash';
import {Body} from "@/business/components/api/definition/model/ApiTestModel";
export default {
name: "ApiTestInfo",
components: {HttpBaseInfo, TcpBaseInfo, SqlBaseInfo, DubboBaseInfo},
props: {
api: {},
projectId: String,
currentProtocol: String,
syncTabs: Array,
isEdit: Boolean,
},
data() {
return {
formCheckResult: false,
}
},
created() {
this.formatApi();
},
methods: {
refresh() {
this.$emit("refresh");
},
formatApi() {
if (this.api.request !== null && this.api.request !== 'null' && this.api.request !== undefined) {
if (Object.prototype.toString.call(this.api.request).match(/\[object (\w+)\]/)[1].toLowerCase() !== 'object') {
this.api.request = JSON.parse(this.api.request);
if (this.currentProtocol === 'HTTP') {
if (this.api.request.body && !this.api.request.body.type) {
let tempRequest = _.cloneDeep(this.api.request);
tempRequest.body = {type: null};
this.api.request = tempRequest;
}
}
}
}
if (this.api && this.api.request && !this.api.request.hashTree) {
this.api.request.hashTree = [];
}
if (this.currentProtocol === "HTTP") {
if (this.api && this.api.request && this.api.request.body && !this.api.request.body.binary) {
this.api.request.body.binary = [];
}
}
if (this.currentProtocol === "TCP" || this.currentProtocol === "SQL") {
if (this.api && this.api.request && !this.api.request.variables) {
this.api.request.variables = [];
}
}
if (this.api.request) {
this.api.request.clazzName = TYPE_TO_C.get(this.api.request.type);
this.sort(this.api.request.hashTree);
}
if (this.api.response !== null && this.api.response !== 'null' && this.api.response !== undefined) {
if (Object.prototype.toString.call(this.api.response).match(/\[object (\w+)\]/)[1].toLowerCase() !== 'object') {
this.api.response = JSON.parse(this.api.response);
}
} else {
this.api.response = {headers: [], body: new Body(), statusCode: [], type: "HTTP"};
}
//
if (this.api.response.body) {
let body = new Body();
Object.assign(body, this.api.response.body);
if (!body.binary) {
body.binary = [];
}
if (!body.kvs) {
body.kvs = [];
}
if (!body.binary) {
body.binary = [];
}
this.api.response.body = body;
}
},
sort(stepArray) {
if (stepArray) {
for (let i in stepArray) {
if (!stepArray[i].clazzName) {
stepArray[i].clazzName = TYPE_TO_C.get(stepArray[i].type);
}
if (stepArray[i].type === "Assertions" && !stepArray[i].document) {
stepArray[i].document = {
type: "JSON",
data: {xmlFollowAPI: false, jsonFollowAPI: false, json: [], xml: []}
};
}
if (stepArray[i].hashTree && stepArray[i].hashTree.length > 0) {
this.sort(stepArray[i].hashTree);
}
}
}
},
getApi() {
this.formCheckResult = false;
let newApiInfo = null;
if (this.currentProtocol === 'HTTP' && this.$refs.httpTestPage) {
this.formCheckResult = this.$refs.httpTestPage.validateForm();
newApiInfo = this.$refs.httpTestPage.getApi();
} else if (this.currentProtocol === 'TCP' && this.$refs.tcpTestPage) {
this.formCheckResult = true;
newApiInfo = this.$refs.tcpTestPage.getApi();
} else if (this.currentProtocol === 'SQL' && this.$refs.sqlTestPage) {
this.formCheckResult = true;
newApiInfo = this.$refs.sqlTestPage.getApi();
} else if (this.currentProtocol === 'DUBBO' && this.$refs.dubboTestPage) {
this.formCheckResult = true;
newApiInfo = this.$refs.dubboTestPage.getApi();
}
return newApiInfo;
},
saveApi() {
let newApiInfo = this.getApi();
if (this.formCheckResult && newApiInfo) {
newApiInfo.path = newApiInfo.request.path;
this.$emit("saveApi", newApiInfo);
}
},
saveApiAndCase(apiStruct) {
this.$emit("saveApiAndCase", apiStruct);
},
},
}
</script>
<style scoped>
/deep/ .ms-opt-btn {
position: fixed;
right: 50px;
z-index: 1;
top: 128px;
float: right;
margin-right: 20px;
margin-top: 5px;
}
</style>

View File

@ -0,0 +1,330 @@
<template>
<div class="card-container">
<div v-if="versionEnable">
<slot name="rightHeader"></slot>
</div>
<el-card class="card-content">
<div>
<p class="tip" style="display: inline-block">{{ $t('api_test.definition.request.req_param') }} </p>
<el-button size="small" type="primary" v-if="apiData.operationType==='create'||apiData.operationType==='edit'"
@click="runTest">
{{ $t('commons.test') }}
</el-button>
<!-- 操作按钮 -->
<el-dropdown split-button type="primary" class="ms-api-buttion" @click="handleCommand('add')"
@command="handleCommand" size="small" style="margin-left: 20px" v-else-if="!runLoading">
{{ $t('commons.test') }}
<el-dropdown-menu slot="dropdown" v-if="isEdit">
<el-dropdown-item command="load_case">{{ $t('api_test.definition.request.load_case') }}
</el-dropdown-item>
<el-dropdown-item command="save_as_case">{{ $t('api_test.definition.request.save_as_case') }}
</el-dropdown-item>
<el-dropdown-item command="update_api">{{ $t('api_test.definition.request.update_api') }}</el-dropdown-item>
<el-dropdown-item command="save_as_api">{{ $t('api_test.definition.request.save_as') }}</el-dropdown-item>
</el-dropdown-menu>
<el-dropdown-menu slot="dropdown" v-else>
<el-dropdown-item command="save_as_case">{{ $t('api_test.definition.request.save_as_case') }}
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<el-button size="small" type="primary" v-else @click.once="stop" style="margin-left: 20px">
{{ $t('report.stop_btn') }}
</el-button>
</div>
<div v-loading="loading">
<!-- TCP 请求参数 -->
<ms-basis-parameters :request="api.request" :show-script="false" ref="requestForm" :response="responseData"/>
<!--返回结果-->
<!-- HTTP 请求返回数据 -->
<p class="tip">{{ $t('api_test.definition.request.res_param') }} </p>
<ms-request-result-tail :response="responseData" ref="runResult"/>
</div>
<api-other-info :api="api" ref="apiOtherInfo"/>
</el-card>
<!-- 加载用例 -->
<ms-api-case-list @apiCaseClose="apiCaseClose" @refresh="refresh" @selectTestCase="selectTestCase" :currentApi="api"
:loaded="loaded" :refreshSign="refreshSign" :createCase="createCase"
ref="caseList"/>
<!-- 环境 -->
<api-environment-config ref="environmentConfig" @close="environmentConfigClose"/>
<!-- 执行组件 -->
<ms-run :debug="false" :environment="api.environment" :reportId="reportId" :run-data="runData"
@runRefresh="runRefresh" @errorRefresh="errorRefresh" ref="runTest"/>
</div>
</template>
<script>
import {getUUID, hasLicense} from "@/common/js/utils";
import MsApiCaseList from "@/business/components/api/definition/components/case/ApiCaseList";
import MsContainer from "@/business/components/common/components/MsContainer";
import MsBottomContainer from "@/business/components/api/definition/components/BottomContainer";
import {parseEnvironment} from "@/business/components/api/definition/model/EnvironmentModel";
import ApiEnvironmentConfig from "@/business/components/api/definition/components/environment/ApiEnvironmentConfig";
import MsRequestResultTail from "@/business/components/api/definition/components/response/RequestResultTail";
import MsRun from "@/business/components/api/definition/components/Run";
import MsBasisParameters from "@/business/components/api/definition/components/request/dubbo/BasisParameters";
import {REQ_METHOD} from "@/business/components/api/definition/model/JsonData";
import {TYPE_TO_C} from "@/business/components/api/automation/scenario/Setting";
import ApiOtherInfo from "@/business/components/api/definition/components/complete/ApiOtherInfo";
export default {
name: "DubboBaseInfo",
components: {
MsApiCaseList,
MsContainer,
MsBottomContainer,
MsRequestResultTail,
ApiEnvironmentConfig,
MsRun,
MsBasisParameters,
ApiOtherInfo,
},
data() {
return {
visible: false,
api: {},
loaded: false,
loading: false,
currentRequest: {},
createCase: "",
refreshSign: "",
responseData: {type: 'HTTP', responseResult: {}, subRequestResults: []},
reqOptions: REQ_METHOD,
environments: [],
rules: {
method: [{required: true, message: this.$t('test_track.case.input_maintainer'), trigger: 'change'}],
url: [{required: true, message: this.$t('api_test.definition.request.path_info'), trigger: 'blur'}],
environmentId: [{required: true, message: this.$t('api_test.definition.request.run_env'), trigger: 'change'}],
},
runData: [],
reportId: "",
runLoading: false,
versionEnable: false,
}
},
props: {apiData: {}, currentProtocol: String, syncTabs: Array, projectId: String, isEdit: Boolean},
methods: {
handleCommand(e) {
switch (e) {
case "load_case":
return this.loadCase();
case "save_as_case":
return this.saveAsCase();
case "update_api":
return this.updateApi();
case "save_as_api":
return this.saveAsApi();
default:
return this.runTest();
}
},
refresh() {
this.$emit('refresh');
},
runTest() {
this.runLoading = true;
this.loading = true;
this.api.request.name = this.api.id;
this.api.protocol = this.currentProtocol;
this.runData = [];
this.runData.push(this.api.request);
/*触发执行操作*/
this.reportId = getUUID().substring(0, 8);
},
runRefresh(data) {
this.responseData = data;
this.loading = false;
this.runLoading = false;
},
errorRefresh() {
this.loading = false;
this.runLoading = false;
},
saveAs() {
this.$emit('saveAs', this.api);
},
loadCase() {
this.refreshSign = getUUID();
this.$refs.caseList.open();
this.visible = true;
},
apiCaseClose() {
this.visible = false;
},
getBodyUploadFiles() {
let bodyUploadFiles = [];
this.api.bodyUploadIds = [];
let request = this.api.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;
this.api.bodyUploadIds.push(fileId);
bodyUploadFiles.push(item.file);
}
});
}
});
}
return bodyUploadFiles;
},
saveAsCase() {
//
this.$emit('saveApiAndCase', this.api);
},
saveAsApi() {
let data = {};
let req = this.api.request;
req.id = getUUID();
data.request = JSON.stringify(req);
data.method = this.api.method;
data.status = this.api.status;
data.userId = this.api.userId;
data.description = this.api.description;
this.$emit('saveAsApi', data);
this.$emit('refresh');
},
compatibleHistory(stepArray) {
if (stepArray) {
for (let i in stepArray) {
if (!stepArray[i].clazzName) {
stepArray[i].clazzName = TYPE_TO_C.get(stepArray[i].type);
}
if (stepArray[i].hashTree && stepArray[i].hashTree.length > 0) {
this.compatibleHistory(stepArray[i].hashTree);
}
}
}
},
updateApi() {
let url = "/api/definition/update";
let bodyFiles = this.getBodyUploadFiles();
if (Object.prototype.toString.call(this.api.response).match(/\[object (\w+)\]/)[1].toLowerCase() !== 'object') {
this.api.response = JSON.parse(this.api.response);
}
if (this.api.tags instanceof Array) {
this.api.tags = JSON.stringify(this.api.tags);
}
//
if (this.api.request) {
this.api.request.clazzName = TYPE_TO_C.get(this.api.request.type);
this.compatibleHistory(this.api.request.hashTree);
}
this.$fileUpload(url, null, bodyFiles, this.api, () => {
this.$success(this.$t('commons.save_success'));
if (this.syncTabs.indexOf(this.api.id) === -1) {
this.syncTabs.push(this.api.id);
}
this.$emit('saveApi', this.api);
});
},
selectTestCase(item) {
if (item != null) {
this.api.request = item.request;
} else {
this.api.request = this.currentRequest;
}
},
getEnvironments() {
this.$get('/api/environment/list/' + this.projectId, response => {
this.environments = response.data;
this.environments.forEach(environment => {
parseEnvironment(environment);
});
let hasEnvironment = false;
for (let i in this.environments) {
if (this.environments[i].id === this.api.environmentId) {
this.api.environment = this.environments[i];
hasEnvironment = true;
break;
}
}
if (!hasEnvironment) {
this.api.environmentId = '';
this.api.environment = undefined;
}
});
},
openEnvironmentConfig() {
this.$refs.environmentConfig.open(this.projectId);
},
environmentChange(value) {
for (let i in this.environments) {
if (this.environments[i].id === value) {
this.api.request.useEnvironment = this.environments[i].id;
break;
}
}
},
environmentConfigClose() {
this.getEnvironments();
},
getResult() {
if (this.api.id) {
let url = "/api/definition/report/getReport/" + this.api.id;
this.$get(url, response => {
if (response.data) {
let data = JSON.parse(response.data.content);
this.responseData = data;
}
});
}
},
stop() {
let url = "/api/automation/stop/" + this.reportId;
this.$get(url, () => {
this.runLoading = false;
this.loading = false;
this.$success(this.$t('report.test_stop_success'));
});
},
checkVersionEnable() {
if (!this.projectId) {
return;
}
if (hasLicense()) {
this.$get('/project/version/enable/' + this.projectId, response => {
this.versionEnable = response.data;
});
}
},
getApi() {
return this.api;
}
},
created() {
//
this.api = JSON.parse(JSON.stringify(this.apiData));
this.api.protocol = this.currentProtocol;
this.currentRequest = this.api.request;
this.runLoading = false;
this.getEnvironments();
this.getResult();
this.checkVersionEnable();
}
}
</script>
<style scoped>
.ms-htt-width {
width: 350px;
}
.environment-button {
margin-left: 20px;
padding: 7px;
}
/deep/ .el-drawer {
overflow: auto;
}
</style>

View File

@ -0,0 +1,501 @@
<template>
<div class="card-container">
<div v-if="versionEnable">
<slot name="rightHeader"></slot>
</div>
<el-card class="card-content">
<el-form :model="api" :rules="rules" ref="apiData" :inline="true" label-position="right">
<p class="tip">{{ $t('test_track.plan_view.base_info') }} </p>
<!-- 请求方法 -->
<el-form-item :label="$t('api_report.request')" prop="request.method">
<el-select v-model="api.request.method" style="width: 100px" size="small">
<el-option v-for="item in reqOptions" :key="item.id" :label="item.label" :value="item.id"/>
</el-select>
</el-form-item>
<!-- 执行环境 -->
<el-form-item prop="environmentId">
<environment-select :current-data="api" :project-id="projectId" ref="environmentSelect"/>
</el-form-item>
<!-- 请求地址 -->
<el-form-item prop="request.path">
<el-input :placeholder="$t('api_test.definition.request.path_info')" v-model="api.request.path"
class="ms-htt-width"
size="small" :disabled="false"/>
</el-form-item>
<!-- 操作按钮 -->
<el-form-item>
<!--新建接口-->
<el-button size="small" type="primary" v-if="apiData.operationType==='create'||apiData.operationType==='edit'"
@click="runTest">
{{ $t('commons.test') }}
</el-button>
<!--编辑接口-->
<el-dropdown split-button type="primary" class="ms-api-buttion" @click="handleCommand('add')"
@command="handleCommand" size="small" v-else-if="!runLoading">
{{ $t('commons.test') }}
<el-dropdown-menu slot="dropdown" v-if="isEdit">
<el-dropdown-item command="load_case">{{ $t('api_test.definition.request.load_case') }}
</el-dropdown-item>
<el-dropdown-item command="save_as_case">{{ $t('api_test.definition.request.save_as_case') }}
</el-dropdown-item>
<el-dropdown-item command="update_api">{{
$t('api_test.definition.request.update_api')
}}
</el-dropdown-item>
<el-dropdown-item command="save_as_api">{{ $t('api_test.definition.request.save_as') }}</el-dropdown-item>
</el-dropdown-menu>
<el-dropdown-menu slot="dropdown" v-else>
<el-dropdown-item command="save_as_case">{{ $t('api_test.definition.request.save_as_case') }}
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<el-button size="small" type="primary" v-else @click.once="stop">{{ $t('report.stop_btn') }}</el-button>
<el-button size="small" type="primary" @click.stop @click="generate"
style="margin-left: 10px"
v-if="hasPermission('PROJECT_API_DEFINITION:READ+CREATE_API') && hasLicense()">
{{ $t('commons.generate_test_data') }}
</el-button>
</el-form-item>
</el-form>
<div v-loading="loading">
<p class="tip">{{ $t('api_test.definition.request.req_param') }} </p>
<!-- HTTP 请求参数 -->
<ms-api-request-form :isShowEnable="true" :definition-test="true" :headers="api.request.headers"
:response="responseData"
v-if="loadRequest"
:show-script="false"
:request="api.request" ref="apiRequestForm"/>
<!--返回结果-->
<!-- HTTP 请求返回数据 -->
<div v-if="isEdit">
<ms-form-divider :title="$t('api_test.definition.request.res_param')"/>
<ms-response-text :response="api.response"/>
</div>
<div v-else>
<p class="tip">{{ $t('api_test.definition.request.res_param') }} </p>
<ms-request-result-tail :response="responseData" ref="runResult"/>
</div>
</div>
<api-other-info :api="api" ref="apiOtherInfo"/>
</el-card>
<!-- 加载用例 -->
<ms-api-case-list @selectTestCase="selectTestCase" @refresh="refresh"
:loaded="loaded"
:refreshSign="refreshSign"
:createCase="createCase"
:currentApi="api"
ref="caseList"/>
<!-- 执行组件 -->
<ms-run :debug="false" :environment="api.environment" :reportId="reportId" :run-data="runData" :env-map="envMap"
@runRefresh="runRefresh" @errorRefresh="errorRefresh" ref="runTest"/>
</div>
</template>
<script>
import MsApiRequestForm from "@/business/components/api/definition/components/request/http/ApiHttpRequestForm";
import {getCurrentUser, getUUID, hasLicense, hasPermission} from "@/common/js/utils";
import MsApiCaseList from "@/business/components/api/definition/components/case/ApiCaseList";
import MsContainer from "@/business/components/common/components/MsContainer";
import MsRequestResultTail from "@/business/components/api/definition/components/response/RequestResultTail";
import MsRun from "@/business/components/api/definition/components/Run";
import {REQ_METHOD} from "@/business/components/api/definition/model/JsonData";
import EnvironmentSelect from "@/business/components/api/definition/components/environment/EnvironmentSelect";
import {TYPE_TO_C} from "@/business/components/api/automation/scenario/Setting";
import MsResponseText from "@/business/components/api/definition/components/response/ResponseText";
import MsFormDivider from "@/business/components/common/components/MsFormDivider";
import ApiOtherInfo from "@/business/components/api/definition/components/complete/ApiOtherInfo";
export default {
name: "HttpBaseInfo",
components: {
EnvironmentSelect,
MsApiRequestForm,
MsApiCaseList,
MsContainer,
MsRequestResultTail,
MsRun,
MsResponseText,
MsFormDivider,
ApiOtherInfo,
},
data() {
return {
visible: false,
api: {},
loaded: false,
loading: false,
loadRequest: true,
createCase: "",
currentRequest: {},
refreshSign: "",
responseData: {type: 'HTTP', responseResult: {}, subRequestResults: []},
reqOptions: REQ_METHOD,
rules: {
'request.method': [{required: true, message: this.$t('test_track.case.input_maintainer'), trigger: 'change'}],
'request.path': [{required: true, message: this.$t('api_test.definition.request.path_info'), trigger: 'blur'}],
},
runData: [],
reportId: "",
envMap: new Map,
runLoading: false,
versionEnable: false,
}
},
props: {apiData: {}, currentProtocol: String, syncTabs: Array, projectId: String, isEdit: Boolean},
computed: {
'api.environmentId'() {
return this.$store.state.useEnvironment;
}
},
watch: {
'$store.state.useEnvironment': function () {
this.api.environmentId = this.$store.state.useEnvironment;
},
responseData() {
this.updateRequest();
}
},
methods: {
hasPermission, hasLicense,
generate() {
this.$refs.apiRequestForm.generate();
},
setRequestParam(param, isEnvironmentMock) {
this.init();
if (param) {
if (param.headers) {
this.api.request.headers = param.headers;
}
if (param.arguments !== null && param.arguments.length > 0) {
for (let i = 0; i < param.arguments.length; i++) {
if (!param.arguments[i].required) {
param.arguments[i].required = true;
}
}
this.api.request.arguments = param.arguments;
}
if (param.body) {
if (param.body.kvs) {
for (let i = 0; i < param.body.kvs.length; i++) {
if (!param.body.kvs[i].required) {
param.body.kvs[i].required = true;
}
}
}
this.api.request.body = param.body;
}
if (param.rest) {
for (let i = 0; i < param.rest.length; i++) {
if (!param.rest[i].required) {
param.rest[i].required = true;
}
}
this.api.request.rest = param.rest;
}
}
if (isEnvironmentMock) {
this.$nextTick(() => {
let url = "/api/definition/getMockEnvironment/";
this.$get(url + this.projectId, response => {
let mockEnvironment = response.data;
if (mockEnvironment !== null) {
this.$refs.environmentSelect.setEnvironment(mockEnvironment.id);
}
});
})
}
this.loadRequest = false;
this.$nextTick(() => {
this.loadRequest = true;
})
},
handleCommand(e) {
switch (e) {
case "load_case":
return this.loadCase();
case "save_as_case":
return this.saveAsNewCase();
case "update_api":
return this.updateApi();
case "save_as_api":
return this.saveAsApi();
default:
return this.runTest();
}
},
updateRequest() {
if (this.responseData) {
let result = this.responseData.responseResult;
if (!result) {
return;
}
//
if (result.responseCode) {
let statusCodeArr = [{
enable: true,
file: false,
name: result.responseCode,
required: true,
value: result.responseCode
}];
this.api.response.statusCode = statusCodeArr;
}
//
if (result.headers) {
let headers = result.headers.split("\n");
let headerArr = [];
headers.forEach(item => {
let headerRow = item.split(":");
if (headerRow.length >= 2) {
let headerKey = headerRow[0];
let headerValue = "";
for (let i = 1; i < headerRow.length; i++) {
headerValue += headerRow[i];
if (i !== (headerRow.length - 1)) {
headerValue += ":";
}
}
let headerItem = {enable: true, file: false, name: headerKey, required: true, value: headerValue};
headerArr.push(headerItem);
}
});
if (headerArr.length > 0) {
this.api.response.headers = headerArr;
}
}
//raw
if (this.api.response.body) {
this.api.response.body.type = "Raw";
this.api.response.body.raw = result.body;
}
}
},
validateForm() {
let validResult = false;
this.$refs['apiData'].validate((valid) => {
validResult = valid;
});
return validResult;
},
runTest() {
if (!this.api.environmentId || this.api.environmentId === '') {
this.$error(this.$t('workspace.env_group.please_select_env'));
return false;
}
this.$refs['apiData'].validate((valid) => {
if (valid) {
this.runLoading = true;
this.loading = true;
this.api.request.name = this.api.id;
this.api.request.url = undefined;
this.api.request.useEnvironment = this.api.environmentId;
this.api.protocol = this.currentProtocol;
this.runData = [];
this.runData.push(this.api.request);
/*触发执行操作*/
this.reportId = getUUID().substring(0, 8);
}
})
},
saveAsNewCase() {
this.$refs['apiData'].validate((valid) => {
if (valid) {
let request = this.api.request;
request.id = getUUID();
this.protocol = this.currentProtocol;
this.api.path = request.path;
this.api.method = request.method;
this.api.id = request.id;
this.api.request = request;
this.api.userId = getCurrentUser().id;
this.api.status = "Underway";
this.api.protocol = this.currentProtocol;
this.api.saved = true;
this.$emit("saveApiAndCase", this.api)
} else {
return false;
}
})
},
errorRefresh() {
this.loading = false;
this.runLoading = false;
},
runRefresh(data) {
this.responseData = {type: 'HTTP', responseResult: {responseCode: ""}, subRequestResults: []};
if (data) {
this.responseData = data;
}
this.loading = false;
this.runLoading = false;
},
saveAs() {
this.$emit('saveAs', this.api);
},
loadCase() {
this.refreshSign = getUUID();
this.loaded = true;
this.$refs.caseList.open();
},
apiCaseClose() {
this.visible = false;
},
getBodyUploadFiles() {
let bodyUploadFiles = [];
this.api.bodyUploadIds = [];
let request = this.api.request;
if (request.body) {
request.body.kvs.forEach(param => {
if (param.files) {
param.files.forEach(item => {
if (item.file) {
item.name = item.file.name;
bodyUploadFiles.push(item.file);
}
});
}
});
}
return bodyUploadFiles;
},
saveAsCase() {
//
this.$emit('saveAsCase', this.api);
},
saveAsApi() {
let data = {};
let req = this.api.request;
req.id = getUUID();
data.request = JSON.stringify(req);
data.method = req.method;
data.path = req.path;
data.url = this.api.url;
data.status = this.api.status;
data.userId = this.api.userId;
data.description = this.api.description;
this.$emit('saveAsApi', data);
},
compatibleHistory(stepArray) {
if (stepArray) {
for (let i in stepArray) {
if (!stepArray[i].clazzName) {
stepArray[i].clazzName = TYPE_TO_C.get(stepArray[i].type);
}
if (stepArray[i] && stepArray[i].authManager && !stepArray[i].authManager.clazzName) {
stepArray[i].authManager.clazzName = TYPE_TO_C.get(stepArray[i].authManager.type);
}
if (stepArray[i].hashTree && stepArray[i].hashTree.length > 0) {
this.compatibleHistory(stepArray[i].hashTree);
}
}
}
},
updateApi() {
let url = "/api/definition/update";
let bodyFiles = this.getBodyUploadFiles();
this.api.method = this.api.request.method;
this.api.path = this.api.request.path;
if (Object.prototype.toString.call(this.api.response).match(/\[object (\w+)\]/)[1].toLowerCase() !== 'object') {
this.api.response = JSON.parse(this.api.response);
}
if (this.api.tags instanceof Array) {
this.api.tags = JSON.stringify(this.api.tags);
}
//
if (this.api.request) {
this.api.request.clazzName = TYPE_TO_C.get(this.api.request.type);
this.compatibleHistory(this.api.request.hashTree);
}
this.$fileUpload(url, null, bodyFiles, this.api, () => {
this.$success(this.$t('commons.save_success'));
this.$emit('saveApi', this.api);
if (this.syncTabs.indexOf(this.api.id) === -1) {
this.syncTabs.push(this.api.id);
}
});
},
selectTestCase(item) {
if (item != null) {
this.api.request = item.request;
} else {
this.api.request = this.currentRequest;
}
},
refresh() {
this.$emit('refresh');
},
getResult() {
if (this.api.id) {
let url = "/api/definition/report/getReport/" + this.api.id;
this.$get(url, response => {
if (response.data) {
let data = JSON.parse(response.data.content);
this.responseData = data;
}
});
}
},
stop() {
let url = "/api/automation/stop/" + this.reportId;
this.$get(url, () => {
this.runLoading = false;
this.loading = false;
this.$success(this.$t('report.test_stop_success'));
});
},
checkVersionEnable() {
if (!this.projectId) {
return;
}
if (hasLicense()) {
this.$get('/project/version/enable/' + this.projectId, response => {
this.versionEnable = response.data;
});
}
},
init() {
//
this.api = JSON.parse(JSON.stringify(this.apiData));
this.api.protocol = this.currentProtocol;
this.currentRequest = this.api.request;
if (!this.api.environmentId && this.$store.state.useEnvironment) {
this.api.environmentId = this.$store.state.useEnvironment;
}
this.runLoading = false;
this.checkVersionEnable();
},
getApi() {
return this.api;
}
},
created() {
this.init();
}
}
</script>
<style scoped>
.ms-htt-width {
width: 350px;
}
/deep/ .el-drawer {
overflow: auto;
}
</style>

View File

@ -0,0 +1,320 @@
<template>
<div class="card-container">
<div v-if="versionEnable">
<slot name="rightHeader"></slot>
</div>
<el-card class="card-content">
<el-row>
<p class="tip" style="display: inline-block">{{ $t('api_test.definition.request.req_param') }} </p>
<el-button size="small" type="primary" v-if="apiData.operationType==='create'||apiData.operationType==='edit'"
@click="runTest">
{{ $t('commons.test') }}
</el-button>
<!-- 操作按钮 -->
<el-dropdown split-button type="primary" class="ms-api-buttion" @click="handleCommand('add')"
@command="handleCommand" size="small" v-else-if="!runLoading" style="margin-left: 20px">
{{ $t('commons.test') }}
<el-dropdown-menu slot="dropdown" v-if="isEdit">
<el-dropdown-item command="load_case">{{ $t('api_test.definition.request.load_case') }}
</el-dropdown-item>
<el-dropdown-item command="save_as_case">{{ $t('api_test.definition.request.save_as_case') }}
</el-dropdown-item>
<el-dropdown-item command="update_api">{{ $t('api_test.definition.request.update_api') }}</el-dropdown-item>
<el-dropdown-item command="save_as_api">{{ $t('api_test.definition.request.save_as') }}</el-dropdown-item>
</el-dropdown-menu>
<el-dropdown-menu slot="dropdown" v-else>
<el-dropdown-item command="save_as_case">{{ $t('api_test.definition.request.save_as_case') }}
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<el-button size="small" type="primary" v-else @click.once="stop" style="margin-left: 20px">
{{ $t('report.stop_btn') }}
</el-button>
</el-row>
<div v-loading="loading">
<ms-basis-parameters :show-script="false" :request="api.request" @callback="runTest" ref="requestForm"
:response="responseData"/>
<!--返回结果-->
<!-- HTTP 请求返回数据 -->
<p class="tip">{{ $t('api_test.definition.request.res_param') }} </p>
<ms-request-result-tail :response="responseData" :currentProtocol="currentProtocol" ref="runResult"/>
</div>
<api-other-info :api="api" ref="apiOtherInfo"/>
</el-card>
<!-- 加载用例 -->
<ms-api-case-list @apiCaseClose="apiCaseClose" @refresh="refresh" @selectTestCase="selectTestCase" :currentApi="api"
:refreshSign="refreshSign"
:loaded="loaded" :createCase="createCase"
ref="caseList"/>
<!-- 环境 -->
<api-environment-config ref="environmentConfig" @close="environmentConfigClose"/>
<!-- 执行组件 -->
<ms-run :debug="false" :environment="api.environment" :reportId="reportId" :run-data="runData"
@runRefresh="runRefresh" @errorRefresh="errorRefresh" ref="runTest"/>
</div>
</template>
<script>
import {getUUID, hasLicense} from "@/common/js/utils";
import MsApiCaseList from "@/business/components/api/definition/components/case/ApiCaseList";
import MsContainer from "@/business/components/common/components/MsContainer";
import MsBottomContainer from "@/business/components/api/definition/components/BottomContainer";
import ApiEnvironmentConfig from "@/business/components/api/definition/components/environment/ApiEnvironmentConfig";
import {parseEnvironment} from "@/business/components/api/definition/model/EnvironmentModel";
import MsRequestResultTail from "@/business/components/api/definition/components/response/RequestResultTail";
import MsRun from "@/business/components/api/definition/components/Run";
import MsBasisParameters from "@/business/components/api/definition/components/request/database/BasisParameters";
import {REQ_METHOD} from "@/business/components/api/definition/model/JsonData";
import {TYPE_TO_C} from "@/business/components/api/automation/scenario/Setting";
import ApiOtherInfo from "@/business/components/api/definition/components/complete/ApiOtherInfo";
export default {
name: "SqlBaseInfo",
components: {
MsApiCaseList,
MsContainer,
MsBottomContainer,
MsRequestResultTail,
ApiEnvironmentConfig,
MsRun,
MsBasisParameters,
ApiOtherInfo
},
data() {
return {
visible: false,
api: {},
loaded: false,
loading: false,
currentRequest: {},
responseData: {type: 'HTTP', responseResult: {}, subRequestResults: []},
reqOptions: REQ_METHOD,
refreshSign: "",
createCase: "",
environments: [],
rules: {
method: [{required: true, message: this.$t('test_track.case.input_maintainer'), trigger: 'change'}],
url: [{required: true, message: this.$t('api_test.definition.request.path_info'), trigger: 'blur'}],
environmentId: [{required: true, message: this.$t('api_test.definition.request.run_env'), trigger: 'change'}],
},
runData: [],
reportId: "",
runLoading: false,
versionEnable: false,
}
},
props: {apiData: {}, currentProtocol: String, syncTabs: Array, projectId: String, isEdit: Boolean},
methods: {
handleCommand(e) {
switch (e) {
case "load_case":
return this.loadCase();
case "save_as_case":
return this.saveAsCase();
case "update_api":
return this.updateApi();
case "save_as_api":
return this.saveAsApi();
default:
return this.$refs['requestForm'].validate();
}
},
refresh() {
this.$emit('refresh');
},
errorRefresh() {
this.loading = false;
this.runLoading = false;
},
runTest() {
this.runLoading = true;
this.loading = true;
this.api.request.name = this.api.id;
this.api.protocol = this.currentProtocol;
this.runData = [];
this.runData.push(this.api.request);
/*触发执行操作*/
this.reportId = getUUID().substring(0, 8);
},
runRefresh(data) {
this.responseData = data;
this.loading = false;
this.runLoading = false;
},
saveAs() {
this.$emit('saveAs', this.api);
},
loadCase() {
this.refreshSign = getUUID();
this.$refs.caseList.open();
this.visible = true;
},
apiCaseClose() {
this.visible = false;
},
getBodyUploadFiles() {
let bodyUploadFiles = [];
this.api.bodyUploadIds = [];
let request = this.api.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;
this.api.bodyUploadIds.push(fileId);
bodyUploadFiles.push(item.file);
}
});
}
});
}
return bodyUploadFiles;
},
saveAsCase() {
this.$emit('saveApiAndCase', this.api);
},
saveAsApi() {
let data = {};
let req = this.api.request;
req.id = getUUID();
data.request = JSON.stringify(req);
data.method = this.api.method;
data.status = this.api.status;
data.userId = this.api.userId;
data.description = this.api.description;
this.$emit('saveAsApi', data);
this.$emit('refresh');
},
compatibleHistory(stepArray) {
if (stepArray) {
for (let i in stepArray) {
if (!stepArray[i].clazzName) {
stepArray[i].clazzName = TYPE_TO_C.get(stepArray[i].type);
}
if (stepArray[i].hashTree && stepArray[i].hashTree.length > 0) {
this.compatibleHistory(stepArray[i].hashTree);
}
}
}
},
updateApi() {
let url = "/api/definition/update";
let bodyFiles = this.getBodyUploadFiles();
if (Object.prototype.toString.call(this.api.response).match(/\[object (\w+)\]/)[1].toLowerCase() !== 'object') {
this.api.response = JSON.parse(this.api.response);
}
if (this.api.tags instanceof Array) {
this.api.tags = JSON.stringify(this.api.tags);
}
//
if (this.api.request) {
this.api.request.clazzName = TYPE_TO_C.get(this.api.request.type);
this.compatibleHistory(this.api.request.hashTree);
}
this.$fileUpload(url, null, bodyFiles, this.api, () => {
this.$success(this.$t('commons.save_success'));
if (this.syncTabs.indexOf(this.api.id) === -1) {
this.syncTabs.push(this.api.id);
}
this.$emit('refresh');
});
},
selectTestCase(item) {
if (item != null) {
this.api.request = item.request;
} else {
this.api.request = this.currentRequest;
}
},
getEnvironments() {
this.$get('/api/environment/list/' + this.projectId, response => {
this.environments = response.data;
this.environments.forEach(environment => {
parseEnvironment(environment);
});
let hasEnvironment = false;
for (let i in this.environments) {
if (this.environments[i].id === this.api.environmentId) {
this.api.environment = this.environments[i];
hasEnvironment = true;
break;
}
}
if (!hasEnvironment) {
this.api.environmentId = '';
this.api.environment = undefined;
}
});
},
openEnvironmentConfig() {
this.$refs.environmentConfig.open(this.projectId);
},
environmentChange(value) {
for (let i in this.environments) {
if (this.environments[i].id === value) {
this.api.request.useEnvironment = this.environments[i].id;
break;
}
}
},
environmentConfigClose() {
this.getEnvironments();
},
getResult() {
if (this.api.id) {
let url = "/api/definition/report/getReport/" + this.api.id;
this.$get(url, response => {
if (response.data) {
let data = JSON.parse(response.data.content);
this.responseData = data;
}
});
}
},
stop() {
let url = "/api/automation/stop/" + this.reportId;
this.$get(url, () => {
this.runLoading = false;
this.loading = false;
this.$success(this.$t('report.test_stop_success'));
});
},
checkVersionEnable() {
if (!this.projectId) {
return;
}
if (hasLicense()) {
this.$get('/project/version/enable/' + this.projectId, response => {
this.versionEnable = response.data;
});
}
},
getApi() {
return this.api;
}
},
created() {
//
this.api = JSON.parse(JSON.stringify(this.apiData));
this.api.protocol = this.currentProtocol;
this.currentRequest = this.api.request;
this.runLoading = false;
this.getEnvironments();
this.getResult();
this.checkVersionEnable();
}
}
</script>
<style scoped>
/deep/ .el-drawer {
overflow: auto;
}
</style>

View File

@ -0,0 +1,391 @@
<template>
<div class="card-container">
<div v-if="versionEnable">
<slot name="rightHeader"></slot>
</div>
<el-card class="card-content">
<el-form :model="api" :rules="rules" ref="apiData" :inline="true" label-position="right">
<!-- 执行环境 -->
<el-form-item prop="environmentId">
{{ $t('api_test.definition.request.run_env') }}
<environment-select :type="'TCP'" :current-data="api" :project-id="projectId" ref="environmentSelect"/>
</el-form-item>
<el-form-item>
<el-button size="small" type="primary" v-if="apiData.operationType==='create'||apiData.operationType==='edit'"
@click="runTest">
{{ $t('commons.test') }}
</el-button>
<!-- 操作按钮 -->
<el-dropdown split-button type="primary" class="ms-api-buttion" @click="handleCommand('add')"
@command="handleCommand" size="small" v-else-if="!runLoading">
{{ $t('commons.test') }}
<el-dropdown-menu slot="dropdown" v-if="isEdit">
<el-dropdown-item command="load_case">{{ $t('api_test.definition.request.load_case') }}
</el-dropdown-item>
<el-dropdown-item command="save_as_case">{{ $t('api_test.definition.request.save_as_case') }}
</el-dropdown-item>
<el-dropdown-item command="update_api">{{
$t('api_test.definition.request.update_api')
}}
</el-dropdown-item>
<el-dropdown-item command="save_as_api">{{ $t('api_test.definition.request.save_as') }}</el-dropdown-item>
</el-dropdown-menu>
<el-dropdown-menu slot="dropdown" v-else>
<el-dropdown-item command="save_as_case">{{ $t('api_test.definition.request.save_as_case') }}
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<el-button size="small" type="primary" v-else @click.once="stop">
{{ $t('report.stop_btn') }}
</el-button>
</el-form-item>
<div>
<p class="tip" style="display: inline-block">{{ $t('api_test.definition.request.req_param') }} </p>
<el-select v-model="api.method" slot="prepend" style="width: 100px" size="small">
<el-option v-for="item in methodTypes" :key="item.key" :label="item.value" :value="item.key"/>
</el-select>
</div>
<!-- TCP 请求参数 -->
<div v-if="api.method=='TCP'" v-loading="loading">
<ms-tcp-format-parameters :show-script="false" :request="api.request" @callback="runTest"
:response="responseData"
ref="requestForm"/>
<ms-request-result-tail :response="responseData" ref="runResult"/>
</div>
<div v-else-if="api.method=='ESB'" v-loading="loading">
<esb-definition v-xpack v-if="showXpackCompnent" :show-script="false" :request="api.request"
@callback="runTest" ref="requestForm"/>
</div>
<div v-if="api.method=='ESB'">
<p class="tip">{{ $t('api_test.definition.request.res_param') }}</p>
<esb-definition-response v-xpack v-if="showXpackCompnent" :is-api-component="false" :show-options-button="false"
:request="api.request" :response-data="responseData"/>
</div>
</el-form>
<api-other-info :api="api" ref="apiOtherInfo"/>
</el-card>
<!-- 加载用例 -->
<ms-api-case-list @apiCaseClose="apiCaseClose" @refresh="refresh" @selectTestCase="selectTestCase" :currentApi="api"
:refreshSign="refreshSign"
:loaded="loaded" :createCase="createCase"
ref="caseList"/>
<!-- 执行组件 -->
<ms-run :debug="false" :environment="api.environment" :reportId="reportId" :run-data="runData"
@runRefresh="runRefresh" @errorRefresh="errorRefresh" ref="runTest"/>
</div>
</template>
<script>
import {getUUID, hasLicense} from "@/common/js/utils";
import MsTcpFormatParameters from "@/business/components/api/definition/components/request/tcp/TcpFormatParameters";
import MsApiRequestForm from "@/business/components/api/definition/components/request/http/ApiHttpRequestForm";
import MsApiCaseList from "@/business/components/api/definition/components/case/ApiCaseList";
import MsContainer from "@/business/components/common/components/MsContainer";
import MsBottomContainer from "@/business/components/api/definition/components/BottomContainer";
import MsRequestResultTail from "@/business/components/api/definition/components/response/RequestResultTail";
import MsRun from "@/business/components/api/definition/components/Run";
import {REQ_METHOD} from "@/business/components/api/definition/model/JsonData";
import EnvironmentSelect from "@/business/components/api/definition/components/environment/EnvironmentSelect";
import {TYPE_TO_C} from "@/business/components/api/automation/scenario/Setting";
import ApiOtherInfo from "@/business/components/api/definition/components/complete/ApiOtherInfo";
const requireComponent = require.context('@/business/components/xpack/', true, /\.vue$/);
const esbDefinition = (requireComponent != null && requireComponent.keys().length) > 0 ? requireComponent("./apidefinition/EsbDefinition.vue") : {};
const esbDefinitionResponse = (requireComponent != null && requireComponent.keys().length) > 0 ? requireComponent("./apidefinition/EsbDefinitionResponse.vue") : {};
export default {
name: "TcpBaseInfo",
components: {
EnvironmentSelect,
MsApiRequestForm,
MsApiCaseList,
MsContainer,
MsBottomContainer,
MsRequestResultTail,
MsRun,
MsTcpFormatParameters, ApiOtherInfo,
"esbDefinition": esbDefinition.default,
"esbDefinitionResponse": esbDefinitionResponse.default
},
data() {
return {
visible: false,
api: {},
loaded: false,
loading: false,
currentRequest: {},
responseData: {type: 'HTTP', responseResult: {}, subRequestResults: []},
reqOptions: REQ_METHOD,
environments: [],
refreshSign: "",
createCase: "",
methodTypes: [
{
'key': "TCP",
'value': this.$t('api_test.request.tcp.general_format'),
}
],
rules: {
environmentId: [{required: true, message: this.$t('api_test.definition.request.run_env'), trigger: 'change'}],
},
runData: [],
reportId: "",
showXpackCompnent: false,
runLoading: false,
versionEnable: false,
}
},
props: {apiData: {}, currentProtocol: String, syncTabs: Array, projectId: String, isEdit: Boolean},
methods: {
setRequestParam(param, isEnvironmentMock) {
this.init();
if (this.api.method === "TCP" && param && this.api.request) {
if (param.reportType) {
this.api.request.reportType = param.reportType;
}
if (param.jsonDataStruct) {
this.api.request.jsonDataStruct = param.jsonDataStruct;
}
if (param.rawDataStruct) {
this.api.request.rawDataStruct = param.rawDataStruct;
}
if (param.xmlDataStruct) {
this.api.request.xmlDataStruct = param.xmlDataStruct;
}
this.$nextTick(() => {
this.$refs.requestForm.reload();
this.$refs.requestForm.setReportType(param.reportType);
});
}
if (isEnvironmentMock) {
this.$nextTick(() => {
let url = "/api/definition/getMockEnvironment/";
this.$get(url + this.projectId, response => {
let mockEnvironment = response.data;
if (mockEnvironment !== null) {
this.$refs.environmentSelect.setEnvironment(mockEnvironment.id);
}
});
})
}
},
handleCommand(e) {
switch (e) {
case "load_case":
return this.loadCase();
case "save_as_case":
return this.saveAsCase();
case "update_api":
return this.updateApi();
case "save_as_api":
return this.saveAsApi();
default:
return this.$refs['requestForm'].validate();
}
},
refresh() {
this.$emit('refresh');
},
runTest() {
this.$refs['apiData'].validate((valid) => {
if (valid) {
this.runLoading = true;
this.loading = true;
this.api.request.name = this.api.id;
this.api.protocol = this.currentProtocol;
this.runData = [];
this.runData.push(this.api.request);
/*触发执行操作*/
this.reportId = getUUID().substring(0, 8);
}
})
},
runRefresh(data) {
this.responseData = data;
this.loading = false;
this.runLoading = false;
},
errorRefresh() {
this.loading = false;
this.runLoading = false;
},
saveAs() {
this.$emit('saveAs', this.api);
},
loadCase() {
this.refreshSign = getUUID();
this.$refs.caseList.open();
this.visible = true;
},
apiCaseClose() {
this.visible = false;
},
getBodyUploadFiles() {
let bodyUploadFiles = [];
this.api.bodyUploadIds = [];
let request = this.api.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;
this.api.bodyUploadIds.push(fileId);
bodyUploadFiles.push(item.file);
}
});
}
});
}
return bodyUploadFiles;
},
saveAsCase() {
this.$emit('saveApiAndCase', this.api);
},
saveAsApi() {
let data = {};
let req = this.api.request;
req.id = getUUID();
data.request = JSON.stringify(req);
data.method = this.api.method;
data.status = this.api.status;
data.userId = this.api.userId;
data.description = this.api.description;
this.$emit('saveAsApi', data);
this.$emit('refresh');
},
compatibleHistory(stepArray) {
if (stepArray) {
for (let i in stepArray) {
if (!stepArray[i].clazzName) {
stepArray[i].clazzName = TYPE_TO_C.get(stepArray[i].type);
}
if (stepArray[i].hashTree && stepArray[i].hashTree.length > 0) {
this.compatibleHistory(stepArray[i].hashTree);
}
}
}
},
updateApi() {
let url = "/api/definition/update";
let bodyFiles = this.getBodyUploadFiles();
if (Object.prototype.toString.call(this.api.response).match(/\[object (\w+)\]/)[1].toLowerCase() !== 'object') {
this.api.response = JSON.parse(this.api.response);
}
if (this.api.tags instanceof Array) {
this.api.tags = JSON.stringify(this.api.tags);
}
if (this.api.method === 'ESB') {
this.api.esbDataStruct = JSON.stringify(this.api.request.esbDataStruct);
this.api.backEsbDataStruct = JSON.stringify(this.api.request.backEsbDataStruct);
}
//
if (this.api.request) {
this.api.request.clazzName = TYPE_TO_C.get(this.api.request.type);
this.compatibleHistory(this.api.request.hashTree);
}
this.$fileUpload(url, null, bodyFiles, this.api, () => {
this.$success(this.$t('commons.save_success'));
if (this.syncTabs.indexOf(this.api.id) === -1) {
this.syncTabs.push(this.api.id);
}
this.$emit('saveApi', this.api);
});
},
selectTestCase(item) {
if (item != null) {
this.api.request = item.request;
} else {
this.api.request = this.currentRequest;
}
},
getResult() {
let url = "/api/definition/report/getReport/" + this.api.id;
this.$get(url, response => {
if (response.data) {
let data = JSON.parse(response.data.content);
this.responseData = data;
}
});
},
stop() {
let url = "/api/automation/stop/" + this.reportId;
this.$get(url, () => {
this.runLoading = false;
this.loading = false;
this.$success(this.$t('report.test_stop_success'));
});
},
checkVersionEnable() {
if (!this.projectId) {
return;
}
if (hasLicense()) {
this.$get('/project/version/enable/' + this.projectId, response => {
this.versionEnable = response.data;
});
}
},
init() {
//
this.api = JSON.parse(JSON.stringify(this.apiData));
this.api.protocol = this.currentProtocol;
if (!this.api.environmentId) {
this.api.environmentId = this.$store.state.useEnvironment;
}
this.currentRequest = this.api.request;
this.runLoading = false;
this.getResult();
if (requireComponent != null && JSON.stringify(esbDefinition) !== '{}') {
this.showXpackCompnent = true;
}
this.checkVersionEnable();
},
getApi() {
if (this.api.method === 'ESB') {
this.api.esbDataStruct = JSON.stringify(this.api.request.esbDataStruct);
this.api.backEsbDataStruct = JSON.stringify(this.api.request.backEsbDataStruct);
}
return this.api;
}
},
created() {
if (requireComponent !== null && JSON.stringify(esbDefinition) !== '{}' && JSON.stringify(esbDefinitionResponse) !== '{}') {
this.showXpackCompnent = true;
if (hasLicense()) {
if (this.methodTypes.length === 1) {
let esbMethodType = {};
esbMethodType.key = "ESB";
esbMethodType.value = "ESB";
this.methodTypes.push(esbMethodType);
}
}
}
this.init();
}
}
</script>
<style scoped>
.ms-htt-width {
width: 350px;
}
.environment-button {
margin-left: 20px;
padding: 7px;
}
/deep/ .el-drawer {
overflow: auto;
}
</style>

View File

@ -0,0 +1,578 @@
<template>
<div>
<el-tabs v-model="activeName" type="card" class="api-info-tab" @tab-click="tabChange">
<el-tab-pane label="API" name="api">
<api-information :api-info="apiInfo" :api="currentApi" style="margin:5px 5px 5px 5px">
<template v-slot:headerRight>
<div style="float: right;margin-right: 20px; position: unset" class="ms-opt-btn">
<el-tooltip :content="$t('commons.follow')" placement="bottom" effect="dark" v-if="!showFollow">
<i class="el-icon-star-off"
style="color: #783987; font-size: 25px; margin-right: 5px; position: relative; top: 5px; cursor: pointer "
@click="saveFollow"/>
</el-tooltip>
<el-tooltip :content="$t('commons.cancel')" placement="bottom" effect="dark" v-if="showFollow">
<i class="el-icon-star-on"
style="color: #783987; font-size: 28px; margin-right: 5px; position: relative; top: 5px; cursor: pointer "
@click="saveFollow"/>
</el-tooltip>
<el-link type="primary" style="margin-right: 5px" @click="openHis" v-if="apiInfo.id">
{{ $t('operating_log.change_history') }}
</el-link>
<!-- 版本历史 -->
<ms-version-history v-xpack
ref="versionHistory"
:version-data="versionData"
:current-id="apiInfo.id"
:test-users="maintainerOptions" :use-external-users="true"
@compare="compare" @checkout="checkout" @create="create" @del="del"/>
<el-button type="primary" size="small" @click="editApi" title="ctrl + s"
v-permission="['PROJECT_API_DEFINITION:READ+EDIT_API']">{{ $t('commons.edit') }}
</el-button>
</div>
</template>
</api-information>
</el-tab-pane>
<el-tab-pane label="TEST" name="test">
<div style="margin:5px 5px 5px 5px">
<ms-run-test-http-page
:syncTabs="syncTabs"
:currentProtocol="currentProtocol"
:api-data="currentApi"
:project-id="projectId"
@saveAsApi="editApi"
@saveAsCase="saveAsCase"
@refresh="refresh"
ref="httpTestPage"
v-if="currentProtocol==='HTTP'"
/>
<ms-run-test-tcp-page
:syncTabs="syncTabs"
:currentProtocol="currentProtocol"
:api-data="currentApi"
:project-id="projectId"
@saveAsApi="editApi"
@saveAsCase="saveAsCase"
@refresh="refresh"
ref="tcpTestPage"
v-else-if="currentProtocol==='TCP'"
/>
<ms-run-test-sql-page
:syncTabs="syncTabs"
:currentProtocol="currentProtocol"
:api-data="currentApi"
:project-id="projectId"
@saveAsApi="editApi"
@saveAsCase="saveAsCase"
@refresh="refresh"
v-else-if="currentProtocol==='SQL'"
/>
<ms-run-test-dubbo-page
:syncTabs="syncTabs"
:currentProtocol="currentProtocol"
:api-data="currentApi"
:project-id="projectId"
@saveAsApi="editApi"
@saveAsCase="saveAsCase"
@refresh="refresh"
v-else-if="currentProtocol==='DUBBO'"
/>
</div>
</el-tab-pane>
<el-tab-pane label="CASE" name="testCase">
<!--测试用例列表-->
<api-case-simple-list
class="api-case-simple-list"
:apiDefinitionId="currentApi.id"
:apiDefinition="currentApi"
:current-version="currentApi.versionId"
:trash-enable="false"
:test-users="maintainerOptions" :use-external-users="true"
@changeSelectDataRangeAll="changeSelectDataRangeAll"
@handleCase="handleCase"
@refreshTable="refresh"
@showExecResult="showExecResult" style="margin:5px 5px 5px 5px"
ref="trashCaseList"/>
</el-tab-pane>
<el-tab-pane label="MOCK" name="mock" v-if="currentProtocol === 'HTTP' || currentProtocol === 'TCP'">
<div style="margin:5px 5px 5px 5px">
<mock-tab :base-mock-config-data="baseMockConfigData" @redirectToTest="redirectToTest"
:version-name="currentApi.versionName" :api-id="apiInfo.id"
:is-tcp="currentProtocol === 'TCP'"/>
</div>
</el-tab-pane>
</el-tabs>
<ms-change-history ref="changeHistory"/>
<!-- 加载用例 -->
<ms-api-case-list
:createCase="createCase"
:test-users="maintainerOptions" :use-external-users="true"
:currentApi="api"
@reLoadCase="reLoadCase"
ref="caseList"/>
</div>
</template>
<script>
import MsApiConfig from "@/business/components/api/definition/components/ApiConfig";
import MsRunTestHttpPage from "@/business/components/api/definition/components/runtest/RunTestHTTPPage";
import MsRunTestTcpPage from "@/business/components/api/definition/components/runtest/RunTestTCPPage";
import MsRunTestSqlPage from "@/business/components/api/definition/components/runtest/RunTestSQLPage";
import MsRunTestDubboPage from "@/business/components/api/definition/components/runtest/RunTestDubboPage";
import MockTab from "@/business/components/api/definition/components/mock/MockTab";
import TcpMockConfig from "@/business/components/api/definition/components/mock/TcpMockConfig";
import ApiCaseSimpleList from "@/business/components/api/definition/components/list/ApiCaseSimpleList";
import MsApiCaseList from "@/business/components/api/definition/components/case/ApiCaseList";
import {getCurrentProjectID, getUUID, hasLicense} from "@/common/js/utils";
import {TYPE_TO_C} from "@/business/components/api/automation/scenario/Setting";
import _ from 'lodash';
import ApiInformation from "@/business/components/api/definition/components/document/components/ApiInformation";
import MsVersionHistory from "@/business/components/xpack/version/VersionHistory";
import {createComponent} from "@/business/components/api/definition/components/jmeter/components";
import MsChangeHistory from "@/business/components/history/ChangeHistory";
export default {
name: "ApiDefinitionInformation",
components: {
MsApiConfig,
MsRunTestHttpPage,
MsRunTestTcpPage,
MsRunTestSqlPage,
MsRunTestDubboPage,
MockTab,
TcpMockConfig,
ApiCaseSimpleList,
MsApiCaseList,
ApiInformation,
MsVersionHistory,
MsChangeHistory
},
data() {
return {
activeName: "api",
isShow: true,
baseMockConfigData: {},
showFollow: false,
versionData: [],
maintainerOptions: [],
httpForm: {environmentId: "", path: "", tags: []},
loading: false,
createCase: "",
api: {},
};
},
props: {
apiId: String,
activeDom: String,
isShowChangeButton: {
type: Boolean,
default: true
},
apiInfo: {},
moduleOptions: {},
currentApi: {},
currentProtocol: String,
syncTabs: Array,
projectId: String,
selectNodeIds: Array,
visible: {
type: Boolean,
default: false,
},
},
created() {
this.refreshButtonActiveClass(this.activeDom);
if (this.currentApi.id && (this.currentProtocol === "HTTP" || this.currentProtocol === "TCP")) {
this.mockSetting();
}
this.getMaintainerOptions();
if (!this.httpForm.environmentId) {
this.httpForm.environmentId = "";
}
this.$get('/api/definition/follow/' + this.apiId, response => {
this.httpForm.follows = response.data;
for (let i = 0; i < response.data.length; i++) {
if (response.data[i] === this.currentUser().id) {
this.showFollow = true;
break;
}
}
});
this.formatApi();
if (hasLicense()) {
this.getVersionHistory();
}
},
watch: {
activeName() {
if (this.activeName === "mock") {
this.mockSetting();
}
},
currentProtocol() {
this.initMockEnvironment();
},
'$store.state.currentApiCase.case'() {
if (this.$store.state.currentApiCase && this.$store.state.currentApiCase.api) {
this.refreshButtonActiveClass("testCase");
}
},
'$store.state.currentApiCase.mock'() {
this.mockSetting();
this.refreshButtonActiveClass("mock");
}
},
methods: {
tabChange() {
this.beforeChangeTab();
this.refreshButtonActiveClass(this.activeName);
},
reLoadCase() {
this.$refs.trashCaseList.initTable();
},
sort(stepArray) {
if (stepArray) {
for (let i in stepArray) {
if (!stepArray[i].clazzName) {
stepArray[i].clazzName = TYPE_TO_C.get(stepArray[i].type);
}
if (stepArray[i] && stepArray[i].authManager && !stepArray[i].authManager.clazzName) {
stepArray[i].authManager.clazzName = TYPE_TO_C.get(stepArray[i].authManager.type);
}
if (stepArray[i].type === "Assertions" && !stepArray[i].document) {
stepArray[i].document = {
type: "JSON",
data: {xmlFollowAPI: false, jsonFollowAPI: false, json: [], xml: []}
};
}
if (stepArray[i].hashTree && stepArray[i].hashTree.length > 0) {
this.sort(stepArray[i].hashTree);
}
}
}
},
formatApi() {
if (this.currentApi.response !== null && this.currentApi.response !== 'null' && this.currentApi.response !== undefined) {
if (Object.prototype.toString.call(this.currentApi.response).match(/\[object (\w+)\]/)[1].toLowerCase() !== 'object') {
this.currentApi.response = JSON.parse(this.currentApi.response);
}
}
if (this.currentApi.request !== null && this.currentApi.request !== 'null' && this.currentApi.request !== undefined) {
if (Object.prototype.toString.call(this.currentApi.request).match(/\[object (\w+)\]/)[1].toLowerCase() !== 'object') {
this.currentApi.request = JSON.parse(this.currentApi.request);
if (this.currentApi.request.body && !this.currentApi.request.body.type) {
let tempRequest = _.cloneDeep(this.currentApi.request);
tempRequest.body = {type: null};
this.currentApi.request = tempRequest;
}
}
}
if (this.currentApi && this.currentApi.request && !this.currentApi.request.hashTree) {
this.currentApi.request.hashTree = [];
}
if (this.currentApi && this.currentApi.request && this.currentApi.request.body && !this.currentApi.request.body.binary) {
this.currentApi.request.body.binary = [];
}
if (this.currentApi.request) {
this.currentApi.request.clazzName = TYPE_TO_C.get(this.currentApi.request.type);
this.sort(this.currentApi.request.hashTree);
}
},
mockSetting() {
let mockParam = {};
mockParam.projectId = this.projectId;
if (this.currentApi.id) {
mockParam.apiId = this.currentApi.id;
this.$post('/mockConfig/genMockConfig', mockParam, response => {
let mockConfig = response.data;
mockConfig.apiName = this.currentApi.name;
mockConfig.versionName = this.currentApi.versionName;
this.baseMockConfigData = mockConfig;
});
}
},
runTest(data) {
this.$emit("runTest", data);
},
saveApi(data) {
if (data != null && data.tags !== 'null' && data.tags !== undefined) {
if (Object.prototype.toString.call(data.tags) === "[object String]") {
data.tags = JSON.parse(data.tags);
}
}
Object.assign(this.currentApi, data);
this.currentApi.isCopy = false;
this.setTabTitle(data);
this.refresh(data);
},
createRootModel() {
this.$emit("createRootModel");
},
editApi(data) {
this.$emit("editApi", data);
},
refresh() {
this.$emit("refresh");
},
checkout(data) {
Object.assign(this.currentApi, data);
this.reload();
},
changeTab(tabType) {
},
beforeChangeTab() {
//
this.$refs.caseList.close();
},
redirectToTest(param) {
this.refreshButtonActiveClass("test");
this.$nextTick(() => {
if (this.currentProtocol === "HTTP" && this.$refs.httpTestPage) {
let requestParam = null;
if (param.params) {
requestParam = param.params;
}
this.$refs.httpTestPage.setRequestParam(requestParam, true);
} else if (this.currentProtocol === "TCP" && this.$refs.tcpTestPage) {
this.$refs.tcpTestPage.setRequestParam(param, true);
}
});
},
removeListener() {
if (this.$refs && this.$refs.apiConfig) {
this.$refs.apiConfig.removeListener();
}
},
changeSelectDataRangeAll() {
this.$emit("changeSelectDataRangeAll");
},
handleCase(api) {
this.$emit("handleCase", api);
},
showExecResult(data) {
this.$emit("showExecResult", data);
},
reload() {
this.loading = true;
this.$nextTick(() => {
this.loading = false;
});
},
saveAsCase(api) {
this.createCase = getUUID();
this.api = api;
this.$refs.caseList.open();
},
refreshButtonActiveClass(tabType) {
if (tabType === "testCase") {
this.$store.state.currentApiCase = {case: true};
} else if (tabType === "test") {
this.$store.state.currentApiCase = undefined;
} else if (tabType === "mock") {
this.$store.state.currentApiCase = undefined;
} else {
this.syncApi();
}
if (tabType) {
this.activeName = tabType;
}
},
changeApi() {
this.$store.state.currentApiCase = undefined;
},
syncApi() {
if (this.syncTabs && this.syncTabs.length > 0 && this.syncTabs.includes(this.currentApi.id)) {
//
let url = "/api/definition/get/";
this.$get(url + this.currentApi.id, response => {
if (response.data) {
let request = JSON.parse(response.data.request);
let index = this.syncTabs.findIndex(item => {
if (item === this.currentApi.id) {
return true;
}
});
this.syncTabs.splice(index, 1);
this.currentApi.request = request;
this.changeApi();
}
});
} else {
this.changeApi();
}
},
getVersionHistory() {
this.$get('/api/definition/versions/' + this.apiInfo.id, response => {
if (this.apiInfo.isCopy) {
this.versionData = response.data.filter(v => v.versionId === this.apiInfo.versionId);
} else {
this.versionData = response.data;
}
});
},
compare(row) {
this.$get('/api/definition/get/' + row.id + "/" + this.apiInfo.refId, response => {
this.$get('/api/definition/get/' + response.data.id, res => {
if (res.data) {
this.newData = res.data;
this.dealWithTag(res.data);
this.setRequest(res.data)
if (!this.setRequest(res.data)) {
this.oldRequest = createComponent("HTTPSamplerProxy");
this.dialogVisible = true;
}
this.formatApi(res.data)
}
});
});
},
checkoutVersion(row) {
let api = this.versionData.filter(v => v.versionId === row.id)[0];
if (api.tags && api.tags.length > 0) {
api.tags = JSON.parse(api.tags);
}
this.$emit("checkout", api);
},
create(row) {
//
this.apiInfo.versionId = row.id;
this.apiInfo.versionName = row.name;
this.$set(this.apiInfo, 'newVersionRemark', !!this.apiInfo.remark);
this.$set(this.apiInfo, 'newVersionDeps', this.$refs.apiOtherInfo.relationshipCount > 0);
if (this.$refs.apiOtherInfo.relationshipCount > 0 || this.apiInfo.remark) {
this.createNewVersionVisible = true;
} else {
this.saveApi();
}
},
del(row) {
this.$alert(this.$t('api_test.definition.request.delete_confirm') + ' ' + row.name + " ", '', {
confirmButtonText: this.$t('commons.confirm'),
callback: (action) => {
if (action === 'confirm') {
this.$get('/api/definition/delete/' + row.id + '/' + this.apiInfo.refId, () => {
this.$success(this.$t('commons.delete_success'));
this.getVersionHistory();
});
}
}
});
},
saveFollow() {
if (this.showFollow) {
this.showFollow = false;
for (let i = 0; i < this.httpForm.follows.length; i++) {
if (this.httpForm.follows[i] === this.currentUser().id) {
this.httpForm.follows.splice(i, 1);
break;
}
}
if (this.apiInfo.id) {
this.$post("/api/definition/update/follows/" + this.apiInfo.id, this.httpForm.follows, () => {
this.$success(this.$t('commons.cancel_follow_success'));
});
}
} else {
this.showFollow = true;
if (!this.httpForm.follows) {
this.httpForm.follows = [];
}
this.httpForm.follows.push(this.currentUser().id);
if (this.apiInfo.id) {
this.$post("/api/definition/update/follows/" + this.apiInfo.id, this.httpForm.follows, () => {
this.$success(this.$t('commons.follow_success'));
});
}
}
},
getMaintainerOptions() {
this.$post('/user/project/member/tester/list', {projectId: getCurrentProjectID()}, response => {
this.maintainerOptions = response.data;
});
},
openHis() {
this.$refs.changeHistory.open(this.httpForm.id, ["接口定义", "接口定義", "Api definition", "API_DEFINITION"]);
},
initMockEnvironment() {
if (this.currentProtocol) {
let protocol = this.currentProtocol;
protocol = protocol.substring(0, protocol.indexOf(":"));
let url = "/api/definition/getMockEnvironment/";
this.$get(url + this.projectId, response => {
this.mockEnvironment = response.data;
let httpConfig = JSON.parse(this.mockEnvironment.config);
if (httpConfig != null) {
httpConfig = httpConfig.httpConfig;
let httpType = httpConfig.defaultCondition;
let conditions = httpConfig.conditions;
conditions.forEach(condition => {
if (condition.type === httpType) {
this.mockBaseUrl = condition.protocol + "://" + condition.socket;
this.newMockBaseUrl = this.mockBaseUrl;
}
});
}
});
}
},
}
};
</script>
<style scoped>
.active {
border: solid 1px #6d317c !important;
background-color: var(--primary_color) !important;
color: #FFFFFF !important;
}
.case-button {
border-left: solid 1px var(--primary_color);
}
.item {
border: solid 1px var(--primary_color);
}
.api-case-simple-list >>> .el-table {
height: calc(100vh - 262px) !important;
}
/deep/ .ms-opt-btn {
position: fixed;
right: 50px;
z-index: 1;
top: 128px;
float: right;
margin-right: 20px;
margin-top: 5px;
}
/*tab样式 start*/
/deep/ .api-info-tab > .el-tabs__header {
background-color: #F4F6F9;
border: none;
}
/deep/ .api-info-tab > .el-tabs__header .el-tabs__item.is-top {
border-color: #F4F6F9;
color: #8F9198;
}
/deep/ .api-info-tab > .el-tabs__header .el-tabs__item.is-active {
background-color: #FFFFFF;
color: var(--count_number);
border: none;
}
/deep/ .api-info-tab > .el-tabs__header .el-tabs__nav.is-top {
border-color: #F4F6F9;
}
/*tab样式 end*/
</style>

View File

@ -345,6 +345,7 @@ export default {
this.currentApi.request = item.request;
this.currentApi.request.changeId = getUUID();
}
this.$emit("setSelectedCaseId",item.id);
},
changePriority(row) {
if (row.id) {
@ -464,6 +465,7 @@ export default {
if (!hideAlert) {
this.$emit('refresh');
}
this.$emit("saveCaseCallback");
}
}, (error) => {
this.isSave = false;

View File

@ -6,7 +6,7 @@
:api="api"
@setEnvironment="setEnvironment"
@addCase="addCase"
@saveCase="saveCase(apiCaseList[0])"
@saveCase="saveCase"
:condition="condition"
:priorities="priorities"
:project-id="projectId"
@ -17,8 +17,9 @@
<el-container v-if="!result.loading">
<el-main>
<div v-for="item in apiCaseList" :key="item.id ? item.id : item.uuid">
<api-case-item
:loading="singleLoading && singleRunId === apiCaseList[0].id || batchLoadingIds.indexOf(apiCaseList[0].id) > -1"
:loading="singleLoading && singleRunId === item.id || batchLoadingIds.indexOf(item.id) > -1"
@refresh="refresh"
@singleRun="singleRun"
@stop="stop"
@ -27,6 +28,8 @@
@showExecResult="showExecResult"
@showHistory="showHistory"
@reLoadCase="reLoadCase"
@saveCaseCallback="close"
@setSelectedCaseId="setSelectedCaseId"
:environment="environment"
:is-case-edit="isCaseEdit"
:api="api"
@ -34,7 +37,8 @@
:loaded="loaded"
:runResult="runResult"
:maintainerOptions="maintainerOptions"
:api-case="apiCaseList[0]" ref="apiCaseItem"/>
:api-case="item" ref="apiCaseItem"/>
</div>
</el-main>
</el-container>
</ms-drawer>
@ -64,6 +68,8 @@ export default {
},
props: {
createCase: String,
testUsers: Array,
useExternalUsers: Boolean,
loaded: {
type: Boolean,
default: false
@ -79,6 +85,7 @@ export default {
environment: "",
priorities: CASE_ORDER,
apiCaseList: [],
selectCaseId:"",
batchLoadingIds: [],
singleLoading: false,
singleRunId: "",
@ -107,6 +114,9 @@ export default {
this.api = this.currentApi;
this.sysAddition();
},
testUsers() {
this.maintainerOptions = this.testUsers;
}
},
created() {
this.api = this.currentApi;
@ -127,13 +137,20 @@ export default {
},
},
methods: {
getMaintainerOptions() {
this.$post('/user/project/member/tester/list', {projectId: getCurrentProjectID()}, response => {
this.maintainerOptions = response.data;
});
setSelectedCaseId(caseId){
this.selectCaseId = caseId;
},
close(){
if(this.$refs.testCaseDrawer){
getMaintainerOptions() {
if (this.useExternalUsers) {
this.maintainerOptions = this.testUsers;
} else {
this.$post('/user/project/member/tester/list', {projectId: getCurrentProjectID()}, response => {
this.maintainerOptions = response.data;
});
}
},
close() {
if (this.$refs.testCaseDrawer) {
this.$refs.testCaseDrawer.close();
}
},
@ -196,8 +213,17 @@ export default {
}
this.visible = true;
},
saveCase(item, hideAlert) {
this.$refs.apiCaseItem.saveTestCase(item, hideAlert);
saveCase(hideAlert) {
let index = 0;
if(this.selectCaseId && this.selectCaseId !== ''){
for(let i = 0; i < this.apiCaseList.length; i++){
if(this.apiCaseList[i].id === this.selectCaseId){
index = i;
}
}
}
let item = this.apiCaseList[index];
this.$refs.apiCaseItem[index].saveTestCase(item, hideAlert);
},
saveApiAndCase(api) {
if (api && api.url) {

View File

@ -1,6 +1,6 @@
<template>
<div style="margin-bottom: 50px;border-bottom-width: 2px" ref="baseDiv">
<div style="font-size: 17px">
<div style="font-size: 18px; margin-left: 15px">
<el-popover
v-if="projectId"
placement="right"
@ -16,10 +16,12 @@
</el-popover>
{{ apiInfo.name }}
<span class="apiStatusTag">
<api-status :value="apiInfo.status"/>
</span>
<api-status :value="apiInfo.status"/>
</span>
<slot name="headerRight"></slot>
</div>
<!--api请求信息-->
<!--api基础信息-->
<el-row class="apiInfoRow">
<div class="simpleFontClass">
<el-tag size="medium"
@ -40,39 +42,16 @@
</el-row>
</div>
</el-row>
<!--api请求头-->
<api-info-collapse table-coloum-type="nameAndValue" :title="$t('api_test.definition.document.request_head')"
:string-data="apiInfo.requestHead"/>
<!--QUERY参数-->
<api-info-collapse table-coloum-type="simple" :title="'QUERY'+$t('api_test.definition.document.request_param')"
:string-data="apiInfo.urlParams"/>
<!--REST参数-->
<api-info-collapse table-coloum-type="simple" :title="'REST'+$t('api_test.definition.document.request_param')"
:string-data="apiInfo.restParams"/>
<!--api请求体 以及表格-->
<api-info-collapse :is-request="true" :remarks="apiInfo.requestBodyParamType"
:title="$t('api_test.definition.document.request_body')">
<api-request-info slot="request" :api-info="apiInfo"></api-request-info>
</api-info-collapse>
<!--响应头-->
<api-info-collapse table-coloum-type="nameAndValue" :title="$t('api_test.definition.document.response_head')"
:string-data="apiInfo.responseHead"/>
<!--响应体-->
<api-info-collapse :is-response="true" :remarks="apiInfo.responseBodyParamType"
:title="$t('api_test.definition.document.response_body')">
<api-response-info slot="response" :api-info="apiInfo"></api-response-info>
</api-info-collapse>
<!--响应状态码-->
<api-info-collapse :is-text="true" :string-data="getName(apiInfo.responseCode)"
:title="$t('api_test.definition.document.response_code')"/>
<http-information v-if="apiInfo.protocol==='HTTP'" :api-info="apiInfo"/>
<tcp-information v-else-if="apiInfo.protocol==='TCP'" :api="apiObject"/>
<sql-api-information v-else-if="apiInfo.protocol==='SQL'" :api="apiObject"/>
<dubbo-information v-else-if="apiInfo.protocol==='DUBBO'" :api="apiObject"/>
<el-divider></el-divider>
</div>
</template>
<script>
import {API_METHOD_COLOUR} from "@/business/components/api/definition/model/JsonData";
import MsCodeEdit from "@/business/components/common/components/MsCodeEdit";
import ApiStatus from "@/business/components/api/definition/components/list/ApiStatus";
import MsJsonCodeEdit from "@/business/components/common/json-schema/JsonSchemaEditor";
@ -81,7 +60,15 @@ import {generateApiDocumentShareInfo} from "@/network/share";
import ApiInfoCollapse from "@/business/components/api/definition/components/document/components/ApiInfoCollapse";
import ApiRequestInfo from "@/business/components/api/definition/components/document/components/ApiRequestInfo";
import ApiResponseInfo from "@/business/components/api/definition/components/document/components/ApiResponseInfo";
import HttpInformation
from "@/business/components/api/definition/components/document/components/protocal/HttpInformation";
import TcpInformation
from "@/business/components/api/definition/components/document/components/protocal/TcpInformation";
import DubboInformation
from "@/business/components/api/definition/components/document/components/protocal/DubboInformation";
import SqlApiInformation
from "@/business/components/api/definition/components/document/components/protocal/SqlApiInformation";
import {API_METHOD_COLOUR} from "@/business/components/api/definition/model/JsonData";
const requireComponent = require.context('@/business/components/xpack/', true, /\.vue$/);
const apiDocumentBatchShare = (requireComponent != null && requireComponent.keys().length) > 0 ? requireComponent("./share/ApiDocumentBatchShare.vue") : {};
@ -91,10 +78,12 @@ export default {
Api,
MsJsonCodeEdit,
ApiStatus, MsCodeEdit, ApiInfoCollapse, ApiRequestInfo, ApiResponseInfo,
HttpInformation,TcpInformation,DubboInformation,SqlApiInformation,
"ApiDocumentBatchShare": apiDocumentBatchShare.default
},
data() {
return {
apiObject:{},
shareUrl: "",
apiActiveInfoNames: ["info"],
batchShareUrl: "",
@ -102,6 +91,7 @@ export default {
apiInfoArray: [],
modes: ['text', 'json', 'xml', 'html'],
formParamTypes: ['form-data', 'x-www-from-urlencoded', 'BINARY'],
methodColorMap: new Map(API_METHOD_COLOUR),
mockVariableFuncs: [],
apiSearch: {
name: "",
@ -130,7 +120,7 @@ export default {
responseBodyStrutureData: "无",
responseCode: "无",
},
methodColorMap: new Map(API_METHOD_COLOUR),
maxCompnentSize: 5, //api
apiShowArray: [],//api
needAsyncSelect: false, //apimaxCompnentSizetrue
@ -140,11 +130,13 @@ export default {
},
props: {
projectId: String,
apiInfo: Object
apiInfo: Object,
api:Object,
},
activated() {
},
created: function () {
this.apiObject = JSON.parse(JSON.stringify(this.api));
if (requireComponent != null && JSON.stringify(apiDocumentBatchShare) != '{}') {
this.showXpackCompnent = true;
}
@ -193,33 +185,15 @@ export default {
getColor(enable, method) {
return this.methodColorMap.get(method);
},
getName(jsonString) {
let returnString = "无";
if (jsonString == '无' || jsonString == null) {
return returnString;
}
try {
let jsonArr = JSON.parse(jsonString);
//
for (var index = 0; index < jsonArr.length; index++) {
var item = jsonArr[index];
if (item.name !== "") {
returnString = item.name;
break;
}
}
} catch (e) {
returnString = jsonString;
}
return returnString;
},
},
};
</script>
<style scoped>
.apiStatusTag {
margin: 10px 10px;
}
.simpleFontClass {
font-weight: normal;
font-size: 14px;
@ -233,64 +207,60 @@ export default {
.apiInfoRow.el-row {
margin: 10px 10px;
}
.apiStatusTag {
margin: 10px 10px;
}
/*
步骤条中已经完成后的节点样式和里面a标签的样式
*/
/deep/ .el-step {
flex-basis: 40px !important;
}
/deep/ .el-step__head.is-finish {
color: #C0C4CC;
border-color: #C0C4CC;
}
/deep/ .el-step__title.is-finish /deep/ .el-link.el-link--default {
color: #C0C4CC;
}
/*
步骤条中当前节点样式和当前a标签的样式
*/
/deep/ .el-step__head {
width: 20px;
}
/deep/ .el-step__head.is-process {
color: #783887;
border-color: #783887;
width: 20px;
}
/deep/ .el-step__title.is-process .el-link.el-link--default.is-underline {
color: #783887;
}
/deep/ .el-link--inner {
font-size: 12px;
}
/deep/ .el-step__icon-inner {
font-size: 12px;
}
/deep/ .el-step.is-vertical .el-step__line {
left: 9px;
}
/deep/ .el-step__icon {
width: 20px;
height: 20px;
}
.attacInfo {
font-size: 12px;
color: #A0A0A0;
margin: 10px;
}
/*!**/
/*步骤条中已经完成后的节点样式和里面a标签的样式*/
/**!*/
/*/deep/ .el-step {*/
/* flex-basis: 40px !important;*/
/*}*/
/*/deep/ .el-step__head.is-finish {*/
/* color: #C0C4CC;*/
/* border-color: #C0C4CC;*/
/*}*/
/*/deep/ .el-step__title.is-finish /deep/ .el-link.el-link--default {*/
/* color: #C0C4CC;*/
/*}*/
/*!**/
/*步骤条中当前节点样式和当前a标签的样式*/
/**!*/
/*/deep/ .el-step__head {*/
/* width: 20px;*/
/*}*/
/*/deep/ .el-step__head.is-process {*/
/* color: #783887;*/
/* border-color: #783887;*/
/* width: 20px;*/
/*}*/
/*/deep/ .el-step__title.is-process .el-link.el-link--default.is-underline {*/
/* color: #783887;*/
/*}*/
/*/deep/ .el-link--inner {*/
/* font-size: 12px;*/
/*}*/
/*/deep/ .el-step__icon-inner {*/
/* font-size: 12px;*/
/*}*/
/*/deep/ .el-step.is-vertical .el-step__line {*/
/* left: 9px;*/
/*}*/
/*/deep/ .el-step__icon {*/
/* width: 20px;*/
/* height: 20px;*/
/*}*/
</style>

View File

@ -0,0 +1,22 @@
<template>
<div>
<!-- 请求参数 -->
<p class="tip">{{ $t('api_test.definition.request.req_param') }} </p>
<ms-basis-parameters :showScript="false" :is-read-only="true" :request="api.request"/>
</div>
</template>
<script>
import MsBasisParameters from "@/business/components/api/definition/components/request/dubbo/BasisParameters";
export default {
name: "DubboInformation",
components:{MsBasisParameters},
props:{
api:{},
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,75 @@
<template>
<div>
<!--api请求头-->
<api-info-collapse table-coloum-type="nameAndValue" :title="$t('api_test.definition.document.request_head')"
:string-data="apiInfo.requestHead"/>
<!--QUERY参数-->
<api-info-collapse table-coloum-type="simple" :title="'QUERY'+$t('api_test.definition.document.request_param')"
:string-data="apiInfo.urlParams"/>
<!--REST参数-->
<api-info-collapse table-coloum-type="simple" :title="'REST'+$t('api_test.definition.document.request_param')"
:string-data="apiInfo.restParams"/>
<!--api请求体 以及表格-->
<api-info-collapse :is-request="true" :remarks="apiInfo.requestBodyParamType"
:title="$t('api_test.definition.document.request_body')">
<api-request-info slot="request" :api-info="apiInfo"></api-request-info>
</api-info-collapse>
<!--响应头-->
<api-info-collapse table-coloum-type="nameAndValue" :title="$t('api_test.definition.document.response_head')"
:string-data="apiInfo.responseHead"/>
<!--响应体-->
<api-info-collapse :is-response="true" :remarks="apiInfo.responseBodyParamType"
:title="$t('api_test.definition.document.response_body')">
<api-response-info slot="response" :api-info="apiInfo"></api-response-info>
</api-info-collapse>
<!--响应状态码-->
<api-info-collapse :is-text="true" :string-data="getName(apiInfo.responseCode)"
:title="$t('api_test.definition.document.response_code')"/>
</div>
</template>
<script>
import {API_METHOD_COLOUR} from "@/business/components/api/definition/model/JsonData";
import ApiInfoCollapse from "@/business/components/api/definition/components/document/components/ApiInfoCollapse";
import ApiRequestInfo from "@/business/components/api/definition/components/document/components/ApiRequestInfo";
import ApiResponseInfo from "@/business/components/api/definition/components/document/components/ApiResponseInfo";
export default {
name: "HttpInformation",
props: {
apiInfo: {},
},
components:{ApiInfoCollapse,ApiResponseInfo,ApiRequestInfo},
data() {
return {
}
},
methods: {
getName(jsonString) {
let returnString = "无";
if (jsonString === '无' || jsonString === null) {
return returnString;
}
try {
let jsonArr = JSON.parse(jsonString);
//
for (var index = 0; index < jsonArr.length; index++) {
var item = jsonArr[index];
if (item.name !== "") {
returnString = item.name;
break;
}
}
} catch (e) {
returnString = jsonString;
}
return returnString;
},
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,22 @@
<template>
<div>
<!-- 请求参数 -->
<p class="tip">{{ $t('api_test.definition.request.req_param') }} </p>
<ms-basis-parameters :showScript="false" :is-read-only="true" :request="api.request"/>
</div>
</template>
<script>
import MsBasisParameters from "@/business/components/api/definition/components/request/database/BasisParameters";
export default {
name: "SqlApiInformation",
components:{MsBasisParameters},
props:{
api:{},
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,71 @@
<template>
<div>
<!-- 请求参数 -->
<div v-if="apiProtocol=='TCP'">
<p class="tip">{{ $t('api_test.definition.request.req_param') }} </p>
<ms-tcp-format-parameters :is-read-only="true" :show-pre-script="true" :show-script="false" :request="api.request"
ref="tcpFormatParameter"/>
</div>
<div v-else-if="apiProtocol=='ESB'">
<p class="tip">{{ $t('api_test.definition.request.req_param') }} </p>
<esb-definition v-xpack :show-pre-script="true" v-if="showXpackCompnent" :show-script="false" :request="api.request"
ref="esbDefinition"/>
<p class="tip">{{ $t('api_test.definition.request.res_param') }}</p>
<esb-definition-response v-xpack v-if="showXpackCompnent" :is-api-component="true" :show-options-button="true"
:request="api.request"/>
</div>
</div>
</template>
<script>
import {hasLicense} from "@/common/js/utils";
const requireComponent = require.context('@/business/components/xpack/', true, /\.vue$/);
const esbDefinition = (requireComponent != null && requireComponent.keys().length) > 0 ? requireComponent("./apidefinition/EsbDefinition.vue") : {};
const esbDefinitionResponse = (requireComponent != null && requireComponent.keys().length) > 0 ? requireComponent("./apidefinition/EsbDefinitionResponse.vue") : {};
import MsTcpFormatParameters from "@/business/components/api/definition/components/request/tcp/TcpFormatParameters";
export default {
name: "TcpInformation",
components:{
MsTcpFormatParameters,
"esbDefinition": esbDefinition.default,
"esbDefinitionResponse": esbDefinitionResponse.default,
},
props:{
api:{},
},
data(){
return{
apiProtocol: "TCP",
showXpackCompnent: false,
methodTypes: [
{
'key': "TCP",
'value': this.$t('api_test.request.tcp.general_format'),
}
],
}
},
created() {
this.apiProtocol = this.api.method;
if (this.apiProtocol === null || this.apiProtocol === "") {
this.apiProtocol = "TCP";
}
if (requireComponent !== null && JSON.stringify(esbDefinition) !== '{}' && JSON.stringify(esbDefinitionResponse) !== '{}') {
this.showXpackCompnent = true;
if (hasLicense()) {
if (this.methodTypes.length === 1) {
let esbMethodType = {};
esbMethodType.key = "ESB";
esbMethodType.value = "ESB";
this.methodTypes.push(esbMethodType);
}
}
}
}
}
</script>
<style scoped>
</style>

View File

@ -213,7 +213,7 @@
:total="total"/>
</span>
<api-case-list @showExecResult="showExecResult" @refreshCase="setRunning" :currentApi="selectCase" ref="caseList"
<api-case-list @showExecResult="showExecResult" @refreshCase="setRunning" :currentApi="selectCase" ref="caseList" :test-users="testUsers" :use-external-users="useExternalUsers"
@stop="stop" @reLoadCase="initTable"/>
<!--批量编辑-->
<ms-batch-edit ref="batchEdit" :data-count="$refs.caseTable ? $refs.caseTable.selectDataCounts : 0"
@ -445,6 +445,8 @@ export default {
};
},
props: {
testUsers:Array,
useExternalUsers:Boolean,
currentProtocol: String,
currentVersion: String,
apiDefinitionId: String,

View File

@ -51,8 +51,8 @@
sortable>
<template slot-scope="scope">
<el-tooltip content="编辑">
<a style="cursor:pointer" @click="editApi(scope.row)"> {{ scope.row.num }} </a>
<el-tooltip :content="$t('commons.view')">
<a style="cursor:pointer" @click="showApi(scope.row)"> {{ scope.row.num }} </a>
</el-tooltip>
</template>
</ms-table-column>
@ -63,7 +63,13 @@
sortable="custom"
:fields-width="fieldsWidth"
min-width="120"
:field="item"/>
:field="item">
<template slot-scope="scope">
<el-tooltip :content="$t('commons.view')">
<a style="cursor:pointer" @click="showApi(scope.row)"> {{ scope.row.name }} </a>
</el-tooltip>
</template>
</ms-table-column>
<ms-table-column
prop="status"
@ -677,6 +683,9 @@ export default {
editApi(row) {
this.$emit('editApi', row);
},
showApi(row) {
this.$emit('showApi', row);
},
handleCopy(row) {
let obj = JSON.parse(JSON.stringify(row));
obj.isCopy = true;

View File

@ -93,7 +93,7 @@ export default {
arguments: [],
rest: [],
body: {
type: 'Form Data',
type: 'Raw',
binary: [],
kvs: [],
}

View File

@ -13,7 +13,7 @@
<ms-table
v-loading="result.loading"
:data="mockConfigData.mockExpectConfigList.filter(data=>!tableSearch || data.name.toLowerCase().includes(tableSearch.toLowerCase()))"
:data="filterMockData()"
:operators="operators"
:page-size="pageSize"
:showSelectAll="false"
@ -72,9 +72,10 @@
</ms-table-column>
</ms-table>
</div>
<mock-edit-drawer :is-tcp="isTcp" :api-id="this.baseMockConfigData.mockConfig.apiId"
<mock-edit-drawer :is-tcp="isTcp" :api-id="apiId"
:api-params="apiParams"
@refreshMockInfo="refreshMockInfo"
v-if="mockConfigData && mockConfigData.mockConfig && mockConfigData.mockConfig.id"
:mock-config-id="mockConfigData.mockConfig.id" ref="mockEditDrawer"/>
</div>
</template>
@ -95,7 +96,8 @@ export default {
},
props: {
baseMockConfigData: {},
versionName:String,
versionName: String,
apiId: String,
isTcp: {
type: Boolean,
default: false,
@ -151,6 +153,14 @@ export default {
},
},
methods: {
filterMockData() {
if (this.mockConfigData && this.mockConfigData.mockExpectConfigList) {
return this.mockConfigData.mockExpectConfigList.filter(
data => !this.tableSearch || data.name.toLowerCase().includes(this.tableSearch.toLowerCase()))
} else {
return [];
}
},
redirectToTest(row) {
let requestParam = null;
if (row && row.request) {

View File

@ -5,7 +5,8 @@
<el-tabs v-model="activeName" class="request-tabs" @tab-click="tabClick">
<!-- 请求头-->
<el-tab-pane :label="$t('api_test.request.headers')" name="headers">
<el-tooltip class="item-tabs" effect="dark" :content="$t('api_test.request.headers')" placement="top-start" slot="label">
<el-tooltip class="item-tabs" effect="dark" :content="$t('api_test.request.headers')" placement="top-start"
slot="label">
<span>{{ $t('api_test.request.headers') }}
<div class="el-step__icon is-text ms-api-col ms-header" v-if="headers.length>1">
<div class="el-step__icon-inner">{{ headers.length - 1 }}</div>
@ -13,14 +14,20 @@
</span>
</el-tooltip>
<el-row>
<el-link class="ms-el-link" @click="batchAdd" style="color: #783887"> {{ $t("commons.batch_add") }}</el-link>
<el-link class="ms-el-link" @click="batchAdd" style="color: #783887"> {{
$t("commons.batch_add")
}}
</el-link>
</el-row>
<ms-api-key-value @editScenarioAdvance="editScenarioAdvance" :scenario-definition="scenarioDefinition" :show-desc="true" :is-read-only="isReadOnly" :isShowEnable="isShowEnable" :suggestions="headerSuggestions" :items="headers" :need-mock="true"/>
<ms-api-key-value @editScenarioAdvance="editScenarioAdvance" :scenario-definition="scenarioDefinition"
:show-desc="true" :is-read-only="isReadOnly" :isShowEnable="isShowEnable"
:suggestions="headerSuggestions" :items="headers" :need-mock="true"/>
</el-tab-pane>
<!--query 参数-->
<el-tab-pane :label="$t('api_test.definition.request.query_param')" name="parameters">
<el-tooltip class="item-tabs" effect="dark" :content="$t('api_test.definition.request.query_info')" placement="top-start" slot="label">
<el-tooltip class="item-tabs" effect="dark" :content="$t('api_test.definition.request.query_info')"
placement="top-start" slot="label">
<span>{{ $t('api_test.definition.request.query_param') }}
<div class="el-step__icon is-text ms-api-col ms-header" v-if="request.arguments.length>1">
<div class="el-step__icon-inner">{{ request.arguments.length - 1 }}</div>
@ -28,14 +35,20 @@
</span>
</el-tooltip>
<el-row>
<el-link class="ms-el-link" @click="batchAdd" style="color: #783887"> {{ $t("commons.batch_add") }}</el-link>
<el-link class="ms-el-link" @click="batchAdd" style="color: #783887"> {{
$t("commons.batch_add")
}}
</el-link>
</el-row>
<ms-api-variable @editScenarioAdvance="editScenarioAdvance" :scenario-definition="scenarioDefinition" :with-mor-setting="true" :is-read-only="isReadOnly" :isShowEnable="isShowEnable" :parameters="request.arguments"/>
<ms-api-variable @editScenarioAdvance="editScenarioAdvance" :scenario-definition="scenarioDefinition"
:with-mor-setting="true" :is-read-only="isReadOnly" :isShowEnable="isShowEnable"
:parameters="request.arguments"/>
</el-tab-pane>
<!--REST 参数-->
<el-tab-pane :label="$t('api_test.definition.request.rest_param')" name="rest">
<el-tooltip class="item-tabs" effect="dark" :content="$t('api_test.definition.request.rest_info')" placement="top-start" slot="label">
<el-tooltip class="item-tabs" effect="dark" :content="$t('api_test.definition.request.rest_info')"
placement="top-start" slot="label">
<span>
{{ $t('api_test.definition.request.rest_param') }}
<div class="el-step__icon is-text ms-api-col ms-header" v-if="request.rest.length>1">
@ -44,9 +57,14 @@
</span>
</el-tooltip>
<el-row>
<el-link class="ms-el-link" @click="batchAdd" style="color: #783887"> {{ $t("commons.batch_add") }}</el-link>
<el-link class="ms-el-link" @click="batchAdd" style="color: #783887"> {{
$t("commons.batch_add")
}}
</el-link>
</el-row>
<ms-api-variable @editScenarioAdvance="editScenarioAdvance" :scenario-definition="scenarioDefinition" :with-mor-setting="true" :is-read-only="isReadOnly" :isShowEnable="isShowEnable" :parameters="request.rest"/>
<ms-api-variable @editScenarioAdvance="editScenarioAdvance" :scenario-definition="scenarioDefinition"
:with-mor-setting="true" :is-read-only="isReadOnly" :isShowEnable="isShowEnable"
:parameters="request.rest"/>
</el-tab-pane>
<!--请求体-->
@ -56,7 +74,8 @@
<!-- 认证配置 -->
<el-tab-pane :label="$t('api_test.definition.request.auth_config')" name="authConfig">
<el-tooltip class="item-tabs" effect="dark" :content="$t('api_test.definition.request.auth_config_info')" placement="top-start" slot="label">
<el-tooltip class="item-tabs" effect="dark" :content="$t('api_test.definition.request.auth_config_info')"
placement="top-start" slot="label">
<span>{{ $t('api_test.definition.request.auth_config') }}</span>
</el-tooltip>
@ -93,7 +112,8 @@
<div class="el-step__icon-inner">{{ request.ruleSize }}</div>
</div>
</span>
<ms-jmx-step :request="request" :apiId="request.id" :response="response" @reload="reloadBody" :tab-type="'assertionsRule'" ref="assertionsRule"/>
<ms-jmx-step :request="request" :apiId="request.id" :response="response" @reload="reloadBody"
:tab-type="'assertionsRule'" ref="assertionsRule"/>
</el-tab-pane>
</el-tabs>

View File

@ -56,7 +56,6 @@
this.isActive = !this.isActive;
},
},
mounted() {
if (!this.response.headers) {
return;

View File

@ -2,7 +2,9 @@
<div class="card-container">
<div class="ms-opt-btn" v-if="versionEnable">
<slot name="msOptBtnLeft"></slot>
{{ $t('project.version.name') }}: {{ apiData.versionName }}
<slot name="msOptBtnRight"></slot>
</div>
<el-card class="card-content">

View File

@ -1,5 +1,5 @@
<template>
<el-card class="table-card" v-loading="result.loading" body-style="padding:16px 5px 16px 16px;" style="height: 350px;margin-top: 5px">
<el-card class="table-card" v-loading="result.loading" body-style="padding:16px 5px 16px 16px;" style="height: 360px;margin-top: 5px">
<div slot="header">
<span class="title">
{{ $t('api_test.home_page.api_count_card.title') }}

View File

@ -1,6 +1,6 @@
<template>
<el-card class="table-card" v-loading="result.loading" body-style="padding:16px 5px 16px 16px;"
style="height: 350px;margin-top: 5px">
style="height: 360px;margin-top: 5px">
<div slot="header">
<span class="title">
{{ $t('api_test.home_page.test_scene_count_card.title') }}

View File

@ -1,6 +1,6 @@
<template>
<el-card class="table-card" v-loading="result.loading" body-style="padding:16px 5px 16px 16px;"
style="height: 350px;margin-top: 5px">
style="height: 360px;margin-top: 5px">
<div slot="header">
<span class="title">
{{ $t('api_test.home_page.schedule_task_count_card.title') }}

View File

@ -1,6 +1,6 @@
<template>
<el-card class="table-card" v-loading="result.loading" body-style="padding:16px 5px 16px 16px;"
style="height: 350px;margin-top: 5px">
style="height: 360px;margin-top: 5px">
<div slot="header">
<span class="title">
{{ $t('api_test.home_page.test_case_count_card.title') }}

View File

@ -42,6 +42,12 @@ export default {
{
path: "definition/:redirectID?/:dataType?/:dataSelectRange?/:projectId?/:type?",
name: "ApiDefinition",
// component: () => import('@/business/components/api/definition/ApiDefinition'),
component: () => import('@/business/components/api/definition/ApiDefinitionBaseView'),
},
{
path: "oldDefinition/:redirectID?/:dataType?/:dataSelectRange?/:projectId?/:type?",
name: "ApiDefinition",
component: () => import('@/business/components/api/definition/ApiDefinition'),
},
{

View File

@ -1,20 +1,29 @@
<template>
<el-main class="ms-main-container">
<el-main class="ms-main-container" :style="{
'height': calHeight,
}">
<slot></slot>
</el-main>
</template>
<script>
export default {
name: "MsMainContainer"
}
export default {
name: "MsMainContainer",
props: {
enableAutoHeight: Boolean
},
computed: {
calHeight() {
return this.enableAutoHeight ? null : 'calc(100vh - 80px)';
},
},
}
</script>
<style scoped>
.ms-main-container {
padding: 5px 10px;
height: calc(100vh - 80px);
}
.ms-main-container {
padding: 5px 10px;
}
</style>

View File

@ -118,5 +118,4 @@ export default {
padding: 5px 8px;
border: solid 1px var(--primary_color);
}
</style>

View File

@ -0,0 +1,39 @@
<template>
<div>
<ms-container>
<ms-aside-container v-show="showAside" :enable-auto-height="true">
<slot name="aside"></slot>
</ms-aside-container>
<ms-main-container :enable-auto-height="true">
<slot name="mainContainer"></slot>
</ms-main-container>
</ms-container>
</div>
</template>
<script>
import MsContainer from "@/business/components/common/components/MsContainer";
import MsMainContainer from "@/business/components/common/components/MsMainContainer";
import MsAsideContainer from "@/business/components/common/components/MsAsideContainer";
export default {
name: "ApiTestBaseContainer",
components: {MsMainContainer, MsAsideContainer,MsContainer},
props:{
showAside:{
type:Boolean,
default(){
return true;
}
}
},
data(){
return{
}
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,32 @@
<template>
<div>
</div>
</template>
<script>
import ApiTestBaseContainer from "@/business/components/common/layout/ApiTestBaseContainer";
export default {
name: "ApiTestBaseLayout",
components:{
ApiTestBaseContainer
},
data() {
return {
trashEnable: false,
activeName:"",
};
},
methods:{
handleClick(){
this.$emit("changeTab")
}
},
}
</script>
<style scoped>
</style>

View File

@ -1259,6 +1259,7 @@ export default {
extract_param: "Extract parameters",
add_module: "Add module",
edit_api: "Edit Api",
show_api: "Api Info",
test_plan_select: "Please select test plan",
create_info: 'Create',
update_info: 'Update',

View File

@ -1265,6 +1265,7 @@ export default {
extract_param: "提取参数",
add_module: "创建模块",
edit_api: "编辑接口",
show_api: "查看接口",
test_plan_select: "请选择测试计划",
create_info: '创建',
update_info: '更新',

View File

@ -1265,6 +1265,7 @@ export default {
extract_param: "提取參數",
add_module: "創建模塊",
edit_api: "編輯接口",
show_api: "查看接口",
test_plan_select: "請選擇測試計劃",
create_info: '創建',
update_info: '更新',