mirror of
https://gitee.com/durcframework/SOP.git
synced 2025-08-11 21:57:56 +08:00
4.2.0
This commit is contained in:
@@ -17,15 +17,16 @@ public class ApiUploadContext implements UploadContext {
|
|||||||
/**
|
/**
|
||||||
* key: 表单name
|
* key: 表单name
|
||||||
*/
|
*/
|
||||||
private Map<String, MultipartFile> fileMap;
|
private Map<String, List<MultipartFile>> fileMap;
|
||||||
private List<MultipartFile> allFile;
|
private List<MultipartFile> allFile;
|
||||||
|
|
||||||
public ApiUploadContext(Map<String, MultipartFile> map) {
|
public ApiUploadContext(Map<String, List<MultipartFile>> map) {
|
||||||
if (map == null) {
|
if (map == null) {
|
||||||
map = Collections.emptyMap();
|
map = Collections.emptyMap();
|
||||||
}
|
}
|
||||||
this.fileMap = map;
|
this.fileMap = map;
|
||||||
this.allFile = new ArrayList<>(map.values());
|
this.allFile = new ArrayList<>();
|
||||||
|
map.values().forEach(list -> this.allFile.addAll(list));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -34,7 +35,7 @@ public class ApiUploadContext implements UploadContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MultipartFile getFile(String name) {
|
public List<MultipartFile> getFile(String name) {
|
||||||
return fileMap.get(name);
|
return fileMap.get(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -25,7 +25,7 @@ public interface UploadContext {
|
|||||||
* 表单名称
|
* 表单名称
|
||||||
* @return 返回上传文件信息
|
* @return 返回上传文件信息
|
||||||
*/
|
*/
|
||||||
MultipartFile getFile(String name);
|
List<MultipartFile> getFile(String name);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取所有的上传文件
|
* 获取所有的上传文件
|
||||||
|
@@ -15,6 +15,7 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.http.HttpHeaders;
|
import org.springframework.http.HttpHeaders;
|
||||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||||
|
import org.springframework.util.MultiValueMap;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
import org.springframework.web.multipart.commons.CommonsMultipartFile;
|
import org.springframework.web.multipart.commons.CommonsMultipartFile;
|
||||||
import org.springframework.web.multipart.support.StandardMultipartHttpServletRequest;
|
import org.springframework.web.multipart.support.StandardMultipartHttpServletRequest;
|
||||||
@@ -36,7 +37,6 @@ import java.util.Locale;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.function.Function;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
|
||||||
@@ -298,9 +298,9 @@ public class RequestUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (multipartFileList.size() > 0) {
|
if (multipartFileList.size() > 0) {
|
||||||
Map<String, MultipartFile> multipartFileMap = multipartFileList
|
Map<String, List<MultipartFile>> multipartFileMap = multipartFileList
|
||||||
.stream()
|
.stream()
|
||||||
.collect(Collectors.toMap(MultipartFile::getName, Function.identity()));
|
.collect(Collectors.groupingBy(MultipartFile::getName));
|
||||||
uploadContext = new ApiUploadContext(multipartFileMap);
|
uploadContext = new ApiUploadContext(multipartFileMap);
|
||||||
}
|
}
|
||||||
uploadInfo.setUploadParams(uploadParams);
|
uploadInfo.setUploadParams(uploadParams);
|
||||||
@@ -315,8 +315,14 @@ public class RequestUtil {
|
|||||||
UploadInfo uploadInfo = new UploadInfo();
|
UploadInfo uploadInfo = new UploadInfo();
|
||||||
Map<String, String> uploadParams = new HashMap<>(16);
|
Map<String, String> uploadParams = new HashMap<>(16);
|
||||||
request.getParameterMap().forEach((key, value)-> uploadParams.put(key, value[0]));
|
request.getParameterMap().forEach((key, value)-> uploadParams.put(key, value[0]));
|
||||||
|
MultiValueMap<String, MultipartFile> multiFileMap = request.getMultiFileMap();
|
||||||
Map<String, MultipartFile> multipartFileMap = request.getMultiFileMap().toSingleValueMap();
|
List<MultipartFile> multipartFileList = new ArrayList<>(10);
|
||||||
|
for (String key : multiFileMap.keySet()) {
|
||||||
|
multipartFileList.addAll(multiFileMap.get(key));
|
||||||
|
}
|
||||||
|
Map<String, List<MultipartFile>> multipartFileMap = multipartFileList
|
||||||
|
.stream()
|
||||||
|
.collect(Collectors.groupingBy(MultipartFile::getName));
|
||||||
UploadContext uploadContext = new ApiUploadContext(multipartFileMap);
|
UploadContext uploadContext = new ApiUploadContext(multipartFileMap);
|
||||||
|
|
||||||
uploadInfo.setUploadParams(uploadParams);
|
uploadInfo.setUploadParams(uploadParams);
|
||||||
|
@@ -27,12 +27,12 @@ public class ResponseUtil {
|
|||||||
private static Logger log = LoggerFactory.getLogger(ResponseUtil.class);
|
private static Logger log = LoggerFactory.getLogger(ResponseUtil.class);
|
||||||
|
|
||||||
public static void writeJson(HttpServletResponse response, Object result) {
|
public static void writeJson(HttpServletResponse response, Object result) {
|
||||||
response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
|
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
|
||||||
response.setCharacterEncoding(UTF_8);
|
response.setCharacterEncoding(UTF_8);
|
||||||
try {
|
try {
|
||||||
response.getWriter().write(result instanceof String ? (String)result : JSON.toJSONString(result));
|
response.getWriter().write(result instanceof String ? (String)result : JSON.toJSONString(result));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
log.error("doWriter", e);
|
log.error("writeJson error", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -198,6 +198,11 @@ public class HttpTool {
|
|||||||
return paramBuilder.build();
|
return paramBuilder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String requestFileString(String url, Map<String, ?> form, Map<String, String> header, List<UploadFile> files) throws IOException {
|
||||||
|
return requestFile(url, form, header, files).body().string();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 提交表单,并且上传文件
|
* 提交表单,并且上传文件
|
||||||
*
|
*
|
||||||
@@ -208,7 +213,7 @@ public class HttpTool {
|
|||||||
* @return
|
* @return
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
public String requestFile(String url, Map<String, ?> form, Map<String, String> header, List<UploadFile> files)
|
public Response requestFile(String url, Map<String, ?> form, Map<String, String> header, List<UploadFile> files)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
// 创建MultipartBody.Builder,用于添加请求的数据
|
// 创建MultipartBody.Builder,用于添加请求的数据
|
||||||
MultipartBody.Builder bodyBuilder = new MultipartBody.Builder();
|
MultipartBody.Builder bodyBuilder = new MultipartBody.Builder();
|
||||||
@@ -236,14 +241,20 @@ public class HttpTool {
|
|||||||
addHeader(builder, header);
|
addHeader(builder, header);
|
||||||
|
|
||||||
Request request = builder.build();
|
Request request = builder.build();
|
||||||
Response response = httpClient.newCall(request).execute();
|
return httpClient.newCall(request).execute();
|
||||||
try {
|
}
|
||||||
return response.body().string();
|
|
||||||
} finally {
|
public Response request(String url, Map<String, ?> form, Map<String, String> header, HTTPMethod method, List<UploadFile> files) throws IOException {
|
||||||
response.close();
|
if (files != null && files.size() > 0) {
|
||||||
|
return requestFile(url, form, header, files);
|
||||||
|
} else {
|
||||||
|
return requestForResponse(url, form, header, method);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 请求数据
|
* 请求数据
|
||||||
*
|
*
|
||||||
|
@@ -30,6 +30,10 @@ public class CorsConfig {
|
|||||||
corsConfiguration.addAllowedOrigin("*");
|
corsConfiguration.addAllowedOrigin("*");
|
||||||
corsConfiguration.addAllowedHeader("*");
|
corsConfiguration.addAllowedHeader("*");
|
||||||
corsConfiguration.addAllowedMethod("*");
|
corsConfiguration.addAllowedMethod("*");
|
||||||
|
corsConfiguration.addExposedHeader("target-response-headers");
|
||||||
|
corsConfiguration.addExposedHeader("sendbox-params");
|
||||||
|
corsConfiguration.addExposedHeader("sendbox-beforesign");
|
||||||
|
corsConfiguration.addExposedHeader("sendbox-sign");
|
||||||
return corsConfiguration;
|
return corsConfiguration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -62,6 +62,9 @@ public class IsvController {
|
|||||||
@Value("${api.url-prod}")
|
@Value("${api.url-prod}")
|
||||||
String urlProd;
|
String urlProd;
|
||||||
|
|
||||||
|
@Value("${api.url-sandbox}")
|
||||||
|
String gatewayUrl;
|
||||||
|
|
||||||
@GetMapping("/getIsvPortal")
|
@GetMapping("/getIsvPortal")
|
||||||
public Result<IsvInfoResult> getIsvInfo() {
|
public Result<IsvInfoResult> getIsvInfo() {
|
||||||
LoginUser loginUser = UserContext.getLoginUser();
|
LoginUser loginUser = UserContext.getLoginUser();
|
||||||
@@ -180,6 +183,9 @@ public class IsvController {
|
|||||||
return menuProject;
|
return menuProject;
|
||||||
}).collect(Collectors.toList());
|
}).collect(Collectors.toList());
|
||||||
DocVO docVO = new DocVO();
|
DocVO docVO = new DocVO();
|
||||||
|
LoginUser loginUser = UserContext.getLoginUser();
|
||||||
|
docVO.setGatewayUrl(gatewayUrl);
|
||||||
|
docVO.setAppId(loginUser.getAppKey());
|
||||||
docVO.setMenuProjects(menuProjects);
|
docVO.setMenuProjects(menuProjects);
|
||||||
docVO.setUrlProd(urlProd);
|
docVO.setUrlProd(urlProd);
|
||||||
docVO.setUrlTest(urlTest);
|
docVO.setUrlTest(urlTest);
|
||||||
|
@@ -137,7 +137,7 @@ public class SandboxController {
|
|||||||
response.flushBuffer();
|
response.flushBuffer();
|
||||||
return null;
|
return null;
|
||||||
} else if (!CollectionUtils.isEmpty(files)) {
|
} else if (!CollectionUtils.isEmpty(files)) {
|
||||||
responseData = httpTool.requestFile(url, params, Collections.emptyMap(), files);
|
responseData = httpTool.requestFileString(url, params, Collections.emptyMap(), files);
|
||||||
} else {
|
} else {
|
||||||
responseData = httpTool.request(url, params, Collections.emptyMap(), HttpTool.HTTPMethod.fromValue(httpMethod));
|
responseData = httpTool.request(url, params, Collections.emptyMap(), HttpTool.HTTPMethod.fromValue(httpMethod));
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,211 @@
|
|||||||
|
package com.gitee.sop.websiteserver.controller;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import com.gitee.sop.websiteserver.bean.HttpTool;
|
||||||
|
import com.gitee.sop.websiteserver.sign.AlipayApiException;
|
||||||
|
import com.gitee.sop.websiteserver.sign.AlipaySignature;
|
||||||
|
import com.gitee.sop.websiteserver.util.UploadUtil;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import okhttp3.Response;
|
||||||
|
import okhttp3.ResponseBody;
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
import org.apache.http.NameValuePair;
|
||||||
|
import org.apache.http.client.entity.UrlEncodedFormEntity;
|
||||||
|
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||||
|
import org.apache.http.client.methods.HttpGet;
|
||||||
|
import org.apache.http.impl.client.CloseableHttpClient;
|
||||||
|
import org.apache.http.impl.client.HttpClients;
|
||||||
|
import org.apache.http.message.BasicNameValuePair;
|
||||||
|
import org.apache.http.util.EntityUtils;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
import org.springframework.web.util.UriUtils;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 沙箱环境代理类
|
||||||
|
*
|
||||||
|
* @author tanghc
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("sandbox")
|
||||||
|
public class SandboxV2Controller {
|
||||||
|
|
||||||
|
@Value("${api.url-sandbox}")
|
||||||
|
private String url;
|
||||||
|
|
||||||
|
static HttpTool httpTool = new HttpTool();
|
||||||
|
|
||||||
|
@RequestMapping("/test_v2")
|
||||||
|
public void proxy(
|
||||||
|
@RequestParam(required = false) String gatewayUrl
|
||||||
|
, @RequestParam String appId
|
||||||
|
, @RequestParam String privateKey
|
||||||
|
, @RequestParam(required = false) String token
|
||||||
|
, @RequestParam String method
|
||||||
|
, @RequestParam String version
|
||||||
|
, @RequestParam String bizContent
|
||||||
|
, @RequestParam(defaultValue = "get") String httpMethod
|
||||||
|
, @RequestParam(defaultValue = "false") boolean isDownloadRequest
|
||||||
|
, HttpServletRequest request
|
||||||
|
, HttpServletResponse response
|
||||||
|
) throws AlipayApiException, IOException {
|
||||||
|
|
||||||
|
Assert.isTrue(StringUtils.isNotBlank(appId), "AppId不能为空");
|
||||||
|
Assert.isTrue(StringUtils.isNotBlank(privateKey), "PrivateKey不能为空");
|
||||||
|
Assert.isTrue(StringUtils.isNotBlank(method), "method不能为空");
|
||||||
|
if (StringUtils.isEmpty(gatewayUrl)) {
|
||||||
|
gatewayUrl = url;
|
||||||
|
}
|
||||||
|
// 公共请求参数
|
||||||
|
Map<String, String> params = new HashMap<String, String>();
|
||||||
|
params.put("app_id", appId);
|
||||||
|
params.put("method", method);
|
||||||
|
params.put("format", "json");
|
||||||
|
params.put("charset", "utf-8");
|
||||||
|
params.put("sign_type", "RSA2");
|
||||||
|
params.put("timestamp", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
|
||||||
|
params.put("version", version);
|
||||||
|
|
||||||
|
if (StringUtils.isNotBlank(token)) {
|
||||||
|
params.put("app_auth_token", token);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 业务参数
|
||||||
|
params.put("biz_content", bizContent);
|
||||||
|
|
||||||
|
String paramsQuery = buildParamQuery(params);
|
||||||
|
|
||||||
|
String content = AlipaySignature.getSignContent(params);
|
||||||
|
|
||||||
|
String sign = null;
|
||||||
|
try {
|
||||||
|
sign = AlipaySignature.rsa256Sign(content, privateKey, "utf-8");
|
||||||
|
} catch (AlipayApiException e) {
|
||||||
|
throw new RuntimeException("构建签名失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
params.put("sign", sign);
|
||||||
|
|
||||||
|
Collection<MultipartFile> uploadFiles = UploadUtil.getUploadFiles(request);
|
||||||
|
List<HttpTool.UploadFile> files = uploadFiles.stream()
|
||||||
|
.map(multipartFile -> {
|
||||||
|
try {
|
||||||
|
return new HttpTool.UploadFile(multipartFile.getName(), multipartFile.getOriginalFilename(), multipartFile.getBytes());
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("封装文件失败", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
try {
|
||||||
|
Response resp = httpTool.request(gatewayUrl, params, Collections.emptyMap(), HttpTool.HTTPMethod.fromValue(httpMethod), files);
|
||||||
|
ResponseBody body = resp.body();
|
||||||
|
if (body == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Map<String, List<String>> headersMap = resp.headers().toMultimap();
|
||||||
|
Map<String, String> targetHeaders = new HashMap<>(headersMap.size() * 2);
|
||||||
|
headersMap.forEach((key, value) -> {
|
||||||
|
String headerValue = String.join(",", value);
|
||||||
|
response.setHeader(key, headerValue);
|
||||||
|
targetHeaders.put(key, headerValue);
|
||||||
|
});
|
||||||
|
response.addHeader("target-response-headers", JSON.toJSONString(targetHeaders));
|
||||||
|
response.addHeader("sendbox-params", UriUtils.encode(paramsQuery, StandardCharsets.UTF_8));
|
||||||
|
response.addHeader("sendbox-beforesign", UriUtils.encode(content, StandardCharsets.UTF_8));
|
||||||
|
response.addHeader("sendbox-sign", UriUtils.encode(sign, StandardCharsets.UTF_8));
|
||||||
|
IOUtils.copy(body.byteStream(), response.getOutputStream());
|
||||||
|
response.flushBuffer();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("请求失败", e);
|
||||||
|
throw new RuntimeException("请求失败");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public static class SandboxResult {
|
||||||
|
private String params;
|
||||||
|
private String beforeSign;
|
||||||
|
private String sign;
|
||||||
|
|
||||||
|
private Object apiResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送get请求
|
||||||
|
*
|
||||||
|
* @param url
|
||||||
|
* @return JSON或者字符串
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public static String get(String url, Map<String, String> params) {
|
||||||
|
CloseableHttpClient httpClient = null;
|
||||||
|
CloseableHttpResponse response = null;
|
||||||
|
try {
|
||||||
|
httpClient = HttpClients.createDefault();
|
||||||
|
List<NameValuePair> nameValuePairs = params.entrySet()
|
||||||
|
.stream()
|
||||||
|
.map(entry -> new BasicNameValuePair(entry.getKey(), String.valueOf(entry.getValue())))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
/**
|
||||||
|
* 包装成一个Entity对象
|
||||||
|
*/
|
||||||
|
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(nameValuePairs, "UTF-8");
|
||||||
|
//参数转换为字符串
|
||||||
|
String paramsStr = EntityUtils.toString(entity);
|
||||||
|
url = url + "?" + paramsStr;
|
||||||
|
/**
|
||||||
|
* 创建一个post对象
|
||||||
|
*/
|
||||||
|
HttpGet get = new HttpGet(url);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行post请求
|
||||||
|
*/
|
||||||
|
response = httpClient.execute(get);
|
||||||
|
/**
|
||||||
|
* 通过EntityUitls获取返回内容
|
||||||
|
*/
|
||||||
|
return EntityUtils.toString(response.getEntity(), "UTF-8");
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
IOUtils.closeQuietly(httpClient);
|
||||||
|
IOUtils.closeQuietly(response);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String buildParamQuery(Map<String, String> params) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (Map.Entry<String, String> entry : params.entrySet()) {
|
||||||
|
sb.append("&").append(entry.getKey()).append("=").append(entry.getValue());
|
||||||
|
}
|
||||||
|
return sb.substring(1);
|
||||||
|
}
|
||||||
|
}
|
@@ -11,6 +11,8 @@ import java.util.Collection;
|
|||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
public class DocVO {
|
public class DocVO {
|
||||||
|
private String gatewayUrl;
|
||||||
|
private String appId;
|
||||||
private String urlTest;
|
private String urlTest;
|
||||||
private String urlProd;
|
private String urlProd;
|
||||||
private Collection<MenuProject> menuProjects;
|
private Collection<MenuProject> menuProjects;
|
||||||
|
@@ -1 +1 @@
|
|||||||
<!DOCTYPE html><html><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge,chrome=1"><meta name=viewport content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"><link rel=icon href=favicon.ico><title>开放平台</title><link href=static/css/chunk-elementUI.ded27da0.css rel=stylesheet><link href=static/css/chunk-libs.3dfb7769.css rel=stylesheet><link href=static/css/app.520ff3b4.css rel=stylesheet></head><body><noscript><strong>We're sorry but 开放平台 doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><script>(function(e){function n(n){for(var r,c,o=n[0],f=n[1],d=n[2],i=0,h=[];i<o.length;i++)c=o[i],u[c]&&h.push(u[c][0]),u[c]=0;for(r in f)Object.prototype.hasOwnProperty.call(f,r)&&(e[r]=f[r]);l&&l(n);while(h.length)h.shift()();return a.push.apply(a,d||[]),t()}function t(){for(var e,n=0;n<a.length;n++){for(var t=a[n],r=!0,c=1;c<t.length;c++){var o=t[c];0!==u[o]&&(r=!1)}r&&(a.splice(n--,1),e=f(f.s=t[0]))}return e}var r={},c={runtime:0},u={runtime:0},a=[];function o(e){return f.p+"static/js/"+({}[e]||e)+"."+{"chunk-27eb7616":"26efb320","chunk-28a29d22":"7852c65c","chunk-2d0ac226":"908e7bac","chunk-2d0b6e8a":"ddfa15ec","chunk-2d0e958e":"1652deea","chunk-2d216d78":"211ad599","chunk-4e7f1f48":"331ccf8a","chunk-5142434b":"623e9909","chunk-6440f6d0":"4dcd9cf4","chunk-2d0d43b7":"a9f25820","chunk-2d0e1a00":"c05ee2a3","chunk-57325c88":"6f1a8ef5","chunk-788f7208":"6f676b03","chunk-eaa69404":"04ac7757"}[e]+".js"}function f(n){if(r[n])return r[n].exports;var t=r[n]={i:n,l:!1,exports:{}};return e[n].call(t.exports,t,t.exports,f),t.l=!0,t.exports}f.e=function(e){var n=[],t={"chunk-27eb7616":1,"chunk-28a29d22":1,"chunk-4e7f1f48":1,"chunk-5142434b":1,"chunk-6440f6d0":1,"chunk-57325c88":1,"chunk-eaa69404":1};c[e]?n.push(c[e]):0!==c[e]&&t[e]&&n.push(c[e]=new Promise((function(n,t){for(var r="static/css/"+({}[e]||e)+"."+{"chunk-27eb7616":"67b30787","chunk-28a29d22":"4dc6f542","chunk-2d0ac226":"31d6cfe0","chunk-2d0b6e8a":"31d6cfe0","chunk-2d0e958e":"31d6cfe0","chunk-2d216d78":"31d6cfe0","chunk-4e7f1f48":"cf843403","chunk-5142434b":"0ad43c8d","chunk-6440f6d0":"b35fc6d0","chunk-2d0d43b7":"31d6cfe0","chunk-2d0e1a00":"31d6cfe0","chunk-57325c88":"77426e4e","chunk-788f7208":"31d6cfe0","chunk-eaa69404":"04f4b7fb"}[e]+".css",u=f.p+r,a=document.getElementsByTagName("link"),o=0;o<a.length;o++){var d=a[o],i=d.getAttribute("data-href")||d.getAttribute("href");if("stylesheet"===d.rel&&(i===r||i===u))return n()}var h=document.getElementsByTagName("style");for(o=0;o<h.length;o++){d=h[o],i=d.getAttribute("data-href");if(i===r||i===u)return n()}var l=document.createElement("link");l.rel="stylesheet",l.type="text/css",l.onload=n,l.onerror=function(n){var r=n&&n.target&&n.target.src||u,a=new Error("Loading CSS chunk "+e+" failed.\n("+r+")");a.code="CSS_CHUNK_LOAD_FAILED",a.request=r,delete c[e],l.parentNode.removeChild(l),t(a)},l.href=u;var s=document.getElementsByTagName("head")[0];s.appendChild(l)})).then((function(){c[e]=0})));var r=u[e];if(0!==r)if(r)n.push(r[2]);else{var a=new Promise((function(n,t){r=u[e]=[n,t]}));n.push(r[2]=a);var d,i=document.createElement("script");i.charset="utf-8",i.timeout=120,f.nc&&i.setAttribute("nonce",f.nc),i.src=o(e),d=function(n){i.onerror=i.onload=null,clearTimeout(h);var t=u[e];if(0!==t){if(t){var r=n&&("load"===n.type?"missing":n.type),c=n&&n.target&&n.target.src,a=new Error("Loading chunk "+e+" failed.\n("+r+": "+c+")");a.type=r,a.request=c,t[1](a)}u[e]=void 0}};var h=setTimeout((function(){d({type:"timeout",target:i})}),12e4);i.onerror=i.onload=d,document.head.appendChild(i)}return Promise.all(n)},f.m=e,f.c=r,f.d=function(e,n,t){f.o(e,n)||Object.defineProperty(e,n,{enumerable:!0,get:t})},f.r=function(e){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},f.t=function(e,n){if(1&n&&(e=f(e)),8&n)return e;if(4&n&&"object"===typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(f.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&n&&"string"!=typeof e)for(var r in e)f.d(t,r,function(n){return e[n]}.bind(null,r));return t},f.n=function(e){var n=e&&e.__esModule?function(){return e["default"]}:function(){return e};return f.d(n,"a",n),n},f.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},f.p="",f.oe=function(e){throw console.error(e),e};var d=window["webpackJsonp"]=window["webpackJsonp"]||[],i=d.push.bind(d);d.push=n,d=d.slice();for(var h=0;h<d.length;h++)n(d[h]);var l=i;t()})([]);</script><script src=static/js/chunk-elementUI.1d3df44e.js></script><script src=static/js/chunk-libs.e265b709.js></script><script src=static/js/app.bfb55890.js></script></body></html>
|
<!DOCTYPE html><html><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge,chrome=1"><meta name=viewport content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"><link rel=icon href=favicon.ico><title>开放平台</title><link href=static/css/chunk-elementUI.ded27da0.css rel=stylesheet><link href=static/css/chunk-libs.3dfb7769.css rel=stylesheet><link href=static/css/app.520ff3b4.css rel=stylesheet></head><body><noscript><strong>We're sorry but 开放平台 doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><script>(function(e){function n(n){for(var r,c,a=n[0],d=n[1],f=n[2],i=0,h=[];i<a.length;i++)c=a[i],u[c]&&h.push(u[c][0]),u[c]=0;for(r in d)Object.prototype.hasOwnProperty.call(d,r)&&(e[r]=d[r]);l&&l(n);while(h.length)h.shift()();return o.push.apply(o,f||[]),t()}function t(){for(var e,n=0;n<o.length;n++){for(var t=o[n],r=!0,c=1;c<t.length;c++){var a=t[c];0!==u[a]&&(r=!1)}r&&(o.splice(n--,1),e=d(d.s=t[0]))}return e}var r={},c={runtime:0},u={runtime:0},o=[];function a(e){return d.p+"static/js/"+({}[e]||e)+"."+{"chunk-28a29d22":"7852c65c","chunk-2d0ac226":"908e7bac","chunk-2d0b6e8a":"ddfa15ec","chunk-2d0e958e":"1652deea","chunk-2d216d78":"211ad599","chunk-3d8e72b0":"d5d1a474","chunk-5142434b":"623e9909","chunk-5356e7e6":"2c0ab073","chunk-6440f6d0":"4dcd9cf4","chunk-2d0d43b7":"a9f25820","chunk-2d0e1a00":"c05ee2a3","chunk-57325c88":"6f1a8ef5","chunk-788f7208":"6f676b03"}[e]+".js"}function d(n){if(r[n])return r[n].exports;var t=r[n]={i:n,l:!1,exports:{}};return e[n].call(t.exports,t,t.exports,d),t.l=!0,t.exports}d.e=function(e){var n=[],t={"chunk-28a29d22":1,"chunk-3d8e72b0":1,"chunk-5142434b":1,"chunk-5356e7e6":1,"chunk-6440f6d0":1,"chunk-57325c88":1};c[e]?n.push(c[e]):0!==c[e]&&t[e]&&n.push(c[e]=new Promise((function(n,t){for(var r="static/css/"+({}[e]||e)+"."+{"chunk-28a29d22":"4dc6f542","chunk-2d0ac226":"31d6cfe0","chunk-2d0b6e8a":"31d6cfe0","chunk-2d0e958e":"31d6cfe0","chunk-2d216d78":"31d6cfe0","chunk-3d8e72b0":"04f4b7fb","chunk-5142434b":"0ad43c8d","chunk-5356e7e6":"52876932","chunk-6440f6d0":"b35fc6d0","chunk-2d0d43b7":"31d6cfe0","chunk-2d0e1a00":"31d6cfe0","chunk-57325c88":"77426e4e","chunk-788f7208":"31d6cfe0"}[e]+".css",u=d.p+r,o=document.getElementsByTagName("link"),a=0;a<o.length;a++){var f=o[a],i=f.getAttribute("data-href")||f.getAttribute("href");if("stylesheet"===f.rel&&(i===r||i===u))return n()}var h=document.getElementsByTagName("style");for(a=0;a<h.length;a++){f=h[a],i=f.getAttribute("data-href");if(i===r||i===u)return n()}var l=document.createElement("link");l.rel="stylesheet",l.type="text/css",l.onload=n,l.onerror=function(n){var r=n&&n.target&&n.target.src||u,o=new Error("Loading CSS chunk "+e+" failed.\n("+r+")");o.code="CSS_CHUNK_LOAD_FAILED",o.request=r,delete c[e],l.parentNode.removeChild(l),t(o)},l.href=u;var s=document.getElementsByTagName("head")[0];s.appendChild(l)})).then((function(){c[e]=0})));var r=u[e];if(0!==r)if(r)n.push(r[2]);else{var o=new Promise((function(n,t){r=u[e]=[n,t]}));n.push(r[2]=o);var f,i=document.createElement("script");i.charset="utf-8",i.timeout=120,d.nc&&i.setAttribute("nonce",d.nc),i.src=a(e),f=function(n){i.onerror=i.onload=null,clearTimeout(h);var t=u[e];if(0!==t){if(t){var r=n&&("load"===n.type?"missing":n.type),c=n&&n.target&&n.target.src,o=new Error("Loading chunk "+e+" failed.\n("+r+": "+c+")");o.type=r,o.request=c,t[1](o)}u[e]=void 0}};var h=setTimeout((function(){f({type:"timeout",target:i})}),12e4);i.onerror=i.onload=f,document.head.appendChild(i)}return Promise.all(n)},d.m=e,d.c=r,d.d=function(e,n,t){d.o(e,n)||Object.defineProperty(e,n,{enumerable:!0,get:t})},d.r=function(e){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},d.t=function(e,n){if(1&n&&(e=d(e)),8&n)return e;if(4&n&&"object"===typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(d.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&n&&"string"!=typeof e)for(var r in e)d.d(t,r,function(n){return e[n]}.bind(null,r));return t},d.n=function(e){var n=e&&e.__esModule?function(){return e["default"]}:function(){return e};return d.d(n,"a",n),n},d.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},d.p="",d.oe=function(e){throw console.error(e),e};var f=window["webpackJsonp"]=window["webpackJsonp"]||[],i=f.push.bind(f);f.push=n,f=f.slice();for(var h=0;h<f.length;h++)n(f[h]);var l=i;t()})([]);</script><script src=static/js/chunk-elementUI.1d3df44e.js></script><script src=static/js/chunk-libs.e265b709.js></script><script src=static/js/app.132894e5.js></script></body></html>
|
@@ -1 +0,0 @@
|
|||||||
.dashboard-container[data-v-7229b958]{margin:30px}.dashboard-text[data-v-7229b958]{font-size:18px;line-height:46px}
|
|
@@ -1 +1 @@
|
|||||||
@font-face{font-family:fontello;src:url(../../static/fonts/fontello.e73a0647.eot);src:url(../../static/fonts/fontello.e73a0647.eot#iefix) format("embedded-opentype"),url(../../static/fonts/fontello.8d4a4e6f.woff2) format("woff2"),url(../../static/fonts/fontello.a782baa8.woff) format("woff"),url(../../static/fonts/fontello.068ca2b3.ttf) format("truetype"),url(../../static/img/fontello.9354499c.svg#fontello) format("svg");font-weight:400;font-style:normal}[class*=" fa-mavon-"]:before,[class^=fa-mavon-]:before{font-family:fontello;font-style:normal;font-weight:400;speak:none;display:inline-block;text-decoration:inherit;width:1em;margin-right:.2em;text-align:center;font-variant:normal;text-transform:none;line-height:1em;margin-left:.2em;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-mavon-bold:before{content:"\E800"}.fa-mavon-italic:before{content:"\E801"}.fa-mavon-thumb-tack:before{content:"\E802"}.fa-mavon-link:before{content:"\E803"}.fa-mavon-picture-o:before{content:"\E804"}.fa-mavon-repeat:before{content:"\E805"}.fa-mavon-undo:before{content:"\E806"}.fa-mavon-trash-o:before{content:"\E807"}.fa-mavon-floppy-o:before{content:"\E808"}.fa-mavon-compress:before{content:"\E809"}.fa-mavon-eye:before{content:"\E80A"}.fa-mavon-eye-slash:before{content:"\E80B"}.fa-mavon-question-circle:before{content:"\E80C"}.fa-mavon-times:before{content:"\E80D"}.fa-mavon-align-left:before{content:"\E80F"}.fa-mavon-align-center:before{content:"\E810"}.fa-mavon-align-right:before{content:"\E811"}.fa-mavon-arrows-alt:before{content:"\F0B2"}.fa-mavon-bars:before{content:"\F0C9"}.fa-mavon-list-ul:before{content:"\F0CA"}.fa-mavon-list-ol:before{content:"\F0CB"}.fa-mavon-strikethrough:before{content:"\F0CC"}.fa-mavon-underline:before{content:"\F0CD"}.fa-mavon-table:before{content:"\F0CE"}.fa-mavon-columns:before{content:"\F0DB"}.fa-mavon-quote-left:before{content:"\F10D"}.fa-mavon-code:before{content:"\F121"}.fa-mavon-superscript:before{content:"\F12B"}.fa-mavon-subscript:before{content:"\F12C"}.fa-mavon-header:before{content:"\F1DC"}.fa-mavon-window-maximize:before{content:"\F2D0"}.markdown-body strong{font-weight:bolder}.markdown-body .hljs-center{text-align:center}.markdown-body .hljs-right{text-align:right}.markdown-body .hljs-left{text-align:left}.api-info[data-v-c361512c]{font-weight:700}.doc-overview[data-v-c361512c]{margin-top:20px;margin-bottom:30px;color:#666;font-size:14px}.doc-request-method[data-v-c361512c]{margin-bottom:20px;color:#666;font-size:14px}
|
@font-face{font-family:fontello;src:url(../../static/fonts/fontello.e73a0647.eot);src:url(../../static/fonts/fontello.e73a0647.eot#iefix) format("embedded-opentype"),url(../../static/fonts/fontello.8d4a4e6f.woff2) format("woff2"),url(../../static/fonts/fontello.a782baa8.woff) format("woff"),url(../../static/fonts/fontello.068ca2b3.ttf) format("truetype"),url(../../static/img/fontello.9354499c.svg#fontello) format("svg");font-weight:400;font-style:normal}[class*=" fa-mavon-"]:before,[class^=fa-mavon-]:before{font-family:fontello;font-style:normal;font-weight:400;speak:none;display:inline-block;text-decoration:inherit;width:1em;margin-right:.2em;text-align:center;font-variant:normal;text-transform:none;line-height:1em;margin-left:.2em;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-mavon-bold:before{content:"\E800"}.fa-mavon-italic:before{content:"\E801"}.fa-mavon-thumb-tack:before{content:"\E802"}.fa-mavon-link:before{content:"\E803"}.fa-mavon-picture-o:before{content:"\E804"}.fa-mavon-repeat:before{content:"\E805"}.fa-mavon-undo:before{content:"\E806"}.fa-mavon-trash-o:before{content:"\E807"}.fa-mavon-floppy-o:before{content:"\E808"}.fa-mavon-compress:before{content:"\E809"}.fa-mavon-eye:before{content:"\E80A"}.fa-mavon-eye-slash:before{content:"\E80B"}.fa-mavon-question-circle:before{content:"\E80C"}.fa-mavon-times:before{content:"\E80D"}.fa-mavon-align-left:before{content:"\E80F"}.fa-mavon-align-center:before{content:"\E810"}.fa-mavon-align-right:before{content:"\E811"}.fa-mavon-arrows-alt:before{content:"\F0B2"}.fa-mavon-bars:before{content:"\F0C9"}.fa-mavon-list-ul:before{content:"\F0CA"}.fa-mavon-list-ol:before{content:"\F0CB"}.fa-mavon-strikethrough:before{content:"\F0CC"}.fa-mavon-underline:before{content:"\F0CD"}.fa-mavon-table:before{content:"\F0CE"}.fa-mavon-columns:before{content:"\F0DB"}.fa-mavon-quote-left:before{content:"\F10D"}.fa-mavon-code:before{content:"\F121"}.fa-mavon-superscript:before{content:"\F12B"}.fa-mavon-subscript:before{content:"\F12C"}.fa-mavon-header:before{content:"\F1DC"}.fa-mavon-window-maximize:before{content:"\F2D0"}.markdown-body strong{font-weight:bolder}.markdown-body .hljs-center{text-align:center}.markdown-body .hljs-right{text-align:right}.markdown-body .hljs-left{text-align:left}.api-info[data-v-0f669452]{font-weight:700}.doc-overview[data-v-0f669452]{margin-top:20px;margin-bottom:30px;color:#666;font-size:14px}.doc-request-method[data-v-0f669452]{margin-bottom:20px;color:#666;font-size:14px}.table-control .el-form-item__error{position:inherit}span.required:before{content:"*";color:#f56c6c;margin-right:4px}.api-info{font-weight:700}.doc-overview{margin-top:20px;margin-bottom:30px;color:#666;font-size:14px}.doc-request-method{margin-bottom:20px;color:#666;font-size:14px}.cell .choose-file{padding:5px}.doc-debug .cell .el-form-item{margin-bottom:0}
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
|
|||||||
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-4e7f1f48"],{9406:function(t,e,n){"use strict";n.r(e);var a=function(){var t=this,e=t.$createElement;t._self._c;return t._m(0)},s=[function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"dashboard-container"},[n("div",{staticClass:"dashboard-text"},[t._v("欢迎使用开放平台")])])}],c=(n("eaba"),n("2877")),i={},r=Object(c["a"])(i,a,s,!1,null,"7229b958",null);e["default"]=r.exports},d4e0:function(t,e,n){},eaba:function(t,e,n){"use strict";n("d4e0")}}]);
|
|
File diff suppressed because one or more lines are too long
@@ -155,10 +155,6 @@ export default {
|
|||||||
type: Object,
|
type: Object,
|
||||||
default: () => {}
|
default: () => {}
|
||||||
},
|
},
|
||||||
uri: {
|
|
||||||
type: String,
|
|
||||||
default: ''
|
|
||||||
},
|
|
||||||
urlProd: {
|
urlProd: {
|
||||||
type: String,
|
type: String,
|
||||||
default: ''
|
default: ''
|
||||||
|
@@ -1,31 +1,61 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="doc-debug">
|
<div class="doc-debug">
|
||||||
<h2>{{ docInfo.summary }}</h2>
|
<h2>{{ docInfo.summary }}</h2>
|
||||||
<el-table
|
<el-form
|
||||||
:data="[{ methodLabel: '接口名(method)', methodValue: docInfo.name, versionLabel: '版本号(version)', versionValue: docInfo.version }]"
|
ref="configForm"
|
||||||
border
|
size="mini"
|
||||||
:cell-style="baseInfoCellStyle"
|
:model="configFormData"
|
||||||
:show-header="false"
|
:rules="configFormRules"
|
||||||
|
label-width="120px"
|
||||||
>
|
>
|
||||||
<el-table-column prop="methodLabel" align="center" width="130">
|
<el-form-item prop="url" label="网关地址">
|
||||||
<template slot-scope="scope"><span class="api-info">{{ scope.row.methodLabel }}</span></template>
|
<el-input v-model="configFormData.url" clearable />
|
||||||
</el-table-column>
|
</el-form-item>
|
||||||
<el-table-column prop="methodValue" />
|
<el-form-item prop="appKey" label="AppId">
|
||||||
<el-table-column prop="versionLabel" align="center" width="130">
|
<el-input v-model="configFormData.appKey" clearable />
|
||||||
<template slot-scope="scope"><span class="api-info">{{ scope.row.versionLabel }}</span></template>
|
</el-form-item>
|
||||||
</el-table-column>
|
<el-form-item prop="privateKey" label="应用私钥">
|
||||||
<el-table-column prop="versionValue" width="120" />
|
<el-input v-model="configFormData.privateKey" clearable @change="onPrivateKeyChange" />
|
||||||
</el-table>
|
</el-form-item>
|
||||||
<h3>接口描述</h3>
|
<el-form-item label="token">
|
||||||
<div class="doc-overview">{{ docInfo.description || docInfo.title }}</div>
|
<el-input v-model="configFormData.token" clearable />
|
||||||
<h3>请求方法</h3>
|
</el-form-item>
|
||||||
<div class="doc-request-method">
|
</el-form>
|
||||||
{{ docInfo.httpMethodList && docInfo.httpMethodList.join(' / ').toUpperCase() }}
|
|
||||||
</div>
|
|
||||||
<h2>请求参数</h2>
|
<h2>请求参数</h2>
|
||||||
<parameter-table :data="docInfo.requestParameters" :editable="true" />
|
<parameter-table-edit ref="paramTableRef" :data="docInfo.requestParameters" />
|
||||||
|
<!-- 多文件选择 -->
|
||||||
|
<el-upload
|
||||||
|
v-show="docInfo.multiple"
|
||||||
|
action=""
|
||||||
|
:multiple="true"
|
||||||
|
:auto-upload="false"
|
||||||
|
style="width: 500px;margin-top: 10px"
|
||||||
|
:on-remove="(file, fileList) => onSelectMultiFile(file, fileList)"
|
||||||
|
:on-change="(file, fileList) => onSelectMultiFile(file, fileList)"
|
||||||
|
>
|
||||||
|
<el-button slot="trigger" type="primary" size="mini">上传多个文件</el-button>
|
||||||
|
</el-upload>
|
||||||
<br/>
|
<br/>
|
||||||
|
<el-form
|
||||||
|
size="mini"
|
||||||
|
>
|
||||||
|
<el-form-item label="HttpMethod">
|
||||||
|
<el-radio-group v-model="httpMethod">
|
||||||
|
<el-radio v-for="method in docInfo.httpMethodList" :key="method" :label="method">{{ method.toUpperCase() }}</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
<el-button type="primary" @click="send">发送请求</el-button>
|
<el-button type="primary" @click="send">发送请求</el-button>
|
||||||
|
<el-tabs v-show="resultShow">
|
||||||
|
<el-tabs v-model="resultActive" type="card">
|
||||||
|
<el-tab-pane label="请求信息" name="reqInfo">
|
||||||
|
<el-input v-model="reqInfo" type="textarea" :rows="10" readonly />
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane label="请求结果" name="resultContent">
|
||||||
|
<el-input v-model="resultContent" type="textarea" :rows="16" readonly />
|
||||||
|
</el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
</el-tabs>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<style>
|
<style>
|
||||||
@@ -36,20 +66,21 @@
|
|||||||
.doc-debug .cell .el-form-item {margin-bottom: 0;}
|
.doc-debug .cell .el-form-item {margin-bottom: 0;}
|
||||||
</style>
|
</style>
|
||||||
<script>
|
<script>
|
||||||
import ParameterTable from '@/components/ParameterTable'
|
import ParameterTableEdit from '@/components/ParameterTableEdit'
|
||||||
|
const privateKeyStoreKey = 'sop.sendbox.privateKey'
|
||||||
export default {
|
export default {
|
||||||
name: 'Docdebug',
|
name: 'Docdebug',
|
||||||
components: { ParameterTable },
|
components: { ParameterTableEdit },
|
||||||
props: {
|
props: {
|
||||||
item: {
|
item: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: () => {}
|
default: () => {}
|
||||||
},
|
},
|
||||||
uri: {
|
appId: {
|
||||||
type: String,
|
type: String,
|
||||||
default: ''
|
default: ''
|
||||||
},
|
},
|
||||||
urlProd: {
|
gatewayUrl: {
|
||||||
type: String,
|
type: String,
|
||||||
default: ''
|
default: ''
|
||||||
}
|
}
|
||||||
@@ -63,31 +94,192 @@ export default {
|
|||||||
return { padding: '5px 0' }
|
return { padding: '5px 0' }
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
configFormRules: {
|
||||||
|
appKey: [
|
||||||
|
{ required: true, message: '请填写AppId', trigger: 'blur' }
|
||||||
|
],
|
||||||
|
privateKey: [
|
||||||
|
{ required: true, message: '请填写应用私钥', trigger: 'blur' }
|
||||||
|
],
|
||||||
|
url: [
|
||||||
|
{ required: true, message: '请填写URL', trigger: 'blur' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
configFormData: {
|
||||||
|
url: '',
|
||||||
|
appKey: '',
|
||||||
|
privateKey: '',
|
||||||
|
token: ''
|
||||||
|
},
|
||||||
|
httpMethod: '',
|
||||||
docInfo: {
|
docInfo: {
|
||||||
summary: '',
|
summary: '',
|
||||||
|
name: '',
|
||||||
|
version: '',
|
||||||
|
multiple: false,
|
||||||
|
uploadRequest: false,
|
||||||
httpMethodList: [],
|
httpMethodList: [],
|
||||||
requestParameters: [],
|
requestParameters: [],
|
||||||
responseParameters: [],
|
responseParameters: [],
|
||||||
bizCodes: []
|
bizCodes: []
|
||||||
}
|
},
|
||||||
|
uploadFiles: [],
|
||||||
|
resultActive: 'resultContent',
|
||||||
|
resultShow: false,
|
||||||
|
reqInfo: '',
|
||||||
|
resultContent: ''
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
item(newVal) {
|
item(newVal) {
|
||||||
this.initItem(newVal)
|
this.initItem(newVal)
|
||||||
|
},
|
||||||
|
appId(newVal) {
|
||||||
|
this.configFormData.appKey = newVal
|
||||||
|
},
|
||||||
|
gatewayUrl(url) {
|
||||||
|
this.configFormData.url = url
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
|
const privateKey = this.getAttr(privateKeyStoreKey)
|
||||||
|
if (privateKey) {
|
||||||
|
this.configFormData.privateKey = privateKey
|
||||||
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
send() {
|
send() {
|
||||||
|
this.$refs.configForm.validate(valid => {
|
||||||
|
if (valid) {
|
||||||
|
// 验证表格参数
|
||||||
|
const promiseRequestArr = this.validateTable(this.docInfo.requestParameters, ['req_form_example_'])
|
||||||
|
Promise.all(promiseRequestArr).then(validArr => {
|
||||||
|
// 到这里来表示全部内容校验通过
|
||||||
|
this.doSend()
|
||||||
|
}).catch((e) => {
|
||||||
|
// this.tipError('请完善表单内容')
|
||||||
|
}) // 加上这个控制台不会报Uncaught (in promise)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
doSend() {
|
||||||
|
const bizContent = this.buildParamData(this.docInfo.requestParameters)
|
||||||
|
const data = {
|
||||||
|
gatewayUrl: this.configFormData.url,
|
||||||
|
appId: this.configFormData.appKey,
|
||||||
|
privateKey: this.configFormData.privateKey,
|
||||||
|
token: this.configFormData.token,
|
||||||
|
method: this.docInfo.name,
|
||||||
|
version: this.docInfo.version,
|
||||||
|
httpMethod: this.httpMethod,
|
||||||
|
bizContent: JSON.stringify(bizContent)
|
||||||
|
}
|
||||||
|
const files = this.buildFiles(this.docInfo.requestParameters)
|
||||||
|
const isForm = this.httpMethod.toUpperCase() === 'POST'
|
||||||
|
this.request(this.httpMethod, '/sandbox/test_v2', data, {}, false, isForm, files, function(error, response) {
|
||||||
|
this.resultShow = true
|
||||||
|
this.resultActive = 'resultContent'
|
||||||
|
const status = response.statusCode || response.status
|
||||||
|
if (!error && status === 200) {
|
||||||
|
this.successHandler(response)
|
||||||
|
} else {
|
||||||
|
console.log(error)
|
||||||
|
this.$message.error('请求异常,请查看日志')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
validateTable: function(arr, refPrefixArr) {
|
||||||
|
const $refs = this.$refs.paramTableRef.$refs
|
||||||
|
let promiseArr = []
|
||||||
|
for (let i = 0; i < arr.length; i++) {
|
||||||
|
const row = arr[i]
|
||||||
|
const id = row.id
|
||||||
|
refPrefixArr.forEach(refPrefix => {
|
||||||
|
const ref = $refs[refPrefix + id]
|
||||||
|
if (ref) {
|
||||||
|
promiseArr.push(ref.validate())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const children = arr[i].children
|
||||||
|
if (children && children.length > 0) {
|
||||||
|
const childrenPromiseArr = this.validateTable(children, refPrefixArr)
|
||||||
|
promiseArr = promiseArr.concat(childrenPromiseArr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return promiseArr
|
||||||
|
},
|
||||||
|
successHandler(response) {
|
||||||
|
this.setReqInfo(response)
|
||||||
|
this.setRespInfo(response)
|
||||||
|
},
|
||||||
|
setReqInfo(response) {
|
||||||
|
const headers = response.headers
|
||||||
|
if (headers) {
|
||||||
|
const html = []
|
||||||
|
html.push('【请求参数】:' + decodeURIComponent(headers['sendbox-params']))
|
||||||
|
html.push('【待签名内容】:' + decodeURIComponent(headers['sendbox-beforesign']))
|
||||||
|
html.push('【签名(sign)】:' + decodeURIComponent(headers['sendbox-sign']))
|
||||||
|
this.reqInfo = html.join('\r\n')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setRespInfo(response) {
|
||||||
|
const headers = response.headers
|
||||||
|
const targetHeadersString = headers['target-response-headers'] || '{}'
|
||||||
|
const targetHeaders = JSON.parse(targetHeadersString)
|
||||||
|
const contentType = targetHeaders['content-type'] || ''
|
||||||
|
const contentDisposition = targetHeaders['content-disposition'] || ''
|
||||||
|
if (contentType.indexOf('stream') > -1 || contentDisposition.indexOf('attachment') > -1) {
|
||||||
|
const filename = this.getDispositionFilename(contentDisposition)
|
||||||
|
this.downloadFile(filename, response.raw)
|
||||||
|
} else {
|
||||||
|
const body = response.body || response.data
|
||||||
|
this.resultContent = JSON.stringify(body, null, 4)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
downloadFile(filename, buffer) {
|
||||||
|
const url = window.URL.createObjectURL(new Blob([buffer]))
|
||||||
|
const link = document.createElement('a')
|
||||||
|
link.href = url
|
||||||
|
link.setAttribute('download', filename)
|
||||||
|
document.body.appendChild(link)
|
||||||
|
link.click()
|
||||||
|
},
|
||||||
|
getDispositionFilename(disposition) {
|
||||||
|
const dispositionArr = disposition.split(';')
|
||||||
|
for (let i = 0; i < dispositionArr.length; i++) {
|
||||||
|
const item = dispositionArr[i].trim()
|
||||||
|
// filename="xx"
|
||||||
|
if (item.toLowerCase().startsWith('filename')) {
|
||||||
|
const result = item.match(new RegExp('filename="(.*?)"', 'i'))
|
||||||
|
return result ? result[1] : ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
resetResult() {
|
||||||
|
this.reqInfo = ''
|
||||||
|
this.resultContent = ''
|
||||||
|
this.resultShow = false
|
||||||
},
|
},
|
||||||
initItem(item) {
|
initItem(item) {
|
||||||
|
if (item) {
|
||||||
this.setData(item)
|
this.setData(item)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
setData: function(data) {
|
setData: function(data) {
|
||||||
|
this.resetResult()
|
||||||
this.docInfo = data
|
this.docInfo = data
|
||||||
|
this.httpMethod = this.docInfo.httpMethodList[0]
|
||||||
|
},
|
||||||
|
onSelectMultiFile(file, fileList) {
|
||||||
|
const files = []
|
||||||
|
fileList.forEach(file => {
|
||||||
|
const rawFile = file.raw
|
||||||
|
files.push(rawFile)
|
||||||
|
})
|
||||||
|
this.uploadFiles = files
|
||||||
|
},
|
||||||
|
onPrivateKeyChange() {
|
||||||
|
this.setAttr(privateKeyStoreKey, this.configFormData.privateKey)
|
||||||
},
|
},
|
||||||
buildParamData: function(params) {
|
buildParamData: function(params) {
|
||||||
const responseJson = {}
|
const responseJson = {}
|
||||||
@@ -117,6 +309,22 @@ export default {
|
|||||||
return Object.values(responseJson)[0]
|
return Object.values(responseJson)[0]
|
||||||
}
|
}
|
||||||
return responseJson
|
return responseJson
|
||||||
|
},
|
||||||
|
buildFiles(params) {
|
||||||
|
const files = []
|
||||||
|
for (let i = 0; i < params.length; i++) {
|
||||||
|
const row = params[i]
|
||||||
|
// 处理文件上传
|
||||||
|
const fileConfig = row.__file__
|
||||||
|
if (fileConfig) {
|
||||||
|
files.push(fileConfig)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 全局上传
|
||||||
|
if (this.uploadFiles.length > 0) {
|
||||||
|
files.push({ name: 'file', files: this.uploadFiles })
|
||||||
|
}
|
||||||
|
return files
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -50,17 +50,12 @@
|
|||||||
label="示例值"
|
label="示例值"
|
||||||
>
|
>
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<div v-if="editable">
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div v-else>
|
|
||||||
<div v-if="scope.row.type === 'enum'">
|
<div v-if="scope.row.type === 'enum'">
|
||||||
{{ (scope.row.enums || []).join('、') }}
|
{{ (scope.row.enums || []).join('、') }}
|
||||||
</div>
|
</div>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
{{ scope.row.paramExample }}
|
{{ scope.row.paramExample }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
@@ -74,10 +69,6 @@ export default {
|
|||||||
type: Array,
|
type: Array,
|
||||||
default: () => []
|
default: () => []
|
||||||
},
|
},
|
||||||
editable: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
tree: {
|
tree: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true
|
default: true
|
||||||
|
@@ -0,0 +1,121 @@
|
|||||||
|
<template>
|
||||||
|
<el-table
|
||||||
|
:data="data"
|
||||||
|
border
|
||||||
|
row-key="id"
|
||||||
|
default-expand-all
|
||||||
|
:tree-props="{ children: 'refs', hasChildren: 'hasChildren' }"
|
||||||
|
:cell-style="cellStyleSmall()"
|
||||||
|
:header-cell-style="headCellStyleSmall()"
|
||||||
|
empty-text="无参数"
|
||||||
|
>
|
||||||
|
<el-table-column
|
||||||
|
prop="name"
|
||||||
|
label="名称"
|
||||||
|
width="250"
|
||||||
|
>
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<span :class="{ 'required': scope.row.required}">{{ scope.row.name }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column
|
||||||
|
prop="type"
|
||||||
|
label="类型"
|
||||||
|
width="100"
|
||||||
|
>
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<span>{{ scope.row.type }}</span>
|
||||||
|
<span v-show="scope.row.type === 'array' && scope.row.elementType">
|
||||||
|
<el-tooltip effect="dark" :content="`元素类型:${scope.row.elementType}`" placement="top">
|
||||||
|
<i class="el-icon-info"></i>
|
||||||
|
</el-tooltip>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column
|
||||||
|
prop="paramExample"
|
||||||
|
label="参数值"
|
||||||
|
>
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-form
|
||||||
|
v-if="scope.row.type !== 'object'"
|
||||||
|
:ref="'req_form_example_' + scope.row.id"
|
||||||
|
:model="scope.row"
|
||||||
|
:rules="buildParamRules(scope.row)"
|
||||||
|
size="mini"
|
||||||
|
style="display: inline-block"
|
||||||
|
>
|
||||||
|
<el-form-item
|
||||||
|
prop="paramExample"
|
||||||
|
label-width="0"
|
||||||
|
class="table-control"
|
||||||
|
>
|
||||||
|
<el-upload
|
||||||
|
v-if="scope.row.type === 'file' || scope.row.elementType === 'file'"
|
||||||
|
action=""
|
||||||
|
:multiple="false"
|
||||||
|
:auto-upload="false"
|
||||||
|
:on-change="(file, fileList) => onSelectFile(file, fileList, scope.row)"
|
||||||
|
:on-remove="(file, fileList) => onSelectFile(file, fileList, scope.row)"
|
||||||
|
>
|
||||||
|
<el-button slot="trigger" class="choose-file" type="primary">选择文件</el-button>
|
||||||
|
</el-upload>
|
||||||
|
<el-input v-else v-model="scope.row.paramExample" placeholder="参数值" clearable />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column
|
||||||
|
prop="description"
|
||||||
|
label="描述"
|
||||||
|
/>
|
||||||
|
</el-table>
|
||||||
|
</template>
|
||||||
|
<style>
|
||||||
|
.table-control .el-form-item__error {
|
||||||
|
position: inherit;
|
||||||
|
}
|
||||||
|
span.required:before {
|
||||||
|
content: '*';
|
||||||
|
color: #F56C6C;
|
||||||
|
margin-right: 4px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'ParameterTableEdit',
|
||||||
|
props: {
|
||||||
|
data: {
|
||||||
|
type: Array,
|
||||||
|
default: () => []
|
||||||
|
},
|
||||||
|
tree: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
buildParamRules(row) {
|
||||||
|
const rules = []
|
||||||
|
if (row.required && row.type !== 'file') {
|
||||||
|
rules.push({ required: true, message: '请填写参数值', trigger: 'blur' })
|
||||||
|
}
|
||||||
|
const max = parseInt(row.maxLength)
|
||||||
|
if (max) {
|
||||||
|
rules.push({ max: max, message: `长度不超过 ${max} 个字符`, trigger: 'blur' })
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
paramExample: rules
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onSelectFile(f, fileList, row) {
|
||||||
|
const files = []
|
||||||
|
fileList.forEach(file => {
|
||||||
|
const rawFile = file.raw
|
||||||
|
files.push(rawFile)
|
||||||
|
})
|
||||||
|
row.__file__ = { name: row.name, files: files }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
@@ -5,9 +5,6 @@ Vue.use(Router)
|
|||||||
|
|
||||||
/* Layout */
|
/* Layout */
|
||||||
import Layout from '@/layout'
|
import Layout from '@/layout'
|
||||||
const _import = require('@/router/_import_' + process.env.NODE_ENV)
|
|
||||||
|
|
||||||
const menuKey = 'route-menus'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Note: sub-menus only appear when route children.length >= 1
|
* Note: sub-menus only appear when route children.length >= 1
|
||||||
|
@@ -55,6 +55,43 @@ Object.assign(Vue.prototype, {
|
|||||||
that.doResponse(error, response, callback, errorCallback)
|
that.doResponse(error, response, callback, errorCallback)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
request(method, uri, data, headers, isJson, isForm, files, callback) {
|
||||||
|
// 如果是文件上传,使用axios,needle上传文件不完美,不支持一个name对应多个文件
|
||||||
|
if (files && files.length > 0) {
|
||||||
|
this.doMultipart(uri, data, files, headers, callback)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const that = this
|
||||||
|
if (isForm) {
|
||||||
|
headers['Content-Type'] = 'application/x-www-form-urlencoded'
|
||||||
|
}
|
||||||
|
needle.request(method, baseURL + uri, data, {
|
||||||
|
// 设置header
|
||||||
|
headers: headers,
|
||||||
|
json: isJson
|
||||||
|
}, (error, response) => {
|
||||||
|
callback.call(that, error, response)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
doMultipart(uri, data, files, headers, callback) {
|
||||||
|
const that = this
|
||||||
|
const formData = new FormData()
|
||||||
|
files.forEach(fileConfig => {
|
||||||
|
fileConfig.files.forEach(file => {
|
||||||
|
formData.append(fileConfig.name, file)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
for (const name in data) {
|
||||||
|
formData.append(name, data[name])
|
||||||
|
}
|
||||||
|
client.post(uri, formData, {
|
||||||
|
headers: headers
|
||||||
|
}).then(function(response) {
|
||||||
|
callback.call(that, null, response)
|
||||||
|
}).catch(function(error) {
|
||||||
|
callback.call(that, error, null)
|
||||||
|
})
|
||||||
|
},
|
||||||
doResponse(error, response, callback, errorCallback) {
|
doResponse(error, response, callback, errorCallback) {
|
||||||
// 成功
|
// 成功
|
||||||
if (!error && response.statusCode === 200) {
|
if (!error && response.statusCode === 200) {
|
||||||
@@ -226,9 +263,6 @@ Object.assign(Vue.prototype, {
|
|||||||
goLogin() {
|
goLogin() {
|
||||||
removeToken()
|
removeToken()
|
||||||
this.$router.replace({ path: `/login` })
|
this.$router.replace({ path: `/login` })
|
||||||
setTimeout(function() {
|
|
||||||
location.reload()
|
|
||||||
}, 200)
|
|
||||||
},
|
},
|
||||||
goRoute: function(path) {
|
goRoute: function(path) {
|
||||||
this.$router.push({ path: path })
|
this.$router.push({ path: path })
|
||||||
|
@@ -24,12 +24,25 @@
|
|||||||
/>
|
/>
|
||||||
</el-aside>
|
</el-aside>
|
||||||
<el-main style="padding-top: 0">
|
<el-main style="padding-top: 0">
|
||||||
|
<el-tabs>
|
||||||
|
<el-tabs v-show="item" v-model="active" type="card">
|
||||||
|
<el-tab-pane name="info">
|
||||||
|
<span slot="label"><i class="el-icon-document"></i> 接口信息</span>
|
||||||
<doc-view
|
<doc-view
|
||||||
v-show="item"
|
|
||||||
:item="item"
|
:item="item"
|
||||||
:url-prod="docVO.urlProd"
|
:url-prod="docVO.urlProd"
|
||||||
uri="/portal/isv/getDocItem"
|
|
||||||
/>
|
/>
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane name="debug">
|
||||||
|
<span slot="label"><i class="el-icon-position"></i> 接口调试</span>
|
||||||
|
<docdebug
|
||||||
|
:item="item"
|
||||||
|
:app-id="docVO.appId"
|
||||||
|
:gateway-url="docVO.gatewayUrl"
|
||||||
|
/>
|
||||||
|
</el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
</el-tabs>
|
||||||
</el-main>
|
</el-main>
|
||||||
</el-container>
|
</el-container>
|
||||||
</div>
|
</div>
|
||||||
@@ -38,13 +51,16 @@
|
|||||||
<script>
|
<script>
|
||||||
import 'mavon-editor/dist/css/index.css'
|
import 'mavon-editor/dist/css/index.css'
|
||||||
import docView from '@/components/DocView'
|
import docView from '@/components/DocView'
|
||||||
|
import docdebug from '@/components/Docdebug'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: { docView },
|
components: { docView, docdebug },
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
active: 'info',
|
active: 'info',
|
||||||
docVO: {
|
docVO: {
|
||||||
|
appId: '',
|
||||||
|
gatewayUrl: '',
|
||||||
urlProd: '',
|
urlProd: '',
|
||||||
urlTest: '',
|
urlTest: '',
|
||||||
menuProjects: []
|
menuProjects: []
|
||||||
|
Reference in New Issue
Block a user