实现swagger的代理请求和数据的格式化展示开发
This commit is contained in:
@@ -75,7 +75,8 @@ public class SwaggerDocumentController {
|
|||||||
// UI地址替换为文档json地址
|
// UI地址替换为文档json地址
|
||||||
String docUrl = SwaggerDocUtil.replaceSwaggerResources(swaggerDoc.getDocUrl());
|
String docUrl = SwaggerDocUtil.replaceSwaggerResources(swaggerDoc.getDocUrl());
|
||||||
if (SwaggerDocUtil.isSwaggerResources(docUrl)) {
|
if (SwaggerDocUtil.isSwaggerResources(docUrl)) {
|
||||||
String resourcesStr = swaggerHttpRequestService.requestSwaggerUrl(request, docUrl);
|
String swaggerDomain = SwaggerDocUtil.getSwaggerResourceDomain(docUrl);
|
||||||
|
String resourcesStr = swaggerHttpRequestService.requestSwaggerUrl(request, docUrl, swaggerDomain);
|
||||||
List<SwaggerResource> resourceList = JSON.parseArray(resourcesStr, SwaggerResource.class);
|
List<SwaggerResource> resourceList = JSON.parseArray(resourcesStr, SwaggerResource.class);
|
||||||
if (resourceList == null || resourceList.isEmpty()) {
|
if (resourceList == null || resourceList.isEmpty()) {
|
||||||
return DocResponseJson.warn("该地址未找到文档");
|
return DocResponseJson.warn("该地址未找到文档");
|
||||||
@@ -85,7 +86,6 @@ public class SwaggerDocumentController {
|
|||||||
swaggerDocService.removeById(swaggerDoc.getId());
|
swaggerDocService.removeById(swaggerDoc.getId());
|
||||||
}
|
}
|
||||||
// 存明细地址
|
// 存明细地址
|
||||||
String swaggerDomain = SwaggerDocUtil.getSwaggerResourceDomain(docUrl);
|
|
||||||
for (SwaggerResource resource : resourceList) {
|
for (SwaggerResource resource : resourceList) {
|
||||||
swaggerDoc.setId(null);
|
swaggerDoc.setId(null);
|
||||||
swaggerDoc.setDocUrl(swaggerDomain + resource.getUrl());
|
swaggerDoc.setDocUrl(swaggerDomain + resource.getUrl());
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import com.zyplayer.doc.core.exception.ConfirmException;
|
|||||||
import com.zyplayer.doc.data.repository.manage.entity.SwaggerDoc;
|
import com.zyplayer.doc.data.repository.manage.entity.SwaggerDoc;
|
||||||
import com.zyplayer.doc.data.service.manage.SwaggerDocService;
|
import com.zyplayer.doc.data.service.manage.SwaggerDocService;
|
||||||
import com.zyplayer.doc.swaggerplus.controller.vo.SwaggerResourceVo;
|
import com.zyplayer.doc.swaggerplus.controller.vo.SwaggerResourceVo;
|
||||||
|
import com.zyplayer.doc.swaggerplus.framework.utils.SwaggerDocUtil;
|
||||||
import com.zyplayer.doc.swaggerplus.service.SwaggerHttpRequestService;
|
import com.zyplayer.doc.swaggerplus.service.SwaggerHttpRequestService;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
@@ -63,7 +64,8 @@ public class SwaggerProxyController {
|
|||||||
throw new ConfirmException("文档不存在");
|
throw new ConfirmException("文档不存在");
|
||||||
}
|
}
|
||||||
if (Objects.equals(swaggerDoc.getDocType(), 1)) {
|
if (Objects.equals(swaggerDoc.getDocType(), 1)) {
|
||||||
String contentStr = swaggerHttpRequestService.requestSwaggerUrl(request, swaggerDoc.getDocUrl());
|
String docsDomain = SwaggerDocUtil.getV2ApiDocsDomain(swaggerDoc.getDocUrl());
|
||||||
|
String contentStr = swaggerHttpRequestService.requestSwaggerUrl(request, swaggerDoc.getDocUrl(), docsDomain);
|
||||||
return new ResponseEntity<>(new Json(contentStr), HttpStatus.OK);
|
return new ResponseEntity<>(new Json(contentStr), HttpStatus.OK);
|
||||||
}
|
}
|
||||||
return new ResponseEntity<>(new Json(swaggerDoc.getJsonContent()), HttpStatus.OK);
|
return new ResponseEntity<>(new Json(swaggerDoc.getJsonContent()), HttpStatus.OK);
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
public class ProxyRequestParam {
|
public class ProxyRequestParam {
|
||||||
private String url;
|
private String url;
|
||||||
|
private String host;
|
||||||
private String method;
|
private String method;
|
||||||
private String contentType;
|
private String contentType;
|
||||||
private String headerParam;
|
private String headerParam;
|
||||||
@@ -99,4 +100,12 @@ public class ProxyRequestParam {
|
|||||||
public void setContentType(String contentType) {
|
public void setContentType(String contentType) {
|
||||||
this.contentType = contentType;
|
this.contentType = contentType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getHost() {
|
||||||
|
return host;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHost(String host) {
|
||||||
|
this.host = host;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ public class ProxyRequestResultVo {
|
|||||||
private List<HttpHeaderVo> headers;
|
private List<HttpHeaderVo> headers;
|
||||||
private Integer status;
|
private Integer status;
|
||||||
private Long useTime;
|
private Long useTime;
|
||||||
|
private Integer bodyLength;
|
||||||
private String data;
|
private String data;
|
||||||
private String errorMsg;
|
private String errorMsg;
|
||||||
|
|
||||||
@@ -58,4 +59,12 @@ public class ProxyRequestResultVo {
|
|||||||
public void setErrorMsg(String errorMsg) {
|
public void setErrorMsg(String errorMsg) {
|
||||||
this.errorMsg = errorMsg;
|
this.errorMsg = errorMsg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Integer getBodyLength() {
|
||||||
|
return bodyLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBodyLength(Integer bodyLength) {
|
||||||
|
this.bodyLength = bodyLength;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,24 @@ public class SwaggerDocUtil {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String getV2ApiDocsDomain(String docUrl) {
|
||||||
|
int index = docUrl.indexOf("/v2/api-docs");
|
||||||
|
if (index >= 0) {
|
||||||
|
return docUrl.substring(0, index);
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getDomainHost(String domain) {
|
||||||
|
domain = domain.replace("http://", "");
|
||||||
|
domain = domain.replace("https://", "");
|
||||||
|
int index = domain.indexOf("/");
|
||||||
|
if (index >= 0) {
|
||||||
|
return domain.substring(0, index);
|
||||||
|
}
|
||||||
|
return domain;
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean isSwaggerLocation(String docUrl) {
|
public static boolean isSwaggerLocation(String docUrl) {
|
||||||
return docUrl.contains("/v2/api-docs");
|
return docUrl.contains("/v2/api-docs");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.zyplayer.doc.swaggerplus.service;
|
|||||||
|
|
||||||
import cn.hutool.http.HttpRequest;
|
import cn.hutool.http.HttpRequest;
|
||||||
import cn.hutool.http.HttpResponse;
|
import cn.hutool.http.HttpResponse;
|
||||||
|
import cn.hutool.http.HttpUtil;
|
||||||
import cn.hutool.http.Method;
|
import cn.hutool.http.Method;
|
||||||
import com.zyplayer.doc.core.exception.ConfirmException;
|
import com.zyplayer.doc.core.exception.ConfirmException;
|
||||||
import com.zyplayer.doc.data.repository.manage.entity.SwaggerGlobalParam;
|
import com.zyplayer.doc.data.repository.manage.entity.SwaggerGlobalParam;
|
||||||
@@ -10,9 +11,9 @@ import com.zyplayer.doc.swaggerplus.controller.param.ProxyRequestParam;
|
|||||||
import com.zyplayer.doc.swaggerplus.controller.vo.HttpCookieVo;
|
import com.zyplayer.doc.swaggerplus.controller.vo.HttpCookieVo;
|
||||||
import com.zyplayer.doc.swaggerplus.controller.vo.HttpHeaderVo;
|
import com.zyplayer.doc.swaggerplus.controller.vo.HttpHeaderVo;
|
||||||
import com.zyplayer.doc.swaggerplus.controller.vo.ProxyRequestResultVo;
|
import com.zyplayer.doc.swaggerplus.controller.vo.ProxyRequestResultVo;
|
||||||
|
import com.zyplayer.doc.swaggerplus.framework.utils.SwaggerDocUtil;
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
import org.apache.commons.collections.MapUtils;
|
import org.apache.commons.collections.MapUtils;
|
||||||
import org.apache.commons.lang.ArrayUtils;
|
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
@@ -32,13 +33,16 @@ public class SwaggerHttpRequestService {
|
|||||||
|
|
||||||
private static final Map<String, Method> requestMethodMap = Stream.of(Method.values()).collect(Collectors.toMap(val -> val.name().toLowerCase(), val -> val));
|
private static final Map<String, Method> requestMethodMap = Stream.of(Method.values()).collect(Collectors.toMap(val -> val.name().toLowerCase(), val -> val));
|
||||||
|
|
||||||
|
List<String> domainHeaderKeys = Arrays.asList("referer", "origin");
|
||||||
|
List<String> needRequestHeaderKeys = Arrays.asList("user-agent");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 请求真实的swagger文档内容
|
* 请求真实的swagger文档内容
|
||||||
*
|
*
|
||||||
* @author 暮光:城中城
|
* @author 暮光:城中城
|
||||||
* @since 2021-11-04
|
* @since 2021-11-04
|
||||||
*/
|
*/
|
||||||
public String requestSwaggerUrl(HttpServletRequest request, String docUrl) {
|
public String requestSwaggerUrl(HttpServletRequest request, String docUrl, String docDomain) {
|
||||||
List<SwaggerGlobalParam> globalParamList = swaggerGlobalParamService.getGlobalParamList();
|
List<SwaggerGlobalParam> globalParamList = swaggerGlobalParamService.getGlobalParamList();
|
||||||
Map<String, Object> globalFormParamMap = globalParamList.stream().filter(item -> Objects.equals(item.getParamType(), 1))
|
Map<String, Object> globalFormParamMap = globalParamList.stream().filter(item -> Objects.equals(item.getParamType(), 1))
|
||||||
.collect(Collectors.toMap(SwaggerGlobalParam::getParamKey, SwaggerGlobalParam::getParamValue));
|
.collect(Collectors.toMap(SwaggerGlobalParam::getParamKey, SwaggerGlobalParam::getParamValue));
|
||||||
@@ -46,10 +50,15 @@ public class SwaggerHttpRequestService {
|
|||||||
.collect(Collectors.toMap(SwaggerGlobalParam::getParamKey, SwaggerGlobalParam::getParamValue));
|
.collect(Collectors.toMap(SwaggerGlobalParam::getParamKey, SwaggerGlobalParam::getParamValue));
|
||||||
Map<String, String> globalCookieParamMap = globalParamList.stream().filter(item -> Objects.equals(item.getParamType(), 3))
|
Map<String, String> globalCookieParamMap = globalParamList.stream().filter(item -> Objects.equals(item.getParamType(), 3))
|
||||||
.collect(Collectors.toMap(SwaggerGlobalParam::getParamKey, SwaggerGlobalParam::getParamValue));
|
.collect(Collectors.toMap(SwaggerGlobalParam::getParamKey, SwaggerGlobalParam::getParamValue));
|
||||||
|
Map<String, String> requestHeaders = this.getHttpHeader(request, globalHeaderParamMap);
|
||||||
|
if (StringUtils.isNotBlank(docDomain)) {
|
||||||
|
domainHeaderKeys.forEach(key -> requestHeaders.put(key, docDomain));
|
||||||
|
requestHeaders.put("host", SwaggerDocUtil.getDomainHost(docDomain));
|
||||||
|
}
|
||||||
// 执行请求
|
// 执行请求
|
||||||
String resultStr = HttpRequest.get(docUrl)
|
String resultStr = HttpRequest.get(docUrl)
|
||||||
.form(globalFormParamMap)
|
.form(globalFormParamMap)
|
||||||
.addHeaders(this.getHttpHeader(request, globalHeaderParamMap))
|
.addHeaders(requestHeaders)
|
||||||
.header("Accept", "application/json, text/javascript, */*; q=0.01")
|
.header("Accept", "application/json, text/javascript, */*; q=0.01")
|
||||||
.cookie(this.getHttpCookie(request, globalCookieParamMap))
|
.cookie(this.getHttpCookie(request, globalCookieParamMap))
|
||||||
.timeout(10000).execute().body();
|
.timeout(10000).execute().body();
|
||||||
@@ -71,9 +80,15 @@ public class SwaggerHttpRequestService {
|
|||||||
if (method == null) {
|
if (method == null) {
|
||||||
throw new ConfirmException("不支持的请求方式:" + requestParam.getMethod());
|
throw new ConfirmException("不支持的请求方式:" + requestParam.getMethod());
|
||||||
}
|
}
|
||||||
HttpRequest httpRequest = new HttpRequest(requestParam.getUrl()).setMethod(method);
|
HttpRequest httpRequest = HttpUtil.createRequest(method, requestParam.getUrl());
|
||||||
|
// header获取
|
||||||
|
Map<String, String> requestHeaders = this.getHttpHeader(request, Collections.emptyMap());
|
||||||
|
if (StringUtils.isNotBlank(requestParam.getHost())) {
|
||||||
|
domainHeaderKeys.forEach(key -> requestHeaders.put(key, requestParam.getHost()));
|
||||||
|
requestHeaders.put("host", SwaggerDocUtil.getDomainHost(requestParam.getHost()));
|
||||||
|
}
|
||||||
// http自带参数
|
// http自带参数
|
||||||
httpRequest.addHeaders(this.getHttpHeader(request, Collections.emptyMap()));
|
httpRequest.addHeaders(requestHeaders);
|
||||||
httpRequest.cookie(this.getHttpCookie(request, Collections.emptyMap()));
|
httpRequest.cookie(this.getHttpCookie(request, Collections.emptyMap()));
|
||||||
// 用户输入的参数
|
// 用户输入的参数
|
||||||
requestParam.getFormParamData().forEach(data -> httpRequest.form(data.getCode(), data.getValue()));
|
requestParam.getFormParamData().forEach(data -> httpRequest.form(data.getCode(), data.getValue()));
|
||||||
@@ -90,6 +105,7 @@ public class SwaggerHttpRequestService {
|
|||||||
HttpResponse httpResponse = httpRequest.timeout(10000).execute();
|
HttpResponse httpResponse = httpRequest.timeout(10000).execute();
|
||||||
resultVo.setData(httpResponse.body());
|
resultVo.setData(httpResponse.body());
|
||||||
resultVo.setStatus(httpResponse.getStatus());
|
resultVo.setStatus(httpResponse.getStatus());
|
||||||
|
resultVo.setBodyLength(httpResponse.bodyBytes().length);
|
||||||
// 设置返回的cookies
|
// 设置返回的cookies
|
||||||
List<HttpCookie> responseCookies = httpResponse.getCookies();
|
List<HttpCookie> responseCookies = httpResponse.getCookies();
|
||||||
if (CollectionUtils.isNotEmpty(responseCookies)) {
|
if (CollectionUtils.isNotEmpty(responseCookies)) {
|
||||||
@@ -141,13 +157,11 @@ public class SwaggerHttpRequestService {
|
|||||||
private Map<String, String> getHttpHeader(HttpServletRequest request, Map<String, String> globalHeaderParamMap) {
|
private Map<String, String> getHttpHeader(HttpServletRequest request, Map<String, String> globalHeaderParamMap) {
|
||||||
Map<String, String> headerParamMap = new HashMap<>();
|
Map<String, String> headerParamMap = new HashMap<>();
|
||||||
Enumeration<String> headerNames = request.getHeaderNames();
|
Enumeration<String> headerNames = request.getHeaderNames();
|
||||||
String[] notNeedHeaders = new String[]{"referer", "origin", "host"};
|
|
||||||
while (headerNames.hasMoreElements()) {
|
while (headerNames.hasMoreElements()) {
|
||||||
String headerName = headerNames.nextElement();
|
String headerName = StringUtils.lowerCase(headerNames.nextElement());
|
||||||
if (ArrayUtils.contains(notNeedHeaders, headerName)) {
|
if (needRequestHeaderKeys.contains(headerName)) {
|
||||||
continue;
|
headerParamMap.put(headerName, request.getHeader(headerName));
|
||||||
}
|
}
|
||||||
// headerParamMap.put(headerName, request.getHeader(headerName));
|
|
||||||
}
|
}
|
||||||
if (MapUtils.isNotEmpty(globalHeaderParamMap)) {
|
if (MapUtils.isNotEmpty(globalHeaderParamMap)) {
|
||||||
headerParamMap.putAll(globalHeaderParamMap);
|
headerParamMap.putAll(globalHeaderParamMap);
|
||||||
|
|||||||
@@ -0,0 +1,209 @@
|
|||||||
|
|
||||||
|
import datasourceApi from '../../api/datasource'
|
||||||
|
/**
|
||||||
|
* 编辑框自动提示数据库、表和字段等
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
isInit: false,
|
||||||
|
source: {},
|
||||||
|
databaseInfo: {},
|
||||||
|
tableInfo: {},
|
||||||
|
columnInfo: {},
|
||||||
|
lastCallbackArr: [],
|
||||||
|
isAutocomplete: false,
|
||||||
|
change(source) {
|
||||||
|
this.source = source;
|
||||||
|
this.lastCallbackArr = [];
|
||||||
|
console.log("change(sourceId):" + JSON.stringify(this.source));
|
||||||
|
if (!this.isInit) {
|
||||||
|
console.log("change(sourceId),isInit:" + this.isInit);
|
||||||
|
this.isInit = true;
|
||||||
|
let languageTools = ace.acequire("ace/ext/language_tools");
|
||||||
|
languageTools.addCompleter(this);
|
||||||
|
}
|
||||||
|
// 初始加载
|
||||||
|
if (!!this.source.sourceId) {
|
||||||
|
// 加载所有库
|
||||||
|
let databaseList = this.databaseInfo[this.source.sourceId] || [];
|
||||||
|
if (databaseList.length <= 0) {
|
||||||
|
datasourceApi.databaseList({sourceId: this.source.sourceId}).then(json => {
|
||||||
|
this.databaseInfo[this.source.sourceId] = json.data || [];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 加载库下所有表
|
||||||
|
if (!!this.source.dbName) {
|
||||||
|
let tableKey = this.source.sourceId + '_' + this.source.dbName;
|
||||||
|
let tableList = this.tableInfo[tableKey] || [];
|
||||||
|
if (tableList.length <= 0) {
|
||||||
|
datasourceApi.tableList({sourceId: this.source.sourceId, dbName: this.source.dbName}).then(json => {
|
||||||
|
this.tableInfo[tableKey] = json.data || [];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 加载表下所有字段
|
||||||
|
if (!!this.source.tableName) {
|
||||||
|
let columnKey = this.source.sourceId + '_' + this.source.dbName + '_' + this.source.tableName;
|
||||||
|
let columnList = this.columnInfo[columnKey] || [];
|
||||||
|
if (columnList.length <= 0) {
|
||||||
|
datasourceApi.tableColumnList({sourceId: this.source.sourceId, dbName: this.source.dbName, tableName: this.source.tableName}).then(json => {
|
||||||
|
this.columnInfo[columnKey] = json.data.columnList || [];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
startAutocomplete(editor) {
|
||||||
|
this.isAutocomplete = true;
|
||||||
|
editor.execCommand("startAutocomplete");
|
||||||
|
},
|
||||||
|
async getCompletions(editor, session, pos, prefix, callback) {
|
||||||
|
let callbackArr = [];
|
||||||
|
let endPos = this.isAutocomplete ? pos.column : pos.column - 1;
|
||||||
|
let lineStr = session.getLine(pos.row).substring(0, endPos);
|
||||||
|
this.isAutocomplete = false;
|
||||||
|
console.log("Executor.vue getCompletions,sourceId:" + JSON.stringify(this.source) + ', lineStr:' + lineStr, pos);
|
||||||
|
if (!!this.source.tableName) {
|
||||||
|
// 如果指定了表名,则只提示字段,其他都不用管,用在表数据查看页面
|
||||||
|
callbackArr = await this.getAssignTableColumns(this.source.dbName, this.source.tableName);
|
||||||
|
callback(null, callbackArr);
|
||||||
|
} else if (lineStr.endsWith("from ") || lineStr.endsWith("join ") || lineStr.endsWith("into ")
|
||||||
|
|| lineStr.endsWith("update ") || lineStr.endsWith("table ")) {
|
||||||
|
// 获取库和表
|
||||||
|
callbackArr = this.getDatabasesAndTables();
|
||||||
|
this.lastCallbackArr = callbackArr;
|
||||||
|
callback(null, callbackArr);
|
||||||
|
} else if (lineStr.endsWith(".")) {
|
||||||
|
// 获取表和字段
|
||||||
|
callbackArr = await this.getTablesAndColumns(lineStr);
|
||||||
|
this.lastCallbackArr = callbackArr;
|
||||||
|
callback(null, callbackArr);
|
||||||
|
} else if (lineStr.endsWith("select ") || lineStr.endsWith("where ") || lineStr.endsWith("and ")
|
||||||
|
|| lineStr.endsWith("or ") || lineStr.endsWith("set ")) {
|
||||||
|
// 获取字段
|
||||||
|
callbackArr = await this.getTableColumns(session, pos);
|
||||||
|
this.lastCallbackArr = callbackArr;
|
||||||
|
callback(null, callbackArr);
|
||||||
|
} else {
|
||||||
|
callback(null, this.lastCallbackArr);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getDatabasesAndTables() {
|
||||||
|
let callbackArr = [];
|
||||||
|
// 所有表
|
||||||
|
let tableList = this.tableInfo[this.source.sourceId + '_' + this.source.dbName] || [];
|
||||||
|
tableList.forEach(item => callbackArr.push({
|
||||||
|
caption: (!!item.tableComment) ? item.tableName + '-' + item.tableComment : item.tableName,
|
||||||
|
snippet: item.tableName,
|
||||||
|
meta: "表",
|
||||||
|
type: "snippet",
|
||||||
|
score: 1000
|
||||||
|
}));
|
||||||
|
// 所有库
|
||||||
|
let databaseList = this.databaseInfo[this.source.sourceId] || [];
|
||||||
|
databaseList.forEach(item => callbackArr.push({
|
||||||
|
caption: item.dbName,
|
||||||
|
snippet: item.dbName,
|
||||||
|
meta: "库",
|
||||||
|
type: "snippet",
|
||||||
|
score: 1000
|
||||||
|
}));
|
||||||
|
return callbackArr;
|
||||||
|
},
|
||||||
|
async getTablesAndColumns(lineStr) {
|
||||||
|
let isFound = false;
|
||||||
|
let callbackArr = [];
|
||||||
|
// 匹配 库名. 搜索表名
|
||||||
|
let databaseList = this.databaseInfo[this.source.sourceId] || [];
|
||||||
|
for (let i = 0; i < databaseList.length; i++) {
|
||||||
|
let item = databaseList[i];
|
||||||
|
if (lineStr.endsWith(item.dbName + ".")) {
|
||||||
|
let tableList = this.tableInfo[this.source.sourceId + '_' + item.dbName] || [];
|
||||||
|
if (tableList.length <= 0) {
|
||||||
|
let res = await datasourceApi.tableList({sourceId: this.source.sourceId, dbName: item.dbName});
|
||||||
|
tableList = res.data || [];
|
||||||
|
this.tableInfo[this.source.sourceId + '_' + item.dbName] = tableList;
|
||||||
|
}
|
||||||
|
tableList.forEach(item => callbackArr.push({
|
||||||
|
caption: (!!item.tableComment) ? item.tableName + '-' + item.tableComment : item.tableName,
|
||||||
|
snippet: item.tableName,
|
||||||
|
meta: "表",
|
||||||
|
type: "snippet",
|
||||||
|
score: 1000
|
||||||
|
}));
|
||||||
|
isFound = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 未找到,匹配 表名. 搜索字段名
|
||||||
|
if (!isFound) {
|
||||||
|
let tableList = this.tableInfo[this.source.sourceId + '_' + this.source.dbName] || [];
|
||||||
|
for (let i = 0; i < tableList.length; i++) {
|
||||||
|
let tableName = tableList[i].tableName;
|
||||||
|
if (lineStr.endsWith(tableName + ".")) {
|
||||||
|
callbackArr = await this.getAssignTableColumns(this.source.dbName, tableName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return callbackArr;
|
||||||
|
},
|
||||||
|
async getTableColumns(session, pos) {
|
||||||
|
let queryText = "";
|
||||||
|
// 往前加
|
||||||
|
for (let i = pos.row; i >= 0; i--) {
|
||||||
|
let tempLine = session.getLine(i);
|
||||||
|
queryText = tempLine + " " + queryText;
|
||||||
|
if (tempLine.indexOf(";") >= 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 往后加
|
||||||
|
for (let i = pos.row + 1; i < session.getLength(); i++) {
|
||||||
|
let tempLine = session.getLine(i);
|
||||||
|
queryText = queryText + " " + tempLine;
|
||||||
|
if (tempLine.indexOf(";") >= 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 所有表,找下面的字段列表
|
||||||
|
let callbackArr = [];
|
||||||
|
let tableList = this.tableInfo[this.source.sourceId + '_' + this.source.dbName] || [];
|
||||||
|
for (let i = 0; i < tableList.length; i++) {
|
||||||
|
let tableName = tableList[i].tableName;
|
||||||
|
if (queryText.indexOf(tableName) >= 0) {
|
||||||
|
let tempArr = await this.getAssignTableColumns(this.source.dbName, tableName);
|
||||||
|
callbackArr = callbackArr.concat(tempArr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return callbackArr;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取指定数据表的字段
|
||||||
|
* @param dbName
|
||||||
|
* @param tableName
|
||||||
|
*/
|
||||||
|
async getAssignTableColumns(dbName, tableName) {
|
||||||
|
let columnKey = this.source.sourceId + '_' + dbName + '_' + tableName;
|
||||||
|
let columnList = this.columnInfo[columnKey] || [];
|
||||||
|
if (columnList.length <= 0) {
|
||||||
|
let res = await datasourceApi.tableColumnList({
|
||||||
|
sourceId: this.source.sourceId,
|
||||||
|
dbName: dbName,
|
||||||
|
tableName: tableName
|
||||||
|
});
|
||||||
|
columnList = res.data.columnList || [];
|
||||||
|
this.columnInfo[columnKey] = columnList;
|
||||||
|
}
|
||||||
|
let callbackArr = [];
|
||||||
|
columnList.forEach(item => {
|
||||||
|
let caption = (!!item.description) ? item.name + "-" + item.description : item.name;
|
||||||
|
callbackArr.push({
|
||||||
|
caption: caption,
|
||||||
|
snippet: item.name,
|
||||||
|
meta: "字段",
|
||||||
|
type: "snippet",
|
||||||
|
score: 1000
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return callbackArr;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
.ace_editor.ace_autocomplete{
|
||||||
|
width: 400px;
|
||||||
|
}
|
||||||
108
zyplayer-doc-ui/swagger-ui/src/assets/ace-editor/index.js
Normal file
108
zyplayer-doc-ui/swagger-ui/src/assets/ace-editor/index.js
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
import ace from 'brace';
|
||||||
|
import 'brace/ext/language_tools';
|
||||||
|
import 'brace/mode/sql';
|
||||||
|
import 'brace/snippets/sql';
|
||||||
|
import 'brace/mode/json';
|
||||||
|
import 'brace/snippets/json';
|
||||||
|
import 'brace/mode/xml';
|
||||||
|
import 'brace/snippets/xml';
|
||||||
|
import 'brace/mode/html';
|
||||||
|
import 'brace/snippets/html';
|
||||||
|
import 'brace/mode/text';
|
||||||
|
import 'brace/snippets/text';
|
||||||
|
import 'brace/theme/monokai';
|
||||||
|
import 'brace/theme/chrome';
|
||||||
|
import './index.css';
|
||||||
|
import { h, reactive } from 'vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
render() {
|
||||||
|
let height = this.height ? this.px(this.height) : '100%';
|
||||||
|
let width = this.width ? this.px(this.width) : '100%';
|
||||||
|
return h('div', {
|
||||||
|
attrs: {
|
||||||
|
style: "height: " + height + '; width: ' + width,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
value: String,
|
||||||
|
lang: String,
|
||||||
|
theme: String,
|
||||||
|
height: String,
|
||||||
|
width: String,
|
||||||
|
options: Object
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
editor: null,
|
||||||
|
contentBackup: ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
value: function (val) {
|
||||||
|
if (this.contentBackup !== val) {
|
||||||
|
this.editor.session.setValue(val, 1);
|
||||||
|
this.contentBackup = val;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
theme: function (newTheme) {
|
||||||
|
this.editor.setTheme('ace/theme/' + newTheme);
|
||||||
|
},
|
||||||
|
lang: function (newLang) {
|
||||||
|
this.editor.getSession().setMode(typeof newLang === 'string' ? ('ace/mode/' + newLang) : newLang);
|
||||||
|
},
|
||||||
|
options: function (newOption) {
|
||||||
|
this.editor.setOptions(newOption);
|
||||||
|
},
|
||||||
|
height: function () {
|
||||||
|
this.$nextTick(function () {
|
||||||
|
this.editor.resize()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
width: function () {
|
||||||
|
this.$nextTick(function () {
|
||||||
|
this.editor.resize()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
this.editor.destroy();
|
||||||
|
this.editor.container.remove();
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
let vm = this;
|
||||||
|
let lang = this.lang || 'text';
|
||||||
|
let theme = this.theme || 'chrome';
|
||||||
|
let editor = vm.editor = ace.edit(this.$el);
|
||||||
|
editor.$blockScrolling = Infinity;
|
||||||
|
this.$emit('init', editor);
|
||||||
|
//editor.setOption("enableEmmet", true);
|
||||||
|
editor.getSession().setMode(typeof lang === 'string' ? ('ace/mode/' + lang) : lang);
|
||||||
|
editor.setTheme('ace/theme/' + theme);
|
||||||
|
if (this.value) {
|
||||||
|
editor.setValue(this.value, 1);
|
||||||
|
}
|
||||||
|
this.contentBackup = this.value;
|
||||||
|
editor.on('change', function () {
|
||||||
|
let content = editor.getValue();
|
||||||
|
vm.$emit('update:value', content);
|
||||||
|
vm.contentBackup = content;
|
||||||
|
// 内容改变就执行输入提示功能,和自动的冲突了,感觉自动的就符合了,但是按空格他不出现提示框
|
||||||
|
// console.log('change content:' + content);
|
||||||
|
// editor.execCommand("startAutocomplete");
|
||||||
|
});
|
||||||
|
if (vm.options) {
|
||||||
|
editor.setOptions(vm.options);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
px: function (n) {
|
||||||
|
if (/^\d*$/.test(n)) {
|
||||||
|
return n + "px";
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
;
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<a-textarea placeholder="" v-model:value="bodyRowParam" :auto-size="{ minRows: 15, maxRows: 15 }"></a-textarea>
|
<!-- <a-textarea placeholder="" v-model:value="bodyRowParam" :auto-size="{ minRows: 15, maxRows: 15 }"></a-textarea>-->
|
||||||
|
<ace-editor v-model:value="bodyRowParam" @init="rowParamInit" lang="json" theme="monokai" width="100%" height="100" :options="rowParamConfig"></ace-editor>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@@ -11,6 +12,7 @@
|
|||||||
import {CloseOutlined, UploadOutlined} from '@ant-design/icons-vue';
|
import {CloseOutlined, UploadOutlined} from '@ant-design/icons-vue';
|
||||||
import 'mavon-editor/dist/markdown/github-markdown.min.css'
|
import 'mavon-editor/dist/markdown/github-markdown.min.css'
|
||||||
import 'mavon-editor/dist/css/index.css'
|
import 'mavon-editor/dist/css/index.css'
|
||||||
|
import aceEditor from "../../assets/ace-editor";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
@@ -20,7 +22,7 @@
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
CloseOutlined, UploadOutlined
|
CloseOutlined, UploadOutlined, aceEditor
|
||||||
},
|
},
|
||||||
emits: [],
|
emits: [],
|
||||||
setup(props, { attrs, slots, emit, expose}) {
|
setup(props, { attrs, slots, emit, expose}) {
|
||||||
@@ -50,9 +52,26 @@
|
|||||||
const getParam = () => {
|
const getParam = () => {
|
||||||
return bodyRowParam.value;
|
return bodyRowParam.value;
|
||||||
}
|
}
|
||||||
|
// 编辑器
|
||||||
|
let rowParamEditor = ref();
|
||||||
|
const rowParamInit = editor => {
|
||||||
|
rowParamEditor.value = editor;
|
||||||
|
rowParamEditor.value.setFontSize(16);
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
getParam,
|
getParam,
|
||||||
|
// 编辑器
|
||||||
|
rowParamInit,
|
||||||
bodyRowParam,
|
bodyRowParam,
|
||||||
|
rowParamConfig: {
|
||||||
|
wrap: true,
|
||||||
|
autoScrollEditorIntoView: true,
|
||||||
|
enableBasicAutocompletion: true,
|
||||||
|
enableSnippets: true,
|
||||||
|
enableLiveAutocompletion: true,
|
||||||
|
minLines: 18,
|
||||||
|
maxLines: 18,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,34 +5,46 @@
|
|||||||
<a-button type="primary" :loading="requestLoading">发送请求</a-button>
|
<a-button type="primary" :loading="requestLoading">发送请求</a-button>
|
||||||
</template>
|
</template>
|
||||||
</a-input-search>
|
</a-input-search>
|
||||||
<a-tabs v-model:activeKey="activePage" closable @tab-click="" style="padding: 5px 10px 0;">
|
<a-tabs v-model:activeKey="activePage" closable @tab-click="activePageChange" style="padding: 5px 10px 0;">
|
||||||
<a-tab-pane tab="URL参数" key="urlParam" forceRender>
|
<a-tab-pane tab="URL参数" key="urlParam" forceRender>
|
||||||
<ParamTable ref="urlParamRef" :paramList="urlParamList"></ParamTable>
|
<div v-show="queryParamVisible">
|
||||||
|
<ParamTable ref="urlParamRef" :paramList="urlParamList"></ParamTable>
|
||||||
|
</div>
|
||||||
</a-tab-pane>
|
</a-tab-pane>
|
||||||
<a-tab-pane tab="请求参数" key="bodyParam" v-if="docInfoShow.method !== 'get'" forceRender>
|
<a-tab-pane tab="请求参数" key="bodyParam" v-if="docInfoShow.method !== 'get'" forceRender>
|
||||||
<a-radio-group v-model:value="bodyParamType" style="margin-bottom: 5px;">
|
<div v-show="queryParamVisible">
|
||||||
<a-radio value="none">none</a-radio>
|
<a-radio-group v-model:value="bodyParamType" style="margin-bottom: 5px;">
|
||||||
<a-radio value="form">form-data</a-radio>
|
<a-radio value="none">none</a-radio>
|
||||||
<a-radio value="formUrlEncode">x-www-form-urlencoded</a-radio>
|
<a-radio value="form">form-data</a-radio>
|
||||||
<a-radio value="row">row</a-radio>
|
<a-radio value="formUrlEncode">x-www-form-urlencoded</a-radio>
|
||||||
<a-radio value="binary">binary</a-radio>
|
<a-radio value="row">row</a-radio>
|
||||||
</a-radio-group>
|
<a-radio value="binary">binary</a-radio>
|
||||||
<div v-show="bodyParamType === 'form'">
|
</a-radio-group>
|
||||||
<ParamTable ref="formParamRef" :paramList="formParamList" showType></ParamTable>
|
<div v-show="bodyParamType === 'form'">
|
||||||
</div>
|
<ParamTable ref="formParamRef" :paramList="formParamList" showType></ParamTable>
|
||||||
<div v-show="bodyParamType === 'formUrlEncode'">
|
</div>
|
||||||
<ParamTable ref="formEncodeParamRef" :paramList="formEncodeParamList"></ParamTable>
|
<div v-show="bodyParamType === 'formUrlEncode'">
|
||||||
</div>
|
<ParamTable ref="formEncodeParamRef" :paramList="formEncodeParamList"></ParamTable>
|
||||||
<div v-show="bodyParamType === 'row'">
|
</div>
|
||||||
<ParamBody ref="bodyParamRef" :paramList="bodyRowParamList"></ParamBody>
|
<div v-show="bodyParamType === 'row'">
|
||||||
|
<ParamBody ref="bodyParamRef" :paramList="bodyRowParamList"></ParamBody>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</a-tab-pane>
|
</a-tab-pane>
|
||||||
<a-tab-pane tab="Header参数" key="headerParam" forceRender>
|
<a-tab-pane tab="Header参数" key="headerParam" forceRender>
|
||||||
<ParamTable ref="headerParamRef" :paramList="headerParamList"></ParamTable>
|
<div v-show="queryParamVisible">
|
||||||
|
<ParamTable ref="headerParamRef" :paramList="headerParamList"></ParamTable>
|
||||||
|
</div>
|
||||||
</a-tab-pane>
|
</a-tab-pane>
|
||||||
<a-tab-pane tab="Cookie参数" key="cookieParam" forceRender>
|
<a-tab-pane tab="Cookie参数" key="cookieParam" forceRender>
|
||||||
<ParamTable ref="cookieParamRef" :paramList="cookieParamList"></ParamTable>
|
<div v-show="queryParamVisible">
|
||||||
|
<ParamTable ref="cookieParamRef" :paramList="cookieParamList"></ParamTable>
|
||||||
|
</div>
|
||||||
</a-tab-pane>
|
</a-tab-pane>
|
||||||
|
<template #rightExtra>
|
||||||
|
<a-button v-if="queryParamVisible" @click="hideQueryParam" type="link">收起参数</a-button>
|
||||||
|
<a-button v-else @click="showQueryParam" type="link">展开参数</a-button>
|
||||||
|
</template>
|
||||||
</a-tabs>
|
</a-tabs>
|
||||||
<DocDebuggerResult :result="requestResult"></DocDebuggerResult>
|
<DocDebuggerResult :result="requestResult"></DocDebuggerResult>
|
||||||
</div>
|
</div>
|
||||||
@@ -47,7 +59,7 @@
|
|||||||
import DocDebuggerResult from './DocDebuggerResult.vue'
|
import DocDebuggerResult from './DocDebuggerResult.vue'
|
||||||
import ParamTable from '../../../components/params/ParamTable.vue'
|
import ParamTable from '../../../components/params/ParamTable.vue'
|
||||||
import ParamBody from '../../../components/params/ParamBody.vue'
|
import ParamBody from '../../../components/params/ParamBody.vue'
|
||||||
import {CloseOutlined} from '@ant-design/icons-vue';
|
import {CloseOutlined, VerticalAlignTopOutlined, VerticalAlignBottomOutlined} from '@ant-design/icons-vue';
|
||||||
import 'mavon-editor/dist/markdown/github-markdown.min.css'
|
import 'mavon-editor/dist/markdown/github-markdown.min.css'
|
||||||
import 'mavon-editor/dist/css/index.css'
|
import 'mavon-editor/dist/css/index.css'
|
||||||
import {zyplayerApi} from "../../../api";
|
import {zyplayerApi} from "../../../api";
|
||||||
@@ -68,7 +80,7 @@
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
CloseOutlined, ParamTable, ParamBody, DocDebuggerResult,
|
VerticalAlignTopOutlined, VerticalAlignBottomOutlined, CloseOutlined, ParamTable, ParamBody, DocDebuggerResult,
|
||||||
},
|
},
|
||||||
setup(props) {
|
setup(props) {
|
||||||
const store = useStore();
|
const store = useStore();
|
||||||
@@ -173,6 +185,7 @@
|
|||||||
// });
|
// });
|
||||||
let url = urlParamStr ? (docUrl.value + '?' + urlParamStr) : docUrl.value;
|
let url = urlParamStr ? (docUrl.value + '?' + urlParamStr) : docUrl.value;
|
||||||
formData.append('url', url);
|
formData.append('url', url);
|
||||||
|
formData.append('host', urlDomain);
|
||||||
formData.append('method', props.docInfoShow.method);
|
formData.append('method', props.docInfoShow.method);
|
||||||
formData.append('contentType', props.docInfoShow.consumes);
|
formData.append('contentType', props.docInfoShow.consumes);
|
||||||
formData.append('headerParam', JSON.stringify(headerParamArr));
|
formData.append('headerParam', JSON.stringify(headerParamArr));
|
||||||
@@ -181,6 +194,7 @@
|
|||||||
formData.append('formEncodeParam', JSON.stringify(formEncodeParamArr));
|
formData.append('formEncodeParam', JSON.stringify(formEncodeParamArr));
|
||||||
formData.append('bodyParam', bodyParamStr);
|
formData.append('bodyParam', bodyParamStr);
|
||||||
requestLoading.value = true;
|
requestLoading.value = true;
|
||||||
|
requestResult.value = {};
|
||||||
zyplayerApi.requestUrl(formData).then(res => {
|
zyplayerApi.requestUrl(formData).then(res => {
|
||||||
requestResult.value = res;
|
requestResult.value = res;
|
||||||
requestLoading.value = false;
|
requestLoading.value = false;
|
||||||
@@ -188,9 +202,20 @@
|
|||||||
requestLoading.value = false;
|
requestLoading.value = false;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
let queryParamVisible = ref(true);
|
||||||
|
const hideQueryParam = () => {
|
||||||
|
queryParamVisible.value = false;
|
||||||
|
}
|
||||||
|
const showQueryParam = () => {
|
||||||
|
queryParamVisible.value = true;
|
||||||
|
}
|
||||||
|
const activePageChange = () => {
|
||||||
|
queryParamVisible.value = true;
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
docUrl,
|
docUrl,
|
||||||
activePage,
|
activePage,
|
||||||
|
activePageChange,
|
||||||
requestLoading,
|
requestLoading,
|
||||||
sendRequest,
|
sendRequest,
|
||||||
requestResult,
|
requestResult,
|
||||||
@@ -223,6 +248,10 @@
|
|||||||
{title: '类型', dataIndex: 'type', width: 250},
|
{title: '类型', dataIndex: 'type', width: 250},
|
||||||
{title: '说明', dataIndex: 'description'},
|
{title: '说明', dataIndex: 'description'},
|
||||||
],
|
],
|
||||||
|
// 界面控制
|
||||||
|
queryParamVisible,
|
||||||
|
hideQueryParam,
|
||||||
|
showQueryParam,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,10 +1,28 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div style="margin-bottom: 30px;">
|
||||||
<a-tabs v-model:activeKey="activePage" closable @tab-click="" style="padding: 5px 10px 0;">
|
<a-tabs v-model:activeKey="activePage" closable @tab-click="" style="padding: 5px 10px 0;">
|
||||||
<a-tab-pane tab="Body" key="body" forceRender>
|
<a-tab-pane tab="Body" key="body" forceRender>
|
||||||
<template v-if="result.data && result.data.data">{{result.data.data}}</template>
|
<div style="margin-bottom: 10px;">
|
||||||
<template v-else-if="result.data">{{result.data}}</template>
|
<a-radio-group v-model:value="bodyShowType" @change="bodyShowTypeChange" size="small">
|
||||||
<template v-else>{{result}}</template>
|
<a-radio-button value="format">格式化</a-radio-button>
|
||||||
|
<a-radio-button value="row">原始值</a-radio-button>
|
||||||
|
<a-radio-button value="preview">预览</a-radio-button>
|
||||||
|
</a-radio-group>
|
||||||
|
<a-select v-if="bodyShowType === 'format'" placeholder="格式化" v-model:value="bodyShowFormatType" size="small" style="margin-left: 10px;">
|
||||||
|
<a-select-option value="json">JSON</a-select-option>
|
||||||
|
<a-select-option value="html">HTML</a-select-option>
|
||||||
|
<a-select-option value="xml">XML</a-select-option>
|
||||||
|
<a-select-option value="text">TEXT</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</div>
|
||||||
|
<ace-editor v-if="bodyShowType === 'format'" v-model:value="resultDataContent" @init="resultDataInit" :lang="bodyShowFormatType" theme="monokai" width="100%" height="100" :options="resultDataConfig"></ace-editor>
|
||||||
|
<ace-editor v-else-if="bodyShowType === 'row'" v-model:value="resultDataContent" @init="resultDataInit" lang="text" theme="chrome" width="100%" height="100" :options="resultDataConfig"></ace-editor>
|
||||||
|
<div v-else-if="bodyShowType === 'preview'">
|
||||||
|
<template v-if="bodyShowFormatPreview === 'html'">
|
||||||
|
<iframe ref="previewHtmlRef" width="100%" height="570px" style="border: 0;"></iframe>
|
||||||
|
</template>
|
||||||
|
<template v-else>{{resultDataContent}}</template>
|
||||||
|
</div>
|
||||||
</a-tab-pane>
|
</a-tab-pane>
|
||||||
<a-tab-pane tab="Headers" key="headers" forceRender>
|
<a-tab-pane tab="Headers" key="headers" forceRender>
|
||||||
<a-table :dataSource="resultHeaders"
|
<a-table :dataSource="resultHeaders"
|
||||||
@@ -20,6 +38,9 @@
|
|||||||
:scroll="{ y: '300px' }">
|
:scroll="{ y: '300px' }">
|
||||||
</a-table>
|
</a-table>
|
||||||
</a-tab-pane>
|
</a-tab-pane>
|
||||||
|
<template #rightExtra>
|
||||||
|
<span class="status-info-box">状态码:<span>{{resultData.status||'200'}}</span>耗时:<span>{{resultData.useTime||0}} ms</span>大小:<span>{{resultData.bodyLength||0}} B</span></span>
|
||||||
|
</template>
|
||||||
</a-tabs>
|
</a-tabs>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -36,6 +57,7 @@
|
|||||||
import 'mavon-editor/dist/markdown/github-markdown.min.css'
|
import 'mavon-editor/dist/markdown/github-markdown.min.css'
|
||||||
import 'mavon-editor/dist/css/index.css'
|
import 'mavon-editor/dist/css/index.css'
|
||||||
import {zyplayerApi} from "../../../api";
|
import {zyplayerApi} from "../../../api";
|
||||||
|
import aceEditor from "../../../assets/ace-editor";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
@@ -45,17 +67,45 @@
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
CloseOutlined, ParamTable, ParamBody
|
CloseOutlined, ParamTable, ParamBody, aceEditor
|
||||||
},
|
},
|
||||||
setup(props) {
|
setup(props) {
|
||||||
const { result } = toRefs(props);
|
const { result } = toRefs(props);
|
||||||
let activePage = ref('body');
|
let activePage = ref('body');
|
||||||
|
let bodyShowType = ref('format');
|
||||||
|
let bodyShowFormatType = ref('json');
|
||||||
|
let bodyShowFormatPreview = ref('');
|
||||||
let resultHeaders = ref([]);
|
let resultHeaders = ref([]);
|
||||||
let resultCookies = ref([]);
|
let resultCookies = ref([]);
|
||||||
|
let resultDataContent = ref('');
|
||||||
|
let resultData = ref({});
|
||||||
|
let previewHtmlRef = ref();
|
||||||
const initData = () => {
|
const initData = () => {
|
||||||
if (props.result.data) {
|
if (props.result.data) {
|
||||||
|
resultData.value = props.result.data;
|
||||||
|
if (props.result.data.data) {
|
||||||
|
try {
|
||||||
|
let realData = JSON.parse(props.result.data.data);
|
||||||
|
resultDataContent.value = JSON.stringify(realData, null, 4);
|
||||||
|
} catch (e) {
|
||||||
|
resultDataContent.value = props.result.data.data;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
resultDataContent.value = JSON.stringify(props.result.data, null, 4);
|
||||||
|
}
|
||||||
if (props.result.data.headers) {
|
if (props.result.data.headers) {
|
||||||
resultHeaders.value = props.result.data.headers;
|
resultHeaders.value = props.result.data.headers;
|
||||||
|
// 依据返回值header判断类型
|
||||||
|
let contentType = resultHeaders.value.find(item => item.name === 'Content-Type');
|
||||||
|
if (contentType && contentType.value) {
|
||||||
|
if (contentType.value.indexOf('text/html') >= 0) {
|
||||||
|
bodyShowFormatType.value = 'html';
|
||||||
|
bodyShowFormatPreview.value = 'html';
|
||||||
|
} else if (contentType.value.indexOf('json') >= 0) {
|
||||||
|
bodyShowFormatType.value = 'json';
|
||||||
|
bodyShowFormatPreview.value = 'json';
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (props.result.data.cookies) {
|
if (props.result.data.cookies) {
|
||||||
resultCookies.value = props.result.data.cookies;
|
resultCookies.value = props.result.data.cookies;
|
||||||
@@ -64,8 +114,25 @@
|
|||||||
};
|
};
|
||||||
initData();
|
initData();
|
||||||
watch(result, () => initData());
|
watch(result, () => initData());
|
||||||
|
// 编辑器
|
||||||
|
const resultDataInit = editor => {
|
||||||
|
editor.setFontSize(16);
|
||||||
|
}
|
||||||
|
const bodyShowTypeChange = () => {
|
||||||
|
if (bodyShowType.value === 'preview') {
|
||||||
|
setTimeout(() => {
|
||||||
|
previewHtmlRef.value.contentDocument.write(resultDataContent.value);
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
activePage,
|
activePage,
|
||||||
|
bodyShowType,
|
||||||
|
bodyShowTypeChange,
|
||||||
|
bodyShowFormatType,
|
||||||
|
bodyShowFormatPreview,
|
||||||
|
previewHtmlRef,
|
||||||
|
resultData,
|
||||||
resultHeaders,
|
resultHeaders,
|
||||||
resultCookies,
|
resultCookies,
|
||||||
resultHeadersColumns: [
|
resultHeadersColumns: [
|
||||||
@@ -76,7 +143,25 @@
|
|||||||
{title: 'KEY', dataIndex: 'name'},
|
{title: 'KEY', dataIndex: 'name'},
|
||||||
{title: 'VALUE', dataIndex: 'value'},
|
{title: 'VALUE', dataIndex: 'value'},
|
||||||
],
|
],
|
||||||
|
// 编辑器
|
||||||
|
resultDataInit,
|
||||||
|
resultDataContent,
|
||||||
|
resultDataConfig: {
|
||||||
|
wrap: true,
|
||||||
|
readOnly: true,
|
||||||
|
autoScrollEditorIntoView: true,
|
||||||
|
enableBasicAutocompletion: true,
|
||||||
|
enableSnippets: true,
|
||||||
|
enableLiveAutocompletion: true,
|
||||||
|
minLines: 30,
|
||||||
|
maxLines: 30,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
<style>
|
||||||
|
.status-info-box{color: #888;}
|
||||||
|
.status-info-box span{color: #00aa00; margin-right: 15px;}
|
||||||
|
.status-info-box span:last-child{margin-right: 0;}
|
||||||
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user