/** * swagger-mg-ui是swagger-ui的一个前端实现,使用简单、解析速度快、走心的设计 * 支持多项目同时展示,多种文档目录的展示方案,多种自定义配置,满足各种使用习惯。 * 使用中您有任何的意见和建议都可到源码地址处反馈哦! * git地址:https://gitee.com/zyplayer/swagger-mg-ui * @author 暮光:城中城 * @since 2018年5月20日 */ // 参数说明对于的map全局对象 var definitionsDataMap = new Map(); // 依据目录树存储的map全局对象 var treePathDataMap = new Map(); var globalLoadingMessager; // 树的下表 var projectTreeIdIndex = 1; // 文档url加载的下标 var projectLoadingIndex = 0; // 请求到的文档列表 var documentJsonArr = []; // 用户的配置对象 var userSettings = {}; // 默认用户的配置对象 var defaultUserSettings = { autoFillParam : 1,// 自动填充参数 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 projects : [],// 所有的项目列表 removedProjects : [],// 被移除的项目列表 prevWNow : 360 }; var swaggerApiDocsArr = []; /** * 网页加载完毕后的处理 */ $(document).ready(function(){ userSettings = defaultUserSettings; changeContentWidth(userSettings.prevWNow); updateTreeShowType(); updateUserSettingsUi(); globalLoadingMessager = new $.zui.Messager({type: 'primary', close: false, time: 0}).show(); showGlobalLoadingMessage('文档解析中,请稍候...', true); if(isEmptyObject(mgUiDataArr)) { Toast.error("文档数据错误,请检查!"); return; } for (var i = 0; i < mgUiDataArr.length; i++) { showGlobalLoadingMessage('解析第'+(i+1)+'份文档,请稍候...', true); var tempDoc = mgUiDataArr[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(); }); /** * 自由拖动改变左右框架的宽度 */ $("#resizebleLeftRight").mgResizebleWidth({ prev:"#leftContent", prevWtMin: 120, prevWtMax: 999999, nextWtMin: 360, nextWtMax: 999999, onresize:function(prevWNow, nextWNow){ changeContentWidth(prevWNow); }, onstart:function(){ $("body").addClass("unselect"); }, onfinish:function(){ $("body").removeClass("unselect"); storeUserSettings(); } }); /** * 切换导航栏的宽度到最小或最大 */ $("#changeContentWidth").click(function(){ var isMinWidth = ($("#leftContent").width() == 120); changeContentWidth(isMinWidth ? 360 : 120); }); /** * 修改tree的class */ $("input[name='treeShowType']").change(function() { userSettings.treeShowType = $("input[name='treeShowType']:checked").val(); updateTreeShowType(); storeUserSettings(); }); /** * 切换url分成一层一层的展示、整个url显示为一层展示 */ $("input[name='catalogShowType']").change(function() { userSettings.catalogShowType = $("input[name='catalogShowType']:checked").val(); regeneratePathTree(); storeUserSettings(); }); /** * 是否展示参数类型 */ $("input[name='showParamType']").change(function() { userSettings.showParamType = $("input[name='showParamType']:checked").val(); storeUserSettings(); }); /** * 是否自动填充请求参数 */ $("input[name='autoFillParam']").change(function() { userSettings.autoFillParam = $("input[name='autoFillParam']:checked").val(); storeUserSettings(); }); /** * 搜索框回车事件 */ $("#searchDocInput").keyup(function(e) { if (e.keyCode == 13) { searchDoc(); } }); /** * 搜索按钮点击 */ $("#searchDocBt").click(function(){ searchDoc(); }); /** * 主页li点击事件,展示主页 */ $("#homePageLi").click(function(){ $(".tab-page").hide(); $(".tab-home-page").show(); }); /** * api文档最后的节点点击,展示文档页面 */ $("#apiPathTree").on("click", ".show-doc", function(){ $(".tab-page").hide(); $(".tab-document").show(); var path = $(this).attr("path"); var data = treePathDataMap.get(path); var docInfo = getNotEmptyStr(data.description); var docUrl = getNotEmptyStr(data.url); if(isEmpty(docInfo)) { docInfo = getNotEmptyStr(data.summary); } // 处理在线文档 $("#docUrl").text(docUrl); $("#docRequestMethod").text(getNotEmptyStr(data.method)); $("#docInfo").text(docInfo); $("#docConsumes").text(arrToString(data.consumes)); $("#docProduces").text(arrToString(data.produces)); // 遍历参数列表 $("#docRequestParam table tbody").empty(); $("#docRequestExample table tbody").empty(); Formatjson.annotationObject = {}; if(isNotEmpty(data.parameters)) { Object.keys(data.parameters).forEach(function(key){ var tempParameters = data.parameters[key]; var htmlStr = "", htmlStrExample = ""; var responsesJson = []; var responsesExample = []; 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); if(isNotEmpty(tempParameters.items)) { htmlStr = paramName + "[0]"; htmlStrExample = paramName + "[0]"; } else if(isNotEmpty(tempParameters.schema)) { if("array" == tempParameters.schema.type) { var responsesObj = definitionsDataMap.get(tempParameters.schema.items.$ref); if(responsesObj != null) { responsesJson[0] = getResponsesJson(responsesObj, "", false, 1); responsesExample[0] = getResponsesJson(responsesObj, "", true, 1); } else { responsesJson = [""]; responsesExample = [""]; if(tempParameters.schema.items.type == "boolean") { responsesJson = [true]; responsesExample = [true]; } else if(tempParameters.schema.items.type == "integer") { responsesJson = [0]; responsesExample = [0]; } } var arrTmp = tempParameters.schema.$ref.split("/"); paramType = arrTmp[arrTmp.length - 1]; htmlStr = Formatjson.processObjectToHtmlPre(responsesJson, 0, false, false, false, true); htmlStrExample = Formatjson.processObjectToHtmlPre(responsesExample, 0, false, false, false, false); } else if(isNotEmpty(tempParameters.schema.$ref)){ var responsesObj = definitionsDataMap.get(tempParameters.schema.$ref); var arrTmp = tempParameters.schema.$ref.split("/"); paramType = arrTmp[arrTmp.length - 1]; if(isNotEmpty(responsesObj)) { responsesJson = getResponsesJson(responsesObj, "", false, 1); responsesExample = getResponsesJson(responsesObj, "", true, 1); htmlStr = Formatjson.processObjectToHtmlPre(responsesJson, 0, false, false, false, true); htmlStrExample = Formatjson.processObjectToHtmlPre(responsesExample, 0, false, false, false, false); } else { htmlStr = paramName; htmlStrExample = paramName; } } else if("string" == tempParameters.schema.type) { htmlStr = paramName; htmlStrExample = paramName; } else { htmlStr = paramName; htmlStrExample = paramName; } } else { htmlStr = paramName; htmlStrExample = paramName; } $("#docRequestParam table tbody").append( '' +'' + htmlStr + '' +'' + paramDesc + '' +'' + paramType + '' +'' + paramIn + '' +'' + required + '' +'' ); $("#docRequestExample table tbody").append( '' +'' + htmlStrExample + '' +'' + paramDesc + '' +'' + paramType + '' +'' + paramIn + '' +'' + required + '' +'' ); }); } // 遍历结果集列表 $("#docResponseModel table tbody").empty(); $("#docResponseExample table tbody").empty(); Formatjson.annotationObject = {}; if(isNotEmpty(data.responses)) { Object.keys(data.responses).forEach(function(key){ var tempRespones = data.responses[key]; if(isNotEmpty(tempRespones.schema)) { var responsesJson, responsesExample; if("array" == tempRespones.schema.type) { responsesJson = []; responsesExample = []; var responsesObj = definitionsDataMap.get(tempRespones.schema.items.$ref); if(responsesObj != null) { responsesJson[0] = getResponsesJson(responsesObj, "", false, 1); responsesExample[0] = getResponsesJson(responsesObj, "", true, 1); } else { responsesJson = [""]; responsesExample = [""]; if(tempParameters.schema.items.type == "boolean") { responsesJson = [true]; responsesExample = [true]; } else if(tempParameters.schema.items.type == "integer") { responsesJson = [0]; responsesExample = [0]; } } } else if(isNotEmpty(tempRespones.schema.$ref)){ var responsesObj = definitionsDataMap.get(tempRespones.schema.$ref); if(isEmptyObject(responsesObj)) { var arrTmp = tempRespones.schema.$ref.split("/"); var lastObjName = arrTmp[arrTmp.length - 1]; responsesJson = lastObjName; responsesExample = lastObjName; } else { responsesJson = getResponsesJson(responsesObj, "", false, 1); responsesExample = getResponsesJson(responsesObj, "", true, 1); } } else { responsesJson = ""; responsesExample = ""; } if(isEmptyObject(responsesJson)) { return; } //console.log(Formatjson.annotationObject); var htmlStr = Formatjson.processObjectToHtmlPre(responsesJson, 0, false, false, false, true); $("#docResponseModel table tbody").append( '' +'' + key + '' +'' + htmlStr + '' +'' ); htmlStr = Formatjson.processObjectToHtmlPre(responsesExample, 0, false, false, false, false); $("#docResponseExample table tbody").append( '' +'' + key + '' +'' + htmlStr + '' +'' ); } }); } }); /** * 搜索文档 * @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(''); for (var i = 0; i < documentJsonArr.length; i++) { var json = documentJsonArr[i]; if(userSettings.catalogShowType == 1) { createTreeViewByTree(json, keywords);// url分成一层一层的展示 } else if(userSettings.catalogShowType == 2){ createTreeViewByTag(json, keywords);// tag方式,整个url显示为一层 } else { createTreeViewByTree(json, keywords);// url分成一层一层的展示 } } $('#apiPathTree .projects').tree(); updateTreeShowType(); } function findInPathsValue(key, pathsValue, keywords) { if(isEmpty(keywords) || isEmpty(key)) { return true; } key = key.toLowerCase(); keywords = keywords.toLowerCase(); // 路径中有就不用再去找了 if(key.indexOf(keywords) >= 0) { return true; } for ( var subKey in pathsValue) { // 找路径和说明里面包含关键字的 var tagsTmp = pathsValue[subKey].tags; var pathTmp = pathsValue[subKey].path; var summaryTmp = pathsValue[subKey].summary; var descriptionTmp = pathsValue[subKey].description; if(isNotEmpty(pathTmp) && pathTmp.toLowerCase().indexOf(keywords) >= 0) { return true; } if(isNotEmpty(summaryTmp) && summaryTmp.toLowerCase().indexOf(keywords) >= 0) { return true; } if(isNotEmpty(descriptionTmp) && descriptionTmp.toLowerCase().indexOf(keywords) >= 0) { return true; } if(isNotEmpty(tagsTmp) && arrToString(tagsTmp).toLowerCase().indexOf(keywords) >= 0) { return true; } } return false; } function getResponsesJson(responsesObj, prevRef, isExample, recursiveCount) { var responsesJson = {}; recursiveCount++;// 多层递归,最多递归10层,防止无限递归 if(isEmpty(responsesObj) || isEmpty(responsesObj.properties) || recursiveCount > 10) { return responsesJson; } var requiredArr = responsesObj.required; Object.keys(responsesObj.properties).forEach(function(prop){ var tmpData = responsesObj.properties[prop]; if("array" == tmpData.type) {// 数组 Formatjson.annotationObject[prop] = getNotEmptyStr(tmpData.description); if(prevRef != tmpData.items.$ref) { var tempObj = definitionsDataMap.get(tmpData.items.$ref); if(tempObj != null) { var tempArr = responsesJson[prop] = []; tempArr[0] = getResponsesJson(tempObj, tmpData.items.$ref, isExample, recursiveCount); } else { var responsesJsonSub = []; var bodyFor = responsesJsonSub; var items = tmpData.items; for (var i = 0; i < 10; i++) { if("array" == items.type) { bodyFor = bodyFor[0] = []; items = items.items; } else { tempObj = definitionsDataMap.get(items.$ref); if(tempObj != null) { bodyFor[0] = getResponsesJson(tempObj, items.$ref, isExample, recursiveCount); } else { if(items.type == "boolean") { bodyFor[0] = true; } else if(items.type == "integer") { bodyFor[0] = 0; } else { bodyFor[0] = ""; } } break; } } responsesJson[prop] = responsesJsonSub; } } else { responsesJson[prop] = "{}" + getNotEmptyStr(tmpData.description); } } else if(isNotEmpty(tmpData.$ref)) {// 对象 Formatjson.annotationObject[prop] = getNotEmptyStr(tmpData.description); if(prevRef != tmpData.$ref) { var tempObj = definitionsDataMap.get(tmpData.$ref); responsesJson[prop] = getResponsesJson(tempObj, tmpData.$ref, isExample, recursiveCount); } else { responsesJson[prop] = "{}" + getNotEmptyStr(tmpData.description); } } else {// 字段 var enumExample = ""; var enumObj = tmpData["enum"]; if(!isEmptyObject(enumObj) && enumObj.length > 0) { enumExample = "枚举值:"; for (var i = 0; i < enumObj.length; i++) { if(i > 0) {enumExample += "、";} enumExample += enumObj[i]; } } var typeStr = getNotEmptyStr(tmpData.format); if(isEmpty(typeStr)) { typeStr = getNotEmptyStr(tmpData.type); } if(isExample) { var tempVal = getNotEmptyStr(tmpData.example); if(isEmpty(tempVal)) { tempVal = getAutoFillValue(typeStr, prop); } if(isNotEmpty(tempVal) && isNotEmpty(enumExample)) { tempVal = tempVal + "," + enumExample; } responsesJson[prop] = tempVal; } else { if(userSettings.showParamType == 1) { if(haveString(requiredArr, prop)) { typeStr = (isNotEmpty(typeStr) ? typeStr + "," : "") + "required"; } if(isNotEmpty(typeStr)) { typeStr = "(" + typeStr + ")"; } } var descriptionStr = typeStr + getNotEmptyStr(tmpData.description); if(isNotEmpty(descriptionStr) && isNotEmpty(enumExample)) { descriptionStr = descriptionStr + "," + enumExample; } responsesJson[prop] = descriptionStr; } } }); return responsesJson; } function getRequestParamObj(responsesObj, prevRef) { var responsesJson = {}; if(isEmpty(responsesObj) || isEmpty(responsesObj.properties)) { return responsesJson; } var requiredArr = responsesObj.required; Object.keys(responsesObj.properties).forEach(function(prop){ var tmpData = responsesObj.properties[prop]; if("array" == tmpData.type) {// 数组 if(prevRef != tmpData.items.$ref) { var tempObj = definitionsDataMap.get(tmpData.items.$ref); if(tempObj != null) { var tempArr = responsesJson[prop] = []; tempArr[0] = getRequestParamObj(tempObj, tmpData.items.$ref); } else { var responsesJsonSub = []; var bodyFor = responsesJsonSub; var items = tmpData.items; for (var i = 0; i < 10; i++) { if("array" == items.type) { bodyFor = bodyFor[0] = []; items = items.items; } else { tempObj = definitionsDataMap.get(items.$ref); if(tempObj != null) { bodyFor[0] = getRequestParamObj(tempObj, items.$ref); } else { if(items.type == "boolean") { bodyFor[0] = true; } else if(items.type == "integer") { bodyFor[0] = 0; } else { bodyFor[0] = ""; } } break; } } responsesJson[prop] = responsesJsonSub; } } else { var required = haveString(requiredArr, prop); var paramType = getNotEmptyStr(tmpData.format); var paramDesc = getNotEmptyStr(tmpData.description); var example = getNotEmptyStr(tmpData.example, tmpData.default); if(isEmpty(paramType)) { paramType = getNotEmptyStr(tmpData.type); } addRequestParamObj(responsesJson, prop, paramType, "", required, paramDesc, example); } } else if(isNotEmpty(tmpData.$ref)) {// 对象 if(prevRef != tmpData.$ref) { var tempObj = definitionsDataMap.get(tmpData.$ref); responsesJson[prop] = getRequestParamObj(tempObj, tmpData.$ref); } else { var required = haveString(requiredArr, prop); var paramType = getNotEmptyStr(tmpData.format); var paramDesc = getNotEmptyStr(tmpData.description); var example = getNotEmptyStr(tmpData.example, tmpData.default); if(isEmpty(paramType)) { paramType = getNotEmptyStr(tmpData.type); } addRequestParamObj(responsesJson, prop, paramType, "", required, paramDesc, example); } } else {// 字段 var required = haveString(requiredArr, prop); var paramType = getNotEmptyStr(tmpData.format); var paramDesc = getNotEmptyStr(tmpData.description); var example = getNotEmptyStr(tmpData.example, tmpData.default); if(isEmpty(paramType)) { paramType = getNotEmptyStr(tmpData.type); } addRequestParamObj(responsesJson, prop, paramType, "", required, paramDesc, example); } }); return responsesJson; } /** * 通过原始json生成引用的字典Map * @param json swagger的原始json * @returns */ function createDefinitionsMapByJson(json) { var pathIndex = {}; var definitions = json.definitions; //console.log(paths); if(isNotEmpty(definitions)) { Object.keys(definitions).forEach(function(key){ //console.log(key); definitionsDataMap.set("#/definitions/" + key, definitions[key]); }); } } /** * 修改左右框架的宽度 * @param width 左侧导航栏的宽度 * @returns */ function changeContentWidth(width) { $("#leftContent").css("width", width + 'px'); $("#resizebleLeftRight").css("left", width + 'px'); $("#rightContent").css("left", width + 'px'); var logoText = "swagger-mg-ui"; if(width < 270 && width > 140){ logoText = "mg-ui"; } else if(width < 140){ logoText = "mui"; } $("#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 += "
邮箱:" + getNotEmptyStr(info.contact.email, "-"); contactName += "
网站:" + getNotEmptyStr(info.contact.url, "-"); } $("#homePageDashboard section").append( '
' +'
' +'
' +'
'+info.title+'
' +'
' +'
' +'
' +'
' +'' +'' +'' +'' +'' +'' +'' +'' +'' +'' +'' +'' +'' //+'' // +'' // +'' //+'' +'
简介'+info.description+'
作者'+contactName+'
版本'+info.version+'
地址'+fullUrl+'
' +'
' +'
' +'
' +'
' ); } /** * 初始化用户的设置 * @param * @returns */ function documentLoadFinish() { showGlobalLoadingMessage('文档解析完成!', false); setTimeout(function() { globalLoadingMessager.hide(); }, 1000); $('#apiPathTree .projects').tree(); $('#homePageDashboard').dashboard({draggable: true}); } /** * 修改用户的选项的显示 * @param * @returns */ function updateUserSettingsUi() { $("input[name='treeShowType'][value='"+userSettings.treeShowType+"']").prop("checked",true); $("input[name='catalogShowType'][value='"+userSettings.catalogShowType+"']").prop("checked",true); $("input[name='showParamType'][value='"+userSettings.showParamType+"']").prop("checked",true); $("input[name='onlyUseLastParam'][value='"+userSettings.onlyUseLastParam+"']").prop("checked",true); $("input[name='autoFillParam'][value='"+userSettings.autoFillParam+"']").prop("checked",true); } /** * 修改树形菜单展示类型 * @param * @returns */ function updateTreeShowType() { $('#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); } } function showGlobalLoadingMessage(text, loading) { if(loading) { text += ''; } globalLoadingMessager.$.find(".messager-content").html(text); }