dubbo文档操作接口和页面

This commit is contained in:
暮光:城中城
2019-02-13 21:29:09 +08:00
parent cca2effbd2
commit 62b6a17c21
51 changed files with 15660 additions and 24 deletions

View File

@@ -4,9 +4,13 @@ import cn.hutool.http.HttpUtil;
import com.alibaba.dubbo.rpc.service.GenericService;
import com.alibaba.fastjson.JSON;
import com.zyplayer.doc.core.json.DocResponseJson;
import com.zyplayer.doc.dubbo.controller.param.DubboRequestParam;
import com.zyplayer.doc.dubbo.framework.bean.DubboDocInfo;
import com.zyplayer.doc.dubbo.framework.bean.DubboInfo;
import com.zyplayer.doc.dubbo.framework.bean.NacosDubboInfo;
import com.zyplayer.doc.dubbo.framework.bean.ReferenceConfigHolder;
import com.zyplayer.doc.dubbo.framework.constant.StorageKeys;
import com.zyplayer.doc.dubbo.framework.service.MgDubboStorageService;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.apache.curator.RetryPolicy;
@@ -20,6 +24,7 @@ import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.net.URLDecoder;
import java.util.*;
import java.util.stream.Collectors;
@@ -28,7 +33,7 @@ import java.util.stream.Collectors;
* 文档控制器
*
* @author 暮光:城中城
* @since 2018年8月8
* @since 2019年2月10
*/
@RestController
@RequestMapping("/zyplayer-doc-dubbo/doc-dubbo")
@@ -41,9 +46,17 @@ public class DubboController {
private String nacosUrl;
@Value("${zyplayer.doc.dubbo.nacos.service:}")
private String nacosService;
@Resource
private MgDubboStorageService mgDubboStorageService;
@GetMapping(value = "/getList")
public DocResponseJson getDataSourceList() throws Exception {
/**
* 重新获取所有的服务列表
*
* @author 暮光:城中城
* @since 2019年2月10日
**/
@GetMapping(value = "/reloadService")
public DocResponseJson loadService() throws Exception {
List<DubboInfo> providerList;
if (StringUtils.isBlank(zookeeperUrl)) {
if (StringUtils.isBlank(nacosUrl) || StringUtils.isBlank(nacosService)) {
@@ -54,17 +67,100 @@ public class DubboController {
} else {
providerList = this.getDubboInfoByZookeeper();
}
GenericService bean = ReferenceConfigHolder.getBean(providerList.get(0).getNodeList().get(0));
Object o = bean.$invoke("getUserList", new String[]{}, new String[]{});
System.out.println(o);
mgDubboStorageService.put(StorageKeys.DUBBO_SERVICE_LIST, JSON.toJSONString(providerList));
return DocResponseJson.ok();
}
/**
* 请求执行服务
*
* @author 暮光:城中城
* @since 2019年2月10日
**/
@GetMapping(value = "/request")
public DocResponseJson request(DubboRequestParam param) {
DubboInfo.DubboNodeInfo dubboNodeInfo = new DubboInfo.DubboNodeInfo();
dubboNodeInfo.setIp(param.getIp());
dubboNodeInfo.setPort(param.getPort());
dubboNodeInfo.setInterfaceX(param.getService());
String[] paramTypes = Optional.ofNullable(param.getParamTypes()).orElse(new String[]{});
Object[] params = Optional.ofNullable(param.getParams()).orElse(new Object[]{});
GenericService bean = ReferenceConfigHolder.getBean(dubboNodeInfo);
try {
Object result = bean.$invoke(param.getMethod(), paramTypes, params);
return DocResponseJson.ok(result);
} catch (Exception e) {
e.printStackTrace();
return DocResponseJson.warn("请求失败:" + e.getMessage());
}
}
/**
* 获取文档列表
*
* @author 暮光:城中城
* @since 2019年2月10日
**/
@GetMapping(value = "/getDocList")
public DocResponseJson getDocList() {
String dubboServiceList = mgDubboStorageService.get(StorageKeys.DUBBO_SERVICE_LIST);
String dubboServiceDoc = mgDubboStorageService.get(StorageKeys.DUBBO_SERVICE_DOC);
if (StringUtils.isBlank(dubboServiceList)) {
return DocResponseJson.ok();
}
List<DubboInfo> providerList = JSON.parseArray(dubboServiceList, DubboInfo.class);
if (StringUtils.isNotBlank(dubboServiceDoc)) {
List<DubboDocInfo> docInfoList = JSON.parseArray(dubboServiceDoc, DubboDocInfo.class);
Map<String, DubboDocInfo> docInfoMap = docInfoList.stream().collect(Collectors.toMap(DubboDocInfo::getService, val -> val));
for (DubboInfo dubboInfo : providerList) {
dubboInfo.setDocInfo(docInfoMap.get(dubboInfo.getInterfaceX()));
}
}
return DocResponseJson.ok(providerList);
}
/**
* 保存文档
*
* @author 暮光:城中城
* @since 2019年2月10日
**/
@GetMapping(value = "/saveDoc")
public DocResponseJson saveDoc(DubboDocInfo param) {
String dubboServiceDoc = mgDubboStorageService.get(StorageKeys.DUBBO_SERVICE_DOC);
Map<String, DubboDocInfo> docInfoMap = new HashMap<>();
if (StringUtils.isNotBlank(dubboServiceDoc)) {
List<DubboDocInfo> docInfoList = JSON.parseArray(dubboServiceDoc, DubboDocInfo.class);
docInfoMap = docInfoList.stream().collect(Collectors.toMap(DubboDocInfo::getService, val -> val));
}
DubboDocInfo dubboDocInfo = docInfoMap.get(param.getService());
if (dubboDocInfo != null) {
Integer newVersion = Optional.ofNullable(param.getVersion()).orElse(1);
Integer oldVersion = Optional.ofNullable(dubboDocInfo.getVersion()).orElse(1);
if (oldVersion > newVersion) {
return DocResponseJson.warn("已有用户在您之前修改过文档,请刷新后再修改");
}
param.setVersion(oldVersion + 1);
} else {
param.setVersion(1);
}
docInfoMap.put(param.getService(), param);
List<DubboDocInfo> docInfoList = new ArrayList<>(docInfoMap.values());
mgDubboStorageService.put(StorageKeys.DUBBO_SERVICE_DOC, JSON.toJSONString(docInfoList));
return DocResponseJson.ok();
}
/**
* 通过nacos方式获取所有服务
*
* @author 暮光:城中城
* @since 2019年2月10日
**/
private List<DubboInfo> getDubboInfoByNacos() {
List<DubboInfo> providerList = new LinkedList<>();
String[] nacosServiceArr = nacosService.split(";");
for (String service : nacosServiceArr) {
String resultStr = HttpUtil.get(nacosUrl + "/v1/ns/instance/list?serviceName=" + service);
String resultStr = HttpUtil.get(nacosUrl + "/v1/ns/instance/list?serviceName=providers:" + service);
NacosDubboInfo dubboInstance = JSON.parseObject(resultStr, NacosDubboInfo.class);
List<NacosDubboInfo.HostsBean> hosts = dubboInstance.getHosts();
DubboInfo dubboInfo = new DubboInfo();
@@ -76,14 +172,21 @@ public class DubboController {
dubboNodeInfo.setInterfaceX(host.getMetadata().getInterfaceX());
dubboNodeInfo.setMethods(host.getMetadata().getMethods().split(","));
dubboNodeInfo.setApplication(host.getMetadata().getApplication());
nodeList.add(dubboNodeInfo);
}
dubboInfo.setInterfaceX(service.substring(service.indexOf(":") + 1));
dubboInfo.setInterfaceX(service);
dubboInfo.setNodeList(nodeList);
providerList.add(dubboInfo);
}
return providerList;
}
/**
* 通过Zookeeper方式获取所有服务
*
* @author 暮光:城中城
* @since 2019年2月10日
**/
private List<DubboInfo> getDubboInfoByZookeeper() throws Exception {
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
CuratorFramework client = CuratorFrameworkFactory.newClient(zookeeperUrl, retryPolicy);

View File

@@ -0,0 +1,64 @@
package com.zyplayer.doc.dubbo.controller.param;
/**
* 请求参数对象
*
* @author 暮光:城中城
* @since 2019年2月10日
*/
public class DubboRequestParam {
private String service;
private String method;
private String ip;
private Integer port;
private String[] paramTypes;
private Object[] params;
public String[] getParamTypes() {
return paramTypes;
}
public void setParamTypes(String[] paramTypes) {
this.paramTypes = paramTypes;
}
public String getService() {
return service;
}
public void setService(String service) {
this.service = service;
}
public String getMethod() {
return method;
}
public void setMethod(String method) {
this.method = method;
}
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
public Integer getPort() {
return port;
}
public void setPort(Integer port) {
this.port = port;
}
public Object[] getParams() {
return params;
}
public void setParams(Object[] params) {
this.params = params;
}
}

View File

@@ -0,0 +1,104 @@
package com.zyplayer.doc.dubbo.framework.bean;
import java.util.List;
/**
* 请求参数对象
*
* @author 暮光:城中城
* @since 2019年2月10日
*/
public class DubboDocInfo {
private String service;
private String method;
private String explain;
private Integer version;
private List<DubboDocParam> params;
public class DubboDocParam {
private String paramName;
private String paramType;
private String paramDesc;
private Object paramVal;
private Integer required;
public String getParamName() {
return paramName;
}
public void setParamName(String paramName) {
this.paramName = paramName;
}
public String getParamType() {
return paramType;
}
public void setParamType(String paramType) {
this.paramType = paramType;
}
public String getParamDesc() {
return paramDesc;
}
public void setParamDesc(String paramDesc) {
this.paramDesc = paramDesc;
}
public Object getParamVal() {
return paramVal;
}
public void setParamVal(Object paramVal) {
this.paramVal = paramVal;
}
public Integer getRequired() {
return required;
}
public void setRequired(Integer required) {
this.required = required;
}
}
public Integer getVersion() {
return version;
}
public void setVersion(Integer version) {
this.version = version;
}
public String getService() {
return service;
}
public void setService(String service) {
this.service = service;
}
public String getMethod() {
return method;
}
public void setMethod(String method) {
this.method = method;
}
public String getExplain() {
return explain;
}
public void setExplain(String explain) {
this.explain = explain;
}
public List<DubboDocParam> getParams() {
return params;
}
public void setParams(List<DubboDocParam> params) {
this.params = params;
}
}

View File

@@ -11,6 +11,7 @@ import java.util.List;
public class DubboInfo {
@JSONField(name = "interface")
private String interfaceX;
private DubboDocInfo docInfo;
private List<DubboNodeInfo> nodeList;
public static class DubboNodeInfo {
@@ -78,4 +79,11 @@ public class DubboInfo {
this.interfaceX = interfaceX;
}
public DubboDocInfo getDocInfo() {
return docInfo;
}
public void setDocInfo(DubboDocInfo docInfo) {
this.docInfo = docInfo;
}
}

View File

@@ -239,8 +239,6 @@ public class NacosDubboInfo {
private String category;
private String generic;
private String anyhost;
@JSONField(name = "bean.name")
private String _$BeanName0; // FIXME check this code
private String timestamp;
public String getSide() {
@@ -323,14 +321,6 @@ public class NacosDubboInfo {
this.anyhost = anyhost;
}
public String get_$BeanName0() {
return _$BeanName0;
}
public void set_$BeanName0(String _$BeanName0) {
this._$BeanName0 = _$BeanName0;
}
public String getTimestamp() {
return timestamp;
}

View File

@@ -33,6 +33,8 @@ public class ReferenceConfigHolder {
referenceConfig.setApplication(application);
referenceConfigMap.put(url, referenceConfig);
}
// 本项目没有dubbo里面申明的类快放弃时看源码发现可以设置generic返回一个GenericService对象通过$invoke去操作具体方法感觉又打开了一扇大门
// 本项目选择的不入侵的方式管理文档,所以文档里面就必须手动加参数,写文档那些了
return (GenericService) referenceConfig.get();
}

View File

@@ -0,0 +1,13 @@
package com.zyplayer.doc.dubbo.framework.constant;
/**
* 存储数据的KEY常量类
*
* @author 暮光:城中城
* @since 2018年8月21日
*/
public class StorageKeys {
// 所有文档地址
public static final String DUBBO_SERVICE_DOC = "dubbo-service-doc";
public static final String DUBBO_SERVICE_LIST = "dubbo-service-list";
}

View File

@@ -0,0 +1,47 @@
package com.zyplayer.doc.dubbo.framework.service;
import java.io.Serializable;
/**
* 数据类型
* @author 暮光:城中城
* @since 2018-11-27
*/
public class MgDubboStorage implements Serializable {
private static final long serialVersionUID = 1L;
private String key;
private String value;
public MgDubboStorage() {
}
public MgDubboStorage(String key, String value) {
this.key = key;
this.value = value;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public static long getSerialversionuid() {
return serialVersionUID;
}
}

View File

@@ -0,0 +1,48 @@
package com.zyplayer.doc.dubbo.framework.service;
import java.util.List;
/**
* 实现此类才能使用服务器端的存贮功能
* dubbo的文档需要手动写的比较重要所以重起一个存储service实现类尽量操作另外的库
* @author 暮光:城中城
* @since 2018年8月19日
*/
public interface MgDubboStorageService {
/**
* 获取存储的值
* @author 暮光:城中城
* @since 2018年8月19日
* @param key 参数
* @return 值
*/
String get(String key);
/**
* 模糊获取存储的值
* @author 暮光:城中城
* @since 2018年8月19日
* @param key 参数
* @param value 值
* @return 值
*/
List<MgDubboStorage> like(String key, String value);
/**
* 存储数据
* @author 暮光:城中城
* @since 2018年8月19日
* @param key 参数
* @param value 值
*/
void put(String key, String value);
/**
* 删除数据
* @author 暮光:城中城
* @since 2018年8月19日
* @param key 参数
*/
void remove(String key);
}

View File

@@ -1,4 +1,9 @@
一些地址:
http://127.0.0.1:8082/zyplayer-doc-manage/zyplayer-doc-dubbo/doc-dubbo/getList
http://127.0.0.1.56:8848/nacos/index.html
zookeeper 格式:
路劲ls /dubbo/com.zyplayer.dubbo.service.UserService/providers
格式:

View File

@@ -0,0 +1,112 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html lang="en">
<head>
<meta charset="UTF-8">
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
<title>dubbo文档管理系统</title>
<link rel="shortcut icon" href="webjars/doc-dubbo/img/api.ico"/>
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
</head>
<body>
<div id="app">
<el-container style="height: 100%;">
<el-aside width="200px" style="height: 100%;">
<el-radio-group v-model="isCollapse" style="margin-bottom: 20px;">
<el-radio-button :label="false">展开</el-radio-button>
<el-radio-button :label="true">收起</el-radio-button>
</el-radio-group>
<el-menu default-active="1-4-1" class="el-menu-vertical-demo" @open="handleOpen" @close="handleClose" :collapse="isCollapse">
<el-submenu index="1">
<template slot="title">
<i class="el-icon-location"></i>
<span slot="title">导航一</span>
</template>
<el-menu-item-group>
<span slot="title">分组一</span>
<el-menu-item index="1-1">选项1</el-menu-item>
<el-menu-item index="1-2">选项2</el-menu-item>
</el-menu-item-group>
<el-menu-item-group title="分组2">
<el-menu-item index="1-3">选项3</el-menu-item>
</el-menu-item-group>
<el-submenu index="1-4">
<span slot="title">选项4</span>
<el-menu-item index="1-4-1">选项1</el-menu-item>
</el-submenu>
</el-submenu>
<el-menu-item index="2">
<i class="el-icon-menu"></i>
<span slot="title">导航二</span>
</el-menu-item>
<el-menu-item index="3" disabled>
<i class="el-icon-document"></i>
<span slot="title">导航三</span>
</el-menu-item>
<el-menu-item index="4">
<i class="el-icon-setting"></i>
<span slot="title">导航四</span>
</el-menu-item>
</el-menu>
</el-aside>
<el-container>
<el-main>Main</el-main>
</el-container>
</el-container>
</div>
</body>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
<script>
new Vue({
el: '#app',
data() {
const item = {
date: '2016-05-02',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
};
return {
tableData: Array(20).fill(item)
}
}
});
</script>
<style>
.el-header, .el-footer {
background-color: #B3C0D1;
color: #333;
text-align: center;
line-height: 60px;
}
.el-aside {
background-color: #fff;
color: #333;
text-align: center;
}
.el-main {
background-color: #E9EEF3;
color: #333;
text-align: center;
line-height: 160px;
}
.el-menu {
box-sizing: border-box;
}
body > .el-container {
margin-bottom: 40px;
}
.el-menu-vertical-demo:not(.el-menu--collapse) {
width: 200px;
}
html,body {
margin: 0;
padding: 0;
}
</style>
</html>

View File

@@ -0,0 +1,91 @@
<!doctype html>
<html xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>调试数据管理</title>
<link rel="stylesheet" type="text/css" href="../doc-dubbo/zui/css/zui.min.css">
</head>
<body>
<div id="app">
<div class="title-info">
<div class="alert alert-primary">
<div class="content">Tips每次点击在线调试的发送请求后都会默认保存一次请求的form、header、body数据以备下次使用在此页面可以管理这些数据</div>
</div>
</div>
<table class="table table-bordered" id="onlineDebugParamTable">
<thead>
<tr><th>接口地址</th><th>参数配置</th><th>操作</th></tr>
</thead>
<tbody>
<tr v-for="(item,index) in debugDataList" :key="item.id" :data-id="item.id" :data-index="index" >
<td>{{item.key}}</td>
<td>{{item.value}}</td>
<td>
<button class="btn btn-danger" type="button" v-on:click="deleteDebugData($event)">删除</button>
</td>
</tr>
<tr>
<td colspan="3" align="center">
<button class="btn" type="button" v-on:click="btnRefreshList"> 刷新 </button>
</td>
</tr>
</tbody>
</table>
</div>
</body>
<script src="../mg-ui/js/jquery-3.1.0.min.js"></script>
<script src="../doc-dubbo/zui/js/zui.min.js"></script>
<script src="../mg-ui/js/common.js"></script>
<script src="../mg-ui/js/mg-ui-cache-keys.js"></script>
<script src="../doc-dubbo/vue/vue.js"></script>
<script src="../mg-ui/js/toast.js"></script>
<script>
var urlBase = "../../";
var app = new Vue({
el: '#app',
data: {
debugDataList: [],
},
mounted: function(){
this.refreshList();
},
methods: {
btnRefreshList: function(){
this.refreshList();
Toast.success("刷新成功!");
},
deleteDebugData: function(event){
var tr = $(event.currentTarget).parents("tr");
var index = tr.data("index");
var delKey = app.debugDataList[index].key;
var newDebugList = [];
for(var i=0;i<app.debugDataList.length;i++){
if(i != index) {
newDebugList.push(app.debugDataList[i]);
}
}
deleteStorage(delKey, function(data){
app.debugDataList = newDebugList;
Toast.success("删除成功!");
});
},
refreshList: function () {
getStorageLike(cacheKeys.pRequestObjStart, function(data){
// console.log(data);
app.debugDataList = data;
});
}
}
});
</script>
<style>
#app{padding-top: 10px;}
</style>
</html>

View File

@@ -0,0 +1,177 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>文档展示配置</title>
<link rel="stylesheet" type="text/css" href="../doc-dubbo/zui/css/zui.min.css">
</head>
<body>
<div id="app">
<table class="table table-bordered setting-table">
<thead>
<tr>
<td style="width: 150px;">参数名</td>
<td style="width: 300px;">参数值</td>
<td>说明</td>
</tr>
</thead>
<tbody>
<tr>
<td class="info">目录展示方式</td>
<td>
<label><input type="radio" name="catalogShowType" value="1" v-model="catalogShowType">分路径展示</label>
<label><input type="radio" name="catalogShowType" value="2" v-model="catalogShowType">分标签展示</label>
</td>
<td>分路径:/api/data/getDataList 分标签:/api└/data└/getDateList└post└get</td>
</tr>
<tr>
<td class="info">树形菜单展示方式</td>
<td>
<label><input type="radio" name="treeShowType" value="1" v-model="treeShowType">直角</label>
<label><input type="radio" name="treeShowType" value="2" v-model="treeShowType">导航</label>
<label><input type="radio" name="treeShowType" value="3" v-model="treeShowType">加减</label>
<label><input type="radio" name="treeShowType" value="4" v-model="treeShowType">文件夹</label>
<label><input type="radio" name="treeShowType" value="5" v-model="treeShowType">V型</label>
</td>
<td>请自行修改体验</td>
</tr>
<tr>
<td class="info">是否展示字段的类型</td>
<td>
<label><input type="radio" name="showParamType" value="1" v-model="showParamType"></label>
<label><input type="radio" name="showParamType" value="0" v-model="showParamType"></label>
</td>
<td>文档中是否展示类型:"reference": "(boolean)"</td>
</tr>
<tr>
<td class="info">仅使用上次请求参数</td>
<td>
<label><input type="radio" name="onlyUseLastParam" value="1" v-model="onlyUseLastParam"></label>
<label><input type="radio" name="onlyUseLastParam" value="0" v-model="onlyUseLastParam"></label>
</td>
<td>每个接口都使用最后一次请求的header、form、body参数参数列表有但上一次请求没有使用的则不会展示在请求参数里面从未请求过则展示所有参数</td>
</tr>
<tr>
<td class="info">自动填充请求参数</td>
<td>
<label><input type="radio" name="autoFillParam" value="1" v-model="autoFillParam">智能填充</label>
<label><input type="radio" name="autoFillParam" value="2" v-model="autoFillParam">全部填充</label>
<label><input type="radio" name="autoFillParam" value="0" v-model="autoFillParam"></label>
</td>
<td>不填充智能填充只填充flag、time等后缀的参数全部填充对应不上类型的使用“我是默认字符串”填充</td>
</tr>
<tr>
<td class="info">强制重写域名</td>
<td>
<label><input type="radio" name="forceRewriteDomain" value="1" v-model="forceRewriteDomain"></label>
<label><input type="radio" name="forceRewriteDomain" value="0" v-model="forceRewriteDomain"></label>
</td>
<td>文档在本地,想调试线上接口就可以勾选此参数,“在线调试”处的请求地址强制改为:“文档地址管理”处配置的重写域名+接口地址</td>
</tr>
</tbody>
</table>
</div>
</body>
<script src="../mg-ui/js/jquery-3.1.0.min.js"></script>
<script src="../doc-dubbo/zui/js/zui.min.js"></script>
<script src="../mg-ui/js/common.js"></script>
<script src="../mg-ui/js/mg-ui-cache-keys.js"></script>
<script src="../doc-dubbo/vue/vue.js"></script>
<script>
var urlBase = "../../";
var app = new Vue({
el: '#app',
data: {
initCount: 6,
catalogShowType: '',
treeShowType: '',
showParamType:'',
onlyUseLastParam: '',
autoFillParam: '',
forceRewriteDomain: '',
rewriteDomainUrl: '',
userSettings: {},
// 默认用户的配置对象
defaultUserSettings: {
autoFillParam : 0,// 自动填充参数0=否 1=智能填充 2=全部填充
onlyUseLastParam : 0,// 是否仅使用上次请求参数
showParamType : 1,// 是否展示字段的类型
catalogShowType : 2,// 目录的展示方式1=url分成一层一层的展示、2=整个url显示为一层展示
treeShowType : 1,// 树形菜单展示方式1=tree-angles、2=tree-menu、3=默认4=tree-folders、5=tree-chevrons
forceRewriteDomain: 0,// 强制重写域名 0=否 1=是
projects : [],// 所有的项目列表
removedProjects : [],// 被移除的项目列表
prevWNow : 360
}
},
methods: {
},
mounted: function(){
getStorage(cacheKeys.userSettings, function(data){
var empty = isEmpty(data) || isEmptyObject(data);
data = empty ? app.defaultUserSettings : data;
app.userSettings = data;
app.catalogShowType = data.catalogShowType;
app.treeShowType = data.treeShowType;
app.showParamType = data.showParamType;
app.onlyUseLastParam = data.onlyUseLastParam;
app.autoFillParam = data.autoFillParam;
app.forceRewriteDomain = data.forceRewriteDomain;
});
},
watch: {
catalogShowType: function(newVal, oldval){
app.userSettings.catalogShowType = newVal;
storeUserSettings(function(){
getExport().regeneratePathTree();
});
},
treeShowType: function(newVal, oldval){
app.userSettings.treeShowType = newVal;
storeUserSettings(function(){
getExport().updateTreeShowType();
});
},
showParamType: function(newVal, oldval){
app.userSettings.showParamType = newVal;
storeUserSettings();
},
onlyUseLastParam: function(newVal, oldval){
app.userSettings.onlyUseLastParam = newVal;
storeUserSettings();
},
autoFillParam: function(newVal, oldval){
app.userSettings.autoFillParam = newVal;
storeUserSettings();
},
forceRewriteDomain: function(newVal, oldval){
app.userSettings.forceRewriteDomain = newVal;
storeUserSettings();
},
}
});
// 存储用户的配置信息
function storeUserSettings(success) {
if (app.initCount-- <= 0) {
setStorage(cacheKeys.userSettings, app.userSettings, function () {
getExport().updateUserSettings(app.userSettings);
if(typeof success == "function") {
success();
}
});
}
}
</script>
<style>
#app{padding-top: 10px;}
</style>
</html>

View File

@@ -0,0 +1,179 @@
<!doctype html>
<html xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>文档地址管理</title>
<link rel="stylesheet" type="text/css" href="../doc-dubbo/zui/css/zui.min.css">
</head>
<body>
<div id="app">
<table class="table table-bordered setting-table">
<thead>
<tr>
<td style="width: 50px;">序号</td>
<td>地址</td>
<td>重写域名地址</td>
<td>持久化时间</td>
<td>操作</td>
</tr>
</thead>
<tbody>
<tr v-for="(item,index) in swaggerResourcesList" :key="item.id" :data-id="item.id" :data-index="index" >
<td>{{index+1}}</td>
<td>{{item.url}}</td>
<td>{{item.rewriteDomainUrl}}</td>
<td>{{item.lastSync}}</td>
<td>
<button class="btn btn-danger" type="button" v-on:click="deleteDocUrl($event)">删除</button>
<button class="btn btn-info" type="button" v-on:click="editDocUrl($event)">编辑</button>
<!--<button class="btn btn-danger" type="button" v-on:click="syncDocData($event)">持久化</button>-->
</td>
</tr>
<tr>
<td colspan="5" align="center">
<button class="btn" type="button" v-on:click="btnRefreshList"> 刷新 </button>
<button class="btn btn-info" type="button" v-on:click="exportDocument">导出文档</button>
<button class="btn btn-primary" type="button" v-on:click="addNewDocument">增加文档</button>
</td>
</tr>
</tbody>
</table>
<!-- 增加文档弹出框 -->
<div class="modal fade" id="addNewDocumentModal">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">
<span aria-hidden="true">×</span><span class="sr-only">关闭</span>
</button>
<h4 class="modal-title">输入文档地址</h4>
</div>
<div class="modal-body">
<div class="input-line">
地址:
<input v-model="addNewDocumentInput" type="text" class="form-control" placeholder="例http://127.0.0.1/swagger-resources 或 http://127.0.0.1/v2/api-docs">
</div>
<div class="input-line">
重写域名地址:
<input v-model="rewriteDomainUrl" type="text" name="rewriteDomainUrl" class="form-control" placeholder="文档展示配置页 勾选“重写域名”重写的地址">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" v-on:click="addNewDocumentBtn">保存</button>
</div>
</div>
</div>
</div>
</div>
</body>
<script src="../mg-ui/js/jquery-3.1.0.min.js"></script>
<script src="../doc-dubbo/zui/js/zui.min.js"></script>
<script src="../mg-ui/js/common.js"></script>
<script src="../mg-ui/js/mg-ui-cache-keys.js"></script>
<script src="../doc-dubbo/vue/vue.js"></script>
<script src="../mg-ui/js/toast.js"></script>
<script>
var urlBase = "../../";
var app = new Vue({
el: '#app',
data: {
swaggerResourcesList: [],
addNewDocumentInput: '',
rewriteDomainUrl: '',
oldUrl: ''
},
methods: {
btnRefreshList: function(){
this.refreshList();
Toast.success("刷新成功!");
},
refreshList: function(){
getStorage(cacheKeys.swaggerResourcesList, function(data){
//console.log(data);
app.swaggerResourcesList = data;
});
},
editDocUrl: function(event){
var tr = $(event.currentTarget).parents("tr");
var index = tr.data("index");
var item = app.swaggerResourcesList[index];
app.oldUrl = item.url;
app.addNewDocumentInput = item.url;
app.rewriteDomainUrl = item.rewriteDomainUrl;
$('#addNewDocumentModal').modal({moveable:true});
},
addNewDocument: function(){
app.oldUrl = '';
app.addNewDocumentInput = '';
$('#addNewDocumentModal').modal({moveable:true});
},
addNewDocumentBtn: function(){
var addNewDocumentInput = app.addNewDocumentInput;
if(isEmpty(addNewDocumentInput)) {
Toast.error("地址不可以为空");return;
}
var param = {
resourcesUrl: addNewDocumentInput,
rewriteDomainUrl: app.rewriteDomainUrl,
oldUrl: app.oldUrl
};
ajaxTemp(urlBase + "swagger-mg-ui/document/addSwaggerResources", "post", "json", param, function(json){
if(validateResult(json)) {
//window.parent.document.location.reload();
//app.swaggerResourcesList.push(addNewDocumentInput);
app.refreshList();
$('#addNewDocumentModal').modal('hide');
Toast.success("保存成功,刷新后生效!");
}
});
},
exportDocument: function(){
getExport().exportDocument();
},
deleteDocUrl: function(event){
if(!confirm("确定要删除吗?")) {
return;
}
var tr = $(event.currentTarget).parents("tr");
var index = tr.data("index");
var newDocList = [];
for(var i=0;i<app.swaggerResourcesList.length;i++){
if(i != index) {
newDocList.push(app.swaggerResourcesList[i]);
}
}
setStorage(cacheKeys.swaggerResourcesList, newDocList, function(){
app.swaggerResourcesList = newDocList;
});
},
syncDocData: function(event){
var tr = $(event.currentTarget).parents("tr");
var index = tr.data("index");
var newDocUrl = app.swaggerResourcesList[index].url;
ajaxTemp(urlBase + "swagger-mg-ui/document/syncDocData", "post", "json", {resourcesUrl: newDocUrl}, function(json){
if(validateResult(json)) {
app.refreshList();
Toast.success("持久化成功!");
}
});
}
},
mounted: function(){
this.refreshList();
},
watch: {
}
});
</script>
<style>
#app{padding-top: 10px;}
.input-line{margin-bottom: 15px;}
</style>
</html>

View File

@@ -0,0 +1,211 @@
<!doctype html>
<html xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>详细地址管理</title>
<link rel="stylesheet" type="text/css" href="../doc-dubbo/zui/css/zui.min.css">
</head>
<body>
<div id="app">
<div class="alert alert-primary">
<div class="content">Tips开放文档地址 可以不需要登录即可访问,重写域名地址 填写后需开启:文档展示配置->强制重写域名 后才生效</div>
</div>
<table class="table table-bordered setting-table">
<thead>
<tr>
<td style="width: 50px;">序号</td>
<td>地址</td>
<td>开放文档地址</td>
<td>重写域名地址</td>
<td>操作</td>
</tr>
</thead>
<tbody>
<tr v-for="(item,index) in swaggerLocationList" :key="item.id" :data-id="item.id" :data-index="index" >
<td>{{index+1}}</td>
<td>{{item.location}}</td>
<td>
<!--未开放时即使访问这个地址也看不了-->
<a v-if="item.openVisit == 1" :href="'../../open-doc.html?doc='+item.uuid" target="_blank">{{item.uuid}}</a>
<span v-else>暂未开放</span>
</td>
<td>{{item.rewriteDomainUrl}}</td>
<td>
<button class="btn btn-danger" type="button" @click="deleteDocUrl(item.location)">删除</button>
<button class="btn btn-info" type="button" v-on:click="editDocUrl($event)">编辑</button>
<!--<button class="btn btn-danger" type="button" v-on:click="syncDocData($event)">持久化</button>-->
</td>
</tr>
<tr>
<td colspan="5" align="center">
<button class="btn" type="button" v-on:click="btnRefreshList"> 刷新 </button>
<button class="btn btn-primary" type="button" v-on:click="addNewDocument">增加文档</button>
</td>
</tr>
</tbody>
</table>
<!-- 增加文档弹出框 -->
<div class="modal fade" id="addNewDocumentModal">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">
<span aria-hidden="true">×</span><span class="sr-only">关闭</span>
</button>
<h4 class="modal-title">输入文档地址</h4>
</div>
<div class="modal-body">
<div class="input-line">
地址:
<input v-model="addNewDocumentInput" type="text" class="form-control" placeholder="例http://127.0.0.1/swagger-resources 或 http://127.0.0.1/v2/api-docs">
</div>
<div class="input-line">
重写域名地址:
<input v-model="rewriteDomainUrl" type="text" name="rewriteDomainUrl" class="form-control" placeholder="文档展示配置页 勾选“重写域名”重写的地址">
</div>
<div class="input-line">
<div class="switch switch-inline">
<input type="checkbox" v-model="openVisit">
<label>是否开启开放文档</label>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" v-on:click="addNewDocumentBtn">保存</button>
</div>
</div>
</div>
</div>
</div>
</body>
<script src="../mg-ui/js/jquery-3.1.0.min.js"></script>
<script src="../doc-dubbo/zui/js/zui.min.js"></script>
<script src="../mg-ui/js/common.js"></script>
<script src="../mg-ui/js/mg-ui-cache-keys.js"></script>
<script src="../doc-dubbo/vue/vue.js"></script>
<script src="../mg-ui/js/toast.js"></script>
<script>
var urlBase = "../../";
var app = new Vue({
el: '#app',
data: {
swaggerLocationList: [],
addNewDocumentInput: '',
rewriteDomainUrl: '',
openVisit: '',
oldLocation: ''
},
methods: {
btnRefreshList: function(){
this.refreshList();
Toast.success("刷新成功!");
},
refreshList: function () {
getStorage(cacheKeys.swaggerLocationList, function (data) {
//console.log(data);
var swaggerLocationList = data;
for (var i = 0; i < swaggerLocationList.length; i++) {
swaggerLocationList[i].location = decodeURI(swaggerLocationList[i].location);
}
app.swaggerLocationList = swaggerLocationList;
});
},
editDocUrl: function (event) {
var tr = $(event.currentTarget).parents("tr");
var index = tr.data("index");
var item = app.swaggerLocationList[index];
app.oldLocation = item.location;
app.addNewDocumentInput = item.location;
app.rewriteDomainUrl = item.rewriteDomainUrl;
app.openVisit = (item.openVisit == 1);
$('#addNewDocumentModal').modal({moveable: true});
},
addNewDocument: function(){
app.openVisit = false;
app.oldLocation = '';
app.addNewDocumentInput = '';
$('#addNewDocumentModal').modal({moveable:true});
},
addNewDocumentBtn: function(){
var addNewDocumentInput = app.addNewDocumentInput;
if(isEmpty(addNewDocumentInput)) {
Toast.error("地址不可以为空");return;
}
var param = {
openVisit: app.openVisit ? 1 : 0,
resourcesUrl: addNewDocumentInput,
rewriteDomainUrl: app.rewriteDomainUrl,
oldUrl: app.oldLocation
};
ajaxTemp(urlBase + "swagger-mg-ui/document/addSwaggerResources", "post", "json", param, function(json){
if(validateResult(json)) {
//window.parent.document.location.reload();
//app.swaggerLocationList.push(addNewDocumentInput);
app.refreshList();
$('#addNewDocumentModal').modal('hide');
Toast.success("保存成功,刷新后生效!");
}
});
},
deleteDocUrl: function (location) {
if (!confirm("确定要删除吗?")) {
return;
}
ajaxTemp(urlBase + "swagger-mg-ui/document/deleteSwaggerDoc", "post", "json", {location: location}, function (json) {
if (validateResult(json)) {
app.refreshList();
}
});
},
syncDocData: function (event) {
var tr = $(event.currentTarget).parents("tr");
var index = tr.data("index");
var newDocUrl = app.swaggerLocationList[index].location;
ajaxTemp(urlBase + "swagger-mg-ui/document/syncDocData", "post", "json", {resourcesUrl: newDocUrl}, function (json) {
if (validateResult(json)) {
app.refreshList();
Toast.success("持久化成功!");
}
});
},
encodeUrlParam: function(resourcesUrl) {
var indexOf = resourcesUrl.indexOf("?");
if (indexOf < 0) {
return resourcesUrl;
}
var baseUrl = resourcesUrl.substring(0, indexOf + 1);
var paramArr = resourcesUrl.substring(indexOf + 1).split("&");
for (var i = 0; i < paramArr.length; i++) {
var param = paramArr[i];
var split = param.split("=");
if (i > 0) {
baseUrl.append("&");
}
if (split.length === 2) {
baseUrl += split[0] + "=" + encodeURI(split[1]);
} else {
baseUrl += param;
}
}
return baseUrl.toString();
}
},
mounted: function(){
this.refreshList();
},
watch: {
}
});
</script>
<style>
#app{padding-top: 10px;}
.input-line{margin-bottom: 15px;}
</style>
</html>

View File

@@ -0,0 +1,138 @@
<!doctype html>
<html xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>测试</title>
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
</head>
<body>
<div id="app">
<el-button @click="visible = true">Button</el-button>
<el-dialog :visible.sync="visible" title="Hello world" close-on-click-modal show-close>
<p>Try Element</p>
</el-dialog>
<!-- Table -->
<el-button type="text" @click="dialogTableVisible = true">打开嵌套表格的 Dialog</el-button>
<el-dialog title="收货地址" :visible.sync="dialogTableVisible">
<el-table :data="gridData">
<el-table-column property="date" label="日期" width="150"></el-table-column>
<el-table-column property="name" label="姓名" width="200"></el-table-column>
<el-table-column property="address" label="地址"></el-table-column>
</el-table>
</el-dialog>
<!-- Form -->
<el-button type="text" @click="dialogFormVisible = true">打开嵌套表单的 Dialog</el-button>
<el-dialog title="收货地址" :visible.sync="dialogFormVisible">
<el-form :model="form">
<el-form-item label="活动名称" :label-width="formLabelWidth">
<el-input v-model="form.name" autocomplete="off"></el-input>
</el-form-item>
<el-form-item label="活动区域" :label-width="formLabelWidth">
<el-select v-model="form.region" placeholder="请选择活动区域">
<el-option label="区域一" value="shanghai"></el-option>
<el-option label="区域二" value="beijing"></el-option>
</el-select>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">取 消</el-button>
<el-button type="primary" @click="dialogFormVisible = false">确 定</el-button>
</div>
</el-dialog>
<el-tooltip placement="top" >
<div slot="content">多行信息<br/>第二行信息</div>
<el-button>Top center</el-button>
</el-tooltip>
<el-row>
<el-button>默认按钮</el-button>
<el-button type="primary">主要按钮</el-button>
<el-button type="success">成功按钮</el-button>
<el-button type="info">信息按钮</el-button>
<el-button type="warning">警告按钮</el-button>
<el-button type="danger">危险按钮</el-button>
</el-row>
<el-row>
<el-button plain>朴素按钮</el-button>
<el-button type="primary" plain>主要按钮</el-button>
<el-button type="success" plain>成功按钮</el-button>
<el-button type="info" plain>信息按钮</el-button>
<el-button type="warning" plain>警告按钮</el-button>
<el-button type="danger" plain>危险按钮</el-button>
</el-row>
<el-row>
<el-button round>圆角按钮</el-button>
<el-button type="primary" round>主要按钮</el-button>
<el-button type="success" round>成功按钮</el-button>
<el-button type="info" round>信息按钮</el-button>
<el-button type="warning" round>警告按钮</el-button>
<el-button type="danger" round>危险按钮</el-button>
</el-row>
<el-row>
<el-button icon="el-icon-search" circle></el-button>
<el-button type="primary" icon="el-icon-edit" circle></el-button>
<el-button type="success" icon="el-icon-check" circle></el-button>
<el-button type="info" icon="el-icon-message" circle></el-button>
<el-button type="warning" icon="el-icon-star-off" circle></el-button>
<el-button type="danger" icon="el-icon-delete" circle></el-button>
</el-row>
</div>
</body>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
<script>
new Vue({
el: '#app',
data: function() {
return {
visible: false,
gridData: [{
date: '2016-05-02',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
}, {
date: '2016-05-04',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
}, {
date: '2016-05-01',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
}, {
date: '2016-05-03',
name: '王小虎',
address: '上海市普陀区金沙江路 1518 弄'
}],
dialogTableVisible: false,
dialogFormVisible: false,
form: {
name: '',
region: '',
date1: '',
date2: '',
delivery: false,
type: [],
resource: '',
desc: ''
},
formLabelWidth: '120px'
}
}
});
</script>
<style>
#app{padding-top: 10px;}
</style>
</html>

View File

@@ -0,0 +1,113 @@
<!doctype html>
<html xmlns:v-on="http://www.w3.org/1999/xhtml" xmlns:v-model="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>全局参数管理</title>
<link rel="stylesheet" type="text/css" href="../doc-dubbo/zui/css/zui.min.css">
</head>
<body>
<div id="app">
<div class="alert alert-primary">
<div class="content">Tips所有接口的在线调试页面都将展示本页面配置的参数和值可统一配置会话等数据</div>
</div>
<table class="table table-bordered setting-table">
<thead>
<tr>
<td>参数位置</td>
<td>参数名</td>
<td>参数值</td>
<td>操作</td>
</tr>
</thead>
<tbody>
<tr v-for="(item,index) in globalParamList" :key="item.id" :data-id="item.id" :data-index="index">
<td>
<select class="form-control" v-model:value="item.paramIn">
<option value="header">header</option>
<option value="form">form</option>
</select>
</td>
<td><input type="text" class="form-control" name="paramName" v-model:value="item.key" placeholder=""></td>
<td><input type="text" class="form-control" name="paramName" v-model:value="item.value" placeholder=""></td>
<td>
<button class="btn btn-danger" type="button" v-on:click="deleteParam($event)">删除</button>
</td>
</tr>
<tr>
<td colspan="3" align="center">
<button class="btn" type="button" v-on:click="btnRefreshList"> 刷新 </button>
<button class="btn btn-success" type="button" v-on:click="addGlobalParamLine()"> 新增 </button>
<button class="btn btn-info" type="button" v-on:click="saveAllGlobalParam">全部保存</button>
</td>
</tr>
</tbody>
</table>
</div>
</body>
<script src="../mg-ui/js/jquery-3.1.0.min.js"></script>
<script src="../doc-dubbo/zui/js/zui.min.js"></script>
<script src="../mg-ui/js/common.js"></script>
<script src="../mg-ui/js/mg-ui-cache-keys.js"></script>
<script src="../doc-dubbo/vue/vue.js"></script>
<script src="../mg-ui/js/toast.js"></script>
<script>
var urlBase = "../../";
var app = new Vue({
el: '#app',
data: {
globalParamList: []
},
methods: {
btnRefreshList: function () {
this.refreshList();
Toast.success("刷新成功!");
},
deleteParam: function (event) {
if (!confirm("确定要删除吗?")) {
return;
}
var tr = $(event.currentTarget).parents("tr");
var index = tr.data("index");
var newParamList = [];
for (var i = 0; i < app.globalParamList.length; i++) {
if (i != index) {
newParamList.push(app.globalParamList[i]);
}
}
app.globalParamList = newParamList;
},
addGlobalParamLine: function () {
app.globalParamList.push({
paramIn: 'header', key: '', value: ''
});
},
saveAllGlobalParam: function () {
setStorage(cacheKeys.globalParamList, app.globalParamList, function(){
getExport().updateGlobalParam(app.globalParamList);
Toast.success("保存成功!");
});
},
refreshList: function(){
getStorage(cacheKeys.globalParamList, function(data){
app.globalParamList = data || [];
});
},
},
mounted: function () {
this.refreshList();
}
});
</script>
<style>
#app {
padding-top: 10px;
}
</style>
</html>

View File

@@ -0,0 +1,144 @@
body{width: 100%;height: 100%;margin: 0;padding: 0;}
a:focus{outline:none;}
ul{list-style: none;list-style-type: none;}
.tree li a{white-space: nowrap;}
.tree-menu li > ul{background-color: #f1f1f1;}
.tree-menu li li li li a{padding-left: 68px;}
.tree-menu li li li li li a{padding-left: 88px;}
.tree-menu li li li li li li a{padding-left: 108px;}
.tree-menu li li li li li li li a{padding-left: 128px;}
.tree-menu li li li li li li li li a{padding-left: 148px;}
.tree-menu li li li li li li li li li a{padding-left: 168px;}
.tree-menu li li li li li li li li li li a{padding-left: 188px;}
.table td, .table th {vertical-align: middle;}
.dropdown-menu>li>a{max-width: 100%;overflow: hidden;white-space: nowrap;text-overflow: ellipsis;}
#tabDocInfo{position: absolute; bottom: 0;top: 60px;overflow-y: auto; right: 0; left: 10px;}
#tabOnlineDebug .param-response-box{position: absolute; bottom: 0;top: 100px;overflow-y: auto; right: 0; left: 10px;padding-right: 10px;}
#tabOnlineDebug .panel{margin-bottom: 10px;}
#requestParamForm .nav > li > a{padding: 6px 15px;}
.local-storage{display: none;}
.choice-location-list{margin-bottom: 10px; width: 100%;}
.choice-location-list .btn.dropdown-toggle{width: 100%; text-align: left;}
.choice-location-list .dropdown-menu{width: 100%;}
.choice-location-list .choice-text{max-width: calc(100% - 15px);overflow: hidden;float: left;white-space: nowrap;text-overflow: ellipsis;}
.choice-location-list .caret{float: right;margin-top: 8px;}
/**lable的覆盖样式*/
.label{font-size: 100%;}
.label-warning {background-color: #f9f5ee; color: #f1a325;}
label{font-weight: normal;}
.overwrite-label{margin-bottom: 0;}
.nav.gray{background-color: #f1f1f1;margin-bottom: 10px;}
.doc-table tr .info{text-align: right; width: 100px;}
.setting-table tr .info{text-align: right; max-width: 150px;}
.show-doc span{color: #aaa;}
.mgresizableW{z-index: 90;height: 100%; width: 10px; cursor: e-resize;}
.ui-resizable-handle {display: block;font-size: 0.1px;position: absolute;}
#resizableLeftRight{left: 360px;}
.unselect{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;}
#homePageDashboard{overflow-y: auto;bottom: 0;top: 0;right: 0;left: 0;position: absolute;overflow-x: hidden;padding: 10px;}
#homePageDashboard .panel-body{padding: 10px;}
.content.about{line-height: 30px;}
#homePageLi{margin-top: 5px;}
.left-body{
width: 360px; height:100%; position: fixed; top: 0; bottom: 0; left: 0;
}
.left-header{
background: linear-gradient(-90deg, #03DDE4 0%, #30AFED 51%, #8755FF 100%);width: 100%; height:60px;line-height:60px;
position: absolute; top: 0; bottom: 0; left: 0;text-align: center;
}
.left-header .logo{
font-size: 30px;color: #fff;
}
.left-header .icon-bars{
font-size: 24px;float: right;margin: 18px 18px 0 0;color: #fff;cursor: pointer;
}
.left-container{
width: 100%;position: absolute;background: #f1f1f1;color: rgba(163, 175, 183, .9);
top: 60px; bottom: 0; left: 0; overflow-y: auto; padding: 10px;
}
.left-container .projects{border: 0px; border-radius: 0px;}
.right-container{
position: fixed;top: 0px; bottom: 0; left: 360px; right: 0;padding: 10px;
}
#docResponseModel td:first-child{width: 100px;}
#docResponseExample td:first-child{width: 100px;}
.modal-table-box{margin-top: 10px; max-height: 500px;overflow-y: auto;}
.modal-table-box{list-style: none;}
.modal-table-box ul{padding-left: 10px;}
.modal-table-box li{padding: 10px 15px; margin: 0 10px 10px 0; background-color: #f1f1f1;cursor: pointer;}
.modal-table-box li.checked{background-color: #8666b8;color:#fff;}
#exportDocumentText{height: 350px;}
#rightContentMask{background-color: rgba(0, 0, 0, 0);padding: 0;z-index:9999; height: 100%;display: none;position: absolute;top: 0;bottom: 0;left:0;right: 0;}
#rightZpages{height: 100%;position: relative;top: 0;bottom: 0;left:0;right: 0;}
/* 在线调试框样式 */
#tabParamBody .tab-content{padding-top: 10px;}
.post-url-box{padding: 10px 0;}
.post-url-box .input-group-btn:nth-child(2) button{border-left: 0;border-right: 0;border-radius: 0;}
.post-url-box .send-request .hide{display: none;}
.param-box{}
.param-box .panel-collapse{padding: 10px 10px 0 10px;}
.param-box .nav{background-color: #f1f1f1;}
.param-box .table{margin-bottom: 0;}
/* .param-box .nav > li > *{padding: 8px 25px;} */
.param-box .nav > li > span{position: relative; display: block;background-color: #ccc;padding: 9px 25px;}
.param-box .nav > .form-to-url{position: relative; display: block;padding: 8px 0 0 25px;}
.param-box .nav > .form-to-url label{margin: 0;}
.param-box .nav > .form-to-url input{margin: 0;}
.param-box .tab-content .tab-param-pane{padding: 10px 10px 0 10px;}
.param-box .table.param-table td, .param-box .table.param-table th{padding: 4px 5px;}
.param-box .param-table tbody td:nth-child(4){border-right: 0;}
.param-box .param-table tbody td:nth-child(5){border-left: 0;padding: 0 10px 0 0;width: 10px;}
.param-box .param-table tbody td:nth-child(5) i{cursor: pointer;color: #ccc;}
.param-box .param-table tbody td:nth-child(5) i:hover{color: #888;}
.param-box .param-table tbody tr.base td:last-child i{display: none;}
#bulkEditHeaderCheck{margin: 0 0 0 10px;}
#bulkEditHeader,#bulkEditForm{display: none;}
.response-box{margin-top: 10px;}
.response-box .nav > li > *{padding: 8px 25px;}
.response-box .nav > li span{position: relative; display: block;padding: 9px 25px;}
.response-box .nav > li.info span{background-color: #ccc;}
.response-box .nav > li.right{float: right;}
.response-box .nav > li.right i{color: #3280fc;}
.response-box .nav{background-color: #f1f1f1;}
.response-box .tab-content .tab-response-pane{padding: 10px;}
#responseBodyJsonIframe{width: 100%;height: 300px;border: 0;}
/* S-模拟请求 */
#tabSimulationResult{padding: 0 10px 0 0;position: absolute; bottom: 0;top: 60px;overflow-y: auto; right: 0; left: 10px;}
/* E-模拟请求 */
/* S-JSON展示的样式 */
pre.json{margin-top:0px;margin-bottom:0px;}
pre.json .canvas{font:10pt georgia;background-color:#ececec;color:#000000;border:1px solid #cecece;}
pre.json .object-brace{color:#00aa00;font-weight:bold;}
pre.json .array-brace{color:#0033ff;font-weight:bold;}
pre.json .property-name{color:#cc0000;font-weight:bold;}
pre.json .string{color:#007777;}
pre.json .number{color:#aa00aa;}
pre.json .boolean{color:#0000ff;}
pre.json .function{color:#aa6633;text-decoration:italic;}
pre.json .null{color:#0000ff;}
pre.json .comma{color:#000000;font-weight:bold;}
pre.json .annotation{color:#aaa;}
pre img{cursor: pointer;}
/* E-JSON展示的样式 */

Binary file not shown.

After

Width:  |  Height:  |  Size: 340 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 331 B

View File

@@ -0,0 +1,398 @@
/**
* 一些公用方法
* @author 暮光:城中城
* @since 2017年5月7日
*/
function serialize(value) {
if (typeof value === 'string') {
return value;
}
return JSON.stringify(value);
}
function deserialize(value) {
if (typeof value !== 'string' || isEmpty(value)) {
return value;
}
try {
return JSON.parse(value);
} catch (e) {
try {
return eval('(' + value + ')');// 处理变态的单双引号共存字符串
} catch (e) {
return value || undefined;
}
}
}
function validateResult(result) {
if(result.errCode == 200) {
return true;
} else {
Toast.error(result.errMsg);
}
return false;
}
function getNowDate() {
var date = new Date();
var month = date.getMonth() + 1;
var strDate = date.getDate();
if (month >= 1 && month <= 9) {
month = "0" + month;
}
if (strDate >= 0 && strDate <= 9) {
strDate = "0" + strDate;
}
var currentdate = date.getFullYear() + "-" + month + "-" + strDate;
return currentdate;
}
function getNowTime() {
var date = new Date();
var hours = date.getHours();
var minutes = date.getMinutes();
var seconds = date.getSeconds();
if (hours >= 1 && hours <= 9) {
hours = "0" + hours;
}
if (minutes >= 0 && minutes <= 9) {
minutes = "0" + minutes;
}
if (seconds >= 0 && seconds <= 9) {
seconds = "0" + seconds;
}
var currentdate = hours + ":" + minutes + ":" + seconds;
return currentdate;
}
function getNowDateTime() {
var currentdate = getNowDate() + " " + getNowTime();
return currentdate;
}
/**
* 返回不为空的字符串为空返回def
*/
function getNotEmptyStr(str, def) {
if (isEmpty(str)) {
return isEmpty(def) ? "" : def;
}
return str;
}
/**
* 是否是空对象
* @param obj
* @returns
*/
function isEmptyObject(obj){
return isEmpty(obj) || $.isEmptyObject(obj);
}
/**
* 是否是空字符串
* @param str
* @returns
*/
function isEmpty(str){
return (str == "" || str == null || str == undefined);
}
/**
* 是否不是空字符串
* @param str
* @returns
*/
function isNotEmpty(str){
return !isEmpty(str);
}
/**
* 数组转字符串,使用空格分隔
* @param array
* @returns
*/
function arrToString(array){
var temStr = "";
if(isEmpty(array)){
return temStr;
}
array.forEach(function(e){
if(isNotEmpty(temStr)) {
temStr += " ";
}
temStr += e;
});
return temStr;
}
/**
* 数组array中是否包含str字符串
* @param array
* @param str
* @returns
*/
function haveString(array, str){
if(isEmpty(array)) {
return false;
}
for (var i = 0; i < array.length; i++) {
if(array[i] == str) {
return true;
}
}
return false;
}
/**
* 直接返回对象的第一个属性
* @param data
* @returns
*/
function getObjectFirstAttribute(data) {
for ( var key in data) {
return data[key];
}
}
/**
* 如果对象只有一个属性则返回第一个属性否则返回null
* @param data
* @returns
*/
function getObjectFirstAttributeIfOnly(data) {
var len = 0, value = "";
for ( var key in data) {
if (++len > 1) {
return null;
}
value = data[key];
}
return value;
}
/**
* ajax处理事件模板
*
* @url 后台处理的url即action
* @dataSentType 数据发送的方式有postget方式
* @dataReceiveType 数据接收格式有html json text等
* @paramsStr 传入后台的参数
* @successFunction ajax成功后执行的函数名 ajaxTemp("", "GET", "html", {}, function(){},
* function(){}, "");
*/
function ajaxTemp(url, dataSentType, dataReceiveType, paramsStr, successFunction, errorFunction, completeFunction, id) {
$.ajax({
url : url, // 后台处理程序
sync : false,
type : dataSentType, // 数据发送方式
dataType : dataReceiveType, // 接受数据格式
data : eval(paramsStr),
contentType : "application/x-www-form-urlencoded; charset=UTF-8",
success : function(msg) {
if(typeof successFunction == "function") {
successFunction(msg,id);
}
},
beforeSend : function() {
},
complete : function(msg) {
if(typeof completeFunction == "function") {
completeFunction(msg,id);
}
},
error : function(msg) {
if(typeof errorFunction == "function") {
errorFunction(msg,id);
}
}
});
}
function postWithFile(url, paramsStr, successFunction, errorFunction, completeFunction, id) {
$.ajax({
url: url, // 后台处理程序
sync: false,
type: "POST", // 数据发送方式
dataType: "JSON", // 接受数据格式
data: eval(paramsStr),
processData: false,
contentType: false,
success: function (msg) {
if (typeof successFunction == "function") {
successFunction(msg, id);
}
},
beforeSend: function () {
},
complete: function (msg) {
if (typeof completeFunction == "function") {
completeFunction(msg, id);
}
},
error: function (msg) {
if (typeof errorFunction == "function") {
errorFunction(msg, id);
}
}
});
}
/**
* 获取cookie
* @param name
* @returns
*/
function getCookie(name) {
var arr,reg=new RegExp("(^| )"+name+"=([^;]*)(;|$)");
if(arr=document.cookie.match(reg)){
return unescape(arr[2]);
}
return null;
}
/**
* 字符串格式化
*/
String.prototype.format = function(args) {
if (arguments.length > 0) {
var result = this;
if (arguments.length == 1 && typeof (args) == "object") {
for ( var key in args) {
var reg = new RegExp("({" + key + "})", "g");
result = result.replace(reg, args[key]);
}
} else {
for (var i = 0; i < arguments.length; i++) {
if (arguments[i] == undefined) {
return "";
} else {
var reg = new RegExp("({[" + i + "]})", "g");
result = result.replace(reg, arguments[i]);
}
}
}
return result;
} else {
return this;
}
}
String.prototype.endWith = function(str) {
if (str == null || str == "" || this.length == 0 || str.length > this.length) {
return false;
}
return (this.substring(this.length - str.length) == str);
};
String.prototype.startWith = function(str) {
if (str == null || str == "" || this.length == 0 || str.length > this.length) {
return false;
}
return (this.substr(0, str.length) == str);
};
/**
* 获取数据,异步的操作
*/
function getStorageLike(key, success, fail) {
var start = (typeof urlBase === 'string') ? urlBase : '';
ajaxTemp(start + "swagger-mg-ui/storage/like", "post", "json", {key: key}, function(json){
if(json.errCode == 200) {
if(typeof success == "function") {
var result = deserialize(json.data);
success(result);
}
} else {
if(typeof fail == "function") {
fail();
}
}
}, function(msg){
if(typeof fail == "function") {
fail();
}
});
}
/**
* 获取数据,异步的操作
*/
function getStorage(key, success, fail) {
var start = (typeof urlBase === 'string') ? urlBase : '';
ajaxTemp(start + "swagger-mg-ui/storage/data", "get", "json", {key: key}, function(json){
if(json.errCode == 200) {
if(typeof success == "function") {
var result = deserialize(json.data);
success(result);
}
} else {
if(typeof fail == "function") {
fail();
}
}
}, function(msg){
if(typeof fail == "function") {
fail();
}
});
}
/**
* 存储数据,异步的操作
*/
function setStorage(key, value, success, fail) {
value = $.zui.store.serialize(value);
var start = (typeof urlBase === 'string') ? urlBase : '';
ajaxTemp(start + "swagger-mg-ui/storage/data", "post", "json", {key: key, value: value}, function(json){
if(json.errCode == 200) {
if(typeof success == "function") {
success();
}
} else {
if(typeof fail == "function") {
fail(getNotEmptyStr(json.errMsg));
}
}
}, function(msg){
if(typeof fail == "function") {
fail("");
}
console.log("存储数据到服务器失败,请检查");
});
}
/**
* 删除数据
*/
function deleteStorage(key, success, fail) {
var start = (typeof urlBase === 'string') ? urlBase : '';
ajaxTemp(start + "swagger-mg-ui/storage/delete", "post", "json", {key: key}, function(json){
if(json.errCode == 200) {
if(typeof success == "function") {
success();
}
} else {
if(typeof fail == "function") {
fail(getNotEmptyStr(json.errMsg));
}
}
}, function(msg){
if(typeof fail == "function") {
fail("");
}
console.log("存储数据到服务器失败,请检查");
});
}
/**
* 获取父窗口的exports
* @returns
*/
function getExport(){
return window.parent.window.exports;
}

View File

@@ -0,0 +1,424 @@
/**
* zyplayer-doc-swagger是swagger的一个前端实现使用简单、解析速度快、走心的设计
* 支持多项目同时展示,多种文档目录的展示方案,多种自定义配置,满足各种使用习惯。
* 使用中您有任何的意见和建议都可到源码地址处反馈哦!
* git地址https://gitee.com/zyplayer/zyplayer-doc
* @author 暮光:城中城
* @since 2018年5月20日
*/
// 树的下表
var projectTreeIdIndex = 1;
// 依据目录树存储的map全局对象
var treePathDataMap = new Map();
// dubbo列表
var dubboDocList = [];
/**
* 网页加载完毕后的处理
*/
$(document).ready(function(){
globalLoadingMessager = new $.zui.Messager({type: 'primary', close: false, time: 0}).show();
showGlobalLoadingMessage('获取文档列表中,请稍候...', true);
ajaxTemp("zyplayer-doc-dubbo/doc-dubbo/getDocList", "get", "json", {}, function (json) {
if (validateResult(json) && json.data.length >= 1) {
dubboDocList = json.data;
createTreeViewByTree(json.data);
initDashboard();
documentLoadFinish();
}
});
// 定义配置的标签页
var tabsArr = [
{id: 'docShowConfig', url: 'webjars/doc-dubbo-pages/docShowConfig.html', type: 'iframe', icon: 'icon-cog', forbidClose: true}
];
$('#rightZpages').tabs({tabs: tabsArr});
rightContentTabs = $('#rightZpages').data('zui.tabs');
});
/**
* 增加文档-通过服务器接口
* @returns
*/
function addDocumentByService(choiceDocList) {
// 获取原始的swagger的json对象
showGlobalLoadingMessage('通过服务器端获取文档中,请稍候...', true);
ajaxTemp("swagger-mg-ui/document/docs", "post", "json", {choiceDocList: choiceDocList}, function(json){
//console.log(json);
showGlobalLoadingMessage('文档获取成功,解析中,请稍候...', true);
if(isEmptyObject(json) || json.errCode !== 200) {
Toast.error("获取文档错误,请检查!");
return;
}
for (var i = 0; i < json.data.length; i++) {
showGlobalLoadingMessage('解析第'+(i+1)+'份文档,请稍候...', true);
var tempDoc = deserialize(json.data[i]);
console.log(tempDoc);
documentJsonArr.push(tempDoc);// 加到所有文档
addHomePageDashboard(tempDoc, tempDoc.fullUrl);
createDefinitionsMapByJson(tempDoc);
if(userSettings.catalogShowType == 1) {
createTreeViewByTree(tempDoc);// url分成一层一层的展示
} else if(userSettings.catalogShowType == 2){
createTreeViewByTag(tempDoc);// tag方式整个url显示为一层
} else {
createTreeViewByTree(tempDoc);// url分成一层一层的展示
}
}
documentLoadFinish();
}, function(msg){
Toast.error("获取文档失败,请检查!");
});
}
/**
* 增加文档-通过服务器接口
* @returns
*/
function addDocumentByLocationService(choiceDocList) {
// 获取原始的swagger的json对象
globalLoadingMessager.show();
showGlobalLoadingMessage('通过服务器端获取文档中,请稍候...', true);
ajaxTemp("swagger-mg-ui/document/docs", "post", "json", {choiceLocationList: choiceDocList}, function(json){
//console.log(json);
showGlobalLoadingMessage('文档获取成功,解析中,请稍候...', true);
if(isEmptyObject(json) || json.errCode !== 200) {
Toast.error("获取文档错误,请检查!");
return;
}
documentJsonArr = [];
initDashboard();
for (var i = 0; i < json.data.length; i++) {
showGlobalLoadingMessage('解析第' + (i + 1) + '份文档,请稍候...', true);
var tempDoc = deserialize(json.data[i]);
console.log(tempDoc);
documentJsonArr.push(tempDoc);// 加到所有文档
addHomePageDashboard(tempDoc, tempDoc.fullUrl);
createDefinitionsMapByJson(tempDoc);
if (userSettings.catalogShowType == 1) {
createTreeViewByTree(tempDoc);// url分成一层一层的展示
} else if (userSettings.catalogShowType == 2) {
createTreeViewByTag(tempDoc);// tag方式整个url显示为一层
} else {
createTreeViewByTree(tempDoc);// url分成一层一层的展示
}
}
documentLoadFinish();
}, function(msg){
Toast.error("获取文档失败,请检查!");
});
}
/**
* 自由拖动改变左右框架的宽度
*/
$("#resizableLeftRight").mgResizableWidth({
prev:"#leftContent",
prevWtMin: 120, prevWtMax: 999999,
nextWtMin: 360, nextWtMax: 999999,
onresize:function(prevWNow, nextWNow){
changeContentWidth(prevWNow);
},
onstart:function(){
$("body").addClass("unselect");
$("#rightContentMask").show();
},
onfinish:function(){
$("body").removeClass("unselect");
$("#rightContentMask").hide();
storeUserSettings();
}
});
/**
* 切换导航栏的宽度到最小或最大
*/
$("#changeContentWidth").click(function(){
var isMinWidth = ($("#leftContent").width() == 120);
changeContentWidth(isMinWidth ? 360 : 120);
});
/**
* 切换文档
*/
$("#choiceLocationList").on("click", ".dropdown-menu li", function(){
var text = $(this).find("a").text();
var location = $(this).find("a").data("location");
$("#choiceLocationList .choice-text").text(text);
// 切换文档
addDocumentByLocationService(location);
});
/**
* 搜索框回车事件
*/
$("#searchDocInput").keyup(function(e) {
if (e.keyCode == 13) {
searchDoc();
}
});
/**
* 搜索按钮点击
*/
$("#searchDocBt").click(function(){
searchDoc();
});
/**
* 切换选中和非选中样式
*/
$(".choise").on("click", "li", function(){
$(this).toggleClass("checked");
});
/**
* 页面导航切换
*/
$("#tabZpagesNavigationUl").on("click", ".page-nav", function(){
var id = $(this).data("id");
var href = $(this).data("href");
var icon = $(this).data("icon");
var reload = $(this).data("reload");
$(".tab-page").hide();
$(".tab-online-debug-page").hide();
$(".tab-zpages").show();
if(reload || $("#tab-"+id).length <= 0) {
var newTab = {id: id, url: href, type: 'iframe', icon: icon};
rightContentTabs.open(newTab);
} else {
$("#tab-nav-item-"+id+" .tab-nav-link").click();
}
});
/**
* 主页li点击事件展示主页
*/
$("#homePageLi").click(function(){
$(".tab-page,.tab-zpages").hide();
$(".tab-home-page").show();
});
/**
* api文档最后的节点点击展示文档页面
*/
$("#apiPathTree").on("click", ".show-doc", function(){
$(".tab-page").hide();
$(".tab-document").show();
var path = $(this).attr("path");
var method = $(this).attr("method");
var data = treePathDataMap.get(path);
var docInfo = "";//isNotEmpty(data.docInfo) ? getNotEmptyStr(data.docInfo.explain) : "";
var docUrl = getNotEmptyStr(data.interface);
$("#postUrlInput").val(data.interface + "#" + method + "()");
// 处理在线文档
$("#docUrl").text(docUrl);
$("#docRequestMethod").text(method);
$("#docInfo").text(docInfo);
$("#docConsumes").text(arrToString(data.consumes));
$("#docProduces").text(arrToString(data.produces));
$("#tabParamTypeBody textarea").val("");
// 遍历参数列表
$("#docRequestParam table tbody").empty();
$("#docRequestExample table tbody").empty();
requestParamObj = {};
Formatjson.annotationObject = {};
//addRequestParamObj(requestParamObj, "Content-Type", "string", "header", false, "", arrToString(data.consumes));
if(isNotEmpty(data.parameters)) {
Object.keys(data.parameters).forEach(function(key){
var tempParameters = data.parameters[key];
var htmlStr = "", htmlStrExample = "";
var required = tempParameters.required;
var paramName = getNotEmptyStr(tempParameters.name);
var paramType = getNotEmptyStr(tempParameters.type);
var paramDesc = getNotEmptyStr(tempParameters.description);
var paramIn = getNotEmptyStr(tempParameters.in);
var example = getNotEmptyStr(tempParameters.example, tempParameters.default);
$("#docRequestParam table tbody").append(
'<tr>'
+'<td>' + htmlStr + '</td>'
+'<td>' + paramDesc + '</td>'
+'<td>' + paramType + '</td>'
+'<td>' + paramIn + '</td>'
+'<td>' + required + '</td>'
+'</tr>'
);
});
}
// console.log(requestParamObj);
// var htmlStrTemp = Formatjson.processObjectToHtmlPre(requestParamObj, 0, false, false, false);
// $("#htmlStrTemp").html(htmlStrTemp);
$("#htmlStrTemp").parents("tr").hide();
//createOnlineDebugRequestParam(requestParamObj, getNotEmptyStr(data.url));
// 遍历结果集列表
$("#docResponseModel table tbody").empty();
$("#docResponseExample table tbody").empty();
Formatjson.annotationObject = {};
});
/**
* 搜索文档
* @returns
*/
function searchDoc() {
var keywords = $("#searchDocInput").val();
// 重新生成
regeneratePathTree(keywords);
if (isEmpty(keywords)){
return;
}
$('#apiPathTree .projects').tree('expand');
}
/**
* 重新生成文档
*/
function regeneratePathTree(keywords){
projectTreeIdIndex = 1;
treePathDataMap = new Map();
$('#apiPathTree').empty();
$('#apiPathTree').append('<ul class="tree tree-lines projects"></ul>');
createTreeViewByTree(dubboDocList, keywords);// url分成一层一层的展示
$('#apiPathTree .projects').tree();
updateTreeShowType();
}
function findInPathsValue(pathsValue, keywords) {
if (isEmpty(keywords)) {
return true;
}
keywords = keywords.toLowerCase();
// 找路径和说明里面包含关键字的
var interface = pathsValue.interface;
if (isNotEmpty(interface) && interface.toLowerCase().indexOf(keywords) >= 0) {
return true;
}
return false;
}
/**
* 修改左右框架的宽度
* @param width 左侧导航栏的宽度
* @returns
*/
function changeContentWidth(width) {
$("#leftContent").css("width", width + 'px');
$("#resizableLeftRight").css("left", width + 'px');
$("#rightContent").css("left", width + 'px');
var logoText = "zyplayer-doc-dubbo";
if(width < 370 && width > 290){
logoText = "zyplayer-doc";
} else if(width < 290){
logoText = "doc";
}
$("#logoText").text(logoText);
userSettings.prevWNow = width;
}
/**
* 增加项目文档
* @param json
* @returns
*/
function addHomePageDashboard(json, fullUrl) {
var info = json.info||{};
var contactName = "";
if(isNotEmpty(info.contact)) {
contactName = "昵称:" + getNotEmptyStr(info.contact.name, "-");
contactName += "<br/>邮箱:" + getNotEmptyStr(info.contact.email, "-");
contactName += "<br/>网站:" + getNotEmptyStr(info.contact.url, "-");
}
$("#homePageDashboard section").append(
'<div class="col-md-6 col-sm-6">'
+'<div class="panel" data-id="'+fullUrl+'">'
+'<div class="panel-heading">'
+'<div class="title">'+info.title+'</div>'
+'<div class="panel-actions">'
+'</div>'
+'</div>'
+'<div class="panel-body">'
+'<div class="content">'
+'<table class="table table-bordered setting-table">'
+'<tr>'
+'<td class="info">简介</td>'
+'<td>'+info.description+'</td>'
+'</tr>'
+'<tr>'
+'<td class="info">作者</td>'
+'<td>'+contactName+'</td>'
+'</tr>'
+'<tr>'
+'<td class="info">版本</td>'
+'<td>'+info.version+'</td>'
+'</tr>'
+'<tr>'
+'<td class="info">地址</td>'
+'<td>'+decodeURI(fullUrl)+'</td>'
+'</tr>'
+'</table>'
+'</div>'
+'</div>'
+'</div>'
+'</div>'
);
}
/**
* 修改树形菜单展示类型
* @param
* @returns
*/
function updateTreeShowType() {
return;
$('#apiPathTree .projects').removeClass("tree-angles tree-menu tree-folders tree-chevrons");
//tree-angles、2=tree-menu、3=默认4=tree-folders、5=tree-chevrons
$('#apiPathTree .projects').addClass("tree-lines");
var treeShowType = "tree-angles";
if(userSettings.treeShowType == 1) {
treeShowType = "tree-angles";
} else if(userSettings.treeShowType == 2) {
treeShowType = "tree-menu";
$('#apiPathTree .projects').removeClass("tree-lines");
} else if(userSettings.treeShowType == 3) {
treeShowType = "";
} else if(userSettings.treeShowType == 4) {
treeShowType = "tree-folders";
} else if(userSettings.treeShowType == 5) {
treeShowType = "tree-chevrons";
} else {
userSettings.treeShowType = 1;
}
if(isNotEmpty(treeShowType)) {
$('#apiPathTree .projects').addClass(treeShowType);
}
}
/**
* 初始化用户的设置
* @param
* @returns
*/
function documentLoadFinish() {
showGlobalLoadingMessage('文档解析完成!', false);
// 隐藏提示框
setTimeout(function() {
globalLoadingMessager.hide();
}, 1000);
regeneratePathTree();
//$('#apiPathTree .projects').tree();
$('#homePageDashboard .dashboard').dashboard({draggable: false});
}
function showGlobalLoadingMessage(text, loading) {
if(loading) {
text += '<i class="icon icon-spin icon-spinner-snake hide"></i>';
}
globalLoadingMessager.$.find(".messager-content").html(text);
}
function initDashboard(){
var template = $('#homePageDashboardTemplate').html();
$('#homePageDashboard').empty();
$('#homePageDashboard').append('<div class="dashboard" data-height="320"></div>');
$('#homePageDashboard .dashboard').append(template);
}

View File

@@ -0,0 +1,125 @@
/**
* 将对象处理成json格式化和着色的html
* @author 暮光:城中城
* @since 2017年5月7日
*/
var Formatjson = {
// 需要在对象或列表后面添加注释的对象,例:{userList: "用户列表"}
// 那么在名字为userList的对象或列表后面都会加上“用户列表” 这个注释
annotationObject: {},
tabStr: " ",
isArray: function(obj) {
return obj && typeof obj === 'object' && typeof obj.length === 'number'
&& !(obj.propertyIsEnumerable('length'));
},
processObjectToHtmlPre: function(obj, indent, addComma, isArray, isPropertyContent, showAnnotation) {
var htmlStr = this.processObject(obj, "", indent, addComma, isArray, isPropertyContent, showAnnotation);
htmlStr = '<pre class="json">' + htmlStr + '</pre>';
return htmlStr;
},
processObject: function(obj, keyName, indent, addComma, isArray, isPropertyContent, showAnnotation) {
var html = "";
var comma = (addComma) ? "<span class='comma'>,</span> " : "";
var type = typeof obj;
if (this.isArray(obj)) {
if (obj.length == 0) {
html += this.getRow(indent, "<span class='array-brace'>[ ]</span>" + comma, isPropertyContent);
} else {
var clpsHtml = '<span><img class="option-img" src="webjars/doc-dubbo/img/expanded.png" onClick="Formatjson.expImgClicked(this);" /></span><span class="collapsible">';
var annotation = '';
if(showAnnotation && isNotEmpty(keyName) && isNotEmpty(this.annotationObject[keyName])) {
annotation = '<span class="annotation">// '+this.annotationObject[keyName]+'</span>';
}
html += this.getRow(indent, "<span class='array-brace'>[</span>"+clpsHtml+annotation, isPropertyContent);
for (var i = 0; i < obj.length; i++) {
html += this.processObject(obj[i], "", indent + 1, i < (obj.length - 1), true, false, showAnnotation);
}
clpsHtml = "</span>";
html += this.getRow(indent, clpsHtml + "<span class='array-brace'>]</span>" + comma);
}
} else if (type == 'object' && obj == null) {
html += this.formatLiteral("null", "", comma, indent, isArray, "null");
} else if (type == 'object') {
var numProps = 0;
for ( var prop in obj) {
numProps++;
}
if (numProps == 0) {
html += this.getRow(indent, "<span class='object-brace'>{ }</span>" + comma, isPropertyContent);
} else {
var clpsHtml = '<span><img class="option-img" src="webjars/doc-dubbo/img/expanded.png" onClick="Formatjson.expImgClicked(this);" /></span><span class="collapsible">';
var annotation = '';
if(showAnnotation && isNotEmpty(keyName) && isNotEmpty(this.annotationObject[keyName])) {
annotation = '<span class="annotation">// '+this.annotationObject[keyName]+'</span>';
}
html += this.getRow(indent, "<span class='object-brace'>{</span>"+clpsHtml+annotation, isPropertyContent);
var j = 0;
for ( var prop in obj) {
var processStr = '<span class="property-name">"' + prop + '"</span>: ' + this.processObject(obj[prop], prop, indent + 1, ++j < numProps, false, true, showAnnotation);
html += this.getRow(indent + 1, processStr);
}
clpsHtml = "</span>";
html += this.getRow(indent, clpsHtml + "<span class='object-brace'>}</span>" + comma);
}
} else if (type == 'number') {
html += this.formatLiteral(obj, "", comma, indent, isArray, "number");
} else if (type == 'boolean') {
html += this.formatLiteral(obj, "", comma, indent, isArray, "boolean");
} else if (type == 'function') {
obj = this.formatFunction(indent, obj);
html += this.formatLiteral(obj, "", comma, indent, isArray, "function");
} else if (type == 'undefined') {
html += this.formatLiteral("undefined", "", comma, indent, isArray, "null");
} else {
html += this.formatLiteral(obj, "\"", comma, indent, isArray, "string");
}
return html;
},
expImgClicked: function(img){
var container = img.parentNode.nextSibling;
if(!container) return;
var disp = "none";
var src = "webjars/doc-dubbo/img/collapsed.png";
if(container.style.display == "none"){
disp = "inline";
src = "webjars/doc-dubbo/img/expanded.png";
}
container.style.display = disp;
img.src = src;
},
formatLiteral: function(literal, quote, comma, indent, isArray, style) {
if (typeof literal == 'string') {
literal = literal.split("<").join("&lt;").split(">").join("&gt;");
}
var str = "<span class='" + style + "'>" + quote + literal + quote + comma + "</span>";
if (isArray) {
str = this.getRow(indent, str);
}
return str;
},
formatFunction: function(indent, obj) {
var tabs = "";
for (var i = 0; i < indent; i++) {
tabs += this.tabStr;
}
var funcStrArray = obj.toString().split("\n");
var str = "";
for (var i = 0; i < funcStrArray.length; i++) {
str += ((i == 0) ? "" : tabs) + funcStrArray[i] + "\n";
}
return str;
},
getRow: function(indent, data, isPropertyContent) {
var tabs = "";
for (var i = 0; i < indent && !isPropertyContent; i++) {
tabs += this.tabStr;
}
if (data != null && data.length > 0 && data.charAt(data.length - 1) != "\n") {
data = data + "\n";
}
return tabs + data;
}
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,11 @@
/**
* 页面中所有使用到的缓存key必须定义在这里
*/
var cacheKeys = {
userSettings: 'userSettings',
swaggerResourcesList: 'swagger-resources-list',
swaggerLocationList: 'swagger-location-list',
globalParamList: 'zyplayer-doc-global-param-list',
pRequestObjStart: 'p-request-obj-',
pSimulationResponse: 'p-simulation-response',
}

View File

@@ -0,0 +1,648 @@
/**
* 在线调试页面js
* @author 暮光:城中城
* @since 2018年7月20日
*/
$(document).ready(function(){
$("#debugRequstType .dropdown-menu li").click(function(){
var text = $(this).find("a").text();
$("#debugRequstType .options").text(text);
});
/**
* 保存参数模板
* @returns
*/
$(".save-request-template").click(function(){
Toast.notOpen();
});
/**
* 发送请求
* @returns
*/
$(".send-request").click(function(){
// 多行编辑状态下转成表单,下面读取表单内容
if ($("#bulkEditFormCheck").prop('checked')) {
var bulkEdit = $("#bulkEditForm").val();
bulkEditToTable("#tabParamTypeForm", bulkEdit);
}
if ($("#bulkEditHeaderCheck").prop('checked')) {
var bulkEdit = $("#bulkEditHeader").val();
bulkEditToTable("#tabParamHeader", bulkEdit);
}
$("#tabResponseHeader table tbody").empty();
$("#tabResponseCookie table tbody").empty();
$("#responseBodyTextArea").val("");
$("#responseBodyJsonDiv").html("暂无数据");
var storeRequestParam = {};
var docUrl = $("#docUrl").text();
var options = $("#debugRequstType .btn .options").text();
var postUrl = $("#postUrlInput").val();
var requestHeaderForm = $("#requestHeaderForm").serializeArray();
var requestParamForm = $("#requestParamForm").serializeArray();
var paramHeaderSend = {};
var paramFormSend = {};
var paramBodySend = $("[name=paramBody]").val();
var formToUrl = $("[name=formToUrl]").prop('checked') ? 1 : 0;
// 组装空的表单对象
var formDataToServer = new FormData();
requestHeaderForm = serializeArrayToObj(requestHeaderForm);
requestParamForm = serializeArrayToObj(requestParamForm);
storeRequestParam.formToUrl = formToUrl;
formDataToServer.append("formToUrl", formToUrl);
if (isNotEmpty(paramBodySend)) {
try {
paramBodySend = JSON.stringify(JSON.parse(paramBodySend));
} catch (e) {}
storeRequestParam.body = paramBodySend;
formDataToServer.append("body", paramBodySend);
// 替换path参数
Object.keys(requestParamForm).forEach(function (key) {
postUrl = postUrl.replace("{" + key + "}", requestParamForm[key]);
});
}
var reqParamStr = "";
Object.keys(requestParamForm).forEach(function (key) {
var value = requestParamForm[key];
if (isNotEmpty(key) && isNotEmpty(value)) {
if (isNotEmpty(reqParamStr)) {
reqParamStr += "&";
}
reqParamStr += key + "=" + value;
paramFormSend[key] = value;
// 替换path参数
postUrl = postUrl.replace("{" + key + "}", value);
}
});
storeRequestParam.form = paramFormSend;
// 显示加载中图标
$(".send-request .icon").removeClass("hide");
// 获取header
Object.keys(requestHeaderForm).forEach(function(key){
var value = requestHeaderForm[key];
if(isNotEmpty(key) && isNotEmpty(value)) {
paramHeaderSend[key] = value;
}
});
storeRequestParam.header = paramHeaderSend;
//console.log(paramBodySend);
var beforeSendTime = new Date().getTime();
// 拼装文件
var fileInput = $('#requestParamForm').find(".file-input");
for (var i = 0; i < fileInput.length; i++) {
var fileName = $(fileInput[i]).parents("tr").find("[name=paramName]").val();
for (var j = 0; j < fileInput[i].files.length; j++) {
formDataToServer.append('files', fileInput[i].files[j]);
formDataToServer.append('fileNames', fileName);
}
paramFormSend[fileName] = "-";
}
formDataToServer.append("header", JSON.stringify(paramHeaderSend));
formDataToServer.append("url", postUrl);
formDataToServer.append("method", options);
// 表单参数是否拼在url上
if(formToUrl == 1) {
postUrl += "?" + reqParamStr;
paramFormSend = "";
} else {
formDataToServer.append("form", JSON.stringify(paramFormSend));
}
// debugger;
// 模拟请求开始
postWithFile("swagger-mg-ui/http/request", formDataToServer, function(result){
if (!validateResult(result)) {
return;
}
var afterSendTime = new Date().getTime();
//console.log(result);
var requestObj = result.data;
setStorage(cacheKeys.pRequestObjStart + docUrl, storeRequestParam);
$("#httpRequestStatus").text(requestObj.status);
$("#httpRequestTime").text((afterSendTime - beforeSendTime) + "ms");
try {
var htmlStr = Formatjson.processObjectToHtmlPre(JSON.parse(requestObj.data), 0, false, false, false, false);
$("#responseBodyJsonDiv").html(htmlStr);
} catch (e) {
// 转json失败应该是个页面输出到iframe里不能影响当前页面
$("#responseBodyJsonDiv").html("<iframe id='responseBodyJsonIframe'></iframe>");
setTimeout(function () {
$("#responseBodyJsonIframe").contents().find("body").html(requestObj.data);
}, 300);
}
$("#tabResponseHeader table tbody").empty();
$("#tabResponseCookie table tbody").empty();
var headers = requestObj.header || [];
for (var i = 0; i < headers.length; i++) {
var name = getNotEmptyStr(headers[i].name);
var value = getNotEmptyStr(headers[i].value);
$("#tabResponseHeader table tbody").append(
'<tr>' + '<td>' + name + '</td>' + '<td>' + value + '</td>' + '</tr>'
);
}
var cookies = requestObj.cookie || [];
for (var i = 0; i < cookies.length; i++) {
var name = getNotEmptyStr(cookies[i].name);
var value = getNotEmptyStr(cookies[i].value);
$("#tabResponseCookie table tbody").append(
'<tr>' + '<td>' + name + '</td>' + '<td>' + value + '</td>' + '</tr>'
);
}
}, function () {
Toast.error("请求失败!");
}, function () {
$(".send-request .icon").addClass("hide");
});
});
/**
* 输入框输入之后,如果是最后一行则在增加一行
* @returns
*/
$(".param-table").on("keyup", "input[name=paramName]", function(){
var nextTr = $(this).parents("tr").next();
if(nextTr.length <= 0) {
$(this).parents(".param-table").append(getParamTableTr());
}
});
/**
* 参数删除一行
* @returns
*/
$(".param-table").on("click", ".icon-times", function(){
$(this).parents("tr").remove();
});
/**
* 在线调试管理
*/
$("#onlineDebugLi").click(function(){
$(".tab-page,.tab-zpages").hide();
$(".tab-online-debug-page").show();
createOnlineDebugParamTable();
});
/**
* 在线调试管理-刷新
*/
$(".tab-online-debug-page .refresh").click(function(){
createOnlineDebugParamTable();
});
/**
* 在线调试管理-展开所有
*/
$(".tab-online-debug-page .expand-all").click(function(){
$("#onlineDebugParamTable .option-img").attr("src", "webjars/doc-dubbo/img/expanded.png");
$("#onlineDebugParamTable .option-img").parent().next().show();
});
/**
* 在线调试管理-收起所有
*/
$(".tab-online-debug-page .collapse-all").click(function(){
$("#onlineDebugParamTable .option-img").attr("src", "webjars/doc-dubbo/img/collapsed.png");
$("#onlineDebugParamTable .option-img").parent().next().hide();
});
/**
* 在线调试-删除所有参数
*/
$(".tab-online-debug-page").on("click", ".del-all-param", function(){
$.zui.store.forEach(function(key, value) {// 遍历所有本地存储的条目
if(!key.startWith(cacheKeys.pRequestObjStart)) {
return;
}
$.zui.store.remove(key);
});
createOnlineDebugParamTable();
});
/**
* 在线调试-删除参数
*/
$(".tab-online-debug-page").on("click", ".del-param", function(){
var key = $(this).attr("key");
if(isNotEmpty(key)) {
$.zui.store.remove(key);
$(this).parents("tr").remove();
}
});
/**
* 提交模拟返回值
*/
$("#simulationResultSubmit").click(function(){
var value = $("#simulationResultText").val();
value = getNotEmptyStr(value, "");
var docUrl = $("#simulationResultUrl").text();
setStorage(cacheKeys.pSimulationResponse + docUrl, value, function() {
Toast.warn("提交成功!");
}, function(msg) {
Toast.error("提交失败!" + msg);
});
});
/**
* 获取模拟返回值
*/
$("#simulationResultGet").click(function(){
var docUrl = $("#simulationResultUrl").text();
getStorage(cacheKeys.pSimulationResponse + docUrl, function(data){
$("#simulationResultText").val(data);
});
});
});
/**
* 生成在线调试管理页面
* @returns
*/
function createOnlineDebugParamTable() {
$("#onlineDebugParamTable tbody").empty();
$.zui.store.forEach(function(key, value) {// 遍历所有本地存储的条目
if(!key.startWith(cacheKeys.pRequestObjStart)) {
return;
}
var newKey = key.substring(14, key.length);
var htmlStr = Formatjson.processObjectToHtmlPre(value, 0, false, false, false, false);
$("#onlineDebugParamTable tbody").append(
'<tr>'
+'<td>'+newKey+'</td>'
+'<td>'+htmlStr+'</td>'
+'<td><button class="btn btn-danger del-param" type="button" key="'+key+'">删除</button></td>'
+'</tr>'
);
});
}
/**
* 生成在线调试相关数据
* @param requestParamObj
* @returns
*/
function createOnlineDebugRequestParam(requestParamObj, url) {
// 查询之前的调试参数信息
getStorage(cacheKeys.pRequestObjStart + url, function(data) {
createOnlineDebugRequestParamFun(data, requestParamObj, url);
});
}
/**
* 生成在线调试相关数据
* @param oldRequestObj 之前的调试参数
* @param requestParamObj 参数列表的参数
* @param url 请求url
* @returns
*/
function createOnlineDebugRequestParamFun(oldRequestObj, requestParamObj, url) {
if(isEmptyObject(oldRequestObj)) {
oldRequestObj = {};
}
// 清空参数列表
$("#tabParamHeader table tbody .new").remove();
$("#tabParamTypeForm table tbody .new").remove();
$("#tabResponseHeader table tbody").empty();
$("#tabResponseCookie table tbody").empty();
$("#tabParamHeader .form-control").val("");
$("#tabParamTypeForm .form-control").val("");
$("#responseBodyTextArea").val("");
$("#responseBodyJsonDiv").html("暂无数据");
$("#bulkEditHeaderCheck").prop("checked", false);
$("#bulkEditFormCheck").prop("checked", false);
$("#bulkEditHeader,#bulkEditForm").hide();
$("#tabParamTypeForm table").show();
$("#requestHeaderForm table").show();
$("#tabParamTypeForm table tbody .base input[name=paramValue]")
.attr("type", "text").removeClass("file-input")
.removeAttr("multiple").attr("placeholder", "").val("");
var options = $("#debugRequstType .btn .options").text();
var formToUrl = oldRequestObj.formToUrl || 0;
var formToUrlChecked = (options != "GET" && formToUrl == 1);
$("input[name='formToUrl']").prop("checked", formToUrlChecked);
var onlyUseLastParam = (userSettings.onlyUseLastParam == 1);
var onlyUseLastHeader = onlyUseLastParam && !isEmptyObject(oldRequestObj.header);
var onlyUseLastForm = onlyUseLastParam && !isEmptyObject(oldRequestObj.form);
var onlyUseLastBody = onlyUseLastParam && !isEmptyObject(oldRequestObj.body);
var headerValueCount = 0, formValueCount = 0;
if(typeof oldRequestObj != 'object') {
oldRequestObj = {};
}
if(typeof oldRequestObj.header != 'object') {
oldRequestObj.header = {};
}
if(typeof oldRequestObj.form != 'object') {
oldRequestObj.form = {};
}
for (var i = 0; i < debugGlobalParam.length; i++) {
var item = debugGlobalParam[i];
if (item.paramIn == 'header') {
oldRequestObj.header[item.key] = item.value;
} else if (item.paramIn == 'form') {
oldRequestObj.form[item.key] = item.value;
}
}
Object.keys(requestParamObj).forEach(function(key){
var tempParam = requestParamObj[key];
if (key == "p-body-obj") {
//console.log(tempParam);
var paramObj = onlyUseLastBody ? {} : getParamBodyTransObj(tempParam);
var bodyObj = oldRequestObj.body;
try {
bodyObj = JSON.parse(bodyObj);
if(!isEmptyObject(bodyObj)) {
paramObj = $.extend(true, paramObj, bodyObj);
}
$("#tabParamTypeBody textarea").val(JSON.stringify(paramObj, null, 4));
} catch (e) {
var tempText = isEmptyObject(bodyObj) ? JSON.stringify(paramObj, null, 4) : bodyObj;
$("#tabParamTypeBody textarea").val(tempText);
}
$("#tabParamBody .nav li").eq(1).find("a").click();
} else {
if (tempParam.paramIn == "header" && !onlyUseLastHeader) {
//console.log(tempParam);
var headerVal = getNotEmptyStr(tempParam.value);
var headerObj = oldRequestObj.header;
if(!isEmptyObject(headerObj) && isNotEmpty(headerObj[key])) {
headerVal = headerObj[key];
headerObj[key] = "";// 赋值为空,后面不再使用
}
if(isEmpty(headerVal)) {
headerVal = getAutoFillValue(tempParam.paramType, key);
}
if(headerValueCount > 0) {
$("#tabParamHeader table tbody").append(getParamTableTr(key, headerVal, "", tempParam.paramDesc));
} else {
$("#tabParamHeader table tbody .base input[name=paramName]").val(key);
$("#tabParamHeader table tbody .base input[name=paramValue]").val(headerVal);
$("#tabParamHeader table tbody .base input[name=paramValue]").attr("placeholder", getNotEmptyStr(tempParam.paramDesc));
}
headerValueCount++;
} else {
// 只有这几种类型,列出来后面看单独处理不
var paramInForm = (tempParam.paramIn == "query")
|| (tempParam.paramIn == "path")
|| (tempParam.paramIn == "body")
|| (tempParam.paramIn == "form")
|| (tempParam.paramIn == "formData")
|| isNotEmpty(tempParam.paramIn);
paramInForm = paramInForm && !onlyUseLastForm;
var formObj = oldRequestObj.form;
if (onlyUseLastForm && !isEmptyObject(formObj) && isNotEmpty(formObj[key])) {
paramInForm = onlyUseLastForm || true;
}
if (paramInForm) {
//console.log(tempParam);
var formVal = getNotEmptyStr(tempParam.value);
if(!isEmptyObject(formObj) && isNotEmpty(formObj[key])) {
formVal = formObj[key];
formObj[key] = "";// 赋值为空,后面不再使用
}
if(isEmpty(formVal)) {
formVal = getAutoFillValue(tempParam.paramType, key);
}
if(formValueCount > 0) {
$("#tabParamTypeForm table tbody").append(getParamTableTr(key, formVal, "", tempParam.paramDesc, tempParam.paramType));
} else {
// 文件的input特殊处理
if(tempParam.paramType == 'file'){
$("#tabParamTypeForm table tbody .base input[name=paramValue]")
.attr("type", "file").attr("multiple", "multiple")
.addClass("file-input");
} else {
$("#tabParamTypeForm table tbody .base input[name=paramValue]").val(formVal);
}
$("#tabParamTypeForm table tbody .base input[name=paramName]").val(key);
$("#tabParamTypeForm table tbody .base input[name=paramValue]").attr("placeholder", getNotEmptyStr(tempParam.paramDesc));
}
$("#tabParamBody .nav li").eq(0).find("a").click();
formValueCount++;
}
}
}
});
// 处理参数外的header
var headerObj = oldRequestObj.header;
if(!isEmptyObject(headerObj)) {
Object.keys(headerObj).forEach(function(key){
if(isNotEmpty(headerObj[key])) {
if(headerValueCount > 0) {
$("#tabParamHeader table tbody").append(getParamTableTr(key, headerObj[key], "", ""));
} else {
$("#tabParamHeader table tbody .base input[name=paramName]").val(key);
$("#tabParamHeader table tbody .base input[name=paramValue]").val(headerObj[key]);
}
headerValueCount++;
}
});
}
// 处理参数外的form
var formObj = oldRequestObj.form;
if(!isEmptyObject(formObj)) {
Object.keys(formObj).forEach(function(key){
if(isNotEmpty(formObj[key])) {
if(formValueCount > 0) {
$("#tabParamTypeForm table tbody").append(getParamTableTr(key, formObj[key], "", ""));
} else {
$("#tabParamTypeForm table tbody .base input[name=paramName]").val(key);
$("#tabParamTypeForm table tbody .base input[name=paramValue]").val(formObj[key]);
}
formValueCount++;
}
});
}
if(headerValueCount > 0) {
$("#tabParamHeader table tbody").append(getParamTableTr("", "", "", ""));
}
if(formValueCount > 0) {
$("#tabParamTypeForm table tbody").append(getParamTableTr("", "", "", ""));
}
}
/**
* 获取测试的对象
*/
function getParamBodyTransObj(paramObj) {
var newObject = $.extend(true, {}, paramObj);
Object.keys(newObject).forEach(function(key){
var subObj = newObject[key];
if(typeof subObj == 'object') {
if (subObj.hasOwnProperty("isParamObj")) {
var value = getNotEmptyStr(subObj.value);
if(isEmpty(value) && isNotEmpty(subObj.paramType)) {
value = getAutoFillValue(subObj.paramType, key);
}
newObject[key] = value;
} else if(subObj instanceof Array) {
subObj[0] = getParamBodyTransObj(subObj[0]);
} else {
newObject[key] = getParamBodyTransObj(subObj);
}
}
});
return newObject;
}
function serializeArrayToBulkEdit(formArr) {
var formObj = serializeArrayToObj(formArr);
var formStr = "";
Object.keys(formObj).forEach(function(key){
formStr += key + ":" + formObj[key] + "\n";
});
return formStr;
}
function serializeArrayToObj(formArr) {
var paramObj = {};
for (var i = 0; i < formArr.length; i++) {
if (formArr[i].name == "paramName" && i < formArr.length) {
var key = formArr[i].value;
var value = formArr[i + 1].value;
if (isNotEmpty(key) && formArr[i + 1].name != "paramName") {
paramObj[key] = value;
}
}
}
return paramObj;
}
function bulkEditToTable(tableId, bulkEdit) {
$(tableId + " table tbody .new").remove();
var valueCount = 0;
var headerArr = bulkEdit.split("\n");
for (var i = 0; i < headerArr.length; i++) {
var index = headerArr[i].indexOf(":");
if(index < 0) {
continue;
}
var key = headerArr[i].substring(0, index);
var value = headerArr[i].substring(index+1, headerArr[i].length);
if(valueCount > 0) {
$(tableId + " table tbody").append(getParamTableTr(key, value, "", ""));
} else {
$(tableId + " table tbody .base input[name=paramName]").val(key);
$(tableId + " table tbody .base input[name=paramValue]").val(value);
}
valueCount++;
}
if(valueCount > 0) {
$(tableId + " table tbody").append(getParamTableTr("", "", "", ""));
}
}
/**
* 获取参数的tr
* @param name
* @param value
* @param namePl
* @param valuePl
* @returns
*/
function getParamTableTr(name, value, namePl, valuePl, paramType) {
name = getNotEmptyStr(name);
namePl = getNotEmptyStr(namePl);
value = getNotEmptyStr(value);
valuePl = getNotEmptyStr(valuePl);
var regExp = new RegExp("\"", "gm");
name = (typeof name === 'string') ? name.replace(regExp, "&quot;") : name;
namePl = (typeof namePl === 'string') ? namePl.replace(regExp, "&quot;") : namePl;
value = (typeof value === 'string') ? value.replace(regExp, "&quot;") : value;
valuePl = (typeof valuePl === 'string') ? valuePl.replace(regExp, "&quot;") : valuePl;
var resultStr =
'<tr class="new">'
+'<td><input type="text" class="form-control" name="paramName" value="'+name+'" placeholder="'+namePl+'"></td>';
// 文件的input特殊处理
if(paramType == 'file') {
resultStr += '<td><input type="file" multiple class="form-control file-input" name="paramValue" placeholder="'+valuePl+'"></td>';
} else {
resultStr += '<td><input type="text" class="form-control" name="paramValue" value="'+value+'" placeholder="'+valuePl+'"></td>'
}
resultStr += '<td><i class="icon-times"></i></td>'
+'</tr>';
return resultStr;
}
/**
* 获取自动填充的值
* @param paramType
* @returns
*/
function getAutoFillValue(paramType, paramName) {
if(userSettings.autoFillParam == 0 || isEmpty(paramType)) {
return "";
}
paramName = getNotEmptyStr(paramName).toLowerCase();
var isTimeColumn = (paramType.indexOf("date-time") >= 0
|| paramName.endWith("date") || paramName.endWith("time"));
var isTypeColumn = (paramName.endWith("type") || paramName.endWith("status")
|| paramName.endWith("level") || paramName.endWith("num"));
var isPriceColumn = (paramName.endWith("money") || paramName.endWith("price")
|| paramName.endWith("cash") || paramName.endWith("coin"));
var isBooleanColumn = (paramName.startWith("is"));
var resultValue = "";
if(paramType.indexOf("int") >= 0){
if(isTypeColumn) {
resultValue = Math.ceil(Math.random() * 5);
} else if(paramName.endWith("age")) {
resultValue = Math.ceil(Math.random() * 100);
} else {
resultValue = Math.ceil(Math.random() * 100);
}
} else if(paramType.indexOf("double") >= 0){
resultValue = Math.ceil(Math.random() * 1000);
} else if(paramType.indexOf("float") >= 0){
resultValue = parseFloat(Math.random() * 1000).toFixed(2);
} else if(paramType.indexOf("byte") >= 0){
if(isTypeColumn) {
resultValue = Math.ceil(Math.random() * 5);
} else {
resultValue = Math.ceil(Math.random() * 127);
}
} else if(paramType.indexOf("boolean") >= 0){
resultValue = Math.random() > 0.5;
} else if(isTimeColumn){
resultValue = getNowDateTime();
} else {
if(paramName.endWith("id")) {
resultValue = Math.ceil(Math.random() * 1000);
} else if(paramName.endWith("age")) {
resultValue = Math.ceil(Math.random() * 100);
} else if(isPriceColumn){
resultValue = parseFloat(Math.random() * 1000).toFixed(2);
} else if(isTypeColumn){
resultValue = Math.ceil(Math.random() * 5);
} else if(isBooleanColumn){
resultValue = (Math.random() > 0.5) ? 0 : 1;
} else if(paramName.endWith("phone") || paramName.endWith("mobile")){
var arr = ["15226645814", "15226645815", "15226645816", "15226645817", "15226645818"];
resultValue = arr[Math.ceil(Math.random() * 5) - 1];
} else if(paramName.endWith("ids")){
var counts = Math.ceil(Math.random() * 5);
for (var i = 0; i < counts; i++) {
if(isNotEmpty(resultValue)){resultValue += ",";}
resultValue += Math.ceil(Math.random() * 1000);
}
} else if(paramName.endWith("types")){
var counts = Math.ceil(Math.random() * 3);
for (var i = 0; i < counts; i++) {
if(isNotEmpty(resultValue)){resultValue += ",";}
resultValue += Math.ceil(Math.random() * 5);
}
} else if(paramName.endWith("md5")){
resultValue = "5082079d92a8ef985f59e001d445ff20";
} else if(paramName.endWith("photo")){
resultValue = "http://www.zyplayer.com/freeplay/img/headIcon/myhead.jpg";
} else if(paramName.endWith("url") || paramName.endWith("uri")){
var arr = ["http://www.zyplayer.com", "http://www.kongjianzhou.com"];
resultValue = arr[Math.ceil(Math.random() * 2) - 1];
} else if(paramName.endWith("username")){
var arr = ["张三", "李四", "王二", "暮光:城中城", "海贼王"];
resultValue = arr[Math.ceil(Math.random() * 5) - 1];
} else if(userSettings.autoFillParam == 2){
//var arr = ["您好!","请!","对不起。","谢谢!","再见!","您早!","晚安!","请问您贵姓?","请原谅!","不用谢!","没关系!","欢迎您光临!","请坐!","请喝茶!","请多关照!","请多指教!","谢谢您的合作!","对不起,让您久等了。","没关系,我刚到。","给您添麻烦了。","我能为您做什么?","您好,请问您需要帮助吗?","您走好。","请慢走!"];
//resultValue = arr[Math.ceil(Math.random() * 24) - 1];
resultValue = "我是默认字符串";
}
//console.log(paramType);
}
return resultValue;
}

View File

@@ -0,0 +1,26 @@
/**
* 所有需要iframe页面调用的接口必须定义在这里
* 通过getExport()来吊起父页面的这些接口
*/
var exports = {
regeneratePathTree: function(){
// 定义在mg-ui.js用于重新生成文档树目录
regeneratePathTree();
},
updateTreeShowType: function(){
// 定义在mg-ui.js用于修改树形菜单展示类型
updateTreeShowType();
},
updateUserSettings: function(setting){
// 定义在mg-ui.js用于更新用户设置
updateUserSettings(setting);
},
exportDocument: function(){
// 定义在mg-ui.js用于打开导出文档框
exportDocument();
},
updateGlobalParam: function(param){
// 更新调试的全局参数变量
debugGlobalParam = param;
}
};

View File

@@ -0,0 +1,90 @@
/**
* 以每个Tag方式生成并展示
* 核心信息控制器
* /api/data/getDataList
* /api/data/getDataDetail
* 跟进控制器
* /api/track/getTrackList
* /api/track/getTrackDetail
*
* 先把树形的写完了再写这个,,
*
* @author 暮光:城中城
* @since 2018年5月26日
*/
function createTreeViewByTag(json, keywords) {
var pathIndex = {};
var paths = json.paths;
var domain = json.domainUrl;// 服务器代理会返回此属性
var rewriteDomainUrl = json.rewriteDomainUrl;// 服务器代理会返回此属性
if(isEmpty(domain)) {
domain = "http://" + json.host + json.basePath;
}
if(domain.endWith("/")) {
domain = domain.substring(0, domain.length - 1);
}
if (isEmptyObject(paths)) {
return;
}
//console.log(paths);
Object.keys(paths).forEach(function(key){
//console.log(key, paths[key]);
if(!findInPathsValue(key, paths[key], keywords)) {
return;
}
});
//console.log(pathIndex);
var htmlStr = '<li>';
htmlStr += '<a href="#">'+json.info.title+'</a>';
htmlStr += '<ul>';
htmlStr += getTreeHtmlForTag(pathIndex, projectTreeIdIndex);
htmlStr += '</ul>';
htmlStr += '</li>';
$('#apiPathTree .projects').append(htmlStr);
projectTreeIdIndex++;
}
/**
* 将对象列表递归的方式转换成文档格式html字符串
* @param pathData 处理后的对象列表
* @returns 生成的html字符串
*/
function getTreeHtmlForTag(pathData, treeIdStr) {
var tempStr = "";
var indexNow = 1;
// get, head, post, put, patch, delete, options, trace
var actionArrays = ["get", "head", "post", "put", "patch", "delete", "options", "trace"];
Object.keys(pathData).forEach(function(key){
var tempNode = pathData[key];
var tempTreeId = treeIdStr + "_" + indexNow;
// 只有一个子元素而且有method元素说明是只有一个节点
var nodeSub = getObjectFirstAttributeIfOnly(tempNode);
if(nodeSub != null && isNotEmpty(nodeSub.method)) {
var summary = isEmpty(nodeSub.summary) ? "" : "(" + nodeSub.summary + ")";
if(summary.length > 10){
summary = summary.substring(0, 10)+"...)";// 防止被撑得太长只显示10个字
}
nodeSub.treeId = tempTreeId;
tempStr += '<li m-id="'+tempTreeId+'"><a href="#" class="show-doc" path="'+nodeSub.path+'">'+key+'<span>'+summary+'</span></a></li>';
} else if(haveString(actionArrays, key)) {
//console.log(tempTreeId);
tempNode.treeId = tempTreeId;
var summary = isEmpty(tempNode.summary) ? "" : "("+tempNode.summary+")";
if(summary.length > 10){
summary = summary.substring(0, 10)+"...)";// 防止被撑得太长只显示10个字
}
tempStr += '<li m-id="'+tempTreeId+'"><a href="#" class="show-doc" path="'+tempNode.path+'">'+key+'<span>'+summary+'</span></a></li>';
} else {
tempStr += '<li>';
tempStr += '<a href="#">'+key+'</a>';
tempStr += '<ul>';
tempStr += getTreeHtmlForTag(tempNode, tempTreeId);
tempStr += '</ul>';
tempStr += '</li>';
}
indexNow++;
});
return tempStr;
}

View File

@@ -0,0 +1,96 @@
/**
* 以树形方式生成并展示:
* /api
* /data
* /getDateList
* post
* get
* @author 暮光:城中城
* @since 2018年5月26日
*/
/**
* 把原始的json字符串转换成对象列表的方式方便后续使用
* @param json swagger的原始对象
* @returns
*/
function createTreeViewByTree(json, keywords) {
var pathIndex = {};
if (isEmptyObject(json)) {
return;
}
//console.log(paths);
for (var i = 0; i < json.length; i++) {
var interface = json[i].interface;
//console.log(key, paths[key]);
if (!findInPathsValue(json[i], keywords)) {
continue;
}
if (json[i].nodeList.length <= 0) {
continue;
}
var methods = json[i].nodeList[0].methods;
for (var j = 0; j < methods.length; j++) {
var interfaceTemp = interface + "." + methods[j];
var keyArr = interfaceTemp.split(".");
var nowPathObj = null;
keyArr.forEach(function(val, index) {
//console.log(val, index);
if(isEmpty(val) && index == 0) {
return;
}
var nowPath = val;
if(nowPathObj == null) {
nowPathObj = {};
nowPathObj[nowPath] = pathIndex[nowPath];
if(nowPathObj[nowPath] == null) {
nowPathObj[nowPath] = {};
pathIndex[nowPath] = nowPathObj[nowPath];
}
}
var tempPathObj = nowPathObj[nowPath];
if(isEmpty(tempPathObj)) {
tempPathObj = nowPathObj[nowPath] = {};
}
nowPathObj = tempPathObj;
if(index == keyArr.length - 1) {
var tempPath = projectTreeIdIndex + ":" + interfaceTemp;
tempPathObj.method = methods[j];
tempPathObj.interface = tempPath;
treePathDataMap.set(tempPath, json[i]);
}
});
}
}
var htmlStr = getTreeHtmlForTree(pathIndex, projectTreeIdIndex);
$('#apiPathTree .projects').append(htmlStr);
projectTreeIdIndex++;
}
/**
* 将对象列表递归的方式转换成文档格式html字符串
* @param pathData 处理后的对象列表
* @returns 生成的html字符串
*/
function getTreeHtmlForTree(pathData, treeIdStr) {
var tempStr = "";
var indexNow = 1;
Object.keys(pathData).forEach(function (key) {
var tempNode = pathData[key];
var tempTreeId = treeIdStr + "_" + indexNow;
if (isNotEmpty(tempNode.interface)) {
tempNode.treeId = tempTreeId;
tempStr += '<li m-id="' + tempTreeId + '"><a href="#" class="show-doc" method="' + tempNode.method + '" path="' + tempNode.interface + '">' + key + '</a></li>';
} else {
tempStr += '<li>';
tempStr += '<a href="#">' + key + '</a>';
tempStr += '<ul>';
tempStr += getTreeHtmlForTree(tempNode, tempTreeId);
tempStr += '</ul>';
tempStr += '</li>';
}
indexNow++;
});
return tempStr;
}

View File

@@ -0,0 +1,106 @@
/**
* 两个元素上下、左右拖动动态改变大小
* @author 暮光:城中城
* @since 2017年5月7日
*/
(function($){
$.fn.mgResizableHeight = function(options) {
var defaults = {prev:this,next:this, prevHtMin:0, prevHtMax:999, nextHtMin:0, nextHtMax:999};
var opts = $.extend(defaults, options);
var disY = 0, prevH = 0, nextH = 0, isStart = false;
var prev, next, thisObj = this;
$(document).mousemove(function(ev){
if(!isStart){return;}
var ev = ev || window.event;
var H = ev.clientY - disY;
var prevHNow = prevH+H, nextHNow = nextH-H;
if(opts.prevHtMin >= prevHNow) {
prevHNow = opts.prevHtMin;
nextHNow = next.outerHeight();
}
if(opts.nextHtMin >= nextHNow) {
nextHNow = opts.nextHtMin;
prevHNow = prev.outerHeight();
}
if(opts.prevHtMax <= prevHNow) {
prevHNow = opts.prevHtMax;
nextHNow = next.outerHeight();
}
if(opts.nextHtMax <= nextHNow) {
nextHNow = opts.nextHtMax;
prevHNow = prev.outerHeight();
}
//prev.css("height", prevHNow + 'px');
//next.css("height", nextHNow + 'px');
if(typeof opts.onresize == 'function') {
opts.onresize(prevHNow, nextHNow);
}
}).mouseup(function(ev){
isStart = false;
});
$(this).mousedown(function(ev){
var ev = ev || window.event;
disY = ev.clientY;
prev = (opts.prev == thisObj)?$(opts.prev).prev():$(opts.prev);
next = (opts.next == thisObj)?$(opts.next).next():$(opts.next);
prevH = prev.outerHeight();
nextH = next.outerHeight();
isStart = true;
});
}
/**
* 改变宽度的功能,只是实现各种消息的通知,实际改变大小需要在回调里面自己操作
*/
$.fn.mgResizableWidth = function(options) {
var defaults = {prev:this,next:this, prevWtMin:0, prevWtMax:999, nextWtMin:0, nextWtMax:999};
var opts = $.extend(defaults, options);
var disX = 0, prevW = 0, nextW = 0, isStart = false;
var prev, next, thisObj = this;
$(document).mousemove(function(ev){
if(!isStart){return;}
var ev = ev || window.event;
var W = ev.clientX - disX;
var prevWNow = prevW+W, nextWNow = nextW-W;
if(opts.prevWtMin >= prevWNow) {
prevWNow = opts.prevWtMin;
nextWNow = next.outerWidth();
}
if(opts.nextWtMin >= nextWNow) {
nextWNow = opts.nextWtMin;
prevWNow = prev.outerWidth();
}
if(opts.prevWtMax <= prevWNow) {
prevWNow = opts.prevWtMax;
nextWNow = next.outerWidth();
}
if(opts.nextWtMax <= nextWNow) {
nextWNow = opts.nextWtMax;
prevWNow = prev.outerWidth();
}
//prev.css("width", prevWNow + 'px');
//next.css("width", nextWNow + 'px');
if(typeof opts.onresize == 'function') {
opts.onresize(prevWNow, nextWNow);
}
}).mouseup(function(ev){
if(!isStart){return;}
isStart = false;
if(typeof opts.onfinish == 'function') {
opts.onfinish();
}
});
$(this).mousedown(function(ev){
var ev = ev || window.event;
disX = ev.clientX;
prev = (opts.prev == thisObj)?$(opts.prev).prev():$(opts.prev);
next = (opts.next == thisObj)?$(opts.next).next():$(opts.next);
prevW = prev.outerWidth();
nextW = next.outerWidth();
isStart = true;
if(typeof opts.onstart == 'function') {
opts.onstart();
}
});
}
})(jQuery);

View File

@@ -0,0 +1,40 @@
/**
* 提示工具类
* @author 暮光:城中城
* @since 2017年5月7日
*/
var Toast = {
notOpen: function () {
var data = {
message: "该功能暂未开放,敬请期待!",
icon: 'exclamation-sign', type: "warning",
};
this.show(data);
},
success: function (msg, time) {
var data = {
message: msg, time: time,
icon: 'check-circle-o', type: 'success',
};
this.show(data);
},
warn: function (msg, time) {
var data = {
message: msg, time: time,
icon: 'exclamation-sign', type: 'warning',
};
this.show(data);
},
error: function (msg, time) {
var data = {
message: msg, time: time,
icon: 'exclamation-sign', type: 'danger',
};
this.show(data);
},
show: function (data) {
data.time = isEmpty(data.time) ? 2000 : data.time;
data.placement = isEmpty(data.placement) ? 'top' : data.placement;
new $.zui.Messager(data.message, data).show();
}
}

File diff suppressed because it is too large Load Diff

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

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 290 KiB

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

View File

@@ -0,0 +1,146 @@
/*!
* ZUI: 标签页管理器 - v1.8.1 - 2018-01-18
* http://zui.sexy
* GitHub: https://github.com/easysoft/zui.git
* Copyright (c) 2018 cnezsoft.com; Licensed MIT
*/
.tabs {
position: relative;
min-height: 400px;
}
.tabs-navbar {
padding: 4px 4px 0 4px;
}
.tabs-nav {
height: 30px;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
border-bottom: none;
border-bottom: 1px solid #ddd;
}
.tab-nav-item {
width: 160px;
min-width: 0;
max-width: 160px;
padding-right: 2px;
margin-bottom: 0;
border: none;
}
.tab-nav-item:hover {
min-width: 95px;
}
.tab-nav-link {
position: relative;
height: 30px;
margin: 0;
overflow: hidden;
background-color: rgba(255, 255, 255, .65);
background-color: #e5e5e5;
border-color: #ddd;
border-bottom: none;
border-radius: 2px 2px 0 0;
}
.tab-nav-link > .title {
position: absolute;
top: 5px;
right: 5px;
left: 30px;
display: block;
overflow: hidden;
font-size: 14px;
line-height: 20px;
text-overflow: ellipsis;
white-space: nowrap;
}
.tab-nav-link > .icon {
position: absolute;
top: 5px;
left: 5px;
display: block;
width: 20px;
height: 20px;
line-height: 20px;
text-align: center;
opacity: .8;
}
.tab-nav-item.loading .tab-nav-link > .icon:before {
content: '\e97b';
-webkit-animation: spin 2s infinite linear;
-o-animation: spin 2s infinite linear;
animation: spin 2s infinite linear;
}
.tab-nav-link > .close {
position: absolute;
top: 5px;
right: 5px;
width: 20px;
height: 20px;
font-weight: 200;
line-height: 16px;
text-align: center;
text-shadow: none;
visibility: hidden;
border-radius: 4px;
opacity: 0;
-webkit-transition: all .2s;
-o-transition: all .2s;
transition: all .2s;
}
.tab-nav-link > .close:hover {
color: #fff;
background-color: #ea644a;
}
.tab-nav-link:hover > .title {
right: 25px;
}
.tab-nav-link:hover > .close {
visibility: visible;
opacity: 1;
}
.tab-nav-link.not-closable > .close {
display: none;
}
.nav-tabs.tabs-nav > li > a,
.nav-tabs.tabs-nav > li > a:hover,
.nav-tabs.tabs-nav > li > a:focus {
border-color: #ddd #ddd transparent #ddd;
}
.tab-nav-condensed .tab-nav-link > .title {
left: 5px;
text-overflow: initial;
}
.tab-nav-condensed .tab-nav-link > .icon {
display: none;
}
.tabs-container {
position: absolute;
top: 34px;
right: 0;
bottom: 0;
left: 0;
}
.tabs-container > .tab-pane {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
display: none;
}
.tabs-container > .tab-pane.active {
display: block;
}
.tab-iframe-cover {
display: none;
}
.tabs-show-contextmenu .tab-iframe-cover {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
display: block;
}

View File

@@ -0,0 +1,488 @@
/*!
* ZUI: 标签页管理器 - v1.8.1 - 2018-01-18
* http://zui.sexy
* GitHub: https://github.com/easysoft/zui.git
* Copyright (c) 2018 cnezsoft.com; Licensed MIT
*/
/* ========================================================================
* ZUI: tabs.js
* http://zui.sexy
* ========================================================================
* Copyright (c) 2017-2018 cnezsoft.com; Licensed MIT
* ======================================================================== */
(function($) {
'use strict';
/**
* Tab object
* @param {Object | String} tab
*/
var Tab = function(tab) {
var that = this;
if(typeof tab === 'string') {
that.url = tab;
} else if($.isPlainObject(tab)) {
$.extend(that, tab);
}
if(!that.id) {
that.id = $.zui.uuid();
}
if(!that.type) {
if(that.iframe) {
that.type = 'iframe';
that.url = that.url || that.iframe;
} else if(that.ajax) {
that.type = 'ajax';
that.url = that.url || ($.isPlainObject(that.ajax) ? that.ajax.url : that.ajax);
} else if(that.url) {
that.type = tab.ajax ? 'ajax' : 'iframe';
} else {
that.type = 'custom';
}
}
that.createTime = new Date().getTime();
that.openTime = 0;
that.onCreate && that.onCreate.call(that);
};
Tab.prototype.open = function() {
var that = this;
that.openTime = new Date().getTime();
that.onOpen && that.onOpen.call(that);
};
Tab.prototype.close = function() {
var that = this;
that.openTime = 0;
that.onClose && that.onClose.call(that);
};
Tab.create = function(data) {
if (data instanceof Tab) {
return data;
}
return new Tab(data);
};
var NAME = 'zui.tabs'; // model name
var DEFAULTS = {
tabs: [],
defaultTabIcon: 'icon-window',
contextMenu: true,
errorTemplate: '<div class="alert alert-block alert-danger with-icon"><i class="icon-warning-sign"></i><div class="content">{0}</div></div>',
// messagerOptions: null,
showMessage: true,
navTemplate: '<nav class="tabs-navbar"></nav>',
containerTemplate: '<div class="tabs-container"></div>'
};
var LANG = {
zh_cn: {
reload: '重新加载',
close: '关闭',
closeOthers: '关闭其他标签页',
closeRight: '关闭右侧标签页',
reopenLast: '恢复上次关闭的标签页',
errorCannotFetchFromRemote: '无法从远程服务器({0})获取内容。'
},
zh_tw: {
reload: '重新加載',
close: '關閉',
closeOthers: '關閉其他標籤頁',
closeRight: '關閉右側標籤頁',
reopenLast: '恢復上次關閉的標籤頁',
errorCannotFetchFromRemote: '無法從遠程服務器({0})獲取內容。'
},
en: {
reload: 'Reload',
close: 'Close',
closeOthers: 'Close others',
closeRight: 'Close right',
reopenLast: 'Reopen last',
errorCannotFetchFromRemote: 'Cannot fetch data from remote server {0}.'
}
};
// The tabs model class
var Tabs = function(element, options) {
var that = this;
that.name = NAME;
that.$ = $(element);
options = that.options = $.extend({}, DEFAULTS, this.$.data(), options);
var lang = options.lang || 'zh_cn';
that.lang = $.isPlainObject(lang) ? ($.extend(true, {}, LANG[lang.lang || $.zui.clientLang()], lang)) : LANG[lang];
// Initialize here
var $navbar = that.$.find('.tabs-navbar');
if (!$navbar.length) {
$navbar = $(options.navTemplate).appendTo(that.$);
}
that.$navbar = $navbar;
var $nav = $navbar.find('.tabs-nav');
if (!$nav.length) {
$nav = $('<ul class="tabs-nav nav nav-tabs"></ul>').appendTo($navbar);
}
that.$nav = $nav;
var $tabs = that.$.find('.tabs-container');
if (!$tabs.length) {
$tabs = $(options.containerTemplate).appendTo(that.$);
}
that.$tabs = $tabs;
that.activeTabId = options.defaultTab;
var tabs = options.tabs || [];
that.tabs = {};
$.each(tabs, function(index, item) {
var tab = Tab.create(item);
that.tabs[tab.id] = tab;
if (!that.activeTabId) {
that.activeTabId = tab.id;
}
that.renderTab(tab);
});
that.closedTabs = [];
that.open(that.getActiveTab());
$nav.on('click.' + NAME, '.tab-nav-link', function () {
that.open(that.getTab($(this).data('id')));
}).on('click.' + NAME, '.tab-nav-close', function (e) {
that.close($(this).closest('.tab-nav-link').data('id'));
e.stopPropagation();
}).on('resize.' + NAME, function () {
that.adjustNavs();
});
if (options.contextMenu) {
$nav.contextmenu({
selector: '.tab-nav-link',
itemsCreator: function (e) {
return that.createMenuItems(that.getTab($(this).data('id')));
},
onShow: function () {
that.$.addClass('tabs-show-contextmenu');
},
onHide: function () {
that.$.removeClass('tabs-show-contextmenu');
}
});
}
};
Tabs.prototype.createMenuItems = function (tab) {
var that = this;
var lang = that.lang;
return [{
label: lang.reload,
onClick: function () {
that.open(tab, true);
}
}, '-', {
label: lang.close,
disabled: tab.forbidClose,
onClick: function () {
that.close(tab.id);
}
}, {
label: lang.closeOthers,
disabled: that.$nav.find('.tab-nav-item:not(.hidden)').length <= 1,
onClick: function () {
that.closeOthers(tab.id);
}
}, {
label: lang.closeRight,
disabled: !$('#tab-nav-item-' + tab.id).next('.tab-nav-item:not(.hidden)').length,
onClick: function () {
that.closeRight(tab.id);
}
}, '-', {
label: lang.reopenLast,
disabled: !that.closedTabs.length,
onClick: function () {
that.reopen();
}
}];
};
Tabs.prototype.adjustNavs = function (immediately) {
var that = this;
if (!immediately) {
if (that.adjustNavsTimer) {
clearTimeout(that.adjustNavsTimer);
}
that.adjustNavsTimer = setTimeout(function() {
that.adjustNavs(true);
}, 50);
return;
}
if (that.adjustNavsTimer) {
that.adjustNavsTimer = null;
}
var $nav = that.$nav;
var $navItems = $nav.find('.tab-nav-item:not(.hidden)');
var totalWidth = $nav.width();
var totalCount = $navItems.length;
var maxWidth = Math.floor(totalWidth/totalCount);
if(maxWidth < 96) {
maxWidth = Math.floor((totalWidth-96)/(totalCount-1))
}
$nav.toggleClass('tab-nav-condensed', maxWidth <= 50);
$navItems.css('max-width', maxWidth);
};
Tabs.prototype.renderTab = function(tab, beforeTabId) {
var that = this;
var $nav = that.$nav;
var $tabNav = $('#tab-nav-item-' + tab.id);
if (!$tabNav.length) {
var $a = $('<a class="tab-nav-link"><i class="icon"></i><span class="title"></span><i class="close tab-nav-close" title="' + that.lang.close + '">&times;</i></a>').attr({
href: '#tabs-item-' + tab.id,
'data-id': tab.id
});
$tabNav = $('<li class="tab-nav-item" data-id="' + tab.id + '" id="tab-nav-item-' + tab.id + '" />').append($a).appendTo(that.$nav);
if (beforeTabId) {
var $before$nav = $('#tab-nav-item-' + beforeTabId);
if ($before$nav.length) {
$tabNav.insertAfter($before$nav);
}
}
that.adjustNavs();
}
var $a = $tabNav.find('a').attr('title', tab.desc).toggleClass('not-closable', !!tab.forbidClose);
$a.find('.icon').attr('class', 'icon ' + (tab.icon || that.options.defaultTabIcon));
$a.find('.title').text(tab.title || tab.defaultTitle || '');
return $tabNav;
};
Tabs.prototype.getActiveTab = function() {
var that = this;
return that.activeTabId ? that.tabs[that.activeTabId] : null;
};
Tabs.prototype.getTab = function(tabId) {
var that = this;
if (!tabId) {
return that.getActiveTab();
}
if (typeof tabId === 'object') {
tabId = tabId.id;
}
return that.tabs[tabId];
};
Tabs.prototype.close = function(tabId, forceClose) {
var that = this;
var tab = that.getTab(tabId);
if (tab && (forceClose || !tab.forbidClose)) {
$('#tab-nav-item-' + tab.id).remove();
$('#tab-' + tab.id).remove();
tab.close();
delete that.tabs[tab.id];
that.closedTabs.push(tab);
that.$.callComEvent(that, 'onClose', tab);
var lastTab;
$.each(that.tabs, function (tabId, tab) {
if (!lastTab || lastTab.openTime < tab.openTime) {
lastTab = tab;
}
});
lastTab && that.open(lastTab);
}
};
Tabs.prototype.open = function(tab, forceReload) {
var that = this;
if (!(tab instanceof Tab)) {
tab = Tab.create(tab);
}
var $tabNav = that.renderTab(tab);
that.$nav.find('.tab-nav-item.active').removeClass('active');
$tabNav.addClass('active');
var $tabPane = $('#tab-' + tab.id);
if (!$tabPane.length) {
$tabPane = $('<div class="tab-pane" id="tab-' + tab.id + '" />').appendTo(that.$tabs);
}
that.$tabs.find('.tab-pane.active').removeClass('active');
$tabPane.addClass('active');
tab.open();
that.activeTabId = tab.id;
that.tabs[tab.id] = tab;
if (forceReload || !tab.loaded) {
that.reload(tab);
}
that.$.callComEvent(that, 'onOpen', tab);
};
Tabs.prototype.showMessage = function (message, type) {
$.zui.messager.show(message, $.extend({
placement: 'center'
}, this.options.messagerOptions, {
type: type
}));
};
Tabs.prototype.reload = function(tab) {
var that = this;
if (typeof tab === 'string') {
tab = that.getTab(tab);
} else if (!tab) {
tab = that.getActiveTab();
}
if (!tab) {
return;
}
if (!tab.openTime) {
return that.open(tab);
}
var $tabNav = $('#tab-nav-item-' + tab.id).addClass('loading').removeClass('has-error');
var $tabPane = $('#tab-' + tab.id).addClass('loading').removeClass('has-error');
var afterRefresh = function (content, error) {
if (!tab.openTime) {
return;
}
$tabNav.removeClass('loading');
$tabPane.removeClass('loading');
that.$.callComEvent(that, 'onLoad', tab);
if(typeof content === 'string' || content instanceof $) {
if (tab.contentConverter) {
content = tab.contentConverter(content, tab);
}
$tabPane.empty().append(content);
if (!tab.title) {
content = $tabPane.text().replace(/\n/g, '');
tab.title = content.length > 10 ? content.substr(0, 10) : content;
that.renderTab(tab);
}
}
if (error) {
$tabNav.addClass('has-error');
$tabPane.addClass('has-error');
var showMessage = that.options.showMessage;
if (showMessage) {
if ($.isFunction(showMessage)) {
error = showMessage(error);
}
that.showMessage(error, 'danger');
}
if (!content) {
$tabPane.html(that.options.errorTemplate.format(error));
}
}
tab.loaded = new Date().getTime();
};
if (tab.type === 'ajax') {
var ajaxOption = {
type: 'get',
url: tab.url,
error: function(jqXHR, textStatus, errorThrown) {
afterRefresh(false, that.lang.errorCannotFetchFromRemote.format(tab.url));
},
success: function(data) {
afterRefresh(data);
}
};
if($.isPlainObject(tab.ajax)) {
ajaxOption = $.extend(ajaxOption, tab.ajax);
}
$.ajax(ajaxOption);
} else if (tab.type === 'iframe') {
try {
var iframeName = 'tab-iframe-' + tab.id;
var $iframe = $('<iframe id="' + iframeName + '" name="' + iframeName + '" src="' + (tab.url) + '" frameborder="no" allowfullscreen="true" mozallowfullscreen="true" webkitallowfullscreen="true" allowtransparency="true" scrolling="auto" style="width: 100%; height: 100%; left: 0px;"></iframe>');
$iframe.appendTo($tabPane.empty());
$('<div class="tab-iframe-cover" />').appendTo($tabPane);
var frame = document.getElementById(iframeName);
frame.onload = frame.onreadystatechange = function() {
if(this.readyState && this.readyState != 'complete') return;
afterRefresh();
var contentDocument = frame.contentDocument;
if (contentDocument && !tab.title) {
tab.title = contentDocument.title;
that.renderTab(tab);
}
};
} catch (e) {
afterRefresh();
}
} else {
var content = tab.content || tab.custom;
if (typeof content === 'function') {
content = content(tab, afterRefresh, that);
if (content !== true) {
afterRefresh(content);
}
} else {
afterRefresh(content);
}
}
};
Tabs.prototype.closeOthers = function(tabId) {
var that = this;
that.$nav.find('.tab-nav-link:not(.hidden)').each(function() {
var thisTabId = $(this).data('id');
if (thisTabId !== tabId) {
that.close(thisTabId);
}
});
};
Tabs.prototype.closeRight = function(tabId) {
var $tabNav = $('#tab-nav-item-' + tabId);
var $rightNav = $tabNav.next('.tab-nav-item:not(.hidden)');
while ($rightNav.length) {
this.close($rightNav.data('id'));
$rightNav = $tabNav.next('.tab-nav-item:not(.hidden)');
}
};
Tabs.prototype.closeAll = function() {
var that = this;
that.$nav.find('.tab-nav-link:not(.hidden)').each(function() {
that.close($(this).data('id'));
});
};
Tabs.prototype.reopen = function() {
var that = this;
if(that.closedTabs.length) {
that.open(that.closedTabs.pop());
}
};
// Extense jquery element
$.fn.tabs = function(option) {
return this.each(function() {
var $this = $(this);
var data = $this.data(NAME);
var options = typeof option == 'object' && option;
if(!data) $this.data(NAME, (data = new Tabs(this, options)));
if(typeof option == 'string') data[option]();
});
};
Tabs.NAME = NAME;
$.fn.tabs.Constructor = Tabs;
}(jQuery));

View File

@@ -0,0 +1,6 @@
/*!
* ZUI: 标签页管理器 - v1.8.1 - 2018-01-18
* http://zui.sexy
* GitHub: https://github.com/easysoft/zui.git
* Copyright (c) 2018 cnezsoft.com; Licensed MIT
*/.tabs{position:relative;min-height:400px}.tabs-navbar{padding:4px 4px 0 4px}.tabs-nav{height:30px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;border-bottom:none;border-bottom:1px solid #ddd}.tab-nav-item{width:160px;min-width:0;max-width:160px;padding-right:2px;margin-bottom:0;border:none}.tab-nav-item:hover{min-width:95px}.tab-nav-link{position:relative;height:30px;margin:0;overflow:hidden;background-color:rgba(255,255,255,.65);background-color:#e5e5e5;border-color:#ddd;border-bottom:none;border-radius:2px 2px 0 0}.tab-nav-link>.title{position:absolute;top:5px;right:5px;left:30px;display:block;overflow:hidden;font-size:14px;line-height:20px;text-overflow:ellipsis;white-space:nowrap}.tab-nav-link>.icon{position:absolute;top:5px;left:5px;display:block;width:20px;height:20px;line-height:20px;text-align:center;opacity:.8}.tab-nav-item.loading .tab-nav-link>.icon:before{content:'\e97b';-webkit-animation:spin 2s infinite linear;-o-animation:spin 2s infinite linear;animation:spin 2s infinite linear}.tab-nav-link>.close{position:absolute;top:5px;right:5px;width:20px;height:20px;font-weight:200;line-height:16px;text-align:center;text-shadow:none;visibility:hidden;border-radius:4px;opacity:0;-webkit-transition:all .2s;-o-transition:all .2s;transition:all .2s}.tab-nav-link>.close:hover{color:#fff;background-color:#ea644a}.tab-nav-link:hover>.title{right:25px}.tab-nav-link:hover>.close{visibility:visible;opacity:1}.tab-nav-link.not-closable>.close{display:none}.nav-tabs.tabs-nav>li>a,.nav-tabs.tabs-nav>li>a:focus,.nav-tabs.tabs-nav>li>a:hover{border-color:#ddd #ddd transparent #ddd}.tab-nav-condensed .tab-nav-link>.title{left:5px;text-overflow:initial}.tab-nav-condensed .tab-nav-link>.icon{display:none}.tabs-container{position:absolute;top:34px;right:0;bottom:0;left:0}.tabs-container>.tab-pane{position:absolute;top:0;right:0;bottom:0;left:0;display:none}.tabs-container>.tab-pane.active{display:block}.tab-iframe-cover{display:none}.tabs-show-contextmenu .tab-iframe-cover{position:absolute;top:0;right:0;bottom:0;left:0;display:block}

File diff suppressed because one or more lines are too long