From 02463a852146bfd9483bfcee8373c4dc3844df05 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sat, 1 Dec 2018 23:48:53 +0800 Subject: [PATCH 001/818] =?UTF-8?q?=E8=87=AA=E5=8A=A8=E5=8C=96=E6=B3=A8?= =?UTF-8?q?=E9=87=8A=EF=BC=9A=E6=96=B0=E5=A2=9E=E8=BF=9E=E7=BB=AD=E8=8C=83?= =?UTF-8?q?=E5=9B=B4%=EF=BC=9B=E6=AD=A3=E5=88=99=E7=AC=A6=E5=8F=B7=3F?= =?UTF-8?q?=E6=9B=BF=E6=8D=A2=E4=B8=BA~=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apijson/CodeUtil.js | 10 +++++++++- apijson/JSONResponse.js | 2 +- index.html | 8 ++++---- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/apijson/CodeUtil.js b/apijson/CodeUtil.js index 6776f14..76bac3d 100644 --- a/apijson/CodeUtil.js +++ b/apijson/CodeUtil.js @@ -1028,9 +1028,17 @@ var CodeUtil = { fun = '模糊搜索'; key = columnName.substring(0, columnName.length - 1); } - else if (columnName.endsWith("?")) {//匹配正则表达式,查询时处理 + else if (columnName.endsWith("~")) {//匹配正则表达式,查询时处理 fun = '正则匹配'; key = columnName.substring(0, columnName.length - 1); + if (key.endsWith("*")) { + key = key.substring(0, key.length - 1); + fun += '(忽略大小写)'; + } + } + else if (columnName.endsWith("%")) {//连续范围 BETWEEN AND,查询时处理 + fun = '连续范围'; + key = columnName.substring(0, columnName.length - 1); } else if (columnName.endsWith("{}")) {//被包含,或者说key对应值处于value的范围内。查询时处理 fun = '匹配 选项/条件'; diff --git a/apijson/JSONResponse.js b/apijson/JSONResponse.js index 7305f99..6d5e353 100644 --- a/apijson/JSONResponse.js +++ b/apijson/JSONResponse.js @@ -184,7 +184,7 @@ var JSONResponse = { first = false; } - while (index >=0) + while (index >= 0); return name; }, diff --git a/index.html b/index.html index dc6bce9..8039e57 100755 --- a/index.html +++ b/index.html @@ -1,10 +1,10 @@ - APIJSON.org + APIJSONAuto机器学习测试、自动生成代码、自动静态检查、自动生成文档与注释等,做最先进的接口管理平台。 - - + + @@ -580,7 +580,7 @@ try { var hm = document.createElement("script"); hm.src = "https://hm.baidu.com/hm.js?b8fc421d7c0dc354c6c8fb5a2c4f7729"; //cn - // hm.src = "https://hm.baidu.com/hm.js?965ec968d2d53b729b90efc7ffb3ead2"; //org +// hm.src = "https://hm.baidu.com/hm.js?965ec968d2d53b729b90efc7ffb3ead2"; //org var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(hm, s); } catch (e) { From feb4df33d0b596c9c6993fc729427d1d95cc06be Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sun, 2 Dec 2018 00:43:59 +0800 Subject: [PATCH 002/818] =?UTF-8?q?=E8=87=AA=E5=8A=A8=E7=94=9F=E6=88=90Jav?= =?UTF-8?q?a=E5=B0=81=E8=A3=85=E4=B8=8E=E8=A7=A3=E6=9E=90JSON=E7=9A=84?= =?UTF-8?q?=E4=BB=A3=E7=A0=81:=E8=A7=A3=E5=86=B3=E6=9F=90=E4=BA=9B?= =?UTF-8?q?=E6=83=85=E5=86=B5=E4=B8=8B=E7=94=9F=E6=88=90=E7=9A=84=E5=8F=98?= =?UTF-8?q?=E9=87=8F=E5=90=8D=E4=B8=8D=E5=90=88=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apijson/CodeUtil.js | 10 +-- apijson/JSONResponse.js | 133 +++++++++++++++++++++++++++++----------- 2 files changed, 103 insertions(+), 40 deletions(-) diff --git a/apijson/CodeUtil.js b/apijson/CodeUtil.js index 76bac3d..83a1b4b 100644 --- a/apijson/CodeUtil.js +++ b/apijson/CodeUtil.js @@ -159,7 +159,7 @@ var CodeUtil = { depth = 0; } - const parentKey = JSONObject.isArrayKey(name) ? JSONResponse.getSimpleName(CodeUtil.getItemKey(name)) : CodeUtil.getTableKey(JSONResponse.getSimpleName(name)); + const parentKey = JSONObject.isArrayKey(name) ? JSONResponse.getVariableName(CodeUtil.getItemKey(name)) : CodeUtil.getTableKey(JSONResponse.getVariableName(name)); return CodeUtil.parseCode(name, reqObj, { @@ -194,7 +194,7 @@ var CodeUtil = { log(CodeUtil.TAG, 'parseJava for delete >> count = ' + count + '; page = ' + page); - var name = JSONResponse.getSimpleName(CodeUtil.getItemKey(key)); + var name = JSONResponse.getVariableName(CodeUtil.getItemKey(key)); if (isSmart) { var prefix = key.substring(0, key.length - 2); @@ -245,7 +245,7 @@ var CodeUtil = { s += CodeUtil.parseJava(key, value, depth + 1, isTable); - const name = CodeUtil.getTableKey(JSONResponse.getSimpleName(key)); + const name = CodeUtil.getTableKey(JSONResponse.getVariableName(key)); if (isTable) { s = column == null ? s : s + '\n' + name + '.setColumn(' + CodeUtil.getJavaValue(name, key, column) + ');'; s = group == null ? s : s + '\n' + name + '.setGroup(' + CodeUtil.getJavaValue(name, key, group) + ');'; @@ -348,7 +348,7 @@ var CodeUtil = { onParseJSONArray: function (key, value, index) { var padding = '\n' + CodeUtil.getBlank(depth); var innerPadding = padding + CodeUtil.getBlank(1); - var k = JSONResponse.replaceArray(key); + var k = JSONResponse.getVariableName(key); //还有其它字段冲突以及for循环的i冲突,解决不完的,只能让开发者自己抽出函数 var item = StringUtil.addSuffix(k, 'Item'); var type = CodeUtil.getJavaTypeFromJS('item', value[0], false); @@ -381,7 +381,7 @@ var CodeUtil = { onParseJSONObject: function (key, value, index) { var padding = '\n' + CodeUtil.getBlank(depth); - var k = StringUtil.firstCase(JSONResponse.getSimpleName(key)); + var k = JSONResponse.getVariableName(key); var s = '\n' + padding + '//' + key + '<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<'; diff --git a/apijson/JSONResponse.js b/apijson/JSONResponse.js index 6d5e353..006a652 100644 --- a/apijson/JSONResponse.js +++ b/apijson/JSONResponse.js @@ -87,13 +87,13 @@ var JSONResponse = { value = object[key]; if (value instanceof Array) { // JSONArray,遍历来format内部项 - formattedObject[JSONResponse.replaceArray(key)] = JSONResponse.formatArray(value); + formattedObject[JSONResponse.formatArrayKey(key)] = JSONResponse.formatArray(value); } else if (value instanceof Object) { // JSONObject,往下一级提取 - formattedObject[JSONResponse.getSimpleName(key)] = JSONResponse.formatObject(value); + formattedObject[JSONResponse.formatObjectKey(key)] = JSONResponse.formatObject(value); } else { // 其它Object,直接填充 - formattedObject[JSONResponse.getSimpleName(key)] = value; + formattedObject[JSONResponse.formatOtherKey(key)] = value; } } @@ -131,24 +131,6 @@ var JSONResponse = { return formattedArray; }, - /**替换key+KEY_ARRAY为keyList - * @param key - * @return getSimpleName(isArrayKey(key) ? getArrayKey(...) : key) {@link #getSimpleName(String)} - */ - replaceArray: function(key) { - if (JSONObject.isArrayKey(key)) { - key = JSONResponse.getArrayKey(key.substring(0, key.lastIndexOf('[]'))); - } - return JSONResponse.getSimpleName(key); - }, - /**获取列表变量名 - * @param key => getNoBlankString(key) - * @return empty ? "list" : key + "List" 且首字母小写 - */ - getArrayKey: function(key) { - return StringUtil.addSuffix(key, "List"); - }, - /**获取简单名称 * @param fullName name 或 name:alias * @return name => name; name:alias => alias @@ -159,28 +141,110 @@ var JSONResponse = { return index < 0 ? fullName : fullName.substring(0, index); }, - /**获取简单名称 - * @param fullName name 或 name:alias 或 User-name 或 User-name:alias - * @return name => name; name:alias 或 User-name:alias => alias; User-name => userName + /**获取变量名 + * @param fullName + * @return {@link #formatKey(String, boolean, boolean, boolean)} formatColon = true, formatAt = true, formatHyphen = true, firstCase = true */ - getSimpleName: function(fullName) { - //key:alias -> alias - var index = fullName == null ? -1 : fullName.indexOf(":"); + getVariableName(fullName) { + return JSONResponse.formatKey(fullName, true, true, true, true); + }, + + /**格式化数组的名称 key[] => keyList; key:alias[] => aliasList; Table-column[] => tableColumnList + * @param key empty ? "list" : key + "List" 且首字母小写 + * @return {@link #formatKey(String, boolean, boolean, boolean)} formatColon = false, formatAt = false, formatHyphen = true, firstCase = true + */ + formatArrayKey(key) { + if (JSONObject.isArrayKey(key)) { + key = StringUtil.addSuffix(key.substring(0, key.length - 2), "list"); + } + var index = key == null ? -1 : key.indexOf(":"); if (index >= 0) { - return fullName.substring(index + 1); + return key.substring(index + 1); //不处理自定义的 } - var left = index < 0 ? fullName : fullName.substring(0, index); + return JSONResponse.formatKey(key, false, false, true, true); //节约性能,除了表对象 Table-column:alias[] ,一般都符合变量命名规范 + }, + + /**格式化对象的名称 name => name; name:alias => alias + * @param key name 或 name:alias + * @return {@link #formatKey(String, boolean, boolean, boolean)} formatColon = false, formatAt = false, formatHyphen = false, firstCase = true + */ + formatObjectKey(key) { + var index = key == null ? -1 : key.indexOf(":"); + if (index >= 0) { + return key.substring(index + 1); //不处理自定义的 + } + + return JSONResponse.formatKey(key, false, false, false, true); //节约性能,除了表对象 Table:alias ,一般都符合变量命名规范 + }, + + /**格式化普通值的名称 name => name; name:alias => alias + * @param fullName name 或 name:alias + * @return {@link #formatKey(String, boolean, boolean, boolean)} formatColon = false, formatAt = true, formatHyphen = false, firstCase = false + */ + formatOtherKey(fullName) { + return JSONResponse.formatKey(fullName, false, true, false, false); //节约性能,除了关键词 @key ,一般都符合变量命名规范,不符合也原样返回便于调试 + }, + /**格式化名称 + * @param fullName name 或 name:alias + * @param formatAt 去除前缀 @ , @a => a + * @param formatColon 去除分隔符 : , A:b => b + * @param formatHyphen 去除分隔符 - , A-b-cd-Efg => aBCdEfg + * @param firstCase 第一个单词首字母小写,后面的首字母大写, Ab => ab ; A-b-Cd => aBCd + * @return name => name; name:alias => alias + */ + formatKey(fullName, formatColon, formatAt, formatHyphen, firstCase) { + if (fullName == null) { + log(TAG, "formatKey fullName == null >> return null;"); + return null; + } + + if (formatColon) { + fullName = JSONResponse.formatColon(fullName); + } + if (formatAt) { //关键词只去掉前缀,不格式化单词,例如 @a-b 返回 a-b ,最后不会调用 setter + fullName = JSONResponse.formatAt(fullName); + } + if (formatHyphen) { + fullName = JSONResponse.formatHyphen(fullName, firstCase); + } + + return firstCase ? StringUtil.firstCase(fullName) : fullName; //不格式化普通 key:value (value 不为 [], {}) 的 key + }, + + /**"@key" => "key" + * @param key + * @return + */ + formatAt(key) { + return key.startsWith("@") ? key.substring(1) : key; + }, + /**key:alias => alias + * @param key + * @return + */ + formatColon(key) { + var index = key.indexOf(":"); + return index < 0 ? key : key.substring(index + 1); + }, + + /**A-b-cd-Efg => ABCdEfg + * @param key + * @return + */ + formatHyphen(key, firstCase) { var first = true; - var name = ''; + var index; + + var name = ""; var part; do { - index = left.indexOf("-"); - part = index < 0 ? left : left.substring(0, index); + index = key.indexOf("-"); + part = index < 0 ? key : key.substring(0, index); - name += StringUtil.firstCase(part, ! first); - left = left.substring(index + 1); + name += firstCase && first == false ? StringUtil.firstCase(part, true) : part; + key = key.substring(index + 1); first = false; } @@ -190,7 +254,6 @@ var JSONResponse = { }, - COMPARE_NO_STANDARD: -1, COMPARE_EQUAL: 0, COMPARE_KEY_MORE: 1, From 277c511dc404c892f96ebdc958be2976cb83614a Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sun, 2 Dec 2018 01:14:35 +0800 Subject: [PATCH 003/818] =?UTF-8?q?=E8=87=AA=E5=8A=A8=E7=94=9F=E6=88=90?= =?UTF-8?q?=E8=A7=A3=E6=9E=90JSON=E7=9A=84Java=E4=BB=A3=E7=A0=81=EF=BC=9A?= =?UTF-8?q?=E8=A7=A3=E5=86=B3=E9=83=A8=E5=88=86=E7=94=9F=E6=88=90=E7=9A=84?= =?UTF-8?q?=E5=8F=98=E9=87=8F=E5=90=8D=E5=87=BA=E7=8E=B0@=EF=BC=8C-?= =?UTF-8?q?=E7=AD=89=E7=AC=A6=E5=8F=B7=EF=BC=9BJSONResponse=E4=B8=ADformat?= =?UTF-8?q?ArrayKey=E5=92=8CformatObjectKey=E9=83=BD=E5=8E=BB=E5=89=8D?= =?UTF-8?q?=E7=BC=80@?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apijson/CodeUtil.js | 2 +- apijson/JSONResponse.js | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/apijson/CodeUtil.js b/apijson/CodeUtil.js index 83a1b4b..344e4ff 100644 --- a/apijson/CodeUtil.js +++ b/apijson/CodeUtil.js @@ -341,7 +341,7 @@ var CodeUtil = { var type = CodeUtil.getJavaTypeFromJS(key, value, true); - return '\n' + CodeUtil.getBlank(depth) + type + ' ' + key + ' = ' + name + '.get' + return '\n' + CodeUtil.getBlank(depth) + type + ' ' + JSONResponse.getVariableName(key) + ' = ' + name + '.get' + (/[A-Z]/.test(type.substring(0, 1)) ? type : StringUtil.firstCase(type + 'Value', true)) + '("' + key + '");'; }, diff --git a/apijson/JSONResponse.js b/apijson/JSONResponse.js index 006a652..a60610f 100644 --- a/apijson/JSONResponse.js +++ b/apijson/JSONResponse.js @@ -146,12 +146,15 @@ var JSONResponse = { * @return {@link #formatKey(String, boolean, boolean, boolean)} formatColon = true, formatAt = true, formatHyphen = true, firstCase = true */ getVariableName(fullName) { + if (JSONObject.isArrayKey(fullName)) { + fullName = StringUtil.addSuffix(fullName.substring(0, fullName.length - 2), "list"); + } return JSONResponse.formatKey(fullName, true, true, true, true); }, /**格式化数组的名称 key[] => keyList; key:alias[] => aliasList; Table-column[] => tableColumnList * @param key empty ? "list" : key + "List" 且首字母小写 - * @return {@link #formatKey(String, boolean, boolean, boolean)} formatColon = false, formatAt = false, formatHyphen = true, firstCase = true + * @return {@link #formatKey(String, boolean, boolean, boolean)} formatColon = false, formatAt = true, formatHyphen = true, firstCase = true */ formatArrayKey(key) { if (JSONObject.isArrayKey(key)) { @@ -162,12 +165,12 @@ var JSONResponse = { return key.substring(index + 1); //不处理自定义的 } - return JSONResponse.formatKey(key, false, false, true, true); //节约性能,除了表对象 Table-column:alias[] ,一般都符合变量命名规范 + return JSONResponse.formatKey(key, false, true, true, true); //节约性能,除了表对象 Table-column:alias[] ,一般都符合变量命名规范 }, /**格式化对象的名称 name => name; name:alias => alias * @param key name 或 name:alias - * @return {@link #formatKey(String, boolean, boolean, boolean)} formatColon = false, formatAt = false, formatHyphen = false, firstCase = true + * @return {@link #formatKey(String, boolean, boolean, boolean)} formatColon = false, formatAt = true, formatHyphen = false, firstCase = true */ formatObjectKey(key) { var index = key == null ? -1 : key.indexOf(":"); @@ -175,7 +178,7 @@ var JSONResponse = { return key.substring(index + 1); //不处理自定义的 } - return JSONResponse.formatKey(key, false, false, false, true); //节约性能,除了表对象 Table:alias ,一般都符合变量命名规范 + return JSONResponse.formatKey(key, false, true, false, true); //节约性能,除了表对象 Table:alias ,一般都符合变量命名规范 }, /**格式化普通值的名称 name => name; name:alias => alias From 8aa018582efb30cd963fa5d31e1cd8175c61c219 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sun, 2 Dec 2018 01:20:17 +0800 Subject: [PATCH 004/818] =?UTF-8?q?Response=EF=BC=9A=E4=B8=8D=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F=E5=8C=96=E9=94=99=E8=AF=AF=E7=9A=84=E7=BB=93=E6=9E=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- js/main.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/js/main.js b/js/main.js index 147bd0b..cc9a096 100755 --- a/js/main.js +++ b/js/main.js @@ -1302,11 +1302,11 @@ vOutput.value = "Response:\nurl = " + url + "\nerror = " + err.message; } else { - var json = res.data - if (isSingle) { - json = JSONResponse.formatObject(json); + var data = res.data + if (isSingle && data.code == 200) { //不格式化错误的结果 + data = JSONResponse.formatObject(data); } - App.jsoncon = JSON.stringify(json, null, ' '); + App.jsoncon = JSON.stringify(data, null, ' '); App.view = 'code'; vOutput.value = ''; } From 15fa76a58752a7efa5b9577cb4785b2ce15e9204 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sun, 2 Dec 2018 01:21:39 +0800 Subject: [PATCH 005/818] =?UTF-8?q?=E9=81=BF=E5=85=8D=E5=8F=AF=E8=83=BD?= =?UTF-8?q?=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- js/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/main.js b/js/main.js index cc9a096..bd1ac18 100755 --- a/js/main.js +++ b/js/main.js @@ -1302,7 +1302,7 @@ vOutput.value = "Response:\nurl = " + url + "\nerror = " + err.message; } else { - var data = res.data + var data = res.data || {} if (isSingle && data.code == 200) { //不格式化错误的结果 data = JSONResponse.formatObject(data); } From 428a0d44b47a1f4a1d82261d28173754a6a8c7de Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sun, 2 Dec 2018 02:16:45 +0800 Subject: [PATCH 006/818] =?UTF-8?q?=E6=B5=8B=E8=AF=95=E7=94=A8=E4=BE=8B?= =?UTF-8?q?=EF=BC=9A=E6=96=B0=E5=A2=9E=E5=85=89=E6=A0=87=E6=82=AC=E5=81=9C?= =?UTF-8?q?=E5=90=8E=E6=98=BE=E7=A4=BA=E8=AF=B7=E6=B1=82JSON?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.html | 2 +- js/main.js | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/index.html b/index.html index 8039e57..f4622ac 100755 --- a/index.html +++ b/index.html @@ -132,7 +132,7 @@
+ + + + + 退出 From 905fdd3c4c3728751f557d37260c2c4bcd27977a Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sat, 26 Jan 2019 23:07:42 +0800 Subject: [PATCH 021/818] =?UTF-8?q?=E8=87=AA=E5=8A=A8=E7=94=9F=E6=88=90?= =?UTF-8?q?=E6=96=87=E6=A1=A3:=E6=9D=83=E9=99=90Access=E6=96=B0=E5=A2=9Esc?= =?UTF-8?q?hema=E6=98=BE=E7=A4=BA=E5=B9=B6=E5=9C=A8=E5=8F=B3=E4=BE=A7?= =?UTF-8?q?=E5=AF=B9=E7=A7=B0=E6=96=B0=E5=A2=9E=20=E8=A1=A8=E5=90=8D(Schem?= =?UTF-8?q?a)=20=E6=96=B9=E4=BE=BF=E9=98=85=E8=AF=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- js/main.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/js/main.js b/js/main.js index bb2f18e..9885e6f 100755 --- a/js/main.js +++ b/js/main.js @@ -1422,7 +1422,7 @@ 'Access[]': { 'count': 0, 'Access': { - '@column': 'name,alias,get,head,gets,heads,post,put,delete', + '@column': 'schema,name,alias,get,head,gets,heads,post,put,delete', '@order': 'date-,name+', 'name()': 'getWithDefault(alias,name)', 'r0()': 'removeKey(alias)' @@ -1523,8 +1523,8 @@ log('getDoc Access[] = \n' + format(JSON.stringify(list))); doc += '\n\n\n\n\n\n\n\n\n### 访问权限' - + ' \n 表名 | 允许 get 的角色 | 允许 head 的角色 | 允许 gets 的角色 | 允许 heads 的角色 | 允许 post 的角色 | 允许 put 的角色 | 允许 delete 的角色' - + ' \n -------- | -------------- | -------------- | -------------- | -------------- | -------------- | -------------- | -------------- '; + + ' \n 表名(Schema) | 允许 get 的角色 | 允许 head 的角色 | 允许 gets 的角色 | 允许 heads 的角色 | 允许 post 的角色 | 允许 put 的角色 | 允许 delete 的角色 | 表名(Schema)' + + ' \n -------- | --------- | --------- | --------- | --------- | --------- | --------- | --------- | -------- '; for (var i = 0; i < list.length; i++) { item = list[i]; @@ -1534,14 +1534,15 @@ log('getDoc Access[] for i=' + i + ': item = \n' + format(JSON.stringify(item))); - doc += '\n' + item.name + doc += '\n' + (item.name + '(' + item.schema + ')') + ' | ' + JSONResponse.getShowString(JSON.parse(item.get)) + ' | ' + JSONResponse.getShowString(JSON.parse(item.head)) + ' | ' + JSONResponse.getShowString(JSON.parse(item.gets)) + ' | ' + JSONResponse.getShowString(JSON.parse(item.heads)) + ' | ' + JSONResponse.getShowString(JSON.parse(item.post)) + ' | ' + JSONResponse.getShowString(JSON.parse(item.put)) - + ' | ' + JSONResponse.getShowString(JSON.parse(item.delete)); + + ' | ' + JSONResponse.getShowString(JSON.parse(item.delete)) + + ' | ' + (item.name + '(' + item.schema + ')'); } doc += '\n' //避免没数据时表格显示没有网格 From 00622b5a8acee4a545e2bb9c66c3db63eddcbdae Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sun, 27 Jan 2019 00:28:07 +0800 Subject: [PATCH 022/818] =?UTF-8?q?=E8=87=AA=E5=8A=A8=E7=94=9F=E6=88=90?= =?UTF-8?q?=E6=B3=A8=E9=87=8A:=E6=96=B0=E5=A2=9E=E5=AD=90=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2=E7=9A=84=E6=B3=A8=E9=87=8A=EF=BC=9B=E5=8A=A0=E5=BC=BA?= =?UTF-8?q?@role=EF=BC=8C@database=E5=80=BC=E7=9A=84=E6=A0=A1=E9=AA=8C?= =?UTF-8?q?=EF=BC=8C=E5=A4=A7=E5=B0=8F=E5=86=99=E6=95=8F=E6=84=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apijson/CodeUtil.js | 51 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 42 insertions(+), 9 deletions(-) diff --git a/apijson/CodeUtil.js b/apijson/CodeUtil.js index 344e4ff..a172304 100644 --- a/apijson/CodeUtil.js +++ b/apijson/CodeUtil.js @@ -36,6 +36,7 @@ var CodeUtil = { var depth = 0; var names = []; + var isInSubquery = false; var index; var key; @@ -55,14 +56,19 @@ var CodeUtil = { line = line.trim(); if (line.endsWith('{')) { //对象,判断是不是Table,再加对应的注释 + isInSubquery = key.endsWith('@'); + depth ++; names[depth] = key; - comment = CodeUtil.getComment4Request(tableList, null, key, null, method); + + comment = CodeUtil.getComment4Request(tableList, names[depth - 1], key, null, method, false); } else { if (line.endsWith('}')) { + isInSubquery = false; + if (line.endsWith('{}')) { //对象,判断是不是Table,再加对应的注释 - comment = CodeUtil.getComment4Request(tableList, null, key, null, method); + comment = CodeUtil.getComment4Request(tableList, names[depth], key, null, method, false); } else { depth --; @@ -76,7 +82,7 @@ var CodeUtil = { var isArray = line.endsWith('['); // [] 不影响 // alert('depth = ' + depth + '; line = ' + line + '; isArray = ' + isArray); comment = value == 'null' ? ' ! null无效' : CodeUtil.getComment4Request(tableList, names[depth], key - , isArray ? '' : line.substring(index + 2).trim(), method); + , isArray ? '' : line.substring(index + 2).trim(), method, isInSubquery); } } @@ -830,6 +836,7 @@ var CodeUtil = { QUERY_TYPES: ['数据', '数量', '全部'], + SUBQUERY_RANGES: ['ANY', 'ALL'], QUERY_TYPE_KEYS: [0, 1, 2], QUERY_TYPE_CONSTS: ["JSONRequest.QUERY_TABLE", "JSONRequest.QUERY_TOTAL", "JSONRequest.QUERY_ALL"], REQUEST_ROLE_KEYS: ['UNKNOWN', 'LOGIN', 'CONTACT', 'CIRCLE', 'OWNER', 'ADMIN'], @@ -848,16 +855,29 @@ var CodeUtil = { * @param name * @param key * @param value + * @param isInSubquery */ - getComment4Request: function (tableList, name, key, value, method) { + getComment4Request: function (tableList, name, key, value, method, isInSubquery) { // alert('name = ' + name + '; key = ' + key + '; value = ' + value + '; method = ' + method); if (key == null) { return ''; } + // if (value == null) { + // return ' ! key:value 中 key 或 value 任何一个为 null 时,该 key:value 都无效!' + // } if (value == null || value instanceof Object) { + if (key.endsWith('@')) { + var aliaIndex = name == null ? -1 : name.indexOf(':'); + var objName = aliaIndex < 0 ? name : name.substring(0, aliaIndex); + // if (JSONObject.isTableKey(objName)) { + return CodeUtil.getComment('子查询 < ' + CodeUtil.getCommentFromDoc(tableList, objName, key.substring(0, key.length - 1), method), false, ' '); + // } + // return CodeUtil.getComment('子查询 ' + StringUtil.get(name), false, ' '); + } + if (JSONObject.isArrayKey(key)) { if (method != 'GET') { return ' ! key[]:{}只支持GET方法!'; @@ -887,7 +907,7 @@ var CodeUtil = { return ''; } - if (JSONObject.isArrayKey(name)) { + if (isInSubquery || JSONObject.isArrayKey(name)) { switch (key) { case 'count': return CodeUtil.getType4Request(value) != 'number' ? ' ! value必须是Number类型!' : CodeUtil.getComment('最多数量: 例如 5 10 20 ...', false, ' '); @@ -901,6 +921,19 @@ var CodeUtil = { return StringUtil.isEmpty(query) ? ' ! value必须是[' + CodeUtil.QUERY_TYPE_KEYS.join() + ']中的一种!' : CodeUtil.getComment('查询内容:0-数据 1-总数 2-全部', false, ' '); case 'join': return CodeUtil.getType4Request(value) != 'string' ? ' ! value必须是String类型!' : CodeUtil.getComment('多表连接:例如 &/User/id@, Date: Sun, 27 Jan 2019 00:31:54 +0800 Subject: [PATCH 023/818] =?UTF-8?q?=E8=87=AA=E5=8A=A8=E7=94=9F=E6=88=90?= =?UTF-8?q?=E6=B3=A8=E9=87=8A:=E6=96=B0=E5=A2=9E=E6=98=AF=E5=90=A6?= =?UTF-8?q?=E5=AD=98=E5=9C=A8=E5=88=A4=E6=96=AD=20key}{=20=E7=9A=84?= =?UTF-8?q?=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apijson/CodeUtil.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apijson/CodeUtil.js b/apijson/CodeUtil.js index a172304..52dd856 100644 --- a/apijson/CodeUtil.js +++ b/apijson/CodeUtil.js @@ -1081,6 +1081,10 @@ var CodeUtil = { fun = '包含选项'; key = columnName.substring(0, columnName.length - 2); } + else if (columnName.endsWith("}{")) {//存在,EXISTS。查询时处理 + fun = '是否存在'; + key = columnName.substring(0, columnName.length - 2); + } else if (columnName.endsWith("+")) {//延长,PUT查询时处理 if (method != 'PUT') {//不为PUT就抛异常 return ' ! 功能符 + - 只能用于PUT请求!'; From 5c580f30fcac064090536fcd77daca04e78b4a21 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sun, 27 Jan 2019 00:37:53 +0800 Subject: [PATCH 024/818] =?UTF-8?q?=E8=87=AA=E5=8A=A8=E7=94=9F=E6=88=90?= =?UTF-8?q?=E4=BB=A3=E7=A0=81:=E5=AD=90=E6=9F=A5=E8=AF=A2=20"key@":{}=20?= =?UTF-8?q?=E7=94=9F=E6=88=90=E7=9A=84=E5=8F=98=E9=87=8F=E5=90=8D=E5=8E=BB?= =?UTF-8?q?=E6=8E=89=E5=90=8E=E9=9D=A2=E7=9A=84@,=20=E7=94=B1=20key@=20?= =?UTF-8?q?=E6=94=B9=E4=B8=BA=20key?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apijson/JSONResponse.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apijson/JSONResponse.js b/apijson/JSONResponse.js index 8621488..33b8162 100644 --- a/apijson/JSONResponse.js +++ b/apijson/JSONResponse.js @@ -221,7 +221,8 @@ var JSONResponse = { * @return */ formatAt(key) { - return key.startsWith("@") ? key.substring(1) : key; + var k = key.startsWith("@") ? key.substring(1) : key; + return k.endsWith("@") ? k.substring(0, k.length - 1) : k; }, /**key:alias => alias * @param key From 30539083370ce5f8937194d9e624ee116109734f Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sun, 27 Jan 2019 01:08:29 +0800 Subject: [PATCH 025/818] =?UTF-8?q?=E8=87=AA=E5=8A=A8=E7=94=9F=E6=88=90?= =?UTF-8?q?=E6=B3=A8=E9=87=8A:=E6=96=B0=E5=A2=9E=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E6=9D=A5=E6=BA=90=E7=9A=84=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apijson/CodeUtil.js | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/apijson/CodeUtil.js b/apijson/CodeUtil.js index 52dd856..96c1395 100644 --- a/apijson/CodeUtil.js +++ b/apijson/CodeUtil.js @@ -60,7 +60,7 @@ var CodeUtil = { depth ++; names[depth] = key; - + comment = CodeUtil.getComment4Request(tableList, names[depth - 1], key, null, method, false); } else { @@ -870,12 +870,16 @@ var CodeUtil = { if (value == null || value instanceof Object) { if (key.endsWith('@')) { + if (key == '@from@') { + return CodeUtil.getComment('数据来源:匿名子查询,例如 {"from":"Table", "Table":{}}', false, ' '); + } + var aliaIndex = name == null ? -1 : name.indexOf(':'); var objName = aliaIndex < 0 ? name : name.substring(0, aliaIndex); - // if (JSONObject.isTableKey(objName)) { + if (JSONObject.isTableKey(objName)) { return CodeUtil.getComment('子查询 < ' + CodeUtil.getCommentFromDoc(tableList, objName, key.substring(0, key.length - 1), method), false, ' '); - // } - // return CodeUtil.getComment('子查询 ' + StringUtil.get(name), false, ' '); + } + return CodeUtil.getComment('子查询 ' + StringUtil.get(name) + ",需要被下面的表字段相关 key 引用赋值", false, ' '); } if (JSONObject.isArrayKey(key)) { @@ -945,6 +949,8 @@ var CodeUtil = { switch (key) { case '@column': return CodeUtil.getType4Request(value) != 'string' ? ' ! value必须是String类型!' : CodeUtil.getComment('返回字段:例如 id,name;json_length(contactIdList):contactCount;...', false, ' '); + case '@from@': //value 类型为 Object 时 到不了这里,已在上方处理 + return CodeUtil.getType4Request(value) != 'string' ? ' ! value必须是String或Object类型!' : CodeUtil.getComment('数据来源:引用赋值 子查询 "' + value.substring(1, value.length - 1) + '@":{...} ', false, ' '); case '@group': return CodeUtil.getType4Request(value) != 'string' ? ' ! value必须是String类型!' : CodeUtil.getComment('分组方式:例如 userId,momentId,...', false, ' '); case '@having': From 00a9efc04c9579030158cd009add19546209d4c1 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sun, 27 Jan 2019 01:14:19 +0800 Subject: [PATCH 026/818] =?UTF-8?q?=E8=87=AA=E5=8A=A8=E7=94=9F=E6=88=90?= =?UTF-8?q?=E6=B3=A8=E9=87=8A:=E4=BC=98=E5=8C=96=E5=AD=90=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2=E5=85=B3=E9=94=AE=E8=AF=8D=20from=20=E7=9A=84?= =?UTF-8?q?=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apijson/CodeUtil.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apijson/CodeUtil.js b/apijson/CodeUtil.js index 96c1395..147b812 100644 --- a/apijson/CodeUtil.js +++ b/apijson/CodeUtil.js @@ -934,7 +934,7 @@ var CodeUtil = { } return CodeUtil.SUBQUERY_RANGES.indexOf(value.substring(1, value.length - 1)) <= 0 ? ' ! value必须是[' + CodeUtil.SUBQUERY_RANGES.join() + ']中的一种!' : CodeUtil.getComment('比较范围:ANY-任意 ALL-全部', false, ' '); case 'from': - return CodeUtil.getType4Request(value) != 'string' ? ' ! value必须是String类型!' : CodeUtil.getComment('主表名称:例如 User Comment:to,同一层级必须有对应的 "User": {...}, "Comment:to": {...}', false, ' '); + return CodeUtil.getType4Request(value) != 'string' ? ' ! value必须是String类型!' : CodeUtil.getComment('数据来源:例如 User,同一层级必须有对应的 "User": {...}', false, ' '); } } break; From 04b4ff58dec59c8bbc5a3d017d73736e21d0ebce Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sat, 2 Feb 2019 18:11:51 +0800 Subject: [PATCH 027/818] =?UTF-8?q?=E8=87=AA=E5=8A=A8=E7=94=9F=E6=88=90?= =?UTF-8?q?=E6=B3=A8=E9=87=8A:=E8=A7=A3=E5=86=B3=E5=AF=B9=E5=AD=90?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2range=E6=A0=A1=E9=AA=8CANY=E5=87=BA=E9=94=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apijson/CodeUtil.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apijson/CodeUtil.js b/apijson/CodeUtil.js index 147b812..faf27b1 100644 --- a/apijson/CodeUtil.js +++ b/apijson/CodeUtil.js @@ -932,7 +932,7 @@ var CodeUtil = { if (CodeUtil.getType4Request(value) != 'string') { return ' ! value必须是String类型!'; } - return CodeUtil.SUBQUERY_RANGES.indexOf(value.substring(1, value.length - 1)) <= 0 ? ' ! value必须是[' + CodeUtil.SUBQUERY_RANGES.join() + ']中的一种!' : CodeUtil.getComment('比较范围:ANY-任意 ALL-全部', false, ' '); + return CodeUtil.SUBQUERY_RANGES.indexOf(value.substring(1, value.length - 1)) < 0 ? ' ! value必须是[' + CodeUtil.SUBQUERY_RANGES.join() + ']中的一种!' : CodeUtil.getComment('比较范围:ANY-任意 ALL-全部', false, ' '); case 'from': return CodeUtil.getType4Request(value) != 'string' ? ' ! value必须是String类型!' : CodeUtil.getComment('数据来源:例如 User,同一层级必须有对应的 "User": {...}', false, ' '); } From b55636e1b5e3458cfb7aa0b9153378224e2f86fe Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Mon, 11 Feb 2019 18:35:14 +0800 Subject: [PATCH 028/818] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E5=AF=B9=E8=AF=B7=E6=B1=82=E5=8A=A0=E8=87=AA=E5=AE=9A=E4=B9=89?= =?UTF-8?q?=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- js/main.js | 80 ++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 50 insertions(+), 30 deletions(-) diff --git a/js/main.js b/js/main.js index 9885e6f..bf99163 100755 --- a/js/main.js +++ b/js/main.js @@ -323,15 +323,27 @@ }, //获取请求的tag getTag: function () { - var req = null + var req = null; try { - req = JSON.parse(new String(vInput.value)) + req = this.getRequest(vInput.value); } catch (e) { - log('main.getTag', 'try { req = JSON.parse(new String(vInput.value)) \n } catch (e) {\n' + e.message) + log('main.getTag', 'try { req = this.getRequest(vInput.value); \n } catch (e) {\n' + e.message) } return req == null ? null : req.tag }, + getRequest: function (json) { + var s = App.toDoubleJSON(json); + try { + return jsonlint.parse(s); + } + catch (e) { + log('main.getRequest', 'try { return jsonlint.parse(s); \n } catch (e) {\n' + e.message) + log('main.getRequest', 'return jsonlint.parse(App.removeComment(s));') + return jsonlint.parse(App.removeComment(s)); + } + }, + // 显示保存弹窗 showSave: function (show) { if (show) { @@ -1134,14 +1146,21 @@ before = App.toDoubleJSON(before); log('onHandle before = \n' + before); - before = jsonlint.parse(before); - - before = JSON.stringify(before, null, " "); //用format不能catch! + var after; + try { + after = JSON.stringify(jsonlint.parse(before), null, " "); + before = after; + } + catch (e) { + log('main.onHandle', 'try { return jsonlint.parse(before); \n } catch (e) {\n' + e.message) + log('main.onHandle', 'return jsonlint.parse(App.removeComment(before));') + after = JSON.stringify(jsonlint.parse(App.removeComment(before)), null, " "); + } //关键词let在IE和Safari上不兼容 var code = ''; try { - code = this.getCode(before); //必须在before还是用 " 时使用,后面用会因为解析 ' 导致失败 + code = this.getCode(after); //必须在before还是用 " 时使用,后面用会因为解析 ' 导致失败 } catch(e) { code = '\n\n\n建议:\n使用其它浏览器,例如 谷歌Chrome、火狐FireFox 或者 微软Edge, 因为这样能自动生成请求代码.' + '\nError:\n' + e.message + '\n\n\n'; @@ -1166,7 +1185,7 @@ App.showDoc() try { - vComment.value = isSingle ? '' : CodeUtil.parseComment(before, docObj == null ? null : docObj['[]'], App.getMethod()) + vComment.value = isSingle ? '' : CodeUtil.parseComment(after, docObj == null ? null : docObj['[]'], App.getMethod()) onScrollChanged() } catch (e) { @@ -1209,25 +1228,30 @@ // 删除注释 <<<<<<<<<<<<<<<<<<<<< - var input = new String(vInput.value); + var input = this.removeComment(vInput.value); + if (vInput.value != input) { + vInput.value = input + } + // 删除注释 >>>>>>>>>>>>>>>>>>>>> + + + this.onChange(); + }, + + /** + * 删除注释 + */ + removeComment: function (json) { var reg = /("([^\\\"]*(\\.)?)*")|('([^\\\']*(\\.)?)*')|(\/{2,}.*?(\r|\n))|(\/\*(\n|.)*?\*\/)/g // 正则表达式 try { - input = input.replace(reg, function(word) { // 去除注释后的文本 + return new String(json).replace(reg, function(word) { // 去除注释后的文本 return /^\/{2,}/.test(word) || /^\/\*/.test(word) ? "" : word; }) - - if (vInput.value != input) { - vInput.value = input - } } catch (e) { - log('transfer delete comment in json >> catch \n' + e.message) + log('transfer delete comment in json >> catch \n' + e.message); } - - // 删除注释 >>>>>>>>>>>>>>>>>>>>> - - - this.onChange(); + return json; }, showAndSend: function (url, req, isAdminOperation, callback) { @@ -1249,11 +1273,7 @@ clearTimeout(handler); - var real = new String(vInput.value); - if (real.indexOf("'") >= 0) { - real = real.replace(/'/g, "\""); - } - var req = JSON.parse(real); + var req = this.getRequest(vInput.value); var url = new String(vUrl.value) url = url.replace(/ /g, '') @@ -1274,7 +1294,7 @@ 'userId': App.User.id, 'name': App.formatDateTime() + (StringUtil.isEmpty(req.tag, true) ? '' : ' ' + req.tag), 'url': '/' + method, - 'request': real + 'request': JSON.stringify(req, null, ' ') } }) App.saveCache('', 'locals', this.locals) @@ -1746,7 +1766,7 @@ continue } doc += '\n\n#### ' + (item.version > 0 ? 'V' + item.version : 'V*') + ' ' + item.name + ' ' + item.url - doc += '\n```json\n' + JSON.stringify(JSON.parse(item.request), null, ' ') + '\n```\n' + doc += '\n```json\n' + item.request + '\n```\n' } return doc }, @@ -1815,7 +1835,7 @@ // App.restore(item) // App.onChange(false) - App.request(false, baseUrl + document.url, JSON.parse(document.request), function (url, res, err) { + App.request(false, baseUrl + document.url, App.getRequest(document.request), function (url, res, err) { try { App.onResponse(url, res, err) @@ -2000,7 +2020,7 @@ else { url = App.server + '/post/testrecord/ml' req = { - documentId: document.id + documentId: document.id } } @@ -2032,7 +2052,7 @@ setRequestHint(index, item) { var d = item == null ? null : item.Document; var r = d == null ? null : d.request; - this.$refs.testCaseTexts[index].setAttribute('data-hint', r == null ? '' : JSON.stringify(JSON.parse(r), null, ' ')); + this.$refs.testCaseTexts[index].setAttribute('data-hint', r == null ? '' : JSON.stringify(this.getRequest(r), null, ' ')); }, //显示详细信息, :data-hint :data, :hint 都报错,只能这样 setTestHint(index, item) { From 2e187c6140da0fd21b05738c7870eab5d096c4a0 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sun, 17 Feb 2019 10:56:17 +0800 Subject: [PATCH 029/818] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E4=BB=8E=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E7=94=A8=E4=BE=8B=E5=88=87=E6=8D=A2=E4=B8=BA=E8=BE=93?= =?UTF-8?q?=E5=85=A5=E6=A1=86=E5=90=8E=E6=9C=AA=E6=98=BE=E7=A4=BA=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E7=94=9F=E6=88=90=E7=9A=84=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- js/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/main.js b/js/main.js index bf99163..993ef54 100755 --- a/js/main.js +++ b/js/main.js @@ -1179,7 +1179,7 @@ vInput.value = before; vSend.disabled = false; - vOutput.value = 'OK,请点击 [发送请求] 按钮来测试。[点击这里查看视频教程](http://i.youku.com/apijson)' + code; + vOutput.value = output = 'OK,请点击 [发送请求] 按钮来测试。[点击这里查看视频教程](http://i.youku.com/apijson)' + code; App.showDoc() From 05c864cceb8efcbf8e64993ef3d91c3b132b721e Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sun, 17 Feb 2019 18:30:43 +0800 Subject: [PATCH 030/818] =?UTF-8?q?=E8=A1=A8=E5=92=8C=E5=AD=97=E6=AE=B5?= =?UTF-8?q?=E5=B1=9E=E6=80=A7key=E5=85=A8=E5=B0=8F=E5=86=99=EF=BC=8C?= =?UTF-8?q?=E5=87=86=E5=A4=87=E5=85=BC=E5=AE=B9PostgreSQL=EF=BC=9B?= =?UTF-8?q?=E5=8A=A0=E5=AE=BD=E6=9C=AC=E5=9C=B0=E4=BF=9D=E5=AD=98=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E7=9A=84=E9=80=89=E9=A1=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apijson/CodeUtil.js | 22 +++++++++++----------- index.html | 2 +- js/main.js | 26 +++++++++++++------------- 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/apijson/CodeUtil.js b/apijson/CodeUtil.js index faf27b1..294b810 100644 --- a/apijson/CodeUtil.js +++ b/apijson/CodeUtil.js @@ -502,7 +502,7 @@ var CodeUtil = { //Table table = item == null ? null : item.Table; - model = CodeUtil.getModelName(table == null ? null : table.TABLE_NAME); + model = CodeUtil.getModelName(table == null ? null : table.table_name); if (model != clazz) { continue; } @@ -515,7 +515,7 @@ var CodeUtil = { + '\n\n使用方法\n1.修改包名package \n2.import需要引入的类,可使用快捷键Ctrl+Shift+O ' + '\n*/\n' + '\npackage apijson.demo.server.model;\n\n\n' - + CodeUtil.getComment(table.TABLE_COMMENT, true) + + CodeUtil.getComment(table.table_comment, true) + '\n@MethodAccess' + '\npublic class ' + model + ' implements Serializable {' + '\n private static final long serialVersionUID = 1L;\n'; @@ -532,16 +532,16 @@ var CodeUtil = { for (var j = 0; j < columnList.length; j++) { column = columnList[j]; - name = CodeUtil.getFieldName(column == null ? null : column.COLUMN_NAME); + name = CodeUtil.getFieldName(column == null ? null : column.column_name); if (name == '') { continue; } - type = name == 'id' ? 'Long' : CodeUtil.getJavaType(column.COLUMN_TYPE, false); + type = name == 'id' ? 'Long' : CodeUtil.getJavaType(column.column_type, false); console.log('parseJavaBean [] for j=' + j + ': column = \n' + format(JSON.stringify(column))); - doc += '\n private ' + type + ' ' + name + '; ' + CodeUtil.getComment(column.COLUMN_COMMENT, false); + doc += '\n private ' + type + ' ' + name + '; ' + CodeUtil.getComment(column.column_comment, false); } @@ -559,11 +559,11 @@ var CodeUtil = { for (var j = 0; j < columnList.length; j++) { column = columnList[j]; - name = CodeUtil.getFieldName(column == null ? null : column.COLUMN_NAME); + name = CodeUtil.getFieldName(column == null ? null : column.column_name); if (name == '') { continue; } - type = name == 'id' ? 'Long' : CodeUtil.getJavaType(column.COLUMN_TYPE); + type = name == 'id' ? 'Long' : CodeUtil.getJavaType(column.column_type); console.log('parseJavaBean [] for j=' + j + ': column = \n' + format(JSON.stringify(column))); @@ -1038,13 +1038,13 @@ var CodeUtil = { //Table table = item == null ? null : item.Table; - if (table == null || tableName != CodeUtil.getModelName(table.TABLE_NAME)) { + if (table == null || tableName != CodeUtil.getModelName(table.table_name)) { continue; } log('getDoc [] for i=' + i + ': table = \n' + format(JSON.stringify(table))); if (StringUtil.isEmpty(columnName)) { - return table.TABLE_COMMENT; + return table.table_comment; } @@ -1155,7 +1155,7 @@ var CodeUtil = { var name; for (var j = 0; j < columnList.length; j++) { column = columnList[j]; - name = column == null ? null : column.COLUMN_NAME; + name = column == null ? null : column.column_name; if (name == null || key != name) { continue; } @@ -1163,7 +1163,7 @@ var CodeUtil = { var p = (at.length <= 0 ? '' : at + ' < ') + (fun.length <= 0 ? '' : fun + ' < ') + (logic.length <= 0 ? '' : logic + ' < '); - return (p.length <= 0 ? '' : p + key + ': ') + CodeUtil.getJavaType(column.COLUMN_TYPE, true) + ', ' + column.COLUMN_COMMENT; + return (p.length <= 0 ? '' : p + key + ': ') + CodeUtil.getJavaType(column.column_type, true) + ', ' + column.column_comment; } break; diff --git a/index.html b/index.html index e6c160a..32ce1dd 100755 --- a/index.html +++ b/index.html @@ -207,7 +207,7 @@ -
- +
@@ -150,7 +150,7 @@ {{ crossProcess }} {{ testProcess }} - + @@ -814,7 +814,7 @@ return null; } - var theRequest = {}; + var theRequest = null; var str = url.substring(index + 1); //从第一个字符开始 因为第0个是?号 获取所有除问号的所有符串 var arr = str.split("&"); //截除“&”生成一个数组 @@ -826,6 +826,9 @@ continue } + if (theRequest == null) { + theRequest = {}; + } theRequest[part.substring(0, ind)] = decodeURIComponent(part.substring(ind+1)); } diff --git a/js/main.js b/js/main.js index 1e13482..001ace1 100755 --- a/js/main.js +++ b/js/main.js @@ -528,6 +528,7 @@ testRandomCount: 1, testRandomProcess: '', compareColor: '#0000', + isRandomTest: false, isDelayShow: false, isSaveShow: false, isExportShow: false, @@ -872,6 +873,73 @@ return header }, + // 分享 APIAuto 特有链接,打开即可还原分享人的 JSON 参数、设置项、搜索关键词、分页数量及页码等配置 + shareLink: function (isRandom) { + var jsonStr = null + if (App.isTestCaseShow != true) { + try { + jsonStr = JSON.stringify(encode(JSON.parse(vInput.value))) + } catch (e) { // 可能包含注释 + log(e) + jsonStr = encode(StringUtil.trim(vInput.value)) + } + } + + // URL 太长导致打不开标签 + var settingStr = null + try { + settingStr = JSON.stringify({ + requestVersion: App.requestVersion, + requestCount: App.requestCount, + isTestCaseShow: App.isTestCaseShow, + // isHeaderShow: App.isHeaderShow, + // isRandomShow: App.isRandomShow, + isRandomListShow: App.isRandomShow ? App.isRandomListShow : undefined, + isRandomSubListShow: App.isRandomListShow ? App.isRandomSubListShow : undefined, + // isRandomEditable: App.isRandomEditable, + isCrossEnabled: App.isCrossEnabled, + isMLEnabled: App.isMLEnabled, + isDelegateEnabled: App.isDelegateEnabled, + isPreviewEnabled: App.isPreviewEnabled, + isEncodeEnabled: App.isEncodeEnabled, + isEditResponse: App.isEditResponse, + isLocalShow: App.isTestCaseShow ? App.isLocalShow : undefined, + page: App.page, + count: App.count, + testCasePage: App.testCasePage, + testCaseCount: App.testCaseCount, + randomPage: App.randomPage, + randomCount: App.randomCount, + randomSubPage: App.randomSubPage, + randomSubCount: App.randomSubCount, + host: StringUtil.isEmpty(App.host, true) ? undefined : encodeURIComponent(App.host), + search: StringUtil.isEmpty(App.search, true) ? undefined : encodeURIComponent(App.search), + testCaseSearch: StringUtil.isEmpty(App.testCaseSearch, true) ? undefined : App.testCaseSearch, + randomSearch: StringUtil.isEmpty(App.randomSearch, true) ? undefined : encodeURIComponent(App.randomSearch), + randomSubSearch: StringUtil.isEmpty(App.randomSubSearch, true) ? undefined : encodeURIComponent(App.randomSubSearch) + }) + } catch (e){ + log(e) + } + + var headerStr = App.isTestCaseShow || StringUtil.isEmpty(vHeader.value, true) ? null : encodeURIComponent(StringUtil.trim(vHeader.value)) + var randomStr = App.isTestCaseShow || StringUtil.isEmpty(vRandom.value, true) ? null : encodeURIComponent(StringUtil.trim(vRandom.value)) + + var href = window.location.href || 'http://apijson.cn/api' + var ind = href == null ? -1 : href.indexOf('?') // url 后带参数只能 encodeURIComponent + + // 实测 561059 长度的 URL 都支持,只是输入框显示长度约为 2000 + window.open((ind < 0 ? href : href.substring(0, ind)) + + (App.view != 'code' ? "?send=false" : (isRandom ? "?send=random" : "?send=true")) + + "&type=" + StringUtil.trim(App.type) + + "&url=" + encodeURIComponent(StringUtil.trim(vUrl.value)) + + (StringUtil.isEmpty(jsonStr, true) ? '' : "&json=" + jsonStr) + + (StringUtil.isEmpty(headerStr, true) ? '' : "&header=" + headerStr) + + (StringUtil.isEmpty(randomStr, true) ? '' : "&random=" + randomStr) + + (StringUtil.isEmpty(settingStr, true) ? '' : "&setting=" + settingStr) + ) + }, + // 显示保存弹窗 showSave: function (show) { if (show) { @@ -891,71 +959,18 @@ if (show) { if (isRemote) { //共享测试用例 App.isExportRandom = isRandom + + if (isRandom != true) { + setTimeout(function () { + App.shareLink(App.isRandomTest) + }, 1000) + } + if (App.isTestCaseShow) { alert('请先输入请求内容!') return } - setTimeout(function () { - var href = window.location.href || 'http://apijson.cn/api' - var ind = href == null ? -1 : href.indexOf('?') // url 后带参数只能 encodeURIComponent - var reqStr - try { - reqStr = JSON.stringify(encode(JSON.parse(vInput.value))) - } catch (e){ // 可能包含注释 - log(e) - reqStr = encode(StringUtil.trim(vInput.value)) - } - - // URL 太长导致打不开标签 - var settingStr = null - try { - settingStr = JSON.stringify({ - requestVersion: App.requestVersion, - requestCount: App.requestCount, - isTestCaseShow: App.isTestCaseShow, - // isHeaderShow: App.isHeaderShow, - // isRandomShow: App.isRandomShow, - isRandomListShow: App.isRandomShow ? App.isRandomListShow : undefined, - isRandomSubListShow: App.isRandomListShow ? App.isRandomSubListShow : undefined, - // isRandomEditable: App.isRandomEditable, - isCrossEnabled: App.isCrossEnabled, - isMLEnabled: App.isMLEnabled, - isDelegateEnabled: App.isDelegateEnabled, - isPreviewEnabled: App.isPreviewEnabled, - isEncodeEnabled: App.isEncodeEnabled, - isEditResponse: App.isEditResponse, - isLocalShow: App.isTestCaseShow ? App.isLocalShow : undefined, - page: App.page, - count: App.count, - testCasePage: App.testCasePage, - testCaseCount: App.testCaseCount, - randomPage: App.randomPage, - randomCount: App.randomCount, - randomSubPage: App.randomSubPage, - randomSubCount: App.randomSubCount, - host: StringUtil.isEmpty(App.host, true) ? undefined : encodeURIComponent(App.host), - search: StringUtil.isEmpty(App.search, true) ? undefined : encodeURIComponent(App.search), - testCaseSearch: StringUtil.isEmpty(App.testCaseSearch, true) ? undefined : App.testCaseSearch, - randomSearch: StringUtil.isEmpty(App.randomSearch, true) ? undefined : encodeURIComponent(App.randomSearch), - randomSubSearch: StringUtil.isEmpty(App.randomSubSearch, true) ? undefined : encodeURIComponent(App.randomSubSearch) - }) - } catch (e){ - log(e) - } - - // 实测 561059 长度的 URL 都支持,只是输入框显示长度约为 2000 - window.open((ind < 0 ? href : href.substring(0, ind)) - + (App.view == 'code' ? "?send=true" : "?send=false") - + "&type=" + StringUtil.trim(App.type) - + "&url=" + encodeURIComponent(StringUtil.trim(vUrl.value)) - + "&json=" + reqStr - + (StringUtil.isEmpty(vHeader.value, true) ? '' : "&header=" + encodeURIComponent(StringUtil.trim(vHeader.value))) - + (StringUtil.isEmpty(vRandom.value, true) ? '' : "&random=" + encodeURIComponent(StringUtil.trim(vRandom.value))) - + (StringUtil.isEmpty(settingStr, true) ? '' : "&setting=" + settingStr) - ) - }, 1000) - if (App.view == 'error') { // App.view != 'code') { alert('发现错误,请输入正确的内容!') // alert('请先测试请求,确保是正确可用的!') return @@ -4360,6 +4375,7 @@ * @param show */ onClickTestRandom: function () { + this.isRandomTest = true this.testRandom(! this.isRandomListShow && ! this.isRandomSubListShow, this.isRandomListShow, this.isRandomSubListShow) }, testRandom: function (show, testList, testSubList, limit) { @@ -4886,7 +4902,14 @@ }, - + onClickSend: function () { + this.isRandomTest = false + this.send(false) + }, + onClickTest: function () { + this.isRandomTest = false + this.test(false, this.isCrossEnabled ? -1 : currentAccountIndex) + }, /**回归测试 * 原理: 1.遍历所有上传过的测试用例(URL+请求JSON) @@ -5702,7 +5725,7 @@ setTimeout(function () { var rawReq = getRequestFromURL() - if (rawReq != null && StringUtil.isEmpty(rawReq.json, true) == false) { + if (rawReq != null) { vUrlComment.value = "" vComment.value = "" @@ -5717,6 +5740,10 @@ vUrl.value = StringUtil.trim(rawReq.url) } + if (StringUtil.isEmpty(rawReq.json, true) == false) { + vInput.value = StringUtil.trim(rawReq.json) + } + if (StringUtil.isEmpty(rawReq.header, true) == false) { vHeader.value = StringUtil.trim(rawReq.header, true) App.isHeaderShow = true @@ -5728,8 +5755,6 @@ App.isRandomListShow = false } - vInput.value = StringUtil.trim(rawReq.json) - // URL 太长导致截断和乱码 if (StringUtil.isEmpty(rawReq.setting, true) == false) { @@ -5753,11 +5778,18 @@ } App.onChange(false) - if (rawReq.send != "false") { - App.send(false) + + if (rawReq.send != "false" && rawReq.send != "null") { + if (rawReq.send == 'random') { + App.onClickTestRandom() + } else if (App.isTestCaseShow) { + App.onClickTest() + } else { + App.send(false) + } var url = vUrl.value || '' - if (rawReq.jump == "true" || (rawReq.jump != "false" && (url.endsWith("/get") || url.endsWith("/head")) )) { + if (rawReq.jump == "true" || rawReq.jump == "null" || (rawReq.jump != "false" && (url.endsWith("/get") || url.endsWith("/head")) )) { setTimeout(function () { window.open(vUrl.value + "/" + encodeURIComponent(JSON.stringify(encode(JSON.parse(vInput.value))))) }, 1000) From a1a92c3b94b161a1915be609e1aafef2a32e54e4 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Thu, 30 Sep 2021 02:53:34 +0800 Subject: [PATCH 497/818] =?UTF-8?q?=E5=88=86=E4=BA=AB=EF=BC=9A=E8=A7=A3?= =?UTF-8?q?=E5=86=B3=E5=88=86=E4=BA=AB=E9=93=BE=E6=8E=A5=E6=9C=AA=E5=B8=A6?= =?UTF-8?q?=E4=B8=8A=E9=9A=8F=E6=9C=BA=E6=B5=8B=E8=AF=95=E6=AC=A1=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- js/main.js | 1 + 1 file changed, 1 insertion(+) diff --git a/js/main.js b/js/main.js index 001ace1..4353956 100755 --- a/js/main.js +++ b/js/main.js @@ -908,6 +908,7 @@ count: App.count, testCasePage: App.testCasePage, testCaseCount: App.testCaseCount, + testRandomCount: App.testRandomCount, randomPage: App.randomPage, randomCount: App.randomCount, randomSubPage: App.randomSubPage, From 41af903bf3812c6d92fc015cfe144a77a48fba60 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Thu, 30 Sep 2021 03:22:32 +0800 Subject: [PATCH 498/818] =?UTF-8?q?=E5=88=86=E4=BA=AB=EF=BC=9A=E8=A7=A3?= =?UTF-8?q?=E5=86=B3=E5=88=86=E4=BA=AB=E9=93=BE=E6=8E=A5=E4=B8=AD=20WebSto?= =?UTF-8?q?rm=20=E5=8A=A0=E7=9A=84=E9=9D=9E=20APIAuto=20=E5=8F=82=E6=95=B0?= =?UTF-8?q?=E5=AF=BC=E8=87=B4=20APIAuto=20=E8=87=AA=E5=8A=A8=E8=BF=98?= =?UTF-8?q?=E5=8E=9F=E5=92=8C=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- js/main.js | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/js/main.js b/js/main.js index 4353956..bfe09a4 100755 --- a/js/main.js +++ b/js/main.js @@ -961,7 +961,7 @@ if (isRemote) { //共享测试用例 App.isExportRandom = isRandom - if (isRandom != true) { + if (isRandom != true) { // 分享搜索关键词和分页信息也挺好 } && App.isTestCaseShow != true) { // 没有拿到列表,没用 setTimeout(function () { App.shareLink(App.isRandomTest) }, 1000) @@ -4909,7 +4909,7 @@ }, onClickTest: function () { this.isRandomTest = false - this.test(false, this.isCrossEnabled ? -1 : currentAccountIndex) + this.test(false, this.isCrossEnabled ? -1 : this.currentAccountIndex) }, /**回归测试 * 原理: @@ -5727,10 +5727,10 @@ setTimeout(function () { var rawReq = getRequestFromURL() if (rawReq != null) { - vUrlComment.value = "" - vComment.value = "" + var hasTestArg = false // 避免 http://localhost:63342/APIAuto/index.html?_ijt=fh8di51h7qip2d1s3r3bqn73nt 这种无意义参数 if (StringUtil.isEmpty(rawReq.type, true) == false) { + hasTestArg = true App.type = StringUtil.toUpperCase(rawReq.type, true) if (App.types != null && App.types.indexOf(App.type) < 0) { App.types.push(App.type) @@ -5738,19 +5738,23 @@ } if (StringUtil.isEmpty(rawReq.url, true) == false) { + hasTestArg = true vUrl.value = StringUtil.trim(rawReq.url) } if (StringUtil.isEmpty(rawReq.json, true) == false) { + hasTestArg = true vInput.value = StringUtil.trim(rawReq.json) } if (StringUtil.isEmpty(rawReq.header, true) == false) { + hasTestArg = true vHeader.value = StringUtil.trim(rawReq.header, true) App.isHeaderShow = true } if (StringUtil.isEmpty(rawReq.random, true) == false) { + hasTestArg = true vRandom.value = StringUtil.trim(rawReq.random, true) App.isRandomShow = true App.isRandomListShow = false @@ -5778,9 +5782,14 @@ } } + if (hasTestArg) { + vUrlComment.value = "" + vComment.value = "" + } + App.onChange(false) - if (rawReq.send != "false" && rawReq.send != "null") { + if (hasTestArg && rawReq.send != "false" && rawReq.send != "null") { if (rawReq.send == 'random') { App.onClickTestRandom() } else if (App.isTestCaseShow) { @@ -5793,7 +5802,7 @@ if (rawReq.jump == "true" || rawReq.jump == "null" || (rawReq.jump != "false" && (url.endsWith("/get") || url.endsWith("/head")) )) { setTimeout(function () { window.open(vUrl.value + "/" + encodeURIComponent(JSON.stringify(encode(JSON.parse(vInput.value))))) - }, 1000) + }, App.isTestCaseShow || rawReq.send == 'random' ? 5000 : 2000) } } } From 823ca0e04ffdbf7c62db2fe92079fbba80f30b6e Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Thu, 30 Sep 2021 05:04:55 +0800 Subject: [PATCH 499/818] =?UTF-8?q?=E5=88=86=E4=BA=AB=EF=BC=9A=E8=A7=A3?= =?UTF-8?q?=E5=86=B3=E4=B8=8D=E8=83=BD=E6=88=90=E5=8A=9F=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E6=89=A7=E8=A1=8C=E6=B5=8B=E8=AF=95=E7=94=A8=E4=BE=8B=E5=88=97?= =?UTF-8?q?=E8=A1=A8=E5=9B=9E=E5=BD=92=E6=B5=8B=E8=AF=95=E5=92=8C=E9=9A=8F?= =?UTF-8?q?=E6=9C=BA=E5=88=97=E8=A1=A8=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.html | 29 -------------- js/main.js | 112 ++++++++++++++++++++++++++++++++++++++++------------- 2 files changed, 86 insertions(+), 55 deletions(-) diff --git a/index.html b/index.html index 86f5628..72bcb61 100755 --- a/index.html +++ b/index.html @@ -806,35 +806,6 @@ } - function getRequestFromURL() { - var url = window.location.search; - - var index = url == null ? -1 : url.indexOf("?") - if(index < 0) { //判断是否有参数 - return null; - } - - var theRequest = null; - var str = url.substring(index + 1); //从第一个字符开始 因为第0个是?号 获取所有除问号的所有符串 - var arr = str.split("&"); //截除“&”生成一个数组 - - var len = arr == null ? 0 : arr.length; - for(var i = 0; i < len; i++) { - var part = arr[i]; - var ind = part == null ? -1 : part.indexOf("="); - if (ind <= 0) { - continue - } - - if (theRequest == null) { - theRequest = {}; - } - theRequest[part.substring(0, ind)] = decodeURIComponent(part.substring(ind+1)); - } - - return theRequest; - } - diff --git a/js/main.js b/js/main.js index bfe09a4..373c171 100755 --- a/js/main.js +++ b/js/main.js @@ -363,6 +363,36 @@ // APIJSON <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + + function getRequestFromURL() { + var url = window.location.search; + + var index = url == null ? -1 : url.indexOf("?") + if(index < 0) { //判断是否有参数 + return null; + } + + var theRequest = null; + var str = url.substring(index + 1); //从第一个字符开始 因为第0个是?号 获取所有除问号的所有符串 + var arr = str.split("&"); //截除“&”生成一个数组 + + var len = arr == null ? 0 : arr.length; + for(var i = 0; i < len; i++) { + var part = arr[i]; + var ind = part == null ? -1 : part.indexOf("="); + if (ind <= 0) { + continue + } + + if (theRequest == null) { + theRequest = {}; + } + theRequest[part.substring(0, ind)] = decodeURIComponent(part.substring(ind+1)); + } + + return theRequest; + } + var PLATFORM_POSTMAN = 'POSTMAN' var PLATFORM_SWAGGER = 'SWAGGER' var PLATFORM_YAPI = 'YAPI' @@ -3887,7 +3917,7 @@ var page = this.page || 0 var search = StringUtil.isEmpty(this.search, true) ? null : '%' + StringUtil.trim(this.search) + '%' - App.request(false, REQUEST_TYPE_JSON, this.getBaseUrl() + '/get', { + this.request(false, REQUEST_TYPE_JSON, this.getBaseUrl() + '/get', { format: false, '@database': StringUtil.isEmpty(App.database, true) ? undefined : App.database, // '@schema': StringUtil.isEmpty(App.schema, true) ? undefined : App.schema, @@ -5719,14 +5749,21 @@ '\n} catch (e) {\n' + e.message) } - //无效,只能在index里设置 vUrl.value = this.getCache('', 'URL_BASE') + this.listHistory() - this.transfer() - setTimeout(function () { - var rawReq = getRequestFromURL() - if (rawReq != null) { + var rawReq = getRequestFromURL() + if (rawReq == null || StringUtil.isEmpty(rawReq.type, true)) { + this.transfer() + + if (this.User != null && this.User.id != null && this.User.id > 0) { + this.showTestCase(true, false) // 本地历史仍然要求登录 App.User == null || App.User.id == null) + } + } + else { + setTimeout(function () { + isSingle = ! isSingle var hasTestArg = false // 避免 http://localhost:63342/APIAuto/index.html?_ijt=fh8di51h7qip2d1s3r3bqn73nt 这种无意义参数 if (StringUtil.isEmpty(rawReq.type, true) == false) { @@ -5760,12 +5797,30 @@ App.isRandomListShow = false } - // URL 太长导致截断和乱码 if (StringUtil.isEmpty(rawReq.setting, true) == false) { var save = rawReq.save == 'true' try { - var setting = JSON.parse(StringUtil.trim(rawReq.setting, true)) + var setting = JSON.parse(StringUtil.trim(rawReq.setting, true)) || {} + + var delayTime = 0 + if (setting.count != App.count || setting.page != App.page || setting.search != App.search) { + delayTime += 2000 + App.getDoc(function (d) { + App.setDoc(d); + }) + } + + if (setting.isRandomShow && setting.isRandomListShow) { + delayTime += 2000 + App.showRandomList(true, setting.isRandomSubListShow ? App.currentRandomItem : null, setting.isRandomSubListShow) + } + + if (setting.isTestCaseShow) { + delayTime += 2000 + App.showTestCase(true, setting.isLocalShow) + } + for (var k in setting) { var v = k == null ? null : setting[k] if (v == null) { @@ -5790,26 +5845,31 @@ App.onChange(false) if (hasTestArg && rawReq.send != "false" && rawReq.send != "null") { - if (rawReq.send == 'random') { - App.onClickTestRandom() - } else if (App.isTestCaseShow) { - App.onClickTest() - } else { - App.send(false) - } + setTimeout(function () { + if (rawReq.send == 'random') { + App.onClickTestRandom() + } else if (App.isTestCaseShow) { + App.onClickTest() + } else { + App.send(false) + } - var url = vUrl.value || '' - if (rawReq.jump == "true" || rawReq.jump == "null" || (rawReq.jump != "false" && (url.endsWith("/get") || url.endsWith("/head")) )) { - setTimeout(function () { - window.open(vUrl.value + "/" + encodeURIComponent(JSON.stringify(encode(JSON.parse(vInput.value))))) - }, App.isTestCaseShow || rawReq.send == 'random' ? 5000 : 2000) - } + var url = vUrl.value || '' + if (rawReq.jump == "true" || rawReq.jump == "null" + || (rawReq.jump != "false" && App.isTestCaseShow != true && rawReq.send != 'random' + && (url.endsWith("/get") || url.endsWith("/head")) + ) + ) { + setTimeout(function () { + window.open(vUrl.value + "/" + encodeURIComponent(JSON.stringify(encode(JSON.parse(vInput.value))))) + }, 2000) + } + }, delayTime) } - } - else if (App.User != null && App.User.id != null && App.User.id > 0) { - App.showTestCase(true, false) // 本地历史仍然要求登录 App.User == null || App.User.id == null) - } - }, 1000) + }, 1000) + + } + } }) })() From 49b6764d2487d8de7ed44e226e16655cfa7feb72 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Thu, 30 Sep 2021 05:15:26 +0800 Subject: [PATCH 500/818] =?UTF-8?q?=E5=88=86=E4=BA=AB=EF=BC=9A=E8=A7=A3?= =?UTF-8?q?=E5=86=B3=E8=87=AA=E5=8A=A8=E6=9F=A5=E6=B5=8B=E8=AF=95=E7=94=A8?= =?UTF-8?q?=E4=BE=8B=E5=88=97=E8=A1=A8=E6=9C=AA=E4=BD=BF=E7=94=A8=20URL=20?= =?UTF-8?q?=E6=8F=90=E4=BE=9B=E7=9A=84=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- js/main.js | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/js/main.js b/js/main.js index 373c171..df4f5e0 100755 --- a/js/main.js +++ b/js/main.js @@ -5811,16 +5811,6 @@ }) } - if (setting.isRandomShow && setting.isRandomListShow) { - delayTime += 2000 - App.showRandomList(true, setting.isRandomSubListShow ? App.currentRandomItem : null, setting.isRandomSubListShow) - } - - if (setting.isTestCaseShow) { - delayTime += 2000 - App.showTestCase(true, setting.isLocalShow) - } - for (var k in setting) { var v = k == null ? null : setting[k] if (v == null) { @@ -5832,6 +5822,16 @@ App.saveCache('', k, v) } } + + if (setting.isRandomShow && setting.isRandomListShow) { + delayTime += 2000 + App.showRandomList(true, setting.isRandomSubListShow ? App.currentRandomItem : null, setting.isRandomSubListShow) + } + + if (setting.isTestCaseShow) { + delayTime += 2000 + App.showTestCase(true, setting.isLocalShow) + } } catch (e) { log(e) } From 8f11feec60abc016ef86e76babf217096f968806 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Thu, 7 Oct 2021 01:20:09 +0800 Subject: [PATCH 501/818] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E6=9F=90=E4=BA=9B?= =?UTF-8?q?=E6=83=85=E5=86=B5=E4=B8=8B=E6=89=93=E5=BC=80=E6=8A=A5=E9=94=99?= =?UTF-8?q?=EF=BC=9B=E5=88=86=E4=BA=AB=EF=BC=9A=E8=A7=A3=E5=86=B3=E5=9C=A8?= =?UTF-8?q?=20APIJSON=20GitHub=20=E6=96=87=E6=A1=A3=E4=B8=AD=E8=B7=B3?= =?UTF-8?q?=E8=BD=AC=E8=BF=87=E6=9D=A5=E5=8F=AF=E8=83=BD=E5=9C=A8=E8=AF=B7?= =?UTF-8?q?=E6=B1=82=E6=88=90=E5=8A=9F=E5=90=8E=E5=86=8D=E6=81=A2=E5=A4=8D?= =?UTF-8?q?=E6=98=BE=E7=A4=BA=E4=B8=BA=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- js/main.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/js/main.js b/js/main.js index df4f5e0..68f0534 100755 --- a/js/main.js +++ b/js/main.js @@ -3919,8 +3919,8 @@ var search = StringUtil.isEmpty(this.search, true) ? null : '%' + StringUtil.trim(this.search) + '%' this.request(false, REQUEST_TYPE_JSON, this.getBaseUrl() + '/get', { format: false, - '@database': StringUtil.isEmpty(App.database, true) ? undefined : App.database, - // '@schema': StringUtil.isEmpty(App.schema, true) ? undefined : App.schema, + '@database': StringUtil.isEmpty(this.database, true) ? undefined : this.database, + // '@schema': StringUtil.isEmpty(this.schema, true) ? undefined : this.schema, 'sql@': { 'from': 'Access', 'Access': { @@ -5866,7 +5866,7 @@ } }, delayTime) } - }, 1000) + }, 2000) } From 0faa92a2d18afe07c1cb5941c17a876e58ed56a2 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Thu, 7 Oct 2021 03:24:57 +0800 Subject: [PATCH 502/818] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E6=9C=89=E6=97=B6?= =?UTF-8?q?=E5=90=AF=E5=8A=A8=E6=8A=A5=E9=94=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- js/main.js | 232 +++++++++++++++++++++++++++-------------------------- 1 file changed, 119 insertions(+), 113 deletions(-) diff --git a/js/main.js b/js/main.js index 68f0534..12252af 100755 --- a/js/main.js +++ b/js/main.js @@ -989,44 +989,44 @@ showExport: function (show, isRemote, isRandom) { if (show) { if (isRemote) { //共享测试用例 - App.isExportRandom = isRandom + this.isExportRandom = isRandom if (isRandom != true) { // 分享搜索关键词和分页信息也挺好 } && App.isTestCaseShow != true) { // 没有拿到列表,没用 setTimeout(function () { App.shareLink(App.isRandomTest) }, 1000) } - - if (App.isTestCaseShow) { + + if (this.isTestCaseShow) { alert('请先输入请求内容!') return } - if (App.view == 'error') { // App.view != 'code') { + if (this.view == 'error') { // this.view != 'code') { alert('发现错误,请输入正确的内容!') // alert('请先测试请求,确保是正确可用的!') return } if (isRandom) { - App.exTxt.name = '随机配置 ' + App.formatDateTime() + this.exTxt.name = '随机配置 ' + this.formatDateTime() } else { - if (App.isEditResponse) { - App.isExportRemote = isRemote - App.exportTxt() + if (this.isEditResponse) { + this.isExportRemote = isRemote + this.exportTxt() return } // var tag = App.getTag() - App.exTxt.name = App.urlComment || '' // 避免偷懒不输入名称 App.getMethod() + (StringUtil.isEmpty(tag, true) ? '' : ' ' + tag) + this.exTxt.name = this.urlComment || '' // 避免偷懒不输入名称 App.getMethod() + (StringUtil.isEmpty(tag, true) ? '' : ' ' + tag) } } else { //下载到本地 - if (App.isTestCaseShow) { //文档 - App.exTxt.name = 'APIJSON自动化文档 ' + App.formatDateTime() + if (this.isTestCaseShow) { //文档 + this.exTxt.name = 'APIJSON自动化文档 ' + App.formatDateTime() } - else if (App.view == 'markdown' || App.view == 'output') { + else if (this.view == 'markdown' || this.view == 'output') { var suffix - switch (App.language) { + switch (this.language) { case CodeUtil.LANGUAGE_KOTLIN: suffix = '.kt'; break; @@ -1069,32 +1069,32 @@ break; } - App.exTxt.name = 'User' + suffix + this.exTxt.name = 'User' + suffix alert('自动生成模型代码,可填类名后缀:\n' + 'Kotlin.kt, Java.java, Swift.swift, Objective-C.m, C#.cs, Go.go,' + '\nTypeScript.ts, JavaScript.js, PHP.php, Python.py, C++.cpp'); } else { - App.exTxt.name = 'APIJSON测试 ' + App.getMethod() + ' ' + App.formatDateTime() + this.exTxt.name = 'APIJSON测试 ' + this.getMethod() + ' ' + this.formatDateTime() } } } - App.isExportShow = show - App.isExportRemote = isRemote + this.isExportShow = show + this.isExportRemote = isRemote }, // 显示配置弹窗 showConfig: function (show, index) { - App.isConfigShow = false - if (App.isTestCaseShow) { + this.isConfigShow = false + if (this.isTestCaseShow) { if (index == 3 || index == 4 || index == 5 || index == 10) { - App.showTestCase(false, false) + this.showTestCase(false, false) } } if (show) { - App.exTxt.button = index == 8 ? '上传' : '切换' - App.exTxt.index = index + this.exTxt.button = index == 8 ? '上传' : '切换' + this.exTxt.index = index switch (index) { case 0: case 1: @@ -1102,9 +1102,9 @@ case 6: case 7: case 8: - App.exTxt.name = index == 0 ? App.database : (index == 1 ? App.schema : (index == 2 - ? App.language : (index == 6 ? App.server : (index == 8 ? App.thirdParty : (App.types || []).join())))) - App.isConfigShow = true + this.exTxt.name = index == 0 ? this.database : (index == 1 ? this.schema : (index == 2 + ? this.language : (index == 6 ? this.server : (index == 8 ? this.thirdParty : (this.types || []).join())))) + this.isConfigShow = true if (index == 0) { alert('可填数据库:\nMYSQL,POSTGRESQL,SQLSERVER,ORACLE,DB2,SQLITE') @@ -1116,12 +1116,12 @@ alert('多个类型用 , 隔开,可填类型:\nPARAM(GET ?a=1&b=c&key=value),\nJSON(POST application/json),\nFORM(POST x-www-form-urlencoded),\nDATA(POST form-data),\nGRPC(POST application/json 需要 GRPC 服务开启反射)') } else if (index == 8) { - App.isHeaderShow = true + this.isHeaderShow = true alert('例如:\nSWAGGER http://apijson.cn:8080/v2/api-docs\nSWAGGER /v2/api-docs // 省略 Host\nSWAGGER / // 省略 Host 和 分支 URL\nRAP /repository/joined /repository/get\nYAPI /api/interface/list_menu /api/interface/get') try { - App.getThirdPartyApiList(this.thirdParty, function (platform, docUrl, listUrl, itemUrl, url_, res, err) { + this.getThirdPartyApiList(this.thirdParty, function (platform, docUrl, listUrl, itemUrl, url_, res, err) { CodeUtil.thirdParty = platform if (err != null || ((res || {}).data || {}).errCode != 0) { App.isHeaderShow = true @@ -1182,89 +1182,89 @@ } break case 3: - App.host = App.getBaseUrl() - App.showUrl(false, new String(vUrl.value).substring(App.host.length)) //没必要导致必须重新获取 Response,App.onChange(false) + this.host = this.getBaseUrl() + this.showUrl(false, new String(vUrl.value).substring(this.host.length)) //没必要导致必须重新获取 Response,App.onChange(false) break case 4: - App.isHeaderShow = show - App.saveCache('', 'isHeaderShow', show) + this.isHeaderShow = show + this.saveCache('', 'isHeaderShow', show) break case 5: - App.isRandomShow = show - App.saveCache('', 'isRandomShow', show) + this.isRandomShow = show + this.saveCache('', 'isRandomShow', show) break case 9: - App.isDelegateEnabled = show - App.saveCache('', 'isDelegateEnabled', show) + this.isDelegateEnabled = show + this.saveCache('', 'isDelegateEnabled', show) break case 10: - App.isPreviewEnabled = show - App.saveCache('', 'isPreviewEnabled', show) + this.isPreviewEnabled = show + this.saveCache('', 'isPreviewEnabled', show) - App.onChange(false) + this.onChange(false) break case 12: - App.isEncodeEnabled = show - App.saveCache('', 'isEncodeEnabled', show) + this.isEncodeEnabled = show + this.saveCache('', 'isEncodeEnabled', show) break case 11: - var did = ((App.currentRemoteItem || {}).Document || {}).id + var did = ((this.currentRemoteItem || {}).Document || {}).id if (did == null) { alert('请先选择一个已上传的用例!') return } - App.isEditResponse = show + this.isEditResponse = show // App.saveCache('', 'isEditResponse', show) - vInput.value = ((App.view != 'code' || StringUtil.isEmpty(App.jsoncon, true) ? null : App.jsoncon) - || (App.currentRemoteItem.TestRecord || {}).response) || '' + vInput.value = ((this.view != 'code' || StringUtil.isEmpty(this.jsoncon, true) ? null : this.jsoncon) + || (this.currentRemoteItem.TestRecord || {}).response) || '' - vHeader.value = (App.currentRemoteItem.TestRecord || {}).header || '' + vHeader.value = (this.currentRemoteItem.TestRecord || {}).header || '' - App.isTestCaseShow = false - App.onChange(false) + this.isTestCaseShow = false + this.onChange(false) break } } else if (index == 3) { - var host = StringUtil.get(App.host) + var host = StringUtil.get(this.host) var branch = new String(vUrl.value) - App.host = '' + this.host = '' vUrl.value = host + branch //保证 showUrl 里拿到的 baseUrl = App.host (http://apijson.cn:8080/put /balance) - App.setBaseUrl() //保证自动化测试等拿到的 baseUrl 是最新的 - App.showUrl(false, branch) //没必要导致必须重新获取 Response,App.onChange(false) + this.setBaseUrl() //保证自动化测试等拿到的 baseUrl 是最新的 + this.showUrl(false, branch) //没必要导致必须重新获取 Response,App.onChange(false) } else if (index == 4) { - App.isHeaderShow = show - App.saveCache('', 'isHeaderShow', show) + this.isHeaderShow = show + this.saveCache('', 'isHeaderShow', show) } else if (index == 5) { - App.isRandomShow = show - App.saveCache('', 'isRandomShow', show) + this.isRandomShow = show + this.saveCache('', 'isRandomShow', show) } else if (index == 9) { - App.isDelegateEnabled = show - App.saveCache('', 'isDelegateEnabled', show) + this.isDelegateEnabled = show + this.saveCache('', 'isDelegateEnabled', show) } else if (index == 10) { - App.isPreviewEnabled = show - App.saveCache('', 'isPreviewEnabled', show) + this.isPreviewEnabled = show + this.saveCache('', 'isPreviewEnabled', show) // vRequestMarkdown.innerHTML = '' } else if (index == 12) { - App.isEncodeEnabled = show - App.saveCache('', 'isEncodeEnabled', show) + this.isEncodeEnabled = show + this.saveCache('', 'isEncodeEnabled', show) } else if (index == 11) { - App.isEditResponse = show + this.isEditResponse = show // App.saveCache('', 'isEditResponse', show) - vInput.value = (App.currentRemoteItem.Document || {}).request || '' - vHeader.value = (App.currentRemoteItem.Document || {}).header || '' + vInput.value = (this.currentRemoteItem.Document || {}).request || '' + vHeader.value = (this.currentRemoteItem.Document || {}).header || '' - App.isTestCaseShow = false - App.onChange(false) + this.isTestCaseShow = false + this.onChange(false) } }, @@ -2560,7 +2560,7 @@ onClickAccount: function (index, item, callback) { - App.isTestCaseShow = false + this.isTestCaseShow = false if (this.currentAccountIndex == index) { if (item == null) { @@ -2643,21 +2643,21 @@ }, removeAccountTab: function () { - if (App.accounts.length <= 1) { + if (this.accounts.length <= 1) { alert('至少要 1 个测试账号!') return } - App.accounts.splice(App.currentAccountIndex, 1) - if (App.currentAccountIndex >= App.accounts.length) { - App.currentAccountIndex = App.accounts.length - 1 + this.accounts.splice(this.currentAccountIndex, 1) + if (this.currentAccountIndex >= this.accounts.length) { + this.currentAccountIndex = this.accounts.length - 1 } - App.saveCache(App.getBaseUrl(), 'currentAccountIndex', App.currentAccountIndex) - App.saveCache(App.getBaseUrl(), 'accounts', App.accounts) + this.saveCache(this.getBaseUrl(), 'currentAccountIndex', this.currentAccountIndex) + this.saveCache(this.getBaseUrl(), 'accounts', this.accounts) }, addAccountTab: function () { - App.showLogin(true, false) + this.showLogin(true, false) }, @@ -2698,7 +2698,7 @@ this.isTestCaseShow = false - var types = App.types + var types = this.types var search = StringUtil.isEmpty(this.testCaseSearch, true) ? null : '%' + StringUtil.trim(this.testCaseSearch) + '%' var url = this.server + '/get' var req = { @@ -2708,7 +2708,7 @@ 'page': this.testCasePage || 0, 'Document': { '@order': 'version-,date-', - 'userId': App.User.id, + 'userId': this.User.id, 'name$': search, 'url$': search, '@combine': search == null ? null : 'name$,url$', @@ -2716,19 +2716,19 @@ }, 'TestRecord': { 'documentId@': '/Document/id', - 'userId': App.User.id, - 'testAccountId': App.getCurrentAccountId(), + 'userId': this.User.id, + 'testAccountId': this.getCurrentAccountId(), 'randomId': 0, '@order': 'date-', - '@column': 'id,userId,documentId,duration,minDuration,maxDuration,response' + (App.isMLEnabled ? ',standard' : ''), - '@having': App.isMLEnabled ? 'length(standard)>2' : null //用 MySQL 5.6 '@having': App.isMLEnabled ? 'json_length(standard)>0' : null + '@column': 'id,userId,documentId,duration,minDuration,maxDuration,response' + (this.isMLEnabled ? ',standard' : ''), + '@having': this.isMLEnabled ? 'length(standard)>2' : null //用 MySQL 5.6 '@having': this.isMLEnabled ? 'json_length(standard)>0' : null } }, '@role': 'LOGIN' } - App.onChange(false) - App.request(true, REQUEST_TYPE_JSON, url, req, {}, function (url, res, err) { + this.onChange(false) + this.request(true, REQUEST_TYPE_JSON, url, req, {}, function (url, res, err) { App.onResponse(url, res, err) var rpObj = res.data @@ -3169,7 +3169,7 @@ return; } - App.view = 'output'; + this.view = 'output'; vComment.value = ''; // vUrlComment.value = ''; vOutput.value = 'resolving...'; @@ -3184,7 +3184,7 @@ throw new Error(e2.message) } - before = App.toDoubleJSON(StringUtil.trim(before)); + before = this.toDoubleJSON(StringUtil.trim(before)); log('onHandle before = \n' + before); var afterObj; @@ -3199,7 +3199,7 @@ log('main.onHandle', 'return jsonlint.parse(App.removeComment(before));') try { - afterObj = jsonlint.parse(App.removeComment(before)); + afterObj = jsonlint.parse(this.removeComment(before)); after = JSON.stringify(afterObj, null, " "); } catch (e2) { throw new Error('请求 JSON 格式错误!请检查并编辑请求!\n\n如果JSON中有注释,请 手动删除 或 点击左边的 \'/" 按钮 来去掉。\n\n' + e2.message) @@ -3208,7 +3208,7 @@ //关键词let在IE和Safari上不兼容 var code = ''; - if (App.isEditResponse != true) { + if (this.isEditResponse != true) { try { code = this.getCode(after); //必须在before还是用 " 时使用,后面用会因为解析 ' 导致失败 } catch (e) { @@ -3233,22 +3233,22 @@ + ' \n'; //解决遮挡 vSend.disabled = false; - if (App.isEditResponse != true) { + if (this.isEditResponse != true) { vOutput.value = output = 'OK,请点击 [发送请求] 按钮来测试。[点击这里查看视频教程](https://i.youku.com/i/UNTg1NzI1MjQ4MA==/videos?spm=a2hzp.8244740.0.0)' + code; - App.showDoc() + this.showDoc() } try { var standardObj = null; try { - standardObj = JSON.parse(((App.currentRemoteItem || {})[App.isEditResponse ? 'TestRecord' : 'Document'] || {}).standard); + standardObj = JSON.parse(((this.currentRemoteItem || {})[this.isEditResponse ? 'TestRecord' : 'Document'] || {}).standard); } catch (e3) { log(e3) } - var m = App.getMethod(); - var c = isSingle ? '' : StringUtil.trim(CodeUtil.parseComment(after, docObj == null ? null : docObj['[]'], m, App.database, App.language, App.isEditResponse != true, standardObj)) + var m = this.getMethod(); + var c = isSingle ? '' : StringUtil.trim(CodeUtil.parseComment(after, docObj == null ? null : docObj['[]'], m, this.database, this.language, this.isEditResponse != true, standardObj)) + '\n ' + ' \n'; //解决遮挡 //TODO 统计行数,补全到一致 vInput.value.lineNumbers @@ -3260,12 +3260,12 @@ } } vComment.value = c - vUrlComment.value = isSingle || StringUtil.isEmpty(App.urlComment, true) - ? '' : vUrl.value + CodeUtil.getComment(App.urlComment, false, ' ') - + ' - ' + (App.requestVersion > 0 ? 'V' + App.requestVersion : 'V*'); + vUrlComment.value = isSingle || StringUtil.isEmpty(this.urlComment, true) + ? '' : vUrl.value + CodeUtil.getComment(this.urlComment, false, ' ') + + ' - ' + (this.requestVersion > 0 ? 'V' + this.requestVersion : 'V*'); if (! isSingle) { - var method = App.getMethod(); // m 已经 toUpperCase 了 + var method = this.getMethod(); // m 已经 toUpperCase 了 var isRestful = ! JSONObject.isAPIJSONPath(method); if (isRestful != true) { method = method.toUpperCase(); @@ -3274,8 +3274,8 @@ var api = apiMap == null ? null : apiMap['/' + method]; var name = api == null ? null : api.name; if (StringUtil.isEmpty(name, true) == false) { - App.urlComment = name; - vUrlComment.value = vUrl.value + CodeUtil.getComment(App.urlComment, false, ' ') + this.urlComment = name; + vUrlComment.value = vUrl.value + CodeUtil.getComment(this.urlComment, false, ' ') } } @@ -3300,17 +3300,17 @@ log(e3) } - if (App.isEditResponse) { - App.view = 'code'; - App.jsoncon = after + if (this.isEditResponse) { + this.view = 'code'; + this.jsoncon = after } } catch(e) { log(e) vSend.disabled = true - App.view = 'error' - App.error = { + this.view = 'error' + this.error = { msg: e.message } } @@ -3329,9 +3329,13 @@ this.isDelayShow = delay; - handler = setTimeout(function () { - App.onHandle(inputted); - }, delay ? 2*1000 : 0); + if (delay) { + handler = setTimeout(function () { + App.onHandle(inputted); + }, 2000); + } else { + this.onHandle(inputted); + } }, /**单双引号切换 @@ -3517,7 +3521,7 @@ axios({ method: (type == REQUEST_TYPE_PARAM ? 'get' : 'post'), url: (isAdminOperation == false && this.isDelegateEnabled ? (this.server + '/delegate?' + (type == REQUEST_TYPE_GRPC ? '$_type=GRPC&' : '') + '$_delegate_url=') : '' ) - + (App.isEncodeEnabled ? encodeURI(StringUtil.noBlank(url)) : StringUtil.noBlank(url)), + + (this.isEncodeEnabled ? encodeURI(StringUtil.noBlank(url)) : StringUtil.noBlank(url)), params: (type == REQUEST_TYPE_PARAM || type == REQUEST_TYPE_FORM ? req : null), data: (type == REQUEST_TYPE_JSON || type == REQUEST_TYPE_GRPC ? req : (type == REQUEST_TYPE_DATA ? toFormData(req) : null)), headers: header, //Accept-Encoding(HTTP Header 大小写不敏感,SpringBoot 接收后自动转小写)可能导致 Response 乱码 @@ -3902,7 +3906,7 @@ + '



' ); - App.view = 'markdown'; + this.view = 'markdown'; markdownToHTML(vOutput.value); return true; }, @@ -5803,9 +5807,11 @@ try { var setting = JSON.parse(StringUtil.trim(rawReq.setting, true)) || {} - var delayTime = 0 - if (setting.count != App.count || setting.page != App.page || setting.search != App.search) { - delayTime += 2000 + if ((setting.count != null && setting.count != App.count) + || (setting.page != null && setting.page != App.page) + || (setting.search != null && setting.search != App.search)) { + delayTime += Math.min(5000, 30*(setting.count) + 1000) + App.setDoc(""); App.getDoc(function (d) { App.setDoc(d); }) @@ -5824,12 +5830,12 @@ } if (setting.isRandomShow && setting.isRandomListShow) { - delayTime += 2000 + delayTime += Math.min(5000, 20*(setting.randomCount || App.randomCount) + 1000) App.showRandomList(true, setting.isRandomSubListShow ? App.currentRandomItem : null, setting.isRandomSubListShow) } if (setting.isTestCaseShow) { - delayTime += 2000 + delayTime += Math.min(5000, 10*(setting.testCaseCount || App.testCaseCount) + 1000) App.showTestCase(true, setting.isLocalShow) } } catch (e) { @@ -5864,7 +5870,7 @@ window.open(vUrl.value + "/" + encodeURIComponent(JSON.stringify(encode(JSON.parse(vInput.value))))) }, 2000) } - }, delayTime) + }, Math.max(1000, delayTime)) } }, 2000) From 60d0b13106258ee5932f1da247c288c43a2952d5 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Thu, 7 Oct 2021 04:06:12 +0800 Subject: [PATCH 503/818] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E6=9C=89=E6=97=B6?= =?UTF-8?q?=E5=90=AF=E5=8A=A8=E6=8A=A5=E9=94=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- js/main.js | 616 +++++++++++++++++++++++++++-------------------------- 1 file changed, 309 insertions(+), 307 deletions(-) diff --git a/js/main.js b/js/main.js index 12252af..a867156 100755 --- a/js/main.js +++ b/js/main.js @@ -651,7 +651,7 @@ // 全部展开 expandAll: function () { - if (App.view != 'code') { + if (this.view != 'code') { alert('请先获取正确的JSON Response!') return } @@ -661,12 +661,12 @@ $('.expand-view').show() $('.fold-view').hide() - App.isExpand = true; + this.isExpand = true; }, // 全部折叠 collapseAll: function () { - if (App.view != 'code') { + if (this.view != 'code') { alert('请先获取正确的JSON Response!') return } @@ -676,29 +676,29 @@ $('.expand-view').hide() $('.fold-view').show() - App.isExpand = false; + this.isExpand = false; }, // diff diffTwo: function () { var oldJSON = {} var newJSON = {} - App.view = 'code' + this.view = 'code' try { - oldJSON = jsonlint.parse(App.jsoncon) + oldJSON = jsonlint.parse(this.jsoncon) } catch (ex) { - App.view = 'error' - App.error = { + this.view = 'error' + this.error = { msg: '原 JSON 解析错误\r\n' + ex.message } return } try { - newJSON = jsonlint.parse(App.jsoncon) + newJSON = jsonlint.parse(this.jsoncon) } catch (ex) { - App.view = 'error' - App.error = { + this.view = 'error' + this.error = { msg: '新 JSON 解析错误\r\n' + ex.message } return @@ -720,33 +720,33 @@ }, baseViewToDiff: function () { - App.baseview = 'diff' - App.diffTwo() + this.baseview = 'diff' + this.diffTwo() }, // 回到格式化视图 baseViewToFormater: function () { - App.baseview = 'formater' - App.view = 'code' - App.showJsonView() + this.baseview = 'formater' + this.view = 'code' + this.showJsonView() }, // 根据json内容变化格式化视图 showJsonView: function () { - if (App.baseview === 'diff') { + if (this.baseview === 'diff') { return } try { if (this.jsoncon.trim() === '') { - App.view = 'empty' + this.view = 'empty' } else { - App.view = 'code' + this.view = 'code' if (isSingle) { - App.jsonhtml = jsonlint.parse(this.jsoncon) + this.jsonhtml = jsonlint.parse(this.jsoncon) } else { - App.jsonhtml = Object.assign({ + this.jsonhtml = Object.assign({ _$_this_$_: JSON.stringify({ path: null, table: null @@ -756,8 +756,8 @@ } } catch (ex) { - App.view = 'error' - App.error = { + this.view = 'error' + this.error = { msg: ex.message } } @@ -769,18 +769,18 @@ if (isAdminOperation != true) { baseUrl = this.getBaseUrl() } - vUrl.value = (isAdminOperation ? App.server : baseUrl) + branchUrl + vUrl.value = (isAdminOperation ? this.server : baseUrl) + branchUrl } else { //隐藏(固定)URL Host if (isAdminOperation) { - this.host = App.server + this.host = this.server } vUrl.value = branchUrl } - vUrlComment.value = isSingle || StringUtil.isEmpty(App.urlComment, true) - ? '' : vUrl.value + CodeUtil.getComment(App.urlComment, false, ' ') - + ' - ' + (App.requestVersion > 0 ? 'V' + App.requestVersion : 'V*'); + vUrlComment.value = isSingle || StringUtil.isEmpty(this.urlComment, true) + ? '' : vUrl.value + CodeUtil.getComment(this.urlComment, false, ' ') + + ' - ' + (this.requestVersion > 0 ? 'V' + this.requestVersion : 'V*'); }, //设置基地址 @@ -800,7 +800,7 @@ // this.remotes = [] // var index = baseUrl.indexOf(':') //http://localhost:8080 - // App.server = (index < 0 ? baseUrl : baseUrl.substring(0, baseUrl)) + ':9090' + // this.server = (index < 0 ? baseUrl : baseUrl.substring(0, baseUrl)) + ':9090' } }, @@ -849,7 +849,7 @@ }, getRequest: function (json, defaultValue) { - var s = App.toDoubleJSON(json, defaultValue); + var s = this.toDoubleJSON(json, defaultValue); if (StringUtil.isEmpty(s, true)) { return defaultValue } @@ -858,8 +858,8 @@ } catch (e) { log('main.getRequest', 'try { return jsonlint.parse(s); \n } catch (e) {\n' + e.message) - log('main.getRequest', 'return jsonlint.parse(App.removeComment(s));') - return jsonlint.parse(App.removeComment(s)); + log('main.getRequest', 'return jsonlint.parse(this.removeComment(s));') + return jsonlint.parse(this.removeComment(s)); } }, getHeader: function (text) { @@ -892,7 +892,7 @@ val = eval(val) } catch (e) { - App.log("getHeader if (hs != null && hs.length > 0) { ... if (ind > 0 && val.indexOf(')') > ind) { ... try { val = eval(val) } catch (e) = " + e.message) + this.log("getHeader if (hs != null && hs.length > 0) { ... if (ind > 0 && val.indexOf(')') > ind) { ... try { val = eval(val) } catch (e) = " + e.message) } } @@ -906,7 +906,7 @@ // 分享 APIAuto 特有链接,打开即可还原分享人的 JSON 参数、设置项、搜索关键词、分页数量及页码等配置 shareLink: function (isRandom) { var jsonStr = null - if (App.isTestCaseShow != true) { + if (this.isTestCaseShow != true) { try { jsonStr = JSON.stringify(encode(JSON.parse(vInput.value))) } catch (e) { // 可能包含注释 @@ -919,50 +919,50 @@ var settingStr = null try { settingStr = JSON.stringify({ - requestVersion: App.requestVersion, - requestCount: App.requestCount, - isTestCaseShow: App.isTestCaseShow, - // isHeaderShow: App.isHeaderShow, - // isRandomShow: App.isRandomShow, - isRandomListShow: App.isRandomShow ? App.isRandomListShow : undefined, - isRandomSubListShow: App.isRandomListShow ? App.isRandomSubListShow : undefined, - // isRandomEditable: App.isRandomEditable, - isCrossEnabled: App.isCrossEnabled, - isMLEnabled: App.isMLEnabled, - isDelegateEnabled: App.isDelegateEnabled, - isPreviewEnabled: App.isPreviewEnabled, - isEncodeEnabled: App.isEncodeEnabled, - isEditResponse: App.isEditResponse, - isLocalShow: App.isTestCaseShow ? App.isLocalShow : undefined, - page: App.page, - count: App.count, - testCasePage: App.testCasePage, - testCaseCount: App.testCaseCount, - testRandomCount: App.testRandomCount, - randomPage: App.randomPage, - randomCount: App.randomCount, - randomSubPage: App.randomSubPage, - randomSubCount: App.randomSubCount, - host: StringUtil.isEmpty(App.host, true) ? undefined : encodeURIComponent(App.host), - search: StringUtil.isEmpty(App.search, true) ? undefined : encodeURIComponent(App.search), - testCaseSearch: StringUtil.isEmpty(App.testCaseSearch, true) ? undefined : App.testCaseSearch, - randomSearch: StringUtil.isEmpty(App.randomSearch, true) ? undefined : encodeURIComponent(App.randomSearch), - randomSubSearch: StringUtil.isEmpty(App.randomSubSearch, true) ? undefined : encodeURIComponent(App.randomSubSearch) + requestVersion: this.requestVersion, + requestCount: this.requestCount, + isTestCaseShow: this.isTestCaseShow, + // isHeaderShow: this.isHeaderShow, + // isRandomShow: this.isRandomShow, + isRandomListShow: this.isRandomShow ? this.isRandomListShow : undefined, + isRandomSubListShow: this.isRandomListShow ? this.isRandomSubListShow : undefined, + // isRandomEditable: this.isRandomEditable, + isCrossEnabled: this.isCrossEnabled, + isMLEnabled: this.isMLEnabled, + isDelegateEnabled: this.isDelegateEnabled, + isPreviewEnabled: this.isPreviewEnabled, + isEncodeEnabled: this.isEncodeEnabled, + isEditResponse: this.isEditResponse, + isLocalShow: this.isTestCaseShow ? this.isLocalShow : undefined, + page: this.page, + count: this.count, + testCasePage: this.testCasePage, + testCaseCount: this.testCaseCount, + testRandomCount: this.testRandomCount, + randomPage: this.randomPage, + randomCount: this.randomCount, + randomSubPage: this.randomSubPage, + randomSubCount: this.randomSubCount, + host: StringUtil.isEmpty(this.host, true) ? undefined : encodeURIComponent(this.host), + search: StringUtil.isEmpty(this.search, true) ? undefined : encodeURIComponent(this.search), + testCaseSearch: StringUtil.isEmpty(this.testCaseSearch, true) ? undefined : this.testCaseSearch, + randomSearch: StringUtil.isEmpty(this.randomSearch, true) ? undefined : encodeURIComponent(this.randomSearch), + randomSubSearch: StringUtil.isEmpty(this.randomSubSearch, true) ? undefined : encodeURIComponent(this.randomSubSearch) }) } catch (e){ log(e) } - var headerStr = App.isTestCaseShow || StringUtil.isEmpty(vHeader.value, true) ? null : encodeURIComponent(StringUtil.trim(vHeader.value)) - var randomStr = App.isTestCaseShow || StringUtil.isEmpty(vRandom.value, true) ? null : encodeURIComponent(StringUtil.trim(vRandom.value)) + var headerStr = this.isTestCaseShow || StringUtil.isEmpty(vHeader.value, true) ? null : encodeURIComponent(StringUtil.trim(vHeader.value)) + var randomStr = this.isTestCaseShow || StringUtil.isEmpty(vRandom.value, true) ? null : encodeURIComponent(StringUtil.trim(vRandom.value)) var href = window.location.href || 'http://apijson.cn/api' var ind = href == null ? -1 : href.indexOf('?') // url 后带参数只能 encodeURIComponent // 实测 561059 长度的 URL 都支持,只是输入框显示长度约为 2000 window.open((ind < 0 ? href : href.substring(0, ind)) - + (App.view != 'code' ? "?send=false" : (isRandom ? "?send=random" : "?send=true")) - + "&type=" + StringUtil.trim(App.type) + + (this.view != 'code' ? "?send=false" : (isRandom ? "?send=random" : "?send=true")) + + "&type=" + StringUtil.trim(this.type) + "&url=" + encodeURIComponent(StringUtil.trim(vUrl.value)) + (StringUtil.isEmpty(jsonStr, true) ? '' : "&json=" + jsonStr) + (StringUtil.isEmpty(headerStr, true) ? '' : "&header=" + headerStr) @@ -974,15 +974,15 @@ // 显示保存弹窗 showSave: function (show) { if (show) { - if (App.isTestCaseShow) { + if (this.isTestCaseShow) { alert('请先输入请求内容!') return } - var tag = App.getTag() - App.history.name = (App.urlComment || App.getMethod() + (StringUtil.isEmpty(tag, true) ? '' : ' ' + tag)) + ' ' + App.formatTime() //不自定义名称的都是临时的,不需要时间太详细 + var tag = this.getTag() + this.history.name = (this.urlComment || this.getMethod() + (StringUtil.isEmpty(tag, true) ? '' : ' ' + tag)) + ' ' + this.formatTime() //不自定义名称的都是临时的,不需要时间太详细 } - App.isSaveShow = show + this.isSaveShow = show }, // 显示导出弹窗 @@ -991,7 +991,7 @@ if (isRemote) { //共享测试用例 this.isExportRandom = isRandom - if (isRandom != true) { // 分享搜索关键词和分页信息也挺好 } && App.isTestCaseShow != true) { // 没有拿到列表,没用 + if (isRandom != true) { // 分享搜索关键词和分页信息也挺好 } && this.isTestCaseShow != true) { // 没有拿到列表,没用 setTimeout(function () { App.shareLink(App.isRandomTest) }, 1000) @@ -1016,13 +1016,13 @@ return } - // var tag = App.getTag() - this.exTxt.name = this.urlComment || '' // 避免偷懒不输入名称 App.getMethod() + (StringUtil.isEmpty(tag, true) ? '' : ' ' + tag) + // var tag = this.getTag() + this.exTxt.name = this.urlComment || '' // 避免偷懒不输入名称 this.getMethod() + (StringUtil.isEmpty(tag, true) ? '' : ' ' + tag) } } else { //下载到本地 if (this.isTestCaseShow) { //文档 - this.exTxt.name = 'APIJSON自动化文档 ' + App.formatDateTime() + this.exTxt.name = 'APIJSON自动化文档 ' + this.formatDateTime() } else if (this.view == 'markdown' || this.view == 'output') { var suffix @@ -1183,7 +1183,7 @@ break case 3: this.host = this.getBaseUrl() - this.showUrl(false, new String(vUrl.value).substring(this.host.length)) //没必要导致必须重新获取 Response,App.onChange(false) + this.showUrl(false, new String(vUrl.value).substring(this.host.length)) //没必要导致必须重新获取 Response,this.onChange(false) break case 4: this.isHeaderShow = show @@ -1215,7 +1215,7 @@ } this.isEditResponse = show - // App.saveCache('', 'isEditResponse', show) + // this.saveCache('', 'isEditResponse', show) vInput.value = ((this.view != 'code' || StringUtil.isEmpty(this.jsoncon, true) ? null : this.jsoncon) || (this.currentRemoteItem.TestRecord || {}).response) || '' @@ -1231,9 +1231,9 @@ var host = StringUtil.get(this.host) var branch = new String(vUrl.value) this.host = '' - vUrl.value = host + branch //保证 showUrl 里拿到的 baseUrl = App.host (http://apijson.cn:8080/put /balance) + vUrl.value = host + branch //保证 showUrl 里拿到的 baseUrl = this.host (http://apijson.cn:8080/put /balance) this.setBaseUrl() //保证自动化测试等拿到的 baseUrl 是最新的 - this.showUrl(false, branch) //没必要导致必须重新获取 Response,App.onChange(false) + this.showUrl(false, branch) //没必要导致必须重新获取 Response,this.onChange(false) } else if (index == 4) { this.isHeaderShow = show @@ -1258,7 +1258,7 @@ } else if (index == 11) { this.isEditResponse = show - // App.saveCache('', 'isEditResponse', show) + // this.saveCache('', 'isEditResponse', show) vInput.value = (this.currentRemoteItem.Document || {}).request || '' vHeader.value = (this.currentRemoteItem.Document || {}).header || '' @@ -1346,16 +1346,16 @@ // 保存当前的JSON save: function () { - if (App.history.name.trim() === '') { + if (this.history.name.trim() === '') { Helper.alert('名称不能为空!', 'danger') return } var val = { - name: App.history.name, - type: App.type, + name: this.history.name, + type: this.type, url: '/' + this.getMethod(), request: inputted, - response: App.jsoncon, + response: this.jsoncon, header: vHeader.value, random: vRandom.value } @@ -1407,8 +1407,8 @@ var response = ((item || {}).TestRecord || {}).response if (StringUtil.isEmpty(response, true) == false) { - App.jsoncon = StringUtil.trim(response) - App.view = 'code' + this.jsoncon = StringUtil.trim(response) + this.view = 'code' } }, // 根据测试用例/历史记录恢复数据 @@ -1423,7 +1423,7 @@ }, // 根据历史恢复数据 restore: function (item, response, isRemote, test) { - App.isEditResponse = false + this.isEditResponse = false item = item || {} // localforage.getItem(item.key || '', function (err, value) { @@ -1432,24 +1432,24 @@ branch = '/' + branch } - App.type = item.type; - App.urlComment = item.name; - App.requestVersion = item.version; - App.showUrl(false, branch) + this.type = item.type; + this.urlComment = item.name; + this.requestVersion = item.version; + this.showUrl(false, branch) - App.showTestCase(false, App.isLocalShow) + this.showTestCase(false, this.isLocalShow) vInput.value = StringUtil.get(item.request) vHeader.value = StringUtil.get(item.header) vRandom.value = StringUtil.get(item.random) - App.onChange(false) + this.onChange(false) if (isRemote) { - App.randoms = [] - App.showRandomList(App.isRandomListShow, item) + this.randoms = [] + this.showRandomList(this.isRandomListShow, item) } if (test) { - App.send(false) + this.send(false) } else { if (StringUtil.isEmpty(response, true) == false) { @@ -1479,53 +1479,53 @@ // 导出文本 exportTxt: function () { - App.isExportShow = false + this.isExportShow = false - if (App.isExportRemote == false) { //下载到本地 + if (this.isExportRemote == false) { //下载到本地 - if (App.isTestCaseShow) { //文档 - saveTextAs('# ' + App.exTxt.name + '\n主页: https://github.com/Tencent/APIJSON' + if (this.isTestCaseShow) { //文档 + saveTextAs('# ' + this.exTxt.name + '\n主页: https://github.com/Tencent/APIJSON' + '\n\nBASE_URL: ' + this.getBaseUrl() - + '\n\n\n## 测试用例(Markdown格式,可用工具预览) \n\n' + App.getDoc4TestCase() + + '\n\n\n## 测试用例(Markdown格式,可用工具预览) \n\n' + this.getDoc4TestCase() + '\n\n\n\n\n\n\n\n## 文档(Markdown格式,可用工具预览) \n\n' + doc - , App.exTxt.name + '.txt') + , this.exTxt.name + '.txt') } - else if (App.view == 'markdown' || App.view == 'output') { //model - var clazz = StringUtil.trim(App.exTxt.name) + else if (this.view == 'markdown' || this.view == 'output') { //model + var clazz = StringUtil.trim(this.exTxt.name) var txt = '' //配合下面 +=,实现注释判断,一次全生成,方便测试 if (clazz.endsWith('.java')) { - txt += CodeUtil.parseJavaBean(docObj, clazz.substring(0, clazz.length - 5), App.database) + txt += CodeUtil.parseJavaBean(docObj, clazz.substring(0, clazz.length - 5), this.database) } else if (clazz.endsWith('.swift')) { - txt += CodeUtil.parseSwiftStruct(docObj, clazz.substring(0, clazz.length - 6), App.database) + txt += CodeUtil.parseSwiftStruct(docObj, clazz.substring(0, clazz.length - 6), this.database) } else if (clazz.endsWith('.kt')) { - txt += CodeUtil.parseKotlinDataClass(docObj, clazz.substring(0, clazz.length - 3), App.database) + txt += CodeUtil.parseKotlinDataClass(docObj, clazz.substring(0, clazz.length - 3), this.database) } else if (clazz.endsWith('.m')) { - txt += CodeUtil.parseObjectiveCEntity(docObj, clazz.substring(0, clazz.length - 2), App.database) + txt += CodeUtil.parseObjectiveCEntity(docObj, clazz.substring(0, clazz.length - 2), this.database) } else if (clazz.endsWith('.cs')) { - txt += CodeUtil.parseCSharpEntity(docObj, clazz.substring(0, clazz.length - 3), App.database) + txt += CodeUtil.parseCSharpEntity(docObj, clazz.substring(0, clazz.length - 3), this.database) } else if (clazz.endsWith('.php')) { - txt += CodeUtil.parsePHPEntity(docObj, clazz.substring(0, clazz.length - 4), App.database) + txt += CodeUtil.parsePHPEntity(docObj, clazz.substring(0, clazz.length - 4), this.database) } else if (clazz.endsWith('.go')) { - txt += CodeUtil.parseGoEntity(docObj, clazz.substring(0, clazz.length - 3), App.database) + txt += CodeUtil.parseGoEntity(docObj, clazz.substring(0, clazz.length - 3), this.database) } else if (clazz.endsWith('.cpp')) { - txt += CodeUtil.parseCppStruct(docObj, clazz.substring(0, clazz.length - 4), App.database) + txt += CodeUtil.parseCppStruct(docObj, clazz.substring(0, clazz.length - 4), this.database) } else if (clazz.endsWith('.js')) { - txt += CodeUtil.parseJavaScriptEntity(docObj, clazz.substring(0, clazz.length - 3), App.database) + txt += CodeUtil.parseJavaScriptEntity(docObj, clazz.substring(0, clazz.length - 3), this.database) } else if (clazz.endsWith('.ts')) { - txt += CodeUtil.parseTypeScriptEntity(docObj, clazz.substring(0, clazz.length - 3), App.database) + txt += CodeUtil.parseTypeScriptEntity(docObj, clazz.substring(0, clazz.length - 3), this.database) } else if (clazz.endsWith('.py')) { - txt += CodeUtil.parsePythonEntity(docObj, clazz.substring(0, clazz.length - 3), App.database) + txt += CodeUtil.parsePythonEntity(docObj, clazz.substring(0, clazz.length - 3), this.database) } else { alert('请正确输入对应语言的类名后缀!') @@ -1538,11 +1538,11 @@ saveTextAs(txt, clazz) } else { - var res = JSON.parse(App.jsoncon) + var res = JSON.parse(this.jsoncon) res = this.removeDebugInfo(res) var s = '' - switch (App.language) { + switch (this.language) { case CodeUtil.LANGUAGE_KOTLIN: s += '(Kotlin):\n\n' + CodeUtil.parseKotlinResponse('', res, 0, false, ! isSingle) break; @@ -1585,51 +1585,51 @@ break; } - saveTextAs('# ' + App.exTxt.name + '\n主页: https://github.com/Tencent/APIJSON' + saveTextAs('# ' + this.exTxt.name + '\n主页: https://github.com/Tencent/APIJSON' + '\n\n\nURL: ' + StringUtil.get(vUrl.value) + '\n\n\nHeader:\n' + StringUtil.get(vHeader.value) + '\n\n\nRequest:\n' + StringUtil.get(vInput.value) - + '\n\n\nResponse:\n' + StringUtil.get(App.jsoncon) + + '\n\n\nResponse:\n' + StringUtil.get(this.jsoncon) + '\n\n\n## 解析 Response 的代码' + s - , App.exTxt.name + '.txt') + , this.exTxt.name + '.txt') } } else { //上传到远程服务器 - var id = App.User == null ? null : App.User.id + var id = this.User == null ? null : this.User.id if (id == null || id <= 0) { alert('请先登录!') return } - var isExportRandom = App.isExportRandom + var isExportRandom = this.isExportRandom - if (isExportRandom != true && StringUtil.isEmpty(App.exTxt.name, true)) { + if (isExportRandom != true && StringUtil.isEmpty(this.exTxt.name, true)) { alert('请输入接口名!') return } - var doc = (App.currentRemoteItem || {}).Document || {} - var tr = (App.currentRemoteItem || {}).TestRecord || {} + var doc = (this.currentRemoteItem || {}).Document || {} + var tr = (this.currentRemoteItem || {}).TestRecord || {} var did = doc.id if (isExportRandom && did == null) { alert('请先共享测试用例!') return } - App.isTestCaseShow = false + this.isTestCaseShow = false - var currentAccountId = App.getCurrentAccountId() - var currentResponse = App.view != 'code' || StringUtil.isEmpty(App.jsoncon, true) ? {} : App.removeDebugInfo(JSON.parse(App.jsoncon)); + var currentAccountId = this.getCurrentAccountId() + var currentResponse = this.view != 'code' || StringUtil.isEmpty(this.jsoncon, true) ? {} : this.removeDebugInfo(JSON.parse(this.jsoncon)); - var after = App.toDoubleJSON(inputted); - var inputObj = App.getRequest(after, {}); + var after = this.toDoubleJSON(inputted); + var inputObj = this.getRequest(after, {}); var commentObj = null; if (isExportRandom != true) { - var m = App.getMethod(); + var m = this.getMethod(); var commentStddObj = null try { - commentStddObj = JSON.parse(App.isEditResponse ? tr.standard : doc.standard); + commentStddObj = JSON.parse(this.isEditResponse ? tr.standard : doc.standard); } catch(e) { log(e) @@ -1638,7 +1638,7 @@ inputObj.code = null // delete inputObj.code commentObj = JSONResponse.updateStandard(commentStddObj, inputObj); - CodeUtil.parseComment(after, docObj == null ? null : docObj['[]'], m, App.database, App.language, true, commentObj, true); + CodeUtil.parseComment(after, docObj == null ? null : docObj['[]'], m, this.database, this.language, true, commentObj, true); inputObj.code = code_ } @@ -1648,21 +1648,21 @@ delete currentResponse.code; //code必须一致 delete currentResponse.throw; //throw必须一致 - var isML = App.isMLEnabled; + var isML = this.isMLEnabled; var stddObj = isML ? JSONResponse.updateStandard({}, currentResponse) : {}; stddObj.code = code; stddObj.throw = thrw; currentResponse.code = code; currentResponse.throw = thrw; - var url = App.server + (isExportRandom || App.isEditResponse || did == null ? '/post' : '/put') + var url = this.server + (isExportRandom || this.isEditResponse || did == null ? '/post' : '/put') var req = isExportRandom ? { format: false, 'Random': { toId: 0, documentId: did, - count: App.requestCount, - name: App.exTxt.name, + count: this.requestCount, + name: this.exTxt.name, config: vRandom.value }, 'TestRecord': { @@ -1672,28 +1672,28 @@ 'tag': 'Random' } : { format: false, - 'Document': App.isEditResponse ? null : { + 'Document': this.isEditResponse ? null : { 'id': did == null ? undefined : did, 'testAccountId': currentAccountId, - 'name': App.exTxt.name, - 'type': App.type, - 'url': '/' + App.getMethod(), + 'name': this.exTxt.name, + 'type': this.type, + 'url': '/' + this.getMethod(), 'request': JSON.stringify(inputObj, null, ' '), 'standard': JSON.stringify(commentObj, null, ' '), 'header': vHeader.value }, - 'TestRecord': App.isEditResponse != true && did != null ? null : { - 'documentId': App.isEditResponse ? did : undefined, + 'TestRecord': this.isEditResponse != true && did != null ? null : { + 'documentId': this.isEditResponse ? did : undefined, 'randomId': 0, - 'host': App.getBaseUrl(), + 'host': this.getBaseUrl(), 'testAccountId': currentAccountId, - 'response': JSON.stringify(App.isEditResponse ? inputObj : currentResponse), - 'standard': isML || App.isEditResponse ? JSON.stringify(App.isEditResponse ? commentObj : stddObj) : undefined + 'response': JSON.stringify(this.isEditResponse ? inputObj : currentResponse), + 'standard': isML || this.isEditResponse ? JSON.stringify(this.isEditResponse ? commentObj : stddObj) : undefined }, - 'tag': App.isEditResponse ? 'TestRecord' : 'Document' + 'tag': this.isEditResponse ? 'TestRecord' : 'Document' } - App.request(true, REQUEST_TYPE_JSON, url, req, {}, function (url, res, err) { + this.request(true, REQUEST_TYPE_JSON, url, req, {}, function (url, res, err) { App.onResponse(url, res, err) var rpObj = res.data || {} @@ -1817,7 +1817,7 @@ } } - config += App.newRandomConfig(childPath, k, v) + config += this.newRandomConfig(childPath, k, v) } } else { @@ -1898,45 +1898,45 @@ // 保存配置 saveConfig: function () { - App.isConfigShow = App.exTxt.index == 8 + this.isConfigShow = this.exTxt.index == 8 - switch (App.exTxt.index) { + switch (this.exTxt.index) { case 0: - App.database = CodeUtil.database = App.exTxt.name - App.saveCache('', 'database', App.database) + this.database = CodeUtil.database = this.exTxt.name + this.saveCache('', 'database', this.database) doc = null - var item = App.accounts[App.currentAccountIndex] + var item = this.accounts[this.currentAccountIndex] item.isLoggedIn = false - App.onClickAccount(App.currentAccountIndex, item) + this.onClickAccount(this.currentAccountIndex, item) break case 1: - App.schema = CodeUtil.schema = App.exTxt.name - App.saveCache('', 'schema', App.schema) + this.schema = CodeUtil.schema = this.exTxt.name + this.saveCache('', 'schema', this.schema) doc = null - var item = App.accounts[App.currentAccountIndex] + var item = this.accounts[this.currentAccountIndex] item.isLoggedIn = false - App.onClickAccount(App.currentAccountIndex, item) + this.onClickAccount(this.currentAccountIndex, item) break case 2: - App.language = CodeUtil.language = App.exTxt.name - App.saveCache('', 'language', App.language) + this.language = CodeUtil.language = this.exTxt.name + this.saveCache('', 'language', this.language) doc = null - App.onChange(false) + this.onChange(false) break case 6: - App.server = App.exTxt.name - App.saveCache('', 'server', App.server) - App.logout(true) + this.server = this.exTxt.name + this.saveCache('', 'server', this.server) + this.logout(true) break case 7: - App.types = StringUtil.split(App.exTxt.name) - App.saveCache('', 'types', App.types) + this.types = StringUtil.split(this.exTxt.name) + this.saveCache('', 'types', this.types) break case 8: - App.getThirdPartyApiList(App.exTxt.name, function (platform, docUrl, listUrl, itemUrl, url_, res, err) { + this.getThirdPartyApiList(this.exTxt.name, function (platform, docUrl, listUrl, itemUrl, url_, res, err) { var jsonData = (res || {}).data var isJSONData = jsonData instanceof Object if (isJSONData == false) { //后面是 URL 才存储;是 JSON 数据则不存储 @@ -2076,7 +2076,7 @@ }, getThirdPartyApiList: function (thirdParty, listCallback, itemCallback) { - App.parseThirdParty(thirdParty, function (platform, jsonData, docUrl, listUrl, itemUrl) { + this.parseThirdParty(thirdParty, function (platform, jsonData, docUrl, listUrl, itemUrl) { var isJSONData = jsonData instanceof Object const header = App.getHeader(vHeader.value) @@ -2169,7 +2169,7 @@ } catch (e) {} - var host = App.getBaseUrl() + var host = this.getBaseUrl() var listUrl = null var itemUrl = null @@ -2209,11 +2209,11 @@ var api = docItem == null ? null : docItem[method] if (api == null) { log('postApi', 'api == null >> return') - App.exTxt.button = 'All:' + App.uploadTotal + '\nDone:' + App.uploadDoneCount + '\nFail:' + App.uploadFailCount + this.exTxt.button = 'All:' + this.uploadTotal + '\nDone:' + this.uploadDoneCount + '\nFail:' + this.uploadFailCount return false } - App.uploadTotal ++ + this.uploadTotal ++ var parameters = api.parameters || [] var parameters2 = [] @@ -2230,7 +2230,7 @@ } } - return App.uploadThirdPartyApi(method == 'get' ? REQUEST_TYPE_PARAM : REQUEST_TYPE_JSON + return this.uploadThirdPartyApi(method == 'get' ? REQUEST_TYPE_PARAM : REQUEST_TYPE_JSON , api.summary, url, parameters2, api.headers, api.description) }, @@ -2242,11 +2242,11 @@ var api = docItem if (api == null) { log('postApi', 'api == null >> return') - App.exTxt.button = 'All:' + App.uploadTotal + '\nDone:' + App.uploadDoneCount + '\nFail:' + App.uploadFailCount + this.exTxt.button = 'All:' + this.uploadTotal + '\nDone:' + this.uploadDoneCount + '\nFail:' + this.uploadFailCount return false } - App.uploadTotal ++ + this.uploadTotal ++ var type switch ((api.summary || {}).requestParamsType || '') { @@ -2303,7 +2303,7 @@ } } - return App.uploadThirdPartyApi(type, api.name, api.url, parameters2, header, api.description) + return this.uploadThirdPartyApi(type, api.name, api.url, parameters2, header, api.description) }, /**上传 YApi @@ -2313,11 +2313,11 @@ var api = docItem if (api == null) { log('postApi', 'api == null >> return') - App.exTxt.button = 'All:' + App.uploadTotal + '\nDone:' + App.uploadDoneCount + '\nFail:' + App.uploadFailCount + this.exTxt.button = 'All:' + this.uploadTotal + '\nDone:' + this.uploadDoneCount + '\nFail:' + this.uploadFailCount return false } - App.uploadTotal++ + this.uploadTotal++ var headers = api.req_headers || [] var header = '' @@ -2331,9 +2331,9 @@ + (StringUtil.isEmpty(item.description, true) ? '' : ' // ' + item.description) } - var typeAndParam = App.parseYApiTypeAndParam(api) + var typeAndParam = this.parseYApiTypeAndParam(api) - return App.uploadThirdPartyApi( + return this.uploadThirdPartyApi( typeAndParam.type, api.title, api.path, typeAndParam.param, header , (StringUtil.trim(api.username) + ': ' + StringUtil.trim(api.title) + '\n' + (api.up_time == null ? '' : (typeof api.up_time != 'number' ? api.up_time : new Date(1000*api.up_time).toLocaleString())) @@ -2469,8 +2469,8 @@ } - var currentAccountId = App.getCurrentAccountId() - App.request(true, REQUEST_TYPE_JSON, App.server + '/post', { + var currentAccountId = this.getCurrentAccountId() + this.request(true, REQUEST_TYPE_JSON, this.server + '/post', { format: false, 'Document': { 'creator': creator, @@ -2483,7 +2483,7 @@ }, 'TestRecord': { 'randomId': 0, - 'host': App.getBaseUrl(), + 'host': this.getBaseUrl(), 'testAccountId': currentAccountId, 'response': '' }, @@ -2523,20 +2523,20 @@ if (date == null) { date = new Date() } - return date.getFullYear() + '-' + App.fillZero(date.getMonth() + 1) + '-' + App.fillZero(date.getDate()) + return date.getFullYear() + '-' + this.fillZero(date.getMonth() + 1) + '-' + this.fillZero(date.getDate()) }, //格式化时间 formatTime: function (date) { if (date == null) { date = new Date() } - return App.fillZero(date.getHours()) + ':' + App.fillZero(date.getMinutes()) + return this.fillZero(date.getHours()) + ':' + this.fillZero(date.getMinutes()) }, formatDateTime: function (date) { if (date == null) { date = new Date() } - return App.formatDate(date) + ' ' + App.formatTime(date) + return this.formatDate(date) + ' ' + this.formatTime(date) }, //填充0 fillZero: function (num, n) { @@ -2768,7 +2768,7 @@ var search = isSub ? subSearch : (StringUtil.isEmpty(this.randomSearch, true) ? null : '%' + StringUtil.trim(this.randomSearch) + '%') - var url = App.server + '/get' + var url = this.server + '/get' var req = { '[]': { 'count': (isSub ? this.randomSubCount : this.randomCount) || 100, @@ -2781,8 +2781,8 @@ }, 'TestRecord': { 'randomId@': '/Random/id', - 'testAccountId': App.getCurrentAccountId(), - 'host': App.getBaseUrl(), + 'testAccountId': this.getCurrentAccountId(), + 'host': this.getBaseUrl(), '@order': 'date-' }, '[]': isSub ? null : { @@ -2796,8 +2796,8 @@ }, 'TestRecord': { 'randomId@': '/Random/id', - 'testAccountId': App.getCurrentAccountId(), - 'host': App.getBaseUrl(), + 'testAccountId': this.getCurrentAccountId(), + 'host': this.getBaseUrl(), '@order': 'date-' } } @@ -2853,7 +2853,7 @@ try { cache = JSON.parse(cache) } catch(e) { - App.log('login App.send >> try { cache = JSON.parse(cache) } catch(e) {\n' + e.message) + this.log('login this.send >> try { cache = JSON.parse(cache) } catch(e) {\n' + e.message) } cache = cache || {} var val = key == null ? cache : cache[key] @@ -2863,15 +2863,15 @@ /**登录确认 */ confirm: function () { - switch (App.loginType) { + switch (this.loginType) { case 'login': - App.login(App.isAdminOperation) + this.login(this.isAdminOperation) break case 'register': - App.register(App.isAdminOperation) + this.register(this.isAdminOperation) break case 'forget': - App.resetPassword(App.isAdminOperation) + this.resetPassword(this.isAdminOperation) break } }, @@ -2884,7 +2884,7 @@ return } - var user = isAdmin ? App.User : null // add account App.accounts[App.currentAccountIndex] + var user = isAdmin ? this.User : null // add account this.accounts[this.currentAccountIndex] // alert("showLogin isAdmin = " + isAdmin + "; user = \n" + JSON.stringify(user, null, ' ')) @@ -2905,34 +2905,34 @@ }, getCurrentAccount: function() { - return App.accounts == null ? null : App.accounts[App.currentAccountIndex] + return this.accounts == null ? null : this.accounts[this.currentAccountIndex] }, getCurrentAccountId: function() { - var a = App.getCurrentAccount() + var a = this.getCurrentAccount() return a != null && a.isLoggedIn ? a.id : null }, /**登录 */ login: function (isAdminOperation, callback) { - App.isLoginShow = false - App.isEditResponse = false + this.isLoginShow = false + this.isEditResponse = false const req = { type: 0, // 登录方式,非必须 0-密码 1-验证码 - phone: App.account, - password: App.password, + phone: this.account, + password: this.password, version: 1, // 全局默认版本号,非必须 remember: vRemember.checked, format: false, defaults: { - '@database': StringUtil.isEmpty(App.database, true) ? undefined : App.database, - '@schema': StringUtil.isEmpty(App.schema, true) ? undefined : App.schema + '@database': StringUtil.isEmpty(this.database, true) ? undefined : this.database, + '@schema': StringUtil.isEmpty(this.schema, true) ? undefined : this.schema } } if (isAdminOperation) { - App.request(isAdminOperation, REQUEST_TYPE_JSON, App.server + '/login', req, {}, function (url, res, err) { + this.request(isAdminOperation, REQUEST_TYPE_JSON, this.server + '/login', req, {}, function (url, res, err) { if (callback) { callback(url, res, err) return @@ -2974,25 +2974,25 @@ else { if (callback == null) { var item - for (var i in App.accounts) { - item = App.accounts[i] + for (var i in this.accounts) { + item = this.accounts[i] if (item != null && req.phone == item.phone) { alert(req.phone + ' 已在测试账号中!') - // App.currentAccountIndex = i + // this.currentAccountIndex = i item.remember = vRemember.checked - App.onClickAccount(i, item) + this.onClickAccount(i, item) return } } } - App.showUrl(isAdminOperation, '/login') + this.showUrl(isAdminOperation, '/login') vInput.value = JSON.stringify(req, null, ' ') - App.type = REQUEST_TYPE_JSON - App.showTestCase(false, App.isLocalShow) - App.onChange(false) - App.send(isAdminOperation, function (url, res, err) { + this.type = REQUEST_TYPE_JSON + this.showTestCase(false, this.isLocalShow) + this.onChange(false) + this.send(isAdminOperation, function (url, res, err) { if (callback) { callback(url, res, err) return @@ -3030,12 +3030,12 @@ /**注册 */ register: function (isAdminOperation) { - App.showUrl(isAdminOperation, '/register') + this.showUrl(isAdminOperation, '/register') vInput.value = JSON.stringify( { Privacy: { - phone: App.account, - _password: App.password + phone: this.account, + _password: this.password }, User: { name: 'APIJSONUser' @@ -3043,9 +3043,9 @@ verify: vVerify.value }, null, ' ') - App.showTestCase(false, false) - App.onChange(false) - App.send(isAdminOperation, function (url, res, err) { + this.showTestCase(false, false) + this.onChange(false) + this.send(isAdminOperation, function (url, res, err) { App.onResponse(url, res, err) var rpObj = res.data @@ -3064,19 +3064,19 @@ /**重置密码 */ resetPassword: function (isAdminOperation) { - App.showUrl(isAdminOperation, '/put/password') + this.showUrl(isAdminOperation, '/put/password') vInput.value = JSON.stringify( { verify: vVerify.value, Privacy: { - phone: App.account, - _password: App.password + phone: this.account, + _password: this.password } }, null, ' ') - App.showTestCase(false, App.isLocalShow) - App.onChange(false) - App.send(isAdminOperation, function (url, res, err) { + this.showTestCase(false, this.isLocalShow) + this.onChange(false) + this.send(isAdminOperation, function (url, res, err) { App.onResponse(url, res, err) var rpObj = res.data @@ -3095,17 +3095,17 @@ /**退出 */ logout: function (isAdminOperation, callback) { - App.isEditResponse = false + this.isEditResponse = false var req = {} if (isAdminOperation) { - // alert('logout isAdminOperation this.saveCache(App.server, User, {})') - this.saveCache(App.server, 'User', {}) + // alert('logout isAdminOperation this.saveCache(this.server, User, {})') + this.saveCache(this.server, 'User', {}) } // alert('logout isAdminOperation = ' + isAdminOperation + '; url = ' + url) if (isAdminOperation) { - this.request(isAdminOperation, REQUEST_TYPE_JSON, App.server + '/logout', req, {}, function (url, res, err) { + this.request(isAdminOperation, REQUEST_TYPE_JSON, this.server + '/logout', req, {}, function (url, res, err) { if (callback) { callback(url, res, err) return @@ -3119,10 +3119,10 @@ }) } else { - App.showUrl(isAdminOperation, '/logout') + this.showUrl(isAdminOperation, '/logout') vInput.value = JSON.stringify(req, null, ' ') this.type = REQUEST_TYPE_JSON - this.showTestCase(false, App.isLocalShow) + this.showTestCase(false, this.isLocalShow) this.onChange(false) this.send(isAdminOperation, callback) } @@ -3131,17 +3131,17 @@ /**获取验证码 */ getVerify: function (isAdminOperation) { - App.showUrl(isAdminOperation, '/post/verify') - var type = App.loginType == 'login' ? 0 : (App.loginType == 'register' ? 1 : 2) + this.showUrl(isAdminOperation, '/post/verify') + var type = this.loginType == 'login' ? 0 : (this.loginType == 'register' ? 1 : 2) vInput.value = JSON.stringify( { type: type, - phone: App.account + phone: this.account }, null, ' ') - App.showTestCase(false, App.isLocalShow) - App.onChange(false) - App.send(isAdminOperation, function (url, res, err) { + this.showTestCase(false, this.isLocalShow) + this.onChange(false) + this.send(isAdminOperation, function (url, res, err) { App.onResponse(url, res, err) var data = res.data || {} @@ -3154,10 +3154,10 @@ }, clearUser: function () { - App.User.id = 0 - App.Privacy = {} - App.remotes = [] - App.saveCache(App.server, 'User', App.User) //应该用lastBaseUrl,baseUrl应随watch输入变化重新获取 + this.User.id = 0 + this.Privacy = {} + this.remotes = [] + this.saveCache(this.server, 'User', this.User) //应该用lastBaseUrl,baseUrl应随watch输入变化重新获取 }, /**计时回调 @@ -3196,7 +3196,7 @@ } catch (e) { log('main.onHandle', 'try { return jsonlint.parse(before); \n } catch (e) {\n' + e.message) - log('main.onHandle', 'return jsonlint.parse(App.removeComment(before));') + log('main.onHandle', 'return jsonlint.parse(this.removeComment(before));') try { afterObj = jsonlint.parse(this.removeComment(before)); @@ -3294,7 +3294,7 @@ var start = raw.lastIndexOf('\n\/*') var end = raw.lastIndexOf('\n*\/') markdownToHTML('```js\n' + (StringUtil.isEmpty(ct) ? (start < 0 || end <= start ? raw.substring(0, start) : '') : ct) + '\n```\n' - // + App.toMD(start < 0 || end <= start ? '' : raw.substring(start + '\n\/*'.length, end) ), true); + // + this.toMD(start < 0 || end <= start ? '' : raw.substring(start + '\n\/*'.length, end) ), true); + (start < 0 || end <= start ? '' : raw.substring(start + '\n\/*'.length, end) ), true); } catch (e3) { log(e3) @@ -3431,11 +3431,11 @@ }, showAndSend: function (branchUrl, req, isAdminOperation, callback) { - App.showUrl(isAdminOperation, branchUrl) + this.showUrl(isAdminOperation, branchUrl) vInput.value = JSON.stringify(req, null, ' ') - App.showTestCase(false, App.isLocalShow) - App.onChange(false) - App.send(isAdminOperation, callback) + this.showTestCase(false, this.isLocalShow) + this.onChange(false) + this.send(isAdminOperation, callback) }, /**发送请求 @@ -3446,14 +3446,14 @@ return } - if (StringUtil.isEmpty(App.host, true)) { + if (StringUtil.isEmpty(this.host, true)) { if (StringUtil.get(vUrl.value).startsWith('http://') != true && StringUtil.get(vUrl.value).startsWith('https://') != true) { alert('URL 缺少 http:// 或 https:// 前缀,可能不完整或不合法,\n可能使用同域的 Host,很可能访问出错!') } } else { if (StringUtil.get(vUrl.value).indexOf('://') >= 0) { - alert('URL Host 已经隐藏(固定) 为 \n' + App.host + ' \n将会自动在前面补全,导致 URL 不合法访问出错!\n如果要改 Host,右上角设置 > 显示(编辑)URL Host') + alert('URL Host 已经隐藏(固定) 为 \n' + this.host + ' \n将会自动在前面补全,导致 URL 不合法访问出错!\n如果要改 Host,右上角设置 > 显示(编辑)URL Host') } } @@ -3461,8 +3461,8 @@ clearTimeout(handler) - if (App.isEditResponse) { - App.onChange(false) + if (this.isEditResponse) { + this.onChange(false) return } @@ -3489,18 +3489,18 @@ if (this.locals.length >= 1000) { //最多1000条,太多会很卡 this.locals.splice(999, this.locals.length - 999) } - var method = App.getMethod() + var method = this.getMethod() this.locals.unshift({ 'Document': { - 'userId': App.User.id, - 'name': App.formatDateTime() + ' ' + (App.urlComment || StringUtil.trim(req.tag)), - 'type': App.type, + 'userId': this.User.id, + 'name': this.formatDateTime() + ' ' + (this.urlComment || StringUtil.trim(req.tag)), + 'type': this.type, 'url': '/' + method, 'request': JSON.stringify(req, null, ' '), 'header': vHeader.value } }) - App.saveCache('', 'locals', this.locals) + this.saveCache('', 'locals', this.locals) }, //请求 @@ -3585,18 +3585,18 @@ if (isSingle && data.code == CODE_SUCCESS) { //不格式化错误的结果 data = JSONResponse.formatObject(data); } - App.jsoncon = JSON.stringify(data, null, ' '); - App.view = 'code'; + this.jsoncon = JSON.stringify(data, null, ' '); + this.view = 'code'; vOutput.value = ''; // 会导致断言用了这个 - // if (App.currentRemoteItem == null) { - // App.currentRemoteItem = {} + // if (this.currentRemoteItem == null) { + // this.currentRemoteItem = {} // } - // if (App.currentRemoteItem.TestRecord == null) { - // App.currentRemoteItem.TestRecord = {} + // if (this.currentRemoteItem.TestRecord == null) { + // this.currentRemoteItem.TestRecord = {} // } - // App.currentRemoteItem.TestRecord.response = data + // this.currentRemoteItem.TestRecord.response = data } }, @@ -3610,8 +3610,8 @@ var obj = event.srcElement ? event.srcElement : event.target; if ($(obj).attr('id') == 'vUrl') { vUrlComment.value = '' - App.currentDocItem = null - App.currentRemoteItem = null + this.currentDocItem = null + this.currentRemoteItem = null } if (keyCode == 13) { // enter @@ -3788,20 +3788,20 @@ */ getCode: function (rq) { var s = '\n\n\n### 请求代码(自动生成) \n'; - switch (App.language) { + switch (this.language) { case CodeUtil.LANGUAGE_KOTLIN: s += '\n#### <= Android-Kotlin: 空对象用 HashMap<String, Any>(),空数组用 ArrayList<Any>()\n' + '```kotlin \n' - + CodeUtil.parseKotlinRequest(null, JSON.parse(rq), 0, isSingle, false, false, App.type, App.getBaseUrl(), '/' + App.getMethod(), App.urlComment) + + CodeUtil.parseKotlinRequest(null, JSON.parse(rq), 0, isSingle, false, false, this.type, this.getBaseUrl(), '/' + this.getMethod(), this.urlComment) + '\n ``` \n注:对象 {} 用 mapOf("key": value),数组 [] 用 listOf(value0, value1)\n'; break; case CodeUtil.LANGUAGE_JAVA: s += '\n#### <= Android-Java: 同名变量需要重命名' + ' \n ```java \n' - + StringUtil.trim(CodeUtil.parseJavaRequest(null, JSON.parse(rq), 0, isSingle, false, false, App.type, '/' + App.getMethod(), App.urlComment)) + + StringUtil.trim(CodeUtil.parseJavaRequest(null, JSON.parse(rq), 0, isSingle, false, false, this.type, '/' + this.getMethod(), this.urlComment)) + '\n ``` \n注:' + (isSingle ? '用了 APIJSON 的 JSONRequest, JSONResponse 类,也可使用其它类封装,只要 JSON 有序就行\n' : 'LinkedHashMap<>() 可替换为 fastjson 的 JSONObject(true) 等有序JSON构造方法\n'); - var serverCode = CodeUtil.parseJavaServer(App.type, '/' + App.getMethod(), App.database, App.schema, JSON.parse(rq), isSingle); + var serverCode = CodeUtil.parseJavaServer(this.type, '/' + this.getMethod(), this.database, this.schema, JSON.parse(rq), isSingle); if (StringUtil.isEmpty(serverCode, true) != true) { s += '\n#### <= Server-Java: RESTful 等非 APIJSON 规范的 API' + ' \n ```java \n' @@ -3866,7 +3866,7 @@ break; } - if (((App.User || {}).id || 0) > 0) { + if (((this.User || {}).id || 0) > 0) { s += '\n\n#### 开放源码 ' + '\nAPIJSON 接口测试: https://github.com/TommyLemon/APIAuto ' + '\nAPIJSON 单元测试: https://github.com/TommyLemon/UnitAuto ' @@ -3960,7 +3960,7 @@ }, 'PgClass': this.database != 'POSTGRESQL' ? null : { 'relname@': '/Table/table_name', - //FIXME 多个 schema 有同名表时数据总是取前面的 不属于 pg_class 表 'nspname': App.schema, + //FIXME 多个 schema 有同名表时数据总是取前面的 不属于 pg_class 表 'nspname': this.schema, '@column': 'oid;obj_description(oid):table_comment' }, 'SysTable': this.database != 'SQLSERVER' ? null : { @@ -4374,11 +4374,11 @@ }, log: function (msg) { - // App.log('Main. ' + msg) + // this.log('Main. ' + msg) }, getDoc4TestCase: function () { - var list = App.remotes || [] + var list = this.remotes || [] var doc = '' var item for (var i = 0; i < list.length; i ++) { @@ -4395,13 +4395,13 @@ enableCross: function (enable) { this.isCrossEnabled = enable this.crossProcess = enable ? '交叉账号:已开启' : '交叉账号:已关闭' - this.saveCache(App.server, 'isCrossEnabled', enable) + this.saveCache(this.server, 'isCrossEnabled', enable) }, enableML: function (enable) { this.isMLEnabled = enable this.testProcess = enable ? '机器学习:已开启' : '机器学习:已关闭' - this.saveCache(App.server, 'isMLEnabled', enable) + this.saveCache(this.server, 'isMLEnabled', enable) this.remotes = null this.showTestCase(true, false) }, @@ -4578,7 +4578,7 @@ resetCount: function (randomItem) { if (randomItem == null) { - App.log('resetCount randomItem == null >> return') + this.log('resetCount randomItem == null >> return') return } randomItem.totalCount = 0 @@ -4613,8 +4613,8 @@ log(e) vSend.disabled = true - App.view = 'error' - App.error = { + this.view = 'error' + this.error = { msg: e.message } @@ -4975,7 +4975,7 @@ } } - var baseUrl = StringUtil.trim(App.getBaseUrl()) + var baseUrl = StringUtil.trim(this.getBaseUrl()) if (baseUrl == '') { alert('请先输入有效的URL!') return @@ -4990,7 +4990,7 @@ // return // } - const list = App.remotes || [] + const list = this.remotes || [] const allCount = list.length doneCount = 0 @@ -5015,7 +5015,7 @@ }) } else { - App.startTest(list, allCount, isRandom, accountIndex) + this.startTest(list, allCount, isRandom, accountIndex) } }, @@ -5030,22 +5030,22 @@ continue } if (document.url == '/login' || document.url == '/logout') { //login会导致登录用户改变为默认的但UI上还显示原来的,单独测试OWNER权限时能通过很困惑 - App.log('test document.url == "/login" || document.url == "/logout" >> continue') + this.log('test document.url == "/login" || document.url == "/logout" >> continue') doneCount++ continue } - App.log('test document = ' + JSON.stringify(document, null, ' ')) + this.log('test document = ' + JSON.stringify(document, null, ' ')) const index = i var header = null try { - header = App.getHeader(document.header) + header = this.getHeader(document.header) } catch (e) { - App.log('test for ' + i + ' >> try { header = App.getHeader(document.header) } catch (e) { \n' + e.message) + this.log('test for ' + i + ' >> try { header = this.getHeader(document.header) } catch (e) { \n' + e.message) } - App.request(false, document.type, baseUrl + document.url, App.getRequest(document.request), header, function (url, res, err) { + this.request(false, document.type, baseUrl + document.url, this.getRequest(document.request), header, function (url, res, err) { try { App.onResponse(url, res, err) @@ -5062,7 +5062,7 @@ compareResponse: function (allCount, list, index, item, response, isRandom, accountIndex, justRecoverTest, err) { var it = item || {} //请求异步 - var d = (isRandom ? App.currentRemoteItem.Document : it.Document) || {} //请求异步 + var d = (isRandom ? this.currentRemoteItem.Document : it.Document) || {} //请求异步 var r = isRandom ? it.Random : null //请求异步 var tr = it.TestRecord || {} //请求异步 @@ -5096,13 +5096,13 @@ } } else { - var standardKey = App.isMLEnabled != true ? 'response' : 'standard' + var standardKey = this.isMLEnabled != true ? 'response' : 'standard' var standard = StringUtil.isEmpty(tr[standardKey], true) ? null : JSON.parse(tr[standardKey]) - tr.compare = JSONResponse.compareResponse(standard, App.removeDebugInfo(response) || {}, '', App.isMLEnabled) || {} + tr.compare = JSONResponse.compareResponse(standard, this.removeDebugInfo(response) || {}, '', this.isMLEnabled) || {} tr.compare.duration = it.durationHint } - App.onTestResponse(allCount, list, index, it, d, r, tr, response, tr.compare || {}, isRandom, accountIndex, justRecoverTest); + this.onTestResponse(allCount, list, index, it, d, r, tr, response, tr.compare || {}, isRandom, accountIndex, justRecoverTest); }, onTestResponse: function(allCount, list, index, it, d, r, tr, response, cmp, isRandom, accountIndex, justRecoverTest) { @@ -5198,9 +5198,9 @@ var toId = random == null ? null : random.toId if (toId != null && toId > 0) { - for (var i in App.randoms) { + for (var i in this.randoms) { - var toIt = App.randoms[i] + var toIt = this.randoms[i] if (toIt != null && toIt.Random != null && toIt.Random.id == toId) { var toRandom = toIt.Random @@ -5225,7 +5225,7 @@ } } - Vue.set(App.randoms, i, toIt) + Vue.set(this.randoms, i, toIt) break; } @@ -5255,7 +5255,7 @@ item = item || {} var document; if (isRandom) { - document = App.currentRemoteItem || {} + document = this.currentRemoteItem || {} } else { document = item.Document = item.Document || {} @@ -5510,8 +5510,8 @@ }, TestRecord: isDuration ? Object.assign(testRecord, { id: undefined, - host: App.getBaseUrl(), - testAccountId: App.getCurrentAccountId(), + host: this.getBaseUrl(), + testAccountId: this.getCurrentAccountId(), duration: item.duration, minDuration: minDuration, maxDuration: maxDuration, @@ -5519,8 +5519,8 @@ }) : { documentId: isNewRandom ? null : (isRandom ? random.documentId : document.id), randomId: isRandom && ! isNewRandom ? random.id : null, - host: App.getBaseUrl(), - testAccountId: App.getCurrentAccountId(), + host: this.getBaseUrl(), + testAccountId: this.getCurrentAccountId(), compare: JSON.stringify(testRecord.compare || {}), response: JSON.stringify(currentResponse || {}), standard: isML ? JSON.stringify(stddObj) : null @@ -5529,7 +5529,7 @@ } // } // else { - // url = App.server + '/post/testrecord/ml' + // url = this.server + '/post/testrecord/ml' // req = { // documentId: document.id // } @@ -5611,11 +5611,11 @@ TestRecord: { documentId: isRandom ? doc.documentId : doc.id, randomId: isRandom ? doc.id : null, - testAccountId: App.getCurrentAccountId(), - 'host': App.getBaseUrl(), + testAccountId: this.getCurrentAccountId(), + 'host': this.getBaseUrl(), '@order': 'date-', - '@column': 'id,userId,testAccountId,documentId,randomId,duration,minDuration,maxDuration,response' + (App.isMLEnabled ? ',standard' : ''), - '@having': App.isMLEnabled ? 'length(standard)>2' : null // '@having': App.isMLEnabled ? 'json_length(standard)>0' : null + '@column': 'id,userId,testAccountId,documentId,randomId,duration,minDuration,maxDuration,response' + (this.isMLEnabled ? ',standard' : ''), + '@having': this.isMLEnabled ? 'length(standard)>2' : null // '@having': this.isMLEnabled ? 'json_length(standard)>0' : null } }, {}, function (url, res, err) { App.onResponse(url, res, err) @@ -5660,7 +5660,7 @@ }, watch: { jsoncon: function () { - App.showJsonView() + this.showJsonView() } }, computed: { @@ -5762,7 +5762,7 @@ this.transfer() if (this.User != null && this.User.id != null && this.User.id > 0) { - this.showTestCase(true, false) // 本地历史仍然要求登录 App.User == null || App.User.id == null) + this.showTestCase(true, false) // 本地历史仍然要求登录 this.User == null || this.User.id == null) } } else { @@ -5801,6 +5801,8 @@ App.isRandomListShow = false } + var delayTime = 0 + // URL 太长导致截断和乱码 if (StringUtil.isEmpty(rawReq.setting, true) == false) { var save = rawReq.save == 'true' From e08ab9bd6c3d51d250bbd5e1beaed6593dadbf3d Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Thu, 7 Oct 2021 04:38:26 +0800 Subject: [PATCH 504/818] =?UTF-8?q?=E5=88=86=E4=BA=AB=EF=BC=9A=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E8=87=AA=E5=8A=A8=E6=89=A7=E8=A1=8C=E5=9B=9E=E5=BD=92?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E5=89=8D=E7=9A=84=E7=AD=89=E5=BE=85=E6=97=B6?= =?UTF-8?q?=E9=97=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- js/main.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/js/main.js b/js/main.js index a867156..fae8d8e 100755 --- a/js/main.js +++ b/js/main.js @@ -5832,12 +5832,12 @@ } if (setting.isRandomShow && setting.isRandomListShow) { - delayTime += Math.min(5000, 20*(setting.randomCount || App.randomCount) + 1000) + delayTime += Math.min(5000, (App.isMLEnabled ? 60 : 20)*(setting.randomCount || App.randomCount) + 1000) App.showRandomList(true, setting.isRandomSubListShow ? App.currentRandomItem : null, setting.isRandomSubListShow) } if (setting.isTestCaseShow) { - delayTime += Math.min(5000, 10*(setting.testCaseCount || App.testCaseCount) + 1000) + delayTime += Math.min(5000, (App.isMLEnabled ? 30 : 10)*(setting.testCaseCount || App.testCaseCount) + 1000) App.showTestCase(true, setting.isLocalShow) } } catch (e) { From 211f1d1927dd407c48939e1d6f49ef624d3f0e96 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Mon, 11 Oct 2021 21:11:34 +0800 Subject: [PATCH 505/818] =?UTF-8?q?=E9=80=9A=E8=BF=87=20APIJSON=20?= =?UTF-8?q?=E4=BB=A3=E7=90=86=E6=8E=A5=E5=8F=A3=E8=A7=A3=E5=86=B3=E6=9C=89?= =?UTF-8?q?=E6=97=B6=E5=8F=91=E9=80=81=E4=B8=8D=E4=BA=86=20Cookie=20?= =?UTF-8?q?=E5=AF=BC=E8=87=B4=E7=99=BB=E5=BD=95=E9=89=B4=E6=9D=83=E5=A4=B1?= =?UTF-8?q?=E8=B4=A5=E7=AD=89=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- js/main.js | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/js/main.js b/js/main.js index fae8d8e..f81291a 100755 --- a/js/main.js +++ b/js/main.js @@ -3507,8 +3507,10 @@ request: function (isAdminOperation, type, url, req, header, callback) { type = type || REQUEST_TYPE_JSON + var isDelegateEnabled = this.isDelegateEnabled + if (header != null && header.Cookie != null) { - if (this.isDelegateEnabled) { + if (isDelegateEnabled) { header['Set-Cookie'] = header.Cookie delete header.Cookie } @@ -3517,10 +3519,18 @@ } } + if (isDelegateEnabled && this.delegateId != null && (header == null || header['APIJSON-DELEGATE-ID'] == null)) { + if (header == null) { + header = {}; + } + header['APIJSON-DELEGATE-ID'] = this.delegateId + } + // axios.defaults.withcredentials = true axios({ method: (type == REQUEST_TYPE_PARAM ? 'get' : 'post'), - url: (isAdminOperation == false && this.isDelegateEnabled ? (this.server + '/delegate?' + (type == REQUEST_TYPE_GRPC ? '$_type=GRPC&' : '') + '$_delegate_url=') : '' ) + url: (isAdminOperation == false && isDelegateEnabled ? (this.server + '/delegate?' + (type == REQUEST_TYPE_GRPC ? '$_type=GRPC&' : '') + + (StringUtil.isEmpty(this.delegateId, true) ? '' : '$_delegate_id=' + this.delegateId + '&') + '$_delegate_url=') : '' ) + (this.isEncodeEnabled ? encodeURI(StringUtil.noBlank(url)) : StringUtil.noBlank(url)), params: (type == REQUEST_TYPE_PARAM || type == REQUEST_TYPE_FORM ? req : null), data: (type == REQUEST_TYPE_JSON || type == REQUEST_TYPE_GRPC ? req : (type == REQUEST_TYPE_DATA ? toFormData(req) : null)), @@ -3530,6 +3540,16 @@ }) .then(function (res) { res = res || {} + + if (isDelegateEnabled) { + var hs = res.headers || {} + var delegateId = hs['APIJSON-DELEGATE-ID'] || hs['apijson-delegate-id'] + if (delegateId != null && delegateId != App.delegateId) { + App.delegateId = delegateId; + App.saveCache(App.server, 'delegateId', delegateId) + } + } + //any one of then callback throw error will cause it calls then(null) // if ((res.config || {}).method == 'options') { // return @@ -5745,6 +5765,7 @@ this.randomCount = this.getCache(this.server, 'randomCount', this.randomCount) this.randomSubPage = this.getCache(this.server, 'randomSubPage', this.randomSubPage) this.randomSubCount = this.getCache(this.server, 'randomSubCount', this.randomSubCount) + this.delegateId = this.getCache(this.server, 'delegateId', this.delegateId) CodeUtil.thirdPartyApiMap = this.getCache(this.thirdParty, 'thirdPartyApiMap') } catch (e) { From 2d7f537a6ee1fe62ba2f88a675277dcd1238dc43 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Mon, 11 Oct 2021 22:41:17 +0800 Subject: [PATCH 506/818] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BB=A3=E7=90=86?= =?UTF-8?q?=E8=BD=AC=E4=B9=89=EF=BC=9B=E6=8A=8A=20apijson.cn=20=E5=8A=A0?= =?UTF-8?q?=E5=85=A5=E4=BB=A3=E7=90=86=E5=90=8D=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- js/main.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/js/main.js b/js/main.js index f81291a..5673494 100755 --- a/js/main.js +++ b/js/main.js @@ -3507,7 +3507,7 @@ request: function (isAdminOperation, type, url, req, header, callback) { type = type || REQUEST_TYPE_JSON - var isDelegateEnabled = this.isDelegateEnabled + var isDelegateEnabled = this.isDelegateEnabled || (url != null && url.indexOf('://apijson.cn') > 0) if (header != null && header.Cookie != null) { if (isDelegateEnabled) { @@ -3531,7 +3531,7 @@ method: (type == REQUEST_TYPE_PARAM ? 'get' : 'post'), url: (isAdminOperation == false && isDelegateEnabled ? (this.server + '/delegate?' + (type == REQUEST_TYPE_GRPC ? '$_type=GRPC&' : '') + (StringUtil.isEmpty(this.delegateId, true) ? '' : '$_delegate_id=' + this.delegateId + '&') + '$_delegate_url=') : '' ) - + (this.isEncodeEnabled ? encodeURI(StringUtil.noBlank(url)) : StringUtil.noBlank(url)), + + (isDelegateEnabled || this.isEncodeEnabled ? encodeURIComponent(StringUtil.noBlank(url)) : StringUtil.noBlank(url)), params: (type == REQUEST_TYPE_PARAM || type == REQUEST_TYPE_FORM ? req : null), data: (type == REQUEST_TYPE_JSON || type == REQUEST_TYPE_GRPC ? req : (type == REQUEST_TYPE_DATA ? toFormData(req) : null)), headers: header, //Accept-Encoding(HTTP Header 大小写不敏感,SpringBoot 接收后自动转小写)可能导致 Response 乱码 From d68bcc4be95a16c2452621ad28b19a0830e717a7 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Tue, 12 Oct 2021 00:30:47 +0800 Subject: [PATCH 507/818] =?UTF-8?q?=E4=BC=98=E5=8C=96=E7=AE=80=E4=BB=8B?= =?UTF-8?q?=E5=8F=8A=E6=90=9C=E7=B4=A2=E5=85=B3=E9=94=AE=E8=AF=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/index.html b/index.html index 72bcb61..892f0d7 100755 --- a/index.html +++ b/index.html @@ -1,10 +1,10 @@ - APIAuto-机器学习测试、自动生成代码、自动静态检查、自动生成文档与注释等,做最先进的 HTTP 接口管理平台。 + APIAuto-机器学习零代码测试、生成代码与静态检查、生成文档与光标悬浮注释 - - + + From e42e963dadf198cac3c3de1383c626bfa8368284 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Tue, 12 Oct 2021 00:53:09 +0800 Subject: [PATCH 508/818] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E6=9F=90=E4=BA=9B?= =?UTF-8?q?=E6=83=85=E5=86=B5=E4=B8=8B=E9=94=99=E8=AF=AF=E5=9C=B0=E8=BD=AC?= =?UTF-8?q?=E4=B9=89=20URL?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- js/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/main.js b/js/main.js index 5673494..b39b374 100755 --- a/js/main.js +++ b/js/main.js @@ -3531,7 +3531,7 @@ method: (type == REQUEST_TYPE_PARAM ? 'get' : 'post'), url: (isAdminOperation == false && isDelegateEnabled ? (this.server + '/delegate?' + (type == REQUEST_TYPE_GRPC ? '$_type=GRPC&' : '') + (StringUtil.isEmpty(this.delegateId, true) ? '' : '$_delegate_id=' + this.delegateId + '&') + '$_delegate_url=') : '' ) - + (isDelegateEnabled || this.isEncodeEnabled ? encodeURIComponent(StringUtil.noBlank(url)) : StringUtil.noBlank(url)), + + ((isAdminOperation == false && isDelegateEnabled) || this.isEncodeEnabled ? encodeURIComponent(StringUtil.noBlank(url)) : StringUtil.noBlank(url)), params: (type == REQUEST_TYPE_PARAM || type == REQUEST_TYPE_FORM ? req : null), data: (type == REQUEST_TYPE_JSON || type == REQUEST_TYPE_GRPC ? req : (type == REQUEST_TYPE_DATA ? toFormData(req) : null)), headers: header, //Accept-Encoding(HTTP Header 大小写不敏感,SpringBoot 接收后自动转小写)可能导致 Response 乱码 From a6db519dc13350416053f9c8d3f168f5ca1cf281 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Tue, 12 Oct 2021 01:09:40 +0800 Subject: [PATCH 509/818] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E8=BD=AC=E4=B9=89?= =?UTF-8?q?=E6=A8=A1=E5=BC=8F=E4=B8=8B=E9=94=99=E8=AF=AF=E5=9C=B0=E8=BD=AC?= =?UTF-8?q?=E4=B9=89=20URL?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- js/main.js | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/js/main.js b/js/main.js index b39b374..0446967 100755 --- a/js/main.js +++ b/js/main.js @@ -3506,8 +3506,9 @@ //请求 request: function (isAdminOperation, type, url, req, header, callback) { type = type || REQUEST_TYPE_JSON + url = StringUtil.noBlank(url) - var isDelegateEnabled = this.isDelegateEnabled || (url != null && url.indexOf('://apijson.cn') > 0) + var isDelegateEnabled = this.isDelegateEnabled || url.indexOf('://apijson.cn') > 0 if (header != null && header.Cookie != null) { if (isDelegateEnabled) { @@ -3529,9 +3530,14 @@ // axios.defaults.withcredentials = true axios({ method: (type == REQUEST_TYPE_PARAM ? 'get' : 'post'), - url: (isAdminOperation == false && isDelegateEnabled ? (this.server + '/delegate?' + (type == REQUEST_TYPE_GRPC ? '$_type=GRPC&' : '') - + (StringUtil.isEmpty(this.delegateId, true) ? '' : '$_delegate_id=' + this.delegateId + '&') + '$_delegate_url=') : '' ) - + ((isAdminOperation == false && isDelegateEnabled) || this.isEncodeEnabled ? encodeURIComponent(StringUtil.noBlank(url)) : StringUtil.noBlank(url)), + url: (isAdminOperation == false && isDelegateEnabled + ? ( + this.server + '/delegate?' + (type == REQUEST_TYPE_GRPC ? '$_type=GRPC&' : '') + + (StringUtil.isEmpty(this.delegateId, true) ? '' : '$_delegate_id=' + this.delegateId + '&') + '$_delegate_url=' + encodeURIComponent(url) + ) : ( + this.isEncodeEnabled ? encodeURI(url) : url + ) + ), params: (type == REQUEST_TYPE_PARAM || type == REQUEST_TYPE_FORM ? req : null), data: (type == REQUEST_TYPE_JSON || type == REQUEST_TYPE_GRPC ? req : (type == REQUEST_TYPE_DATA ? toFormData(req) : null)), headers: header, //Accept-Encoding(HTTP Header 大小写不敏感,SpringBoot 接收后自动转小写)可能导致 Response 乱码 From f3e4760d4b73efaa091a72205d7ce22e58434d57 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Tue, 12 Oct 2021 01:26:48 +0800 Subject: [PATCH 510/818] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=9C=8D=E5=8A=A1?= =?UTF-8?q?=E5=99=A8=E4=BB=A3=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- js/main.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/js/main.js b/js/main.js index 0446967..111d6f6 100755 --- a/js/main.js +++ b/js/main.js @@ -3508,10 +3508,10 @@ type = type || REQUEST_TYPE_JSON url = StringUtil.noBlank(url) - var isDelegateEnabled = this.isDelegateEnabled || url.indexOf('://apijson.cn') > 0 + var isDelegate = (isAdminOperation == false && this.isDelegateEnabled) || (isAdminOperation && url.indexOf('://apijson.cn') > 0) if (header != null && header.Cookie != null) { - if (isDelegateEnabled) { + if (isDelegate) { header['Set-Cookie'] = header.Cookie delete header.Cookie } @@ -3520,7 +3520,7 @@ } } - if (isDelegateEnabled && this.delegateId != null && (header == null || header['APIJSON-DELEGATE-ID'] == null)) { + if (isDelegate && this.delegateId != null && (header == null || header['APIJSON-DELEGATE-ID'] == null)) { if (header == null) { header = {}; } @@ -3530,7 +3530,7 @@ // axios.defaults.withcredentials = true axios({ method: (type == REQUEST_TYPE_PARAM ? 'get' : 'post'), - url: (isAdminOperation == false && isDelegateEnabled + url: (isDelegate ? ( this.server + '/delegate?' + (type == REQUEST_TYPE_GRPC ? '$_type=GRPC&' : '') + (StringUtil.isEmpty(this.delegateId, true) ? '' : '$_delegate_id=' + this.delegateId + '&') + '$_delegate_url=' + encodeURIComponent(url) @@ -3547,7 +3547,7 @@ .then(function (res) { res = res || {} - if (isDelegateEnabled) { + if (isDelegate) { var hs = res.headers || {} var delegateId = hs['APIJSON-DELEGATE-ID'] || hs['apijson-delegate-id'] if (delegateId != null && delegateId != App.delegateId) { From bf69e89b13c0f3c0c2a0b2469d400f4f00e736a8 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Tue, 12 Oct 2021 02:35:03 +0800 Subject: [PATCH 511/818] =?UTF-8?q?=E8=B0=83=E6=95=B4=E4=BB=A3=E7=90=86?= =?UTF-8?q?=E7=9B=B8=E5=85=B3=E7=9A=84=E8=AF=B7=E6=B1=82=E5=A4=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- js/main.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/js/main.js b/js/main.js index 111d6f6..7b91d75 100755 --- a/js/main.js +++ b/js/main.js @@ -3520,11 +3520,11 @@ } } - if (isDelegate && this.delegateId != null && (header == null || header['APIJSON-DELEGATE-ID'] == null)) { + if (isDelegate && this.delegateId != null && (header == null || header['Apijson-Delegate-Id'] == null)) { if (header == null) { header = {}; } - header['APIJSON-DELEGATE-ID'] = this.delegateId + header['Apijson-Delegate-Id'] = this.delegateId } // axios.defaults.withcredentials = true @@ -3549,7 +3549,7 @@ if (isDelegate) { var hs = res.headers || {} - var delegateId = hs['APIJSON-DELEGATE-ID'] || hs['apijson-delegate-id'] + var delegateId = hs['Apijson-Delegate-Id'] || hs['apijson-delegate-id'] if (delegateId != null && delegateId != App.delegateId) { App.delegateId = delegateId; App.saveCache(App.server, 'delegateId', delegateId) From 708b11e77cf08c3da3b3bebf5dc4a9b85313920a Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Tue, 12 Oct 2021 03:53:08 +0800 Subject: [PATCH 512/818] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BB=A3=E7=90=86=20?= =?UTF-8?q?id=20=E5=A4=B1=E6=95=88=E7=9A=84=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- js/main.js | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/js/main.js b/js/main.js index 7b91d75..3dae061 100755 --- a/js/main.js +++ b/js/main.js @@ -3100,6 +3100,9 @@ if (isAdminOperation) { // alert('logout isAdminOperation this.saveCache(this.server, User, {})') + this.delegateId = null + this.saveCache(this.server, 'delegateId', null) + this.saveCache(this.server, 'User', {}) } @@ -3157,7 +3160,9 @@ this.User.id = 0 this.Privacy = {} this.remotes = [] + // 导致刚登录成功就马上退出 this.delegateId = null this.saveCache(this.server, 'User', this.User) //应该用lastBaseUrl,baseUrl应随watch输入变化重新获取 + // this.saveCache(this.server, 'delegateId', this.delegateId) //应该用lastBaseUrl,baseUrl应随watch输入变化重新获取 }, /**计时回调 @@ -3508,7 +3513,7 @@ type = type || REQUEST_TYPE_JSON url = StringUtil.noBlank(url) - var isDelegate = (isAdminOperation == false && this.isDelegateEnabled) || (isAdminOperation && url.indexOf('://apijson.cn') > 0) + var isDelegate = (isAdminOperation == false && this.isDelegateEnabled) || (isAdminOperation && url.indexOf('://apijson.cn:9090') > 0) if (header != null && header.Cookie != null) { if (isDelegate) { @@ -3551,7 +3556,7 @@ var hs = res.headers || {} var delegateId = hs['Apijson-Delegate-Id'] || hs['apijson-delegate-id'] if (delegateId != null && delegateId != App.delegateId) { - App.delegateId = delegateId; + App.delegateId = delegateId App.saveCache(App.server, 'delegateId', delegateId) } } @@ -3587,6 +3592,10 @@ }) .catch(function (err) { log('send >> error:\n' + err) + if (isAdminOperation) { + App.delegateId = null + } + if (callback != null) { callback(url, {}, err) return From 3bd4dcb41cc37eaef9373aecf978aaef3036ecf1 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Wed, 20 Oct 2021 00:35:10 +0800 Subject: [PATCH 513/818] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=B8=85=E7=A9=BA?= =?UTF-8?q?=E8=AF=B7=E6=B1=82=E5=8F=82=E6=95=B0=E8=BE=93=E5=85=A5=E6=A1=86?= =?UTF-8?q?=E6=9F=A5=E7=9C=8B=E5=8F=82=E6=95=B0=E7=BC=96=E5=86=99=E8=A7=84?= =?UTF-8?q?=E5=88=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.html | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- js/main.js | 63 +++++++++++++++++++++++++++------------------- 2 files changed, 108 insertions(+), 28 deletions(-) diff --git a/index.html b/index.html index 892f0d7..ed477bf 100755 --- a/index.html +++ b/index.html @@ -159,7 +159,7 @@
-
+
搜索 @@ -193,7 +193,68 @@
-
diff --git a/js/main.js b/js/main.js index 3dae061..12696e5 100755 --- a/js/main.js +++ b/js/main.js @@ -3189,30 +3189,37 @@ throw new Error(e2.message) } - before = this.toDoubleJSON(StringUtil.trim(before)); - log('onHandle before = \n' + before); + before = StringUtil.trim(before); var afterObj; var after; - try { - afterObj = jsonlint.parse(before); - after = JSON.stringify(afterObj, null, " "); - before = after; - } - catch (e) { - log('main.onHandle', 'try { return jsonlint.parse(before); \n } catch (e) {\n' + e.message) - log('main.onHandle', 'return jsonlint.parse(this.removeComment(before));') + var code = ''; + + if (StringUtil.isEmpty(before)) { + afterObj = {}; + after = ''; + } else { + before = this.toDoubleJSON(StringUtil.trim(before)); + log('onHandle before = \n' + before); try { - afterObj = jsonlint.parse(this.removeComment(before)); + afterObj = jsonlint.parse(before); after = JSON.stringify(afterObj, null, " "); - } catch (e2) { - throw new Error('请求 JSON 格式错误!请检查并编辑请求!\n\n如果JSON中有注释,请 手动删除 或 点击左边的 \'/" 按钮 来去掉。\n\n' + e2.message) + before = after; + } + catch (e) { + log('main.onHandle', 'try { return jsonlint.parse(before); \n } catch (e) {\n' + e.message) + log('main.onHandle', 'return jsonlint.parse(this.removeComment(before));') + + try { + afterObj = jsonlint.parse(this.removeComment(before)); + after = JSON.stringify(afterObj, null, " "); + } catch (e2) { + throw new Error('请求 JSON 格式错误!请检查并编辑请求!\n\n如果JSON中有注释,请 手动删除 或 点击左边的 \'/" 按钮 来去掉。\n\n' + e2.message) + } } - } //关键词let在IE和Safari上不兼容 - var code = ''; if (this.isEditResponse != true) { try { code = this.getCode(after); //必须在before还是用 " 时使用,后面用会因为解析 ' 导致失败 @@ -3222,20 +3229,22 @@ } } - if (isSingle) { - if (before.indexOf('"') >= 0) { - before = before.replace(/"/g, "'"); + if (isSingle) { + if (before.indexOf('"') >= 0) { + before = before.replace(/"/g, "'"); + } } - } - else { - if (before.indexOf("'") >= 0) { - before = before.replace(/'/g, '"'); + else { + if (before.indexOf("'") >= 0) { + before = before.replace(/'/g, '"'); + } } + + vInput.value = before + + '\n\n\n ' + + ' \n'; //解决遮挡 } - vInput.value = StringUtil.trim(before) - + '\n ' - + ' \n'; //解决遮挡 vSend.disabled = false; if (this.isEditResponse != true) { @@ -5798,7 +5807,9 @@ this.transfer() if (this.User != null && this.User.id != null && this.User.id > 0) { - this.showTestCase(true, false) // 本地历史仍然要求登录 this.User == null || this.User.id == null) + setTimeout(function () { + App.showTestCase(true, false) // 本地历史仍然要求登录 this.User == null || this.User.id == null) + }, 1000) } } else { From 1e63705ce8fa6ff645d5d3cc1246d756aa57a778 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Wed, 20 Oct 2021 00:57:59 +0800 Subject: [PATCH 514/818] =?UTF-8?q?=E8=AF=B7=E6=B1=82=E5=A4=B4=20Request?= =?UTF-8?q?=20Header=EF=BC=9A=E6=96=B0=E5=A2=9E=E9=80=9A=E8=BF=87=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E8=87=AA=E5=AE=9A=E4=B9=89=E7=9A=84=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.html | 3 ++- js/main.js | 7 ++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/index.html b/index.html index ed477bf..0d84083 100755 --- a/index.html +++ b/index.html @@ -414,7 +414,8 @@
- +
diff --git a/js/main.js b/js/main.js index 12696e5..e1a92dd 100755 --- a/js/main.js +++ b/js/main.js @@ -3262,9 +3262,7 @@ } var m = this.getMethod(); - var c = isSingle ? '' : StringUtil.trim(CodeUtil.parseComment(after, docObj == null ? null : docObj['[]'], m, this.database, this.language, this.isEditResponse != true, standardObj)) - + '\n ' - + ' \n'; //解决遮挡 + var c = isSingle ? '' : StringUtil.trim(CodeUtil.parseComment(after, docObj == null ? null : docObj['[]'], m, this.database, this.language, this.isEditResponse != true, standardObj)); //TODO 统计行数,补全到一致 vInput.value.lineNumbers if (isSingle != true && afterObj.tag == null) { @@ -3274,6 +3272,9 @@ } } vComment.value = c + + '\n\n\n ' + + ' \n'; //解决遮挡 + vUrlComment.value = isSingle || StringUtil.isEmpty(this.urlComment, true) ? '' : vUrl.value + CodeUtil.getComment(this.urlComment, false, ' ') + ' - ' + (this.requestVersion > 0 ? 'V' + this.requestVersion : 'V*'); From b08a2a9aef41a6d57e0dab72c8f50d2d8607da59 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Thu, 21 Oct 2021 18:49:31 +0800 Subject: [PATCH 515/818] =?UTF-8?q?=E8=87=AA=E5=8A=A8=E9=9D=99=E6=80=81?= =?UTF-8?q?=E6=A3=80=E6=9F=A5=EF=BC=9A=E8=AF=B7=E6=B1=82=E8=BE=93=E5=85=A5?= =?UTF-8?q?=E6=A1=86=E7=9A=84=E6=8A=A5=E9=94=99=E6=8F=90=E7=A4=BA=E8=AF=AD?= =?UTF-8?q?=E6=94=B9=E4=B8=BA=E7=BA=A2=E8=89=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apijson/CodeUtil.js | 272 +++++++++++++++++++++++++------------------- index.html | 5 + js/main.js | 11 +- 3 files changed, 170 insertions(+), 118 deletions(-) diff --git a/apijson/CodeUtil.js b/apijson/CodeUtil.js index 2c17424..beea587 100644 --- a/apijson/CodeUtil.js +++ b/apijson/CodeUtil.js @@ -51,7 +51,7 @@ var CodeUtil = { * @param language * @return parseComment */ - parseComment: function (reqStr, tableList, method, database, language, isReq, standardObj, isExtract) { //怎么都获取不到真正的长度,cols不行,默认20不变,maxLineLength不行,默认undefined不变 , maxLineLength) { + parseComment: function (reqStr, tableList, method, database, language, isReq, standardObj, isExtract, isWarning) { //怎么都获取不到真正的长度,cols不行,默认20不变,maxLineLength不行,默认undefined不变 , maxLineLength) { if (StringUtil.isEmpty(reqStr)) { return ''; } @@ -137,7 +137,7 @@ var CodeUtil = { isInSubquery = key.endsWith('@'); - hintComment = CodeUtil.getComment4Request(tableList, names[depth - 1], key, value, method, false, database, language, isReq, names, isRestful, standardObj); + hintComment = CodeUtil.getComment4Request(tableList, names[depth - 1], key, value, method, false, database, language, isReq, names, isRestful, standardObj, isWarning); names[depth] = key; depth ++; @@ -153,7 +153,7 @@ var CodeUtil = { isInSubquery = false; if (line.endsWith('{}')) { //对象,判断是不是Table,再加对应的注释 - hintComment = CodeUtil.getComment4Request(tableList, names[depth - 1], key, value, method, false, database, language, isReq, names, isRestful, standardObj); + hintComment = CodeUtil.getComment4Request(tableList, names[depth - 1], key, value, method, false, database, language, isReq, names, isRestful, standardObj, isWarning); } else { depth --; @@ -176,7 +176,7 @@ var CodeUtil = { standardObj = JSONResponse.updateStandardByPath(standardObj, names, key, value, comment) } - hintComment = CodeUtil.getComment4Request(tableList, names[depth - 1], key, value, method, false, database, language, isReq, names, isRestful, standardObj); + hintComment = CodeUtil.getComment4Request(tableList, names[depth - 1], key, value, method, false, database, language, isReq, names, isRestful, standardObj, isWarning); names[depth] = key; depth ++; @@ -190,7 +190,7 @@ var CodeUtil = { } if (line.endsWith('[]')) { //对象,判断是不是Table,再加对应的注释 - hintComment = CodeUtil.getComment4Request(tableList, names[depth - 1], key, value, method, false, database, language, isReq, names, isRestful, standardObj); + hintComment = CodeUtil.getComment4Request(tableList, names[depth - 1], key, value, method, false, database, language, isReq, names, isRestful, standardObj, isWarning); } else { depth --; @@ -213,7 +213,7 @@ var CodeUtil = { } } // alert('depth = ' + depth + '; line = ' + line + '; isArray = ' + isArray); - hintComment = CodeUtil.getComment4Request(tableList, names[depth - 1], key, value, method, isInSubquery, database, language, isReq, names, isRestful, standardObj); + hintComment = CodeUtil.getComment4Request(tableList, names[depth - 1], key, value, method, isInSubquery, database, language, isReq, names, isRestful, standardObj, isWarning); } } @@ -222,7 +222,12 @@ var CodeUtil = { } } - lines[i] += hintComment; + if (i > 0 && i < lines.length - 1 && StringUtil.isEmpty(hintComment, true)) { + lines[i] = ''; // 节约性能,收尾不能为空,否则外面 trim 一下格式就变了对不上原文本。奇怪的是右大括号 } 总是不走这里 + } + else { + lines[i] += hintComment; + } } var apiMap = isRestful ? CodeUtil.thirdPartyApiMap : null; @@ -5855,7 +5860,7 @@ var CodeUtil = { * @param isInSubquery * @param database */ - getComment4Request: function (tableList, name, key, value, method, isInSubquery, database, language, isReq, names, isRestful, standardObj) { + getComment4Request: function (tableList, name, key, value, method, isInSubquery, database, language, isReq, names, isRestful, standardObj, isWarning) { // alert('name = ' + name + '; key = ' + key + '; value = ' + value + '; method = ' + method); if (key == null) { @@ -5886,9 +5891,12 @@ var CodeUtil = { // } try { - var c = CodeUtil.getCommentFromDoc(tableList, name, key, method, database, language, false, isReq, pathKeys, isRestful, value == null ? {} : value, true, standardObj); + var c = CodeUtil.getCommentFromDoc(tableList, name, key, method, database, language, isRestful, isReq, pathKeys, isRestful, value == null ? {} : value, true, standardObj, null, isWarning); if (isRestful == true || StringUtil.isEmpty(c) == false) { // TODO 最好都放行,查不到都去数据库查表和字段属性 - return StringUtil.isEmpty(c) ? ' ! 字段 ' + key + ' 不存在!' : (c.startsWith(' ! ') ? c : CodeUtil.getComment(c, false, ' ')); + if (c.startsWith(' ! ')) { + return c; + } + return StringUtil.isEmpty(c) ? ' ! 字段 ' + key + ' 不存在!' : (isWarning ? '' : CodeUtil.getComment(c, false, ' ')); } } catch (e) { @@ -5907,9 +5915,12 @@ var CodeUtil = { var objName = key.substring(0, aliaIndex >= 0 ? aliaIndex : key.length - 2); if (JSONObject.isTableKey(objName)) { - var c = CodeUtil.getCommentFromDoc(tableList, objName, null, method, database, language, false, isReq, pathKeys, isRestful, value); - return StringUtil.isEmpty(c) ? ' ! 表 ' + objName + ' 不存在!' : CodeUtil.getComment( - (aliaIndex < 0 ? '' : '新建别名: ' + key.substring(aliaIndex + 1, key.length - 2) + ' < ') + objName + ': ' + c, false, ' '); + var c = CodeUtil.getCommentFromDoc(tableList, objName, null, method, database, language, isRestful, isReq, pathKeys, isRestful, value, null, null, null, isWarning); + if (c.startsWith(' ! ')) { + return c; + } + return StringUtil.isEmpty(c) ? ' ! 表 ' + objName + ' 不存在!' : (isWarning ? '' : CodeUtil.getComment( + (aliaIndex < 0 ? '' : '新建别名: ' + key.substring(aliaIndex + 1, key.length - 2) + ' < ') + objName + ': ' + c, false, ' ')); } } @@ -5917,10 +5928,14 @@ var CodeUtil = { } else if (value instanceof Object) { if (isRestful != true && StringUtil.isEmpty(key, true)) { - return ' ' + CodeUtil.getComment('根对象,可在内部加 format,tag,version,@role,@database,@schema,@datasource,@explain,@cache 等全局关键词键值对', false, ' '); + return isWarning ? '' : ' ' + CodeUtil.getComment('根对象,可在内部加 format,tag,version,@role,@database,@schema,@datasource,@explain,@cache 等全局关键词键值对', false, ' '); } if (isRestful != true && key.endsWith('@')) { + if (isWarning) { + return ''; + } + if (key == '@from@') { return CodeUtil.getComment('数据来源:子查询' + (isValueNotEmpty ? ',里面必须有 "from":Table, Table:{}' : ',例如 { "from":"User", "User":{} }'), false, ' '); } @@ -5928,14 +5943,18 @@ var CodeUtil = { var aliaIndex = name == null ? -1 : name.indexOf(':'); var objName = aliaIndex < 0 ? name : name.substring(0, aliaIndex); if (JSONObject.isTableKey(objName)) { - return CodeUtil.getComment('子查询,里面必须有 "from":Table, Table:{} < ' + CodeUtil.getCommentFromDoc(tableList, objName, key.substring(0, key.length - 1), method, database, language, false, isReq, pathKeys, isRestful, value, null, null, true), false, ' '); + return CodeUtil.getComment('子查询,里面必须有 "from":Table, Table:{} < ' + CodeUtil.getCommentFromDoc(tableList, objName, key.substring(0, key.length - 1), method, database, language, isRestful, isReq, pathKeys, isRestful, value, null, null, true, isWarning), false, ' '); } return CodeUtil.getComment('子查询,可在内部加 from,range 或 数组关键词 等键值对,需要被下面的表字段相关 key 引用赋值', false, ' '); } if (isRestful != true && JSONObject.isArrayKey(key)) { - if (method != 'GET') { - return ' ! key[]:{}只支持GET方法!'; + if (method != 'GET' && method != 'GETS') { + return ' ! key[]:{} 只支持 GET,GETS 方法!'; + } + + if (isWarning) { + return ''; } key = key.substring(0, key.lastIndexOf('[]')); @@ -5955,12 +5974,15 @@ var CodeUtil = { var isTableKey = JSONObject.isTableKey(objName) if (isRestful == true || isTableKey) { - var c = CodeUtil.getCommentFromDoc(tableList, objName, null, method, database, language, false, isReq, pathKeys, isRestful, value); - return StringUtil.isEmpty(c) ? ' ! 表不存在!' : CodeUtil.getComment( - (aliaIndex < 0 ? '' : '新建别名: ' + key.substring(aliaIndex + 1, key.length) + ' < ' + objName + ': ') + c, false, ' '); + var c = CodeUtil.getCommentFromDoc(tableList, objName, null, method, database, language, isRestful, isReq, pathKeys, isRestful, value, null, null, null, isWarning); + if (c.startsWith(' ! ')) { + return c; + } + return StringUtil.isEmpty(c) ? ' ! 表不存在!' : (isWarning ? '' : CodeUtil.getComment( + (aliaIndex < 0 ? '' : '新建别名: ' + key.substring(aliaIndex + 1, key.length) + ' < ' + objName + ': ') + c, false, ' ')); } - if (isRestful != true && isTableKey != true && StringUtil.isEmpty(objName) != true) { + if (isWarning != true && isRestful != true && isTableKey != true && StringUtil.isEmpty(objName) != true) { return CodeUtil.getComment('普通对象。如果要对应数据库表请把 ' + objName + ' 改成 ' + StringUtil.firstCase(objName, true) + ' 这种以大写字母开头的 APIJSON 表名!数据库表不一样要这样,MySQL 默认大小写不敏感。', false, ' '); } @@ -5970,15 +5992,15 @@ var CodeUtil = { if (isRestful != true && (isInSubquery || JSONObject.isArrayKey(name))) { switch (key) { case 'count': - return value != null && valuesIsNotInteger ? ' ! value必须是Integer类型!' : CodeUtil.getComment('每页数量' + (isValueNotEmpty ? '' : ',例如 5 10 20 等'), false, ' '); + return value != null && valuesIsNotInteger ? ' ! value必须是Integer类型!' : (isWarning ? '' : CodeUtil.getComment('每页数量' + (isValueNotEmpty ? '' : ',例如 5 10 20 等'), false, ' ')); case 'page': if (value != null && valuesIsNotInteger) { return ' ! value必须是Integer类型!'; } - return value != null && value < 0 ? ' ! 必须 >= 0 !' : CodeUtil.getComment('分页页码' + (isValueNotEmpty ? '' : ': 例如 0 1 2 ...'), false, ' '); + return value != null && value < 0 ? ' ! 必须 >= 0 !' : (isWarning ? '' : CodeUtil.getComment('分页页码' + (isValueNotEmpty ? '' : ': 例如 0 1 2 ...'), false, ' ')); case 'query': var query = CodeUtil.QUERY_TYPES[value]; - return StringUtil.isEmpty(query) ? ' ! value必须是[' + CodeUtil.QUERY_TYPE_KEYS.join() + ']中的一种!' : CodeUtil.getComment('查询内容:0-对象 1-总数和分页详情 2-数据、总数和分页详情', false, ' '); + return StringUtil.isEmpty(query) ? ' ! value必须是[' + CodeUtil.QUERY_TYPE_KEYS.join() + ']中的一种!' : (isWarning ? '' : CodeUtil.getComment('查询内容:0-对象 1-总数和分页详情 2-数据、总数和分页详情', false, ' ')); case 'join': if (valuesIsNotString) { return ' ! value必须是String类型!'; @@ -6019,12 +6041,14 @@ var CodeUtil = { return ' ! 表名 ' + t + ' 不合法 ! 必须是 Table 这种大驼峰格式' + (isValueNotEmpty ? '' : ',例如 "User" "Comment" "ViewTable" 等 !'); } - s += CodeUtil.JOIN_TYPES[c] + ' JOIN ' + t + (a.length <= 0 ? '' : ' AS ' + a); - must += (i > 0 ? ', ' : ',同一层级必须有 "') + t + '":{ "' + item.substring(lastIndex + 1) + '":"/../.." }'; + if (isWarning != true) { + s += CodeUtil.JOIN_TYPES[c] + ' JOIN ' + t + (a.length <= 0 ? '' : ' AS ' + a); + must += (i > 0 ? ', ' : ',同一层级必须有 "') + t + '":{ "' + item.substring(lastIndex + 1) + '":"/../.." }'; + } } } - return CodeUtil.getComment('多表连接:' + (s + must || '例如 &/User/id@, RIGHT, * CROSS, & INNER, | FULL, ! OUTER, ^ SIDE, ( ANTI, ) FOREIGN'), false, ' '); default: if (isInSubquery) { @@ -6033,9 +6057,9 @@ var CodeUtil = { if (valuesIsNotString) { return ' ! value必须是String类型!'; } - return CodeUtil.SUBQUERY_RANGES.indexOf(value) < 0 ? ' ! value必须是[' + CodeUtil.SUBQUERY_RANGES.join() + ']中的一种!' : CodeUtil.getComment('比较范围:ANY-任意 ALL-全部', false, ' '); + return CodeUtil.SUBQUERY_RANGES.indexOf(value) < 0 ? ' ! value必须是[' + CodeUtil.SUBQUERY_RANGES.join() + ']中的一种!' : (isWarning ? '' : CodeUtil.getComment('比较范围:ANY-任意 ALL-全部', false, ' ')); case 'from': - return valuesIsNotString ? ' ! value必须是String类型!' : CodeUtil.getComment('数据来源' + (isValueNotEmpty ? ',同一层级必须有 "' + value + '":{...}' : ',例如 "User",同一层级必须有 "User":{...}'), false, ' '); + return valuesIsNotString ? ' ! value必须是String类型!' : (isWarning ? '' : CodeUtil.getComment('数据来源' + (isValueNotEmpty ? ',同一层级必须有 "' + value + '":{...}' : ',例如 "User",同一层级必须有 "User":{...}'), false, ' ')); } } break; @@ -6049,69 +6073,72 @@ var CodeUtil = { if (isRestful != true && JSONObject.isTableKey(objName)) { switch (key) { case '@column': - return valuesIsNotString ? ' ! value必须是String类型!' : CodeUtil.getComment('返回字段' + (isValueNotEmpty ? ',可传 字段(:别名)、SQL 函数(:别名,用分号 ; 隔开)、表达式,以及部分 SQL 关键词' : ':例如 "name" "toId:parentId" "id,userId;json_length(praiseUserIdList):praiseCount" 等'), false, ' '); + return valuesIsNotString ? ' ! value必须是String类型!' : (isWarning ? '' : CodeUtil.getComment('返回字段' + (isValueNotEmpty ? ',可传 字段(:别名)、SQL 函数(:别名,用分号 ; 隔开)、表达式,以及部分 SQL 关键词' : ':例如 "name" "toId:parentId" "id,userId;json_length(praiseUserIdList):praiseCount" 等'), false, ' ')); case '@from@': //value 类型为 Object 时 到不了这里,已在上方处理 - return valuesIsNotString && typeOfValue != 'object' ? ' ! value必须是String或Object类型!' : CodeUtil.getComment('数据来源:引用赋值 子查询 "' + value + '@":{...} ', false, ' '); + return valuesIsNotString && typeOfValue != 'object' ? ' ! value必须是String或Object类型!' : (isWarning ? '' : CodeUtil.getComment('数据来源:引用赋值 子查询 "' + value + '@":{...} ', false, ' ')); case '@group': - return valuesIsNotString ? ' ! value必须是String类型!' : CodeUtil.getComment('分组方式' + (isValueNotEmpty ? '' : ',例如 "userId" "momentId,toId" 等'), false, ' '); + return valuesIsNotString ? ' ! value必须是String类型!' : (isWarning ? '' : CodeUtil.getComment('分组方式' + (isValueNotEmpty ? '' : ',例如 "userId" "momentId,toId" 等'), false, ' ')); case '@having': - return valuesIsNotString ? ' ! value必须是String类型!' : CodeUtil.getComment('聚合函数' + (isValueNotEmpty ? ',可传 SQL 函数(用分号 ; 隔开)、表达式,以及部分 SQL 关键词' : ',例如 "max(id)>100" "length(phone)>0;sum(balance)<=10000" 等'), false, ' '); + return valuesIsNotString ? ' ! value必须是String类型!' : (isWarning ? '' : CodeUtil.getComment('聚合函数' + (isValueNotEmpty ? ',可传 SQL 函数(用分号 ; 隔开)、表达式,以及部分 SQL 关键词' : ',例如 "max(id)>100" "length(phone)>0;sum(balance)<=10000" 等'), false, ' ')); case '@order': - return valuesIsNotString ? ' ! value必须是String类型!' : CodeUtil.getComment('排序方式:+升序,-降序' + (isValueNotEmpty ? '' : ',例如 "date-" "name+,id-" 等'), false, ' '); + return valuesIsNotString ? ' ! value必须是String类型!' : (isWarning ? '' : CodeUtil.getComment('排序方式:+升序,-降序' + (isValueNotEmpty ? '' : ',例如 "date-" "name+,id-" 等'), false, ' ')); case '@combine': //TODO 解析 value 并直接给出条件组合结果 - return valuesIsNotString ? ' ! value必须是String类型!' : CodeUtil.getComment('条件组合' + (isValueNotEmpty ? ',| 可省略。合并同类,外层按照 & | ! 顺序,内层按传参顺序组合成 (key0 & key1 & key6 & 其它key) & (key2 | key3 | key7) & !(key4 | key5)' : ',例如 "name$,tag$" "!userId<,!toId" 等'), false, ' '); + return valuesIsNotString ? ' ! value必须是String类型!' : (isWarning ? '' : CodeUtil.getComment('条件组合' + (isValueNotEmpty ? ',| 可省略。合并同类,外层按照 & | ! 顺序,内层按传参顺序组合成 (key0 & key1 & key6 & 其它key) & (key2 | key3 | key7) & !(key4 | key5)' : ',例如 "name$,tag$" "!userId<,!toId" 等'), false, ' ')); case '@schema': - return valuesIsNotString ? ' ! value必须是String类型!' : CodeUtil.getComment('集合空间(数据库名/模式)' + (isValueNotEmpty ? '' : ',例如 "sys" "apijson" "postgres" "dbo" 等'), false, ' '); + return valuesIsNotString ? ' ! value必须是String类型!' : (isWarning ? '' : CodeUtil.getComment('集合空间(数据库名/模式)' + (isValueNotEmpty ? '' : ',例如 "sys" "apijson" "postgres" "dbo" 等'), false, ' ')); case '@datasource': - return valuesIsNotString ? ' ! value必须是String类型!' : CodeUtil.getComment('跨数据源' + (isValueNotEmpty ? '' : ',例如 "DRUID" "HIKARICP" 等'), false, ' '); + return valuesIsNotString ? ' ! value必须是String类型!' : (isWarning ? '' : CodeUtil.getComment('跨数据源' + (isValueNotEmpty ? '' : ',例如 "DRUID" "HIKARICP" 等'), false, ' ')); case '@raw': - return valuesIsNotString ? ' ! value必须是String类型!' : CodeUtil.getComment('原始SQL片段' + (isValueNotEmpty ? ',由后端 RAW_MAP 代码配置指定 "key0,key1.." 中每个 key 对应 key:"SQL片段" 中的 SQL片段' : ',例如 "@column" "id{},@having" 等'), false, ' '); + return valuesIsNotString ? ' ! value必须是String类型!' : (isWarning ? '' : CodeUtil.getComment('原始SQL片段' + (isValueNotEmpty ? ',由后端 RAW_MAP 代码配置指定 "key0,key1.." 中每个 key 对应 key:"SQL片段" 中的 SQL片段' : ',例如 "@column" "id{},@having" 等'), false, ' ')); case '@json': - return valuesIsNotString ? ' ! value必须是String类型!' : CodeUtil.getComment('转为JSON' + (isValueNotEmpty ? '' : ',例如 "request" "gets,heads" 等'), false, ' '); + return valuesIsNotString ? ' ! value必须是String类型!' : (isWarning ? '' : CodeUtil.getComment('转为JSON' + (isValueNotEmpty ? '' : ',例如 "request" "gets,heads" 等'), false, ' ')); case '@database': - return CodeUtil.DATABASE_KEYS.indexOf(value) < 0 ? ' ! value必须是[' + CodeUtil.DATABASE_KEYS.join() + ']中的一种!' : CodeUtil.getComment('数据库类型:例如 "MYSQL" "POSTGRESQL" "SQLSERVER" "ORACLE" "DB2" "CLICKHOUSE" 等', false, ' '); + return CodeUtil.DATABASE_KEYS.indexOf(value) < 0 ? ' ! value必须是[' + CodeUtil.DATABASE_KEYS.join() + ']中的一种!' : (isWarning ? '' : CodeUtil.getComment('数据库类型:例如 "MYSQL" "POSTGRESQL" "SQLSERVER" "ORACLE" "DB2" "CLICKHOUSE" 等', false, ' ')); case '@role': var role = CodeUtil.ROLES[value]; - return StringUtil.isEmpty(role) ? ' ! value必须是[' + CodeUtil.ROLE_KEYS.join() + ']中的一种!' : CodeUtil.getComment('来访角色:' + role + ',限制可操作的数据,假定真实强制匹配', false, ' '); + return StringUtil.isEmpty(role) ? ' ! value必须是[' + CodeUtil.ROLE_KEYS.join() + ']中的一种!' : (isWarning ? '' : CodeUtil.getComment('来访角色:' + role + ',限制可操作的数据,假定真实强制匹配', false, ' ')); case '@cache': var cache = CodeUtil.CACHE_TYPES[value]; - return StringUtil.isEmpty(cache) ? ' ! value必须是[' + CodeUtil.CACHE_TYPE_KEYS.join() + ']中的一种!' : CodeUtil.getComment('缓存方式:0-全部 1-磁盘 2-内存', false, ' '); + return StringUtil.isEmpty(cache) ? ' ! value必须是[' + CodeUtil.CACHE_TYPE_KEYS.join() + ']中的一种!' : (isWarning ? '' : CodeUtil.getComment('缓存方式:0-全部 1-磁盘 2-内存', false, ' ')); case '@explain': - return valuesIsNotBoolean ? ' ! value必须是Boolean类型!' : CodeUtil.getComment('性能分析:true-开启 false-关闭,返回执行的 SQL 及查询计划', false, ' '); + return valuesIsNotBoolean ? ' ! value必须是Boolean类型!' : (isWarning ? '' : CodeUtil.getComment('性能分析:true-开启 false-关闭,返回执行的 SQL 及查询计划', false, ' ')); } if (key.startsWith('@')) { if (key.endsWith('()')) { - return valuesIsNotString ? ' ! value必须是String类型!' : CodeUtil.getComment('存储过程' + (isValueNotEmpty ? ',触发调用数据库存储过程' : ':例如 "getCommentByUserId(id,@limit,@offset)"'), false, ' '); + return valuesIsNotString ? ' ! value必须是String类型!' : (isWarning ? '' : CodeUtil.getComment('存储过程' + (isValueNotEmpty ? ',触发调用数据库存储过程' : ':例如 "getCommentByUserId(id,@limit,@offset)"'), false, ' ')); } return ''; } - var c = CodeUtil.getCommentFromDoc(tableList, objName, key, method, database, language, null, isReq, pathKeys, isRestful, value); - return StringUtil.isEmpty(c) ? ' ! 字段不存在!' : CodeUtil.getComment(c, false, ' '); + var c = CodeUtil.getCommentFromDoc(tableList, objName, key, method, database, language, isRestful, isReq, pathKeys, isRestful, value, null, null, null, isWarning); + if (c.startsWith(' ! ')) { + return c; + } + return StringUtil.isEmpty(c) ? ' ! 字段不存在!' : (isWarning ? '' : CodeUtil.getComment(c, false, ' ')); } // alert('name = ' + name + '; key = ' + key); if (isRestful != true && StringUtil.isEmpty(name)) { switch (key) { case 'tag': - return valuesIsNotString ? ' ! value必须是String类型!' : CodeUtil.getComment('请求标识' + (method == 'GET' || method == 'HEAD' ? ',GET,HEAD 请求不会自动解析,仅为后续迭代可能的手动优化而预留' : (isValueNotEmpty ? ',用来区分不同请求并校验,由后端 Request 表中指定' : ',例如 "User" "Comment[]" "Privacy-CIRCLE" 等')), false, ' '); + return valuesIsNotString ? ' ! value必须是String类型!' : (isWarning ? '' : CodeUtil.getComment('请求标识' + (method == 'GET' || method == 'HEAD' ? ',GET,HEAD 请求不会自动解析,仅为后续迭代可能的手动优化而预留' : (isValueNotEmpty ? ',用来区分不同请求并校验,由后端 Request 表中指定' : ',例如 "User" "Comment[]" "Privacy-CIRCLE" 等')), false, ' ')); case 'version': - return valuesIsNotInteger ? ' ! value必须是Integer类型!' : CodeUtil.getComment('版本号' + (method == 'GET' || method == 'HEAD' ? ',GET,HEAD 请求不会自动解析,仅为后续迭代可能的手动优化而预留' : (isValueNotEmpty ? ',用来使用特定版本的校验规则,由后端 Request 表中指定' : ',例如 1 2 3 等')), false, ' '); + return valuesIsNotInteger ? ' ! value必须是Integer类型!' : (isWarning ? '' : CodeUtil.getComment('版本号' + (method == 'GET' || method == 'HEAD' ? ',GET,HEAD 请求不会自动解析,仅为后续迭代可能的手动优化而预留' : (isValueNotEmpty ? ',用来使用特定版本的校验规则,由后端 Request 表中指定' : ',例如 1 2 3 等')), false, ' ')); case 'format': - return valuesIsNotBoolean ? ' ! value必须是Boolean类型!' : CodeUtil.getComment('格式化: true-是 false-否,将 TableName 转为 tableName, TableName[] 转为 tableNameList, Table:alias 转为 alias 等小驼峰格式', false, ' '); + return valuesIsNotBoolean ? ' ! value必须是Boolean类型!' : (isWarning ? '' : CodeUtil.getComment('格式化: true-是 false-否,将 TableName 转为 tableName, TableName[] 转为 tableNameList, Table:alias 转为 alias 等小驼峰格式', false, ' ')); case '@schema': - return valuesIsNotString ? ' ! value必须是String类型!' : CodeUtil.getComment('集合空间(数据库名/模式)' + (isValueNotEmpty ? '' : ',例如 "sys" "apijson" "postgres" "dbo" 等'), false, ' '); + return valuesIsNotString ? ' ! value必须是String类型!' : (isWarning ? '' : CodeUtil.getComment('集合空间(数据库名/模式)' + (isValueNotEmpty ? '' : ',例如 "sys" "apijson" "postgres" "dbo" 等'), false, ' ')); case '@datasource': - return valuesIsNotString ? ' ! value必须是String类型!' : CodeUtil.getComment('跨数据源' + (isValueNotEmpty ? '' : ',例如 "DRUID" "HIKARICP" 等'), false, ' '); + return valuesIsNotString ? ' ! value必须是String类型!' : (isWarning ? '' : CodeUtil.getComment('跨数据源' + (isValueNotEmpty ? '' : ',例如 "DRUID" "HIKARICP" 等'), false, ' ')); case '@database': - return CodeUtil.DATABASE_KEYS.indexOf(value) < 0 ? ' ! value必须是[' + CodeUtil.DATABASE_KEYS.join() + ']中的一种!' : CodeUtil.getComment('数据库' + (isValueNotEmpty ? '' : ',例如 "MYSQL" "POSTGRESQL" "SQLSERVER" "ORACLE" 等'), false, ' '); + return CodeUtil.DATABASE_KEYS.indexOf(value) < 0 ? ' ! value必须是[' + CodeUtil.DATABASE_KEYS.join() + ']中的一种!' : (isWarning ? '' : CodeUtil.getComment('数据库' + (isValueNotEmpty ? '' : ',例如 "MYSQL" "POSTGRESQL" "SQLSERVER" "ORACLE" 等'), false, ' ')); case '@role': var role = CodeUtil.ROLES[value]; - return StringUtil.isEmpty(role) ? ' ! value必须是[' + CodeUtil.ROLE_KEYS.join() + ']中的一种!' : CodeUtil.getComment('默认角色:' + role, false, ' '); + return StringUtil.isEmpty(role) ? ' ! value必须是[' + CodeUtil.ROLE_KEYS.join() + ']中的一种!' : (isWarning ? '' : CodeUtil.getComment('默认角色:' + role, false, ' ')); case '@cache': var cache = CodeUtil.CACHE_TYPES[value]; - return StringUtil.isEmpty(cache) ? ' ! value必须是[' + CodeUtil.CACHE_TYPE_KEYS.join() + ']中的一种!' : CodeUtil.getComment('缓存方式:0-全部 1-磁盘 2-内存', false, ' '); + return StringUtil.isEmpty(cache) ? ' ! value必须是[' + CodeUtil.CACHE_TYPE_KEYS.join() + ']中的一种!' : (isWarning ? '' : CodeUtil.getComment('缓存方式:0-全部 1-磁盘 2-内存', false, ' ')); case '@explain': - return valuesIsNotBoolean ? ' ! value必须是Boolean类型!' : CodeUtil.getComment('性能分析:true-开启 false-关闭,返回执行的 SQL 及查询计划', false, ' '); + return valuesIsNotBoolean ? ' ! value必须是Boolean类型!' : (isWarning ? '' : CodeUtil.getComment('性能分析:true-开启 false-关闭,返回执行的 SQL 及查询计划', false, ' ')); } } @@ -6128,7 +6155,7 @@ var CodeUtil = { * @param onlyTableAndColumn * @return {*} */ - getCommentFromDoc: function (tableList, tableName, columnName, method, database, language, onlyTableAndColumn, isReq, pathKeys, isRestful, value, ignoreError, standardObj, isSubquery) { + getCommentFromDoc: function (tableList, tableName, columnName, method, database, language, onlyTableAndColumn, isReq, pathKeys, isRestful, value, ignoreError, standardObj, isSubquery, isWarning) { log('getCommentFromDoc tableName = ' + tableName + '; columnName = ' + columnName + '; method = ' + method + '; database = ' + database + '; language = ' + language + '; onlyTableAndColumn = ' + onlyTableAndColumn + '; tableList = \n' + JSON.stringify(tableList)); @@ -6139,10 +6166,14 @@ var CodeUtil = { var targetComment = targetObj == null ? null : targetObj.comment; var c = targetObj == null ? null : CodeUtil.getType4Language(language, t, true) + (targetObj.notnull ? ', ' : '? ') + StringUtil.trim(targetComment); if (CodeUtil.isTypeMatch(t, CodeUtil.getType4Request(value))) { - c = ' ! value必须是' + CodeUtil.getType4Language(language, t) + '类型!' + CodeUtil.getComment(c, false, ' '); + c = ' ! value必须是' + CodeUtil.getType4Language(language, t) + '类型!' + (isWarning ? ' ' : CodeUtil.getComment(c, false, ' ')); if (ignoreError != true) { throw new Error(c); } + + if (isWarning) { + return c; + } } if (StringUtil.isEmpty(targetComment, true) == false) { // 如果这里没注释就从数据库/第三方平台取 @@ -6166,84 +6197,89 @@ var CodeUtil = { if (isRestful == true && StringUtil.isEmpty(columnName, true) == false && StringUtil.isEmpty(CodeUtil.thirdParty, true) == false) { // } && CodeUtil.thirdParty == 'YAPI') { var apiMap = CodeUtil.thirdPartyApiMap; if (apiMap == null) { - return '...'; + // 用 下方 tableList 兜底 return isWarning ? ' ' : '...'; } - - var api = apiMap[(method.startsWith('/') ? '' : '/') + method]; - var doc = api == null ? null : (isReq ? api.request : api.response); - if (doc != null) { - if (pathKeys != null && pathKeys.length > 0) { - for (var i = 0; i < pathKeys.length; i ++) { - var p = pathKeys[i]; - - if (doc instanceof Array) { - var find = false; - for (var j = 0; j < doc.length; j++) { - var d = doc[j]; - if (d != null && d.name == p) { - doc = d; - find = true; - break; + else { + var api = apiMap[(method.startsWith('/') ? '' : '/') + method]; + var doc = api == null ? null : (isReq ? api.request : api.response); + if (doc != null) { + if (pathKeys != null && pathKeys.length > 0) { + for (var i = 0; i < pathKeys.length; i++) { + var p = pathKeys[i]; + + if (doc instanceof Array) { + var find = false; + for (var j = 0; j < doc.length; j++) { + var d = doc[j]; + if (d != null && d.name == p) { + doc = d; + find = true; + break; + } } - } - if (find == false) { - doc = null; - } - } - else if (doc instanceof Object) { - if (doc.type == 'object') { - doc = doc.properties; + if (find == false) { + doc = null; + } } - else if (doc.type == 'array') { - doc = doc.items; - - try { - if (p != null && p != '' && Number.isNaN(+ p)) { - i --; + else if (doc instanceof Object) { + if (doc.type == 'object') { + doc = doc.properties; + } + else if (doc.type == 'array') { + doc = doc.items; + + try { + if (p != null && p != '' && Number.isNaN(+p)) { + i--; + } + } catch (e) { } - } catch (e) {} - continue; - } + continue; + } - doc = doc[p]; + doc = doc[p]; + } } } - } - else if (doc instanceof Array) { - doc = null; - } + else if (doc instanceof Array) { + doc = null; + } - var t = doc == null ? null : doc.type; - var c = doc == null ? null : CodeUtil.getType4Language(language, t, true) + (doc.required ? ', ' : '? ') + StringUtil.trim(doc.description || doc.title); - if (t == null) { - // 避免崩溃 - } - else if (t.endsWith('[]')) { - t = 'array'; - } - else if (t == 'integer') { - t = 'number'; - } + var t = doc == null ? null : doc.type; + var c = doc == null ? null : CodeUtil.getType4Language(language, t, true) + (doc.required ? ', ' : '? ') + StringUtil.trim(doc.description || doc.title); + if (t == null) { + // 避免崩溃 + } + else if (t.endsWith('[]')) { + t = 'array'; + } + else if (t == 'integer') { + t = 'number'; + } - if (CodeUtil.isTypeMatch(t, CodeUtil.getType4Request(value))) { - c = ' ! value必须是' + CodeUtil.getType4Language(language, t) + '类型!' + CodeUtil.getComment(c, false, ' ') + if (CodeUtil.isTypeMatch(t, CodeUtil.getType4Request(value))) { + c = ' ! value必须是' + CodeUtil.getType4Language(language, t) + '类型!' + (isWarning ? ' ' : CodeUtil.getComment(c, false, ' ')) if (ignoreError != true) { throw new Error(c); } return c; - } - else { - if (c != null) { // 可能存在但只是没注释 StringUtil.isEmpty(c, true) == false) { - return c; } + else { + if (c != null) { // 可能存在但只是没注释 StringUtil.isEmpty(c, true) == false) { + return isWarning ? ' ' : c; + } + } + } + } + } if (tableList == null || tableList.length <= 0) { - return '...'; + return isWarning ? ' ' : '...'; } var item; @@ -6305,6 +6341,10 @@ var CodeUtil = { } } + if (isWarning) { + return ' '; + } + var priority = ''; if (columnName.endsWith("-()")) { priority = ' < 在解析所在对象前优先执行'; @@ -6518,10 +6558,10 @@ var CodeUtil = { // if (ignoreError != true) { // throw new Error(c); // } - return ' ! value必须是' + t + '类型!' + CodeUtil.getComment(c, false, ' ') + return ' ! value必须是' + t + '类型!' + (isWarning ? ' ' : CodeUtil.getComment(c, false, ' ')); } - return c; + return isWarning ? ' ' : c; } return onlyTableAndColumn ? '' : ' ! 字段 ' + key + ' 不存在!只能是 [' + columnNames.join() + '] 中的一个!'; diff --git a/index.html b/index.html index 0d84083..4655d19 100755 --- a/index.html +++ b/index.html @@ -193,6 +193,8 @@
+ + // 注释可省略,但如果未省略则前面两个空格必须;清空文本内容可查看规则。 + + // ## 快捷键 + // Ctrl + I 或 Command + I 格式化文本,清除所有注释和无效空格、换行等; + // Ctrl + / 或 Command + / 对选中行 新增行注释 或 取消行注释; +
@@ -424,7 +431,10 @@ +My-Header: 'Secret' + Math.random() // 示例,代码执行结果作为实际值,值为 fun(arg0, arg1..) 等包含函数名与括号的格式 + // ## 快捷键 + // Ctrl + I 或 Command + I 格式化文本,清除所有注释和无效空格、换行等; + // Ctrl + / 或 Command + / 对选中行 新增行注释 或 取消行注释;"> From d2409c5a963accf1934965e4b95bb42f1febaa8c Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sun, 6 Feb 2022 02:25:23 +0800 Subject: [PATCH 555/818] =?UTF-8?q?=E5=BF=AB=E6=8D=B7=E9=94=AE=EF=BC=9A?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=94=AF=E6=8C=81=20URL,=20JSON,=20Header,?= =?UTF-8?q?=20Random=20=E8=BE=93=E5=85=A5=E6=A1=86=E5=A4=8D=E5=88=B6?= =?UTF-8?q?=E7=B2=98=E8=B4=B4=E6=97=B6=E8=87=AA=E5=8A=A8=E8=BD=AC=E6=8D=A2?= =?UTF-8?q?=20JSON=20=E4=B8=8E=20key:=20value=20=E6=A0=BC=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apijson/StringUtil.js | 6 +- index.html | 8 +-- js/main.js | 150 ++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 150 insertions(+), 14 deletions(-) diff --git a/apijson/StringUtil.js b/apijson/StringUtil.js index e922a6b..0bab659 100644 --- a/apijson/StringUtil.js +++ b/apijson/StringUtil.js @@ -55,11 +55,7 @@ var StringUtil = { if (trim) { s = s.trim(); } - if (s == '') { - return true; - } - - return false; + return s.length <= 0; }, /**判断是否为代码名称,只能包含字母,数字或下划线 diff --git a/index.html b/index.html index f4994b1..aa4a0c6 100755 --- a/index.html +++ b/index.html @@ -137,7 +137,7 @@
- +
@@ -195,7 +195,7 @@ - - - - -
- -
- -
- - - - - -
- 搜索 - - - - - 每页 - - -
- - - - -
- 搜索 - - - - - 每页 - - -
- - -
- - -
- - -
- -
- - - - -
- -
-
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
-
    -
  • - - - -
  • -
- -
- -
- - - - - - - - - - - - - - - - - - - -
-
- -
-
-
-
- -
- - -
- - -
- -
- - -
-
- - - - - - -
-
- 搜索 - - - - - 每页 - - -
-
- - - -
-
{{error.msg}}
-
- - - - -
-
- - - - - - - - - - -
- - - - - - -
- - -
-
- -
- - - - - - -
-
- - -
- - - - - - -
- - -
- - - - - - -
- - - -
-
-
-
-
-
-
- -
- -
- - - -
- - - -
- - - -
- -
- -
- -
- -
- -
- {{ loginType == "login" ? "没有账号?" : "已有账号?" }} - - {{ loginType == "login" ? "注册" : "登录" }} - -
-
-
-
-
-
-
-
-
- - - - - - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + APIAuto-机器学习零代码测试、生成代码与静态检查、生成文档与光标悬浮注释 + + + + + + + + + + + + + + + + + + + +
+
+ + + + 2s + + + + + +
+ 文档 + 视频 + 生态 +
+ + +
+ + +
+
+ + +
+ + +
+ +
+ +
+ 搜索 + + + + + 每页 + + +
+
+ +
+ +
+ + + +
+
+ +
+ +
+ + + +
    +
  • + {{ (item.Random || {}).name }} + + +
    + + + + + +
    + + + +
  • +
+ +
+ 搜索 + + + + + 每页 + + +
+ + + + +
+ 搜索 + + + + + 每页 + + +
+ + +
+ + + + +
+
+
+
+ +
+ +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
    +
  • + + + +
  • +
+ +
+ +
+ + + + + + + + + + + + + + + + + + + +
+
+ +
+
+
+
+ +
+ + +
+ + +
+ +
+ + +
+
+ + + + + + +
+
+ 搜索 + + + + + 每页 + + +
+
+ + + +
+
{{error.msg}}
+
+ + + + +
+
+ + + + + + + + + + +
+ + + + + + +
+ + +
+
+ +
+ + + + + + +
+
+ + +
+ + + + + + +
+ + +
+ + + + + + +
+ + + +
+
+
+
+
+
+
+ +
+ +
+ + + +
+ + + +
+ + + +
+ +
+ +
+ +
+ +
+ +
+ {{ loginType == "login" ? "没有账号?" : "已有账号?" }} + + {{ loginType == "login" ? "注册" : "登录" }} + +
+
+
+
+
+
+
+
+
+ + + + +
+ + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/js/main.js b/js/main.js index 796f73e..b502f64 100755 --- a/js/main.js +++ b/js/main.js @@ -1,6626 +1,6631 @@ - -(function () { - Vue.component('vue-item', { - props: ['jsondata', 'theme'], - template: '#item-template' - }) - - Vue.component('vue-outer', { - props: ['jsondata', 'isend', 'path', 'theme'], - template: '#outer-template' - }) - - Vue.component('vue-expand', { - props: [], - template: '#expand-template' - }) - - Vue.component('vue-val', { - props: ['field', 'val', 'isend', 'path', 'theme'], - template: '#val-template' - }) - - Vue.use({ - install: function (Vue, options) { - - // 判断数据类型 - Vue.prototype.getTyp = function (val) { - return toString.call(val).split(']')[0].split(' ')[1] - } - - // 判断是否是对象或者数组,以对下级进行渲染 - Vue.prototype.isObjectArr = function (val) { - return ['Object', 'Array'].indexOf(this.getTyp(val)) > -1 - } - - // 折叠 - Vue.prototype.fold = function ($event) { - var target = Vue.prototype.expandTarget($event) - target.siblings('svg').show() - target.hide().parent().siblings('.expand-view').hide() - target.parent().siblings('.fold-view').show() - } - // 展开 - Vue.prototype.expand = function ($event) { - var target = Vue.prototype.expandTarget($event) - target.siblings('svg').show() - target.hide().parent().siblings('.expand-view').show() - target.parent().siblings('.fold-view').hide() - } - - //获取展开折叠的target - Vue.prototype.expandTarget = function ($event) { - switch($event.target.tagName.toLowerCase()) { - case 'use': - return $($event.target).parent() - case 'label': - return $($event.target).closest('.fold-view').siblings('.expand-wraper').find('.icon-square-plus').first() - default: - return $($event.target) - } - } - - // 格式化值 - Vue.prototype.formatVal = function (val) { - switch(Vue.prototype.getTyp(val)) { - case 'String': - return '"' + val + '"' - case 'Null': - return 'null' - default: - return val - } - } - - // 判断值是否是链接 - Vue.prototype.isaLink = function (val) { - return /^((https|http|ftp|rtsp|mms)?:\/\/)[^\s]+/.test(val) - } - - // 计算对象的长度 - Vue.prototype.objLength = function (obj) { - return Object.keys(obj).length - } - - /**渲染 JSON key:value 项 - * @author TommyLemon - * @param val - * @param key - * @return {boolean} - */ - Vue.prototype.onRenderJSONItem = function (val, key, path) { - if (isSingle || key == null) { - return true - } - if (key == '_$_this_$_') { - // return true - return false - } - - var method = App.getMethod(); - var isRestful = ! JSONObject.isAPIJSONPath(method); - - try { - if (val instanceof Array) { - if (val[0] instanceof Object && (val[0] instanceof Array == false)) { // && JSONObject.isArrayKey(key, null, isRestful)) { - // alert('onRenderJSONItem key = ' + key + '; val = ' + JSON.stringify(val)) - - var ckey = key.substring(0, key.lastIndexOf('[]')); - - var aliaIndex = ckey.indexOf(':'); - var objName = aliaIndex < 0 ? ckey : ckey.substring(0, aliaIndex); - - var firstIndex = objName.indexOf('-'); - var firstKey = firstIndex < 0 ? objName : objName.substring(0, firstIndex); - - for (var i = 0; i < val.length; i++) { - var cPath = (StringUtil.isEmpty(path, false) ? '' : path + '/') + key; - - if (JSONObject.isTableKey(firstKey, val, isRestful)) { - // var newVal = JSON.parse(JSON.stringify(val[i])) - - var newVal = {} - for (var k in val[i]) { - newVal[k] = val[i][k] //提升性能 - delete val[i][k] - } - - val[i]._$_this_$_ = JSON.stringify({ - path: cPath + '/' + i, - table: firstKey - }) - - for (var k in newVal) { - val[i][k] = newVal[k] - } - } - else { - this.onRenderJSONItem(val[i], '' + i, cPath); - } - - // this.$children[i]._$_this_$_ = key - // alert('this.$children[i]._$_this_$_ = ' + this.$children[i]._$_this_$_) - } - } - } - else if (val instanceof Object) { - var aliaIndex = key.indexOf(':'); - var objName = aliaIndex < 0 ? key : key.substring(0, aliaIndex); - - // var newVal = JSON.parse(JSON.stringify(val)) - - var newVal = {} - for (var k in val) { - newVal[k] = val[k] //提升性能 - delete val[k] - } - - val._$_this_$_ = JSON.stringify({ - path: (StringUtil.isEmpty(path, false) ? '' : path + '/') + key, - table: JSONObject.isTableKey(objName, val, isRestful) ? objName : null - }) - - for (var k in newVal) { - val[k] = newVal[k] - } - - // val = Object.assign({ _$_this_$_: objName }, val) //解决多显示一个逗号 , - - // this._$_this_$_ = key TODO 不影响 JSON 的方式,直接在组件读写属性 - // alert('this._$_this_$_ = ' + this._$_this_$_) - } - - - } catch (e) { - alert('onRenderJSONItem try { ... } catch (e) {\n' + e.message) - } - - return true - - } - - - /**显示 Response JSON 的注释 - * @author TommyLemon - * @param val - * @param key - * @param $event - */ - Vue.prototype.setResponseHint = function (val, key, $event) { - console.log('setResponseHint') - this.$refs.responseKey.setAttribute('data-hint', isSingle ? '' : this.getResponseHint(val, key, $event)); - } - /**获取 Response JSON 的注释 - * 方案一: - * 拿到父组件的 key,逐层向下传递 - * 问题:拿不到爷爷组件 "Comment[]": [ { "id": 1, "content": "content1" }, { "id": 2 }... ] - * - * 方案二: - * 改写 jsonon 的 refKey 为 key0/key1/.../refKey - * 问题:遍历,改 key;容易和特殊情况下返回的同样格式的字段冲突 - * - * 方案三: - * 改写 jsonon 的结构,val 里加 .path 或 $.path 之类的隐藏字段 - * 问题:遍历,改 key;容易和特殊情况下返回的同样格式的字段冲突 - * - * @author TommyLemon - * @param val - * @param key - * @param $event - */ - Vue.prototype.getResponseHint = function (val, key, $event) { - // alert('setResponseHint key = ' + key + '; val = ' + JSON.stringify(val)) - - var s = '' - - try { - var standardObj = null; - try { - var currentItem = App.isTestCaseShow ? App.remotes[App.currentDocIndex] : App.currentRemoteItem; - standardObj = JSON.parse(((currentItem || {}).TestRecord || {}).standard); - } catch (e3) { - log(e3) - } - - var path = null - var table = null - var column = null - - var method = App.isTestCaseShow ? ((App.currentRemoteItem || {}).Document || {}).url : App.getMethod(); - var isRestful = ! JSONObject.isAPIJSONPath(method); - - if (val instanceof Object && (val instanceof Array == false)) { - - var parent = $event.currentTarget.parentElement.parentElement - var valString = parent.textContent - - // alert('valString = ' + valString) - - var i = valString.indexOf('"_$_this_$_": "') - if (i >= 0) { - valString = valString.substring(i + '"_$_this_$_": "'.length) - i = valString.indexOf('}"') - if (i >= 0) { - valString = valString.substring(0, i + 1) - // alert('valString = ' + valString) - var _$_this_$_ = JSON.parse(valString) || {} - path = _$_this_$_.path - table = _$_this_$_.table - } - - - var aliaIndex = key == null ? -1 : key.indexOf(':'); - var objName = aliaIndex < 0 ? key : key.substring(0, aliaIndex); - - if (JSONObject.isTableKey(objName, val, isRestful)) { - table = objName - } - else if (JSONObject.isTableKey(table, val, isRestful)) { - column = key - } - - // alert('path = ' + path + '; table = ' + table + '; column = ' + column) - } - } - else { - var parent = $event.currentTarget.parentElement.parentElement - var valString = parent.textContent - - // alert('valString = ' + valString) - - var i = valString.indexOf('"_$_this_$_": "') - if (i >= 0) { - valString = valString.substring(i + '"_$_this_$_": "'.length) - i = valString.indexOf('}"') - if (i >= 0) { - valString = valString.substring(0, i + 1) - // alert('valString = ' + valString) - var _$_this_$_ = JSON.parse(valString) || {} - path = _$_this_$_.path - table = _$_this_$_.table - } - } - - if (val instanceof Array && JSONObject.isArrayKey(key, val, isRestful)) { - var key2 = key == null ? null : key.substring(0, key.lastIndexOf('[]')); - - var aliaIndex = key2 == null ? -1 : key2.indexOf(':'); - var objName = aliaIndex < 0 ? key2 : key2.substring(0, aliaIndex); - - var firstIndex = objName == null ? -1 : objName.indexOf('-'); - var firstKey = firstIndex < 0 ? objName : objName.substring(0, firstIndex); - - // alert('key = ' + key + '; firstKey = ' + firstKey + '; firstIndex = ' + firstIndex) - if (JSONObject.isTableKey(firstKey, null, isRestful)) { - table = firstKey - - var s0 = ''; - if (firstIndex > 0) { - objName = objName.substring(firstIndex + 1); - firstIndex = objName.indexOf('-'); - column = firstIndex < 0 ? objName : objName.substring(0, firstIndex) - - var pathUri = (StringUtil.isEmpty(path) ? '' : path + '/') + key; - - var c = CodeUtil.getCommentFromDoc(docObj == null ? null : docObj['[]'], table, column, method, App.database, App.language, true, false, pathUri.split('/'), isRestful, val, true, standardObj); // this.getResponseHint({}, table, $event - s0 = column + (StringUtil.isEmpty(c, true) ? '' : ': ' + c) - } - - var pathUri = (StringUtil.isEmpty(path) ? '' : path + '/') + (StringUtil.isEmpty(column) ? key : column); - - var c = CodeUtil.getCommentFromDoc(docObj == null ? null : docObj['[]'], table, isRestful ? key : null, method, App.database, App.language, true, false, pathUri.split('/'), isRestful, val, true, standardObj); - s = (StringUtil.isEmpty(path) ? '' : path + '/') + key + ' 中 ' - + ( - StringUtil.isEmpty(c, true) ? '' : table + ': ' - + c + ((StringUtil.isEmpty(s0, true) ? '' : ' - ' + s0) ) - ); - - return s; - } - //导致 key[] 的 hint 显示为 key[]key[] else { - // s = (StringUtil.isEmpty(path) ? '' : path + '/') + key - // } - } - else { - if (isRestful || JSONObject.isTableKey(table)) { - column = key - } - // alert('path = ' + path + '; table = ' + table + '; column = ' + column) - } - } - // alert('setResponseHint table = ' + table + '; column = ' + column) - - var pathUri = (StringUtil.isEmpty(path) ? '' : path + '/') + key; - var c = CodeUtil.getCommentFromDoc(docObj == null ? null : docObj['[]'], table, isRestful ? key : column, method, App.database, App.language, true, false, pathUri.split('/'), isRestful, val, true, standardObj); - - s += pathUri + (StringUtil.isEmpty(c, true) ? '' : ': ' + c) - } - catch (e) { - s += '\n' + e.message - } - - return s; - } - - } - }) - - - var DEBUG = false - - var initJson = {} - -// 主题 [key, String, Number, Boolean, Null, link-link, link-hover] - var themes = [ - ['#92278f', '#3ab54a', '#25aae2', '#f3934e', '#f34e5c', '#717171'], - ['rgb(19, 158, 170)', '#cf9f19', '#ec4040', '#7cc500', 'rgb(211, 118, 126)', 'rgb(15, 189, 170)'], - ['#886', '#25aae2', '#e60fc2', '#f43041', 'rgb(180, 83, 244)', 'rgb(148, 164, 13)'], - ['rgb(97, 97, 102)', '#cf4c74', '#20a0d5', '#cd1bc4', '#c1b8b9', 'rgb(25, 8, 174)'] - ] - - - - -// APIJSON <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< - - - function getRequestFromURL(url_, tryParse) { - var url = url_ || window.location.search; - - var index = url == null ? -1 : url.indexOf("?") - if(index < 0) { //判断是否有参数 - return null; - } - - var theRequest = null; - var str = url.substring(index + 1); //从第一个字符开始 因为第0个是?号 获取所有除问号的所有符串 - var arr = str.split("&"); //截除“&”生成一个数组 - - var len = arr == null ? 0 : arr.length; - for(var i = 0; i < len; i++) { - var part = arr[i]; - var ind = part == null ? -1 : part.indexOf("="); - if (ind <= 0) { - continue - } - - if (theRequest == null) { - theRequest = {}; - } - - var v = decodeURIComponent(part.substring(ind+1)); - if (tryParse == true) { - try { - v = JSON.parse(v) - } - catch (e) { - } - } - - theRequest[part.substring(0, ind)] = v; - } - - return theRequest; - } - - - function markdownToHTML(md, isRequest) { - if (editormd == null) { - return; - } - - if (isRequest) { - vRequestMarkdown.innerHTML = ''; - } - else { - vMarkdown.innerHTML = ''; - } - editormd.markdownToHTML(isRequest ? 'vRequestMarkdown' : "vMarkdown", { - markdown : md ,//+ "\r\n" + $("#append-test").text(), - //htmlDecode : true, // 开启 HTML 标签解析,为了安全性,默认不开启 - htmlDecode : "style,script,iframe", // you can filter tags decode - //toc : false, - tocm : true, // Using [TOCM] - //tocContainer : "#custom-toc-container", // 自定义 ToC 容器层 - //gfm : false, - tocDropdown : true, - // markdownSourceCode : true, // 是否保留 Markdown 源码,即是否删除保存源码的 Textarea 标签 - taskList : true, - tex : true, // 默认不解析 - flowChart : true, // 默认不解析 - sequenceDiagram : true, // 默认不解析 - }); - } - - - - var PLATFORM_POSTMAN = 'POSTMAN' - var PLATFORM_SWAGGER = 'SWAGGER' - var PLATFORM_YAPI = 'YAPI' - var PLATFORM_RAP = 'RAP' - - var REQUEST_TYPE_PARAM = 'PARAM' // GET ?a=1&b=c&key=value - var REQUEST_TYPE_FORM = 'FORM' // POST x-www-form-urlencoded - var REQUEST_TYPE_DATA = 'DATA' // POST form-data - var REQUEST_TYPE_JSON = 'JSON' // POST application/json - var REQUEST_TYPE_GRPC = 'GRPC' // POST application/json - - var CONTENT_TYPE_MAP = { - // 'PARAM': 'plain/text', - 'FORM': 'x-www-form-urlencoded', - 'DATA': 'form-data', - 'JSON': 'application/json', - 'GRPC': 'application/json', - } - var CONTENT_VALUE_TYPE_MAP = { - 'plain/text': 'JSON', - 'x-www-form-urlencoded': 'FORM', - 'form-data': 'DATA', - 'application/json': 'JSON' - } - - var IGNORE_HEADERS = ['status code', 'remote address', 'referrer policy', 'connection', 'content-length' - , 'content-type', 'date', 'keep-alive', 'proxy-connection', 'set-cookie', 'vary', 'accept', 'cache-control', 'dnt' - , 'host', 'origin', 'pragma', 'referer', 'user-agent'] - - var RANDOM_DB = 'RANDOM_DB' - var RANDOM_IN = 'RANDOM_IN' - var RANDOM_INT = 'RANDOM_INT' - var RANDOM_NUM = 'RANDOM_NUM' - var RANDOM_STR = 'RANDOM_STR' - - var ORDER_DB = 'ORDER_DB' - var ORDER_IN = 'ORDER_IN' - var ORDER_INT = 'ORDER_INT' - - var ORDER_MAP = {} - - function randomInt(min, max) { - return randomNum(min, max, 0); - } - function randomNum(min, max, precision) { - // 0 居然也会转成 Number.MIN_SAFE_INTEGER !!! - // start = start || Number.MIN_SAFE_INTEGER - // end = end || Number.MAX_SAFE_INTEGER - - if (min == null) { - min = Number.MIN_SAFE_INTEGER - } - if (max == null) { - max = Number.MAX_SAFE_INTEGER - } - if (precision == null) { - precision = 2 - } - - return + ((max - min)*Math.random() + min).toFixed(precision); - } - function randomStr(minLength, maxLength, availableChars) { - return 'Ab_Cd' + randomNum(); - } - function randomIn(...args) { - return args == null || args.length <= 0 ? null : args[randomInt(0, args.length - 1)]; - } - - function orderInt(desc, index, min, max) { - if (min == null) { - min = Number.MIN_SAFE_INTEGER - } - if (max == null) { - max = Number.MAX_SAFE_INTEGER - } - - if (desc) { - return max - index%(max - min + 1) - } - return min + index%(max - min + 1) - } - function orderIn(desc, index, ...args) { - // alert('orderIn index = ' + index + '; args = ' + JSON.stringify(args)); - index = index || 0; - return args == null || args.length <= index ? null : args[desc ? args.length - index : index]; - } - - function getOrderIndex(randomId, line, argCount) { - // alert('randomId = ' + randomId + '; line = ' + line + '; argCount = ' + argCount); - // alert('ORDER_MAP = ' + JSON.stringify(ORDER_MAP, null, ' ')); - - if (randomId == null) { - randomId = 0; - } - if (ORDER_MAP == null) { - ORDER_MAP = {}; - } - if (ORDER_MAP[randomId] == null) { - ORDER_MAP[randomId] = {}; - } - - var orderIndex = ORDER_MAP[randomId][line]; - // alert('orderIndex = ' + orderIndex) - - if (orderIndex == null || orderIndex < -1) { - orderIndex = -1; - } - - orderIndex ++ - orderIndex = argCount == null || argCount <= 0 ? orderIndex : orderIndex%argCount; - ORDER_MAP[randomId][line] = orderIndex; - - // alert('orderIndex = ' + orderIndex) - // alert('ORDER_MAP = ' + JSON.stringify(ORDER_MAP, null, ' ')); - return orderIndex; - } - //这些全局变量不能放在data中,否则会报undefined错误 - - var baseUrl - var inputted - var handler - var docObj - var doc - var output - - var isSingle = true - - var doneCount - -// APIJSON >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> - - var App = new Vue({ - el: '#app', - data: { - baseview: 'formater', - view: 'output', - jsoncon: JSON.stringify(initJson), - jsonhtml: initJson, - compressStr: '', - error: {}, - requestVersion: 3, - requestCount: 1, - urlComment: '关联查询 Comment.userId = User.id', - historys: [], - history: {name: '请求0'}, - remotes: [], - locals: [], - testCases: [], - randoms: [], - randomSubs: [], - account: '13000082001', - password: '123456', - accounts: [ - { - 'isLoggedIn': false, - 'name': '测试账号1', - 'phone': '13000082001', - 'password': '123456' - }, - { - 'isLoggedIn': false, - 'name': '测试账号2', - 'phone': '13000082002', - 'password': '123456' - }, - { - 'isLoggedIn': false, - 'name': '测试账号3', - 'phone': '13000082003', - 'password': '123456' - } - ], - currentAccountIndex: 0, - currentDocIndex: -1, - currentRandomIndex: -1, - currentRandomSubIndex: -1, - tests: { '-1':{}, '0':{}, '1':{}, '2': {} }, - crossProcess: '交叉账号:已关闭', - testProcess: '机器学习:已关闭', - randomTestTitle: '参数注入 Random Test', - testRandomCount: 1, - testRandomProcess: '', - compareColor: '#0000', - isRandomTest: false, - isDelayShow: false, - isSaveShow: false, - isExportShow: false, - isExportCheckShow: false, - isExportRandom: false, - isTestCaseShow: false, - isHeaderShow: false, - isRandomShow: true, // 默认展示 - isRandomListShow: false, - isRandomSubListShow: false, - isRandomEditable: false, - isLoginShow: false, - isConfigShow: false, - isDeleteShow: false, - currentDocItem: {}, - currentRemoteItem: { - "Document": { - "id": 1560244940013 , - "userId": 82001 , - "testAccountId": 82001 , - "version": 3 , - "name": "测试查询" , - "type": "JSON" , - "url": "/get" , - "date": "2019-06-11 17:22:20.0", -// 导致清空文本后,在说明文档后面重叠显示这个绿色注释 "detail": ` -// 以上 JSON 文本支持 JSON5 格式。清空文本内容可查看规则。 -// 注释可省略。行注释前必须有两个空格;段注释必须在 JSON 下方。 -// -// ## 快捷键 -// Ctrl + I 或 Command + I 格式化 JSON -// -// #### 右上角设置项 > 预览请求输入框,显示对应的预览效果` - }, - "TestRecord": { - "id": 1615135440014 , - "userId": 82001 , - "documentId": 1560244940013 - } - }, - currentRandomItem: {}, - isAdminOperation: false, - loginType: 'login', - isExportRemote: false, - isRegister: false, - isCrossEnabled: false, - isMLEnabled: false, - isDelegateEnabled: false, - isPreviewEnabled: false, - isEncodeEnabled: true, - isEditResponse: false, - isLocalShow: false, - uploadTotal: 0, - uploadDoneCount: 0, - uploadFailCount: 0, - exTxt: { - name: 'APIJSON测试', - label: '发布简单接口', - button: '保存', - index: 0 - }, - themes: themes, - checkedTheme: 0, - isExpand: true, - User: { - id: 0, - name: '', - head: '' - }, - Privacy: { - id: 0, - balance: null //点击更新提示需要判空 0.00 - }, - type: REQUEST_TYPE_JSON, - types: [ REQUEST_TYPE_PARAM, REQUEST_TYPE_JSON], // 很多人喜欢用 GET 接口测试,默认的 JSON 看不懂 , REQUEST_TYPE_FORM, REQUEST_TYPE_DATA, REQUEST_TYPE_GRPC ], //默认展示 - host: '', - database: 'MYSQL', // 查文档必须,除非后端提供默认配置接口 // 用后端默认的,避免用户总是没有配置就问为什么没有生成文档和注释 'MYSQL',// 'POSTGRESQL', - schema: 'sys', // 查文档必须,除非后端提供默认配置接口 // 用后端默认的,避免用户总是没有配置就问为什么没有生成文档和注释 'sys', - server: 'http://apijson.cn:9090/', // Chrome 90+ 跨域问题非常难搞,开发模式启动都不行了 'http://apijson.org:9090/', //apijson.cn - // server: 'http://47.74.39.68:9090/', // apijson.org - thirdParty: 'SWAGGER /v2/api-docs', //apijson.cn - // thirdParty: 'RAP /repository/joined /repository/get', - // thirdParty: 'YAPI /api/interface/list_menu /api/interface/get', - language: CodeUtil.LANGUAGE_KOTLIN, - header: {}, - page: 0, - count: 100, - search: '', - testCasePage: 0, - testCaseCount: 50, - testCaseSearch: '', - randomPage: 0, - randomCount: 50, - randomSearch: '', - randomSubPage: 0, - randomSubCount: 50, - randomSubSearch: '' - }, - methods: { - - // 全部展开 - expandAll: function () { - if (this.view != 'code') { - alert('请先获取正确的JSON Response!') - return - } - - $('.icon-square-min').show() - $('.icon-square-plus').hide() - $('.expand-view').show() - $('.fold-view').hide() - - this.isExpand = true; - }, - - // 全部折叠 - collapseAll: function () { - if (this.view != 'code') { - alert('请先获取正确的JSON Response!') - return - } - - $('.icon-square-min').hide() - $('.icon-square-plus').show() - $('.expand-view').hide() - $('.fold-view').show() - - this.isExpand = false; - }, - - // diff - diffTwo: function () { - var oldJSON = {} - var newJSON = {} - this.view = 'code' - try { - oldJSON = jsonlint.parse(this.jsoncon) - } catch (ex) { - this.view = 'error' - this.error = { - msg: '原 JSON 解析错误\r\n' + ex.message - } - return - } - - try { - newJSON = jsonlint.parse(this.jsoncon) - } catch (ex) { - this.view = 'error' - this.error = { - msg: '新 JSON 解析错误\r\n' + ex.message - } - return - } - - var base = difflib.stringAsLines(JSON.stringify(oldJSON, '', 4)) - var newtxt = difflib.stringAsLines(JSON.stringify(newJSON, '', 4)) - var sm = new difflib.SequenceMatcher(base, newtxt) - var opcodes = sm.get_opcodes() - $('#diffoutput').empty().append(diffview.buildView({ - baseTextLines: base, - newTextLines: newtxt, - opcodes: opcodes, - baseTextName: '原 JSON', - newTextName: '新 JSON', - contextSize: 2, - viewType: 0 - })) - }, - - baseViewToDiff: function () { - this.baseview = 'diff' - this.diffTwo() - }, - - // 回到格式化视图 - baseViewToFormater: function () { - this.baseview = 'formater' - this.view = 'code' - this.showJsonView() - }, - - // 根据json内容变化格式化视图 - showJsonView: function () { - if (this.baseview === 'diff') { - return - } - try { - if (this.jsoncon.trim() === '') { - this.view = 'empty' - } else { - this.view = 'code' - - if (isSingle) { - this.jsonhtml = jsonlint.parse(this.jsoncon) - } - else { - this.jsonhtml = Object.assign({ - _$_this_$_: JSON.stringify({ - path: null, - table: null - }) - }, jsonlint.parse(this.jsoncon)) - } - - } - } catch (ex) { - this.view = 'error' - this.error = { - msg: ex.message - } - } - }, - - - showUrl: function (isAdminOperation, branchUrl) { - if (StringUtil.isEmpty(this.host, true)) { //显示(可编辑)URL Host - if (isAdminOperation != true) { - baseUrl = this.getBaseUrl() - } - vUrl.value = (isAdminOperation ? this.server : baseUrl) + branchUrl - } - else { //隐藏(固定)URL Host - if (isAdminOperation) { - this.host = this.server - } - vUrl.value = branchUrl - } - - vUrlComment.value = isSingle || StringUtil.isEmpty(this.urlComment, true) - ? '' : vUrl.value + CodeUtil.getComment(this.urlComment, false, ' ') - + ' - ' + (this.requestVersion > 0 ? 'V' + this.requestVersion : 'V*'); - }, - - //设置基地址 - setBaseUrl: function () { - if (StringUtil.isEmpty(this.host, true) != true) { - return - } - // 重新拉取文档 - var bu = this.getBaseUrl() - if (baseUrl != bu) { - baseUrl = bu; - doc = null //这个是本地的数据库字典及非开放请求文档 - this.saveCache('', 'URL_BASE', baseUrl) - - //已换成固定的管理系统URL - - // this.remotes = [] - - // var index = baseUrl.indexOf(':') //http://localhost:8080 - // this.server = (index < 0 ? baseUrl : baseUrl.substring(0, baseUrl)) + ':9090' - - } - }, - getUrl: function () { - var url = StringUtil.get(this.host) + new String(vUrl.value) - return url.replace(/ /g, '') - }, - //获取基地址 - getBaseUrl: function () { - var url = new String(vUrl.value).trim() - var length = this.getBaseUrlLength(url) - url = length <= 0 ? '' : url.substring(0, length) - return url == '' ? URL_BASE : url - }, - //获取基地址长度,以://后的第一个/分割baseUrl和method - getBaseUrlLength: function (url_) { - var url = StringUtil.trim(url_) - var index = url.indexOf(' ') - if (index >= 0) { - return index + 1 - } - - index = url.indexOf('://') - return index < 0 ? 0 : index + 3 + url.substring(index + 3).indexOf('/') - }, - //获取操作方法 - getMethod: function () { - var url = new String(vUrl.value).trim() - var index = this.getBaseUrlLength(url) - url = index <= 0 ? url : url.substring(index) - index = url.indexOf("?") - if (index >= 0) { - url = url.substring(0, index) - } - return url.startsWith('/') ? url.substring(1) : url - }, - //获取请求的tag - getTag: function () { - var req = null; - try { - req = this.getRequest(vInput.value); - } catch (e) { - log('main.getTag', 'try { req = this.getRequest(vInput.value); \n } catch (e) {\n' + e.message) - } - return req == null ? null : req.tag - }, - - getRequest: function (json, defaultValue, isRaw) { // JSON5 兜底,减少修改范围 , isSingle) { - var s = isRaw != true && isSingle ? this.switchQuote(json) : json; // this.toDoubleJSON(json, defaultValue); - if (StringUtil.isEmpty(s, true)) { - return defaultValue - } - try { - return jsonlint.parse(s); - } - catch (e) { - log('main.getRequest', 'try { return jsonlint.parse(s); \n } catch (e2) {\n' + e.message) - log('main.getRequest', 'return jsonlint.parse(this.removeComment(s));') - return JSON5.parse(s); // jsonlint.parse(this.removeComment(s)); - } - }, - getExtraComment: function(json) { - var it = json != null ? json : StringUtil.trim(vInput.value); - - var start = it.lastIndexOf('\n\/*'); - var end = it.lastIndexOf('\n*\/'); - - return start < 0 || end <= start ? null : it.substring(start + '\n\/*'.length, end); - }, - - getHeader: function (text) { - var header = {} - var hs = StringUtil.isEmpty(text, true) ? null : StringUtil.split(text, '\n') - - if (hs != null && hs.length > 0) { - var item - for (var i = 0; i < hs.length; i++) { - item = hs[i] || '' - - // 解决整体 trim 后第一行 // 被当成正常的 key 路径而不是注释 - var index = StringUtil.trim(item).startsWith('//') ? 0 : item.lastIndexOf(' //') // 不加空格会导致 http:// 被截断 ('//') //这里只支持单行注释,不用 removeComment 那种带多行的去注释方式 - var item2 = index < 0 ? item : item.substring(0, index) - item2 = item2.trim() - if (item2.length <= 0) { - continue; - } - - index = item2.indexOf(':') - if (index <= 0) { - throw new Error('请求头 Request Header 输入错误!请按照每行 key: value 的格式输入,不要有多余的换行或空格!' - + '\n错误位置: 第 ' + (i + 1) + ' 行' - + '\n错误文本: ' + item) - } - - var val = item2.substring(index + 1, item2.length) - - var ind = val.indexOf('(') //一定要有函数是为了避免里面是一个简短单词和 APIAuto 代码中变量冲突 - if (ind > 0 && val.indexOf(')') > ind) { //不从 0 开始是为了保证是函数,且不是 (1) 这种单纯限制作用域的括号 - try { - val = eval(val) - } - catch (e) { - this.log("getHeader if (hs != null && hs.length > 0) { ... if (ind > 0 && val.indexOf(')') > ind) { ... try { val = eval(val) } catch (e) = " + e.message) - } - } - - header[StringUtil.trim(item2.substring(0, index))] = val - } - } - - return header - }, - - // 分享 APIAuto 特有链接,打开即可还原分享人的 JSON 参数、设置项、搜索关键词、分页数量及页码等配置 - shareLink: function (isRandom) { - var jsonStr = null - if (this.isTestCaseShow != true) { - try { - jsonStr = JSON.stringify(encode(JSON.parse(vInput.value))) - } catch (e) { // 可能包含注释 - log(e) - jsonStr = encode(StringUtil.trim(vInput.value)) - } - } - - // URL 太长导致打不开标签 - var settingStr = null - try { - settingStr = JSON.stringify({ - requestVersion: this.requestVersion, - requestCount: this.requestCount, - isTestCaseShow: this.isTestCaseShow, - // isHeaderShow: this.isHeaderShow, - // isRandomShow: this.isRandomShow, - isRandomListShow: this.isRandomShow ? this.isRandomListShow : undefined, - isRandomSubListShow: this.isRandomListShow ? this.isRandomSubListShow : undefined, - // isRandomEditable: this.isRandomEditable, - isCrossEnabled: this.isCrossEnabled, - isMLEnabled: this.isMLEnabled, - isDelegateEnabled: this.isDelegateEnabled, - isPreviewEnabled: this.isPreviewEnabled, - isEncodeEnabled: this.isEncodeEnabled, - isEditResponse: this.isEditResponse, - isLocalShow: this.isTestCaseShow ? this.isLocalShow : undefined, - page: this.page, - count: this.count, - testCasePage: this.testCasePage, - testCaseCount: this.testCaseCount, - testRandomCount: this.testRandomCount, - randomPage: this.randomPage, - randomCount: this.randomCount, - randomSubPage: this.randomSubPage, - randomSubCount: this.randomSubCount, - host: StringUtil.isEmpty(this.host, true) ? undefined : encodeURIComponent(this.host), - search: StringUtil.isEmpty(this.search, true) ? undefined : encodeURIComponent(this.search), - testCaseSearch: StringUtil.isEmpty(this.testCaseSearch, true) ? undefined : this.testCaseSearch, - randomSearch: StringUtil.isEmpty(this.randomSearch, true) ? undefined : encodeURIComponent(this.randomSearch), - randomSubSearch: StringUtil.isEmpty(this.randomSubSearch, true) ? undefined : encodeURIComponent(this.randomSubSearch) - }) - } catch (e){ - log(e) - } - - var headerStr = this.isTestCaseShow || StringUtil.isEmpty(vHeader.value, true) ? null : encodeURIComponent(StringUtil.trim(vHeader.value)) - var randomStr = this.isTestCaseShow || StringUtil.isEmpty(vRandom.value, true) ? null : encodeURIComponent(StringUtil.trim(vRandom.value)) - - var href = window.location.href || 'http://apijson.cn/api' - var ind = href == null ? -1 : href.indexOf('?') // url 后带参数只能 encodeURIComponent - - // 实测 561059 长度的 URL 都支持,只是输入框显示长度约为 2000 - window.open((ind < 0 ? href : href.substring(0, ind)) - + (this.view != 'code' ? "?send=false" : (isRandom ? "?send=random" : "?send=true")) - + "&type=" + StringUtil.trim(this.type) - + "&url=" + encodeURIComponent(StringUtil.trim(vUrl.value)) - + (StringUtil.isEmpty(jsonStr, true) ? '' : "&json=" + jsonStr) - + (StringUtil.isEmpty(headerStr, true) ? '' : "&header=" + headerStr) - + (StringUtil.isEmpty(randomStr, true) ? '' : "&random=" + randomStr) - + (StringUtil.isEmpty(settingStr, true) ? '' : "&setting=" + settingStr) - ) - }, - - // 显示保存弹窗 - showSave: function (show) { - if (show) { - if (this.isTestCaseShow) { - alert('请先输入请求内容!') - return - } - - var tag = this.getTag() - this.history.name = (this.urlComment || this.getMethod() + (StringUtil.isEmpty(tag, true) ? '' : ' ' + tag)) + ' ' + this.formatTime() //不自定义名称的都是临时的,不需要时间太详细 - } - this.isSaveShow = show - }, - - // 显示导出弹窗 - showExport: function (show, isRemote, isRandom) { - if (show) { - // this.isExportCheckShow = isRemote - - if (isRemote) { //共享测试用例 - this.isExportRandom = isRandom - - // if (isRandom != true) { // 分享搜索关键词和分页信息也挺好 } && this.isTestCaseShow != true) { // 没有拿到列表,没用 - // setTimeout(function () { - // App.shareLink(App.isRandomTest) - // }, 1000) - // } - - if (this.isTestCaseShow) { - alert('请先输入请求内容!') - return - } - - if (this.view == 'error') { // this.view != 'code') { - alert('发现错误,请输入正确的内容!') // alert('请先测试请求,确保是正确可用的!') - return - } - if (isRandom) { - this.exTxt.name = '随机配置 ' + this.formatDateTime() - } - else { - if (this.isEditResponse) { - this.isExportRemote = isRemote - this.exportTxt() - return - } - - // var tag = this.getTag() - this.exTxt.name = this.urlComment || '' // 避免偷懒不输入名称 this.getMethod() + (StringUtil.isEmpty(tag, true) ? '' : ' ' + tag) - } - } - else { //下载到本地 - if (this.isTestCaseShow) { //文档 - this.exTxt.name = 'APIJSON自动化文档 ' + this.formatDateTime() - } - else if (this.view == 'markdown' || this.view == 'output') { - var suffix - switch (this.language) { - case CodeUtil.LANGUAGE_KOTLIN: - suffix = '.kt'; - break; - case CodeUtil.LANGUAGE_JAVA: - suffix = '.java'; - break; - case CodeUtil.LANGUAGE_C_SHARP: - suffix = '.cs'; - break; - - case CodeUtil.LANGUAGE_SWIFT: - suffix = '.swift'; - break; - case CodeUtil.LANGUAGE_OBJECTIVE_C: - suffix = '.h'; - break; - - case CodeUtil.LANGUAGE_GO: - suffix = '.go'; - break; - case CodeUtil.LANGUAGE_C_PLUS_PLUS: - suffix = '.cpp'; - break; - - case CodeUtil.LANGUAGE_TYPE_SCRIPT: - suffix = '.ts'; - break; - case CodeUtil.LANGUAGE_JAVA_SCRIPT: - suffix = '.js'; - break; - - case CodeUtil.LANGUAGE_PHP: - suffix = '.php'; - break; - case CodeUtil.LANGUAGE_PYTHON: - suffix = '.py'; - break; - default: - suffix = '.java'; - break; - } - - this.exTxt.name = 'User' + suffix - alert('自动生成模型代码,可填类名后缀:\n' - + 'Kotlin.kt, Java.java, Swift.swift, Objective-C.m, C#.cs, Go.go,' - + '\nTypeScript.ts, JavaScript.js, PHP.php, Python.py, C++.cpp'); - } - else { - this.exTxt.name = 'APIJSON测试 ' + this.getMethod() + ' ' + this.formatDateTime() - } - } - } - - this.isExportShow = show - this.isExportRemote = isRemote - }, - - // 显示配置弹窗 - showConfig: function (show, index) { - this.isConfigShow = false - if (this.isTestCaseShow) { - if (index == 3 || index == 4 || index == 5 || index == 10) { - this.showTestCase(false, false) - } - } - - if (show) { - this.exTxt.button = index == 8 ? '上传' : '切换' - this.exTxt.index = index - switch (index) { - case 0: - case 1: - case 2: - case 6: - case 7: - case 8: - this.exTxt.name = index == 0 ? this.database : (index == 1 ? this.schema : (index == 2 - ? this.language : (index == 6 ? this.server : (index == 8 ? this.thirdParty : (this.types || []).join())))) - this.isConfigShow = true - - if (index == 0) { - alert('可填数据库:\nMYSQL,POSTGRESQL,SQLSERVER,ORACLE,DB2,SQLITE') - } - else if (index == 2) { - alert('自动生成代码,可填语言:\nKotlin,Java,Swift,Objective-C,C#,Go,\nTypeScript,JavaScript,PHP,Python,C++') - } - else if (index == 7) { - alert('多个类型用 , 隔开,可填类型:\nPARAM(GET ?a=1&b=c&key=value),\nJSON(POST application/json),\nFORM(POST x-www-form-urlencoded),\nDATA(POST form-data),\nGRPC(POST application/json 需要 GRPC 服务开启反射)') - } - else if (index == 8) { - this.isHeaderShow = true - - alert('例如:\nSWAGGER http://apijson.cn:8080/v2/api-docs\nSWAGGER /v2/api-docs // 省略 Host\nSWAGGER / // 省略 Host 和 分支 URL\nRAP /repository/joined /repository/get\nYAPI /api/interface/list_menu /api/interface/get') - - try { - this.getThirdPartyApiList(this.thirdParty, function (platform, docUrl, listUrl, itemUrl, url_, res, err) { - CodeUtil.thirdParty = platform - var data = err != null ? null : (res || {}).data; - var code = data == null ? null : data.errCode || data.errcode || data.err_code - - if (err != null || (code != null && code != 0)) { - App.isHeaderShow = true - App.isRandomShow = false - alert('请把 YApi/Rap/Swagger 等网站的有效 Cookie 粘贴到请求头 Request Header 输入框后再试!') - } - - App.onResponse(url_, res, err) - return false - }, function (platform, docUrl, listUrl, itemUrl, url_, res, err) { - var data = (res || {}).data - var apiMap = CodeUtil.thirdPartyApiMap || {} - - if (platform == PLATFORM_POSTMAN) { - alert('尚未开发 ' + PLATFORM_POSTMAN) - return true - } - else if (platform == PLATFORM_SWAGGER) { - var apis = data == null ? null : data.paths - if (apis != null) { - // var i = 0 - for (var url in apis) { - var item = apis[url] - apiMap[url] = item.post || item.get || item.put || item.delete - } - } - } - else if (platform == PLATFORM_RAP) { - } - else if (platform == PLATFORM_YAPI) { - var api = (data || {}).data - var url = api == null || api.path == null ? null : StringUtil.noBlank(api.path).replace(/\/\//g, '/') - if (StringUtil.isEmpty(url, true)) { - return - } - - var typeAndParam = App.parseYApiTypeAndParam(api) - - var name = StringUtil.trim(api.username) + ': ' + StringUtil.trim(api.title) - apiMap[url] = { - name: name, - request: typeAndParam.param, - response: api.res_body == null ? null : JSON.parse(api.res_body), - detail: name - + '\n' + (api.up_time == null ? '' : (typeof api.up_time != 'number' ? api.up_time : new Date(1000*api.up_time).toLocaleString())) - + '\nhttp://apijson.cn/yapi/project/1/interface/api/' + api._id - + '\n\n' + (StringUtil.isEmpty(api.markdown, true) ? StringUtil.trim(api.description) : api.markdown.trim().replace(/\\_/g, '_')) - } - } - else { - alert('第三方平台只支持 Postman, Swagger, Rap, YApi !') - return true - } - - CodeUtil.thirdPartyApiMap = apiMap - App.saveCache(App.thirdParty, 'thirdPartyApiMap', apiMap); - - return true - }) - } catch (e) { - console.log('created try { ' + - '\nthis.User = this.getCache(this.server, User) || {}' + - '\n} catch (e) {\n' + e.message) - } - - } - break - case 3: - this.host = this.getBaseUrl() - this.showUrl(false, new String(vUrl.value).substring(this.host.length)) //没必要导致必须重新获取 Response,this.onChange(false) - break - case 4: - this.isHeaderShow = show - this.saveCache('', 'isHeaderShow', show) - break - case 5: - this.isRandomShow = show - this.saveCache('', 'isRandomShow', show) - break - case 9: - this.isDelegateEnabled = show - this.saveCache('', 'isDelegateEnabled', show) - break - case 10: - this.isPreviewEnabled = show - this.saveCache('', 'isPreviewEnabled', show) - - this.onChange(false) - break - case 12: - this.isEncodeEnabled = show - this.saveCache('', 'isEncodeEnabled', show) - break - case 11: - var did = ((this.currentRemoteItem || {}).Document || {}).id - if (did == null) { - alert('请先选择一个已上传的用例!') - return - } - - this.isEditResponse = show - // this.saveCache('', 'isEditResponse', show) - - vInput.value = ((this.view != 'code' || StringUtil.isEmpty(this.jsoncon, true) ? null : this.jsoncon) - || (this.currentRemoteItem.TestRecord || {}).response) || '' - - vHeader.value = (this.currentRemoteItem.TestRecord || {}).header || '' - - this.isTestCaseShow = false - this.onChange(false) - break - } - } - else if (index == 3) { - var host = StringUtil.get(this.host) - var branch = new String(vUrl.value) - this.host = '' - vUrl.value = host + branch //保证 showUrl 里拿到的 baseUrl = this.host (http://apijson.cn:8080/put /balance) - this.setBaseUrl() //保证自动化测试等拿到的 baseUrl 是最新的 - this.showUrl(false, branch) //没必要导致必须重新获取 Response,this.onChange(false) - } - else if (index == 4) { - this.isHeaderShow = show - this.saveCache('', 'isHeaderShow', show) - } - else if (index == 5) { - this.isRandomShow = show - this.saveCache('', 'isRandomShow', show) - } - else if (index == 9) { - this.isDelegateEnabled = show - this.saveCache('', 'isDelegateEnabled', show) - } - else if (index == 10) { - this.isPreviewEnabled = show - this.saveCache('', 'isPreviewEnabled', show) - // vRequestMarkdown.innerHTML = '' - } - else if (index == 12) { - this.isEncodeEnabled = show - this.saveCache('', 'isEncodeEnabled', show) - } - else if (index == 11) { - this.isEditResponse = show - // this.saveCache('', 'isEditResponse', show) - - vInput.value = (this.currentRemoteItem.Document || {}).request || '' - vHeader.value = (this.currentRemoteItem.Document || {}).header || '' - - this.isTestCaseShow = false - this.onChange(false) - } - }, - - // 显示删除弹窗 - showDelete: function (show, item, index, isRandom) { - this.isDeleteShow = show - this.isDeleteRandom = isRandom - this.exTxt.name = '请输入' + (isRandom ? '随机配置' : '接口') + '名来确认' - if (isRandom) { - this.currentRandomItem = Object.assign(item, { - index: index - }) - } - else { - this.currentDocItem = Object.assign(item, { - index: index - }) - } - }, - - // 删除接口文档 - deleteDoc: function () { - var isDeleteRandom = this.isDeleteRandom - var item = (isDeleteRandom ? this.currentRandomItem : this.currentDocItem) || {} - var doc = (isDeleteRandom ? item.Random : item.Document) || {} - - var type = isDeleteRandom ? '随机配置' : '接口' - if (doc.id == null) { - alert('未选择' + type + '或' + type + '不存在!') - return - } - if (doc.name != this.exTxt.name) { - alert('输入的' + type + '名和要删除的' + type + '名不匹配!') - return - } - - this.showDelete(false, {}) - - this.isTestCaseShow = false - this.isRandomListShow = false - - var url = this.server + '/delete' - var req = isDeleteRandom ? { - format: false, - 'Random': { - 'id': doc.id - }, - 'tag': 'Random' - } : { - format: false, - 'Document': { - 'id': doc.id - }, - 'tag': 'Document' - } - this.request(true, REQUEST_TYPE_JSON, url, req, {}, function (url, res, err) { - App.onResponse(url, res, err) - - var rpObj = res.data || {} - - if (isDeleteRandom) { - if (rpObj.Random != null && rpObj.Random.code == CODE_SUCCESS) { - if (((item.Random || {}).toId || 0) <= 0) { - App.randoms.splice(item.index, 1) - } - else { - App.randomSubs.splice(item.index, 1) - } - // App.showRandomList(true, App.currentRemoteItem) - } - } else { - if (rpObj.Document != null && rpObj.Document.code == CODE_SUCCESS) { - App.remotes.splice(item.index, 1) - App.showTestCase(true, App.isLocalShow) - } - } - }) - }, - - // 保存当前的JSON - save: function () { - if (this.history.name.trim() === '') { - Helper.alert('名称不能为空!', 'danger') - return - } - var val = { - name: this.history.name, - type: this.type, - url: '/' + this.getMethod(), - request: inputted, - response: this.jsoncon, - header: vHeader.value, - random: vRandom.value - } - var key = String(Date.now()) - localforage.setItem(key, val, function (err, value) { - Helper.alert('保存成功!', 'success') - App.showSave(false) - val.key = key - App.historys.push(val) - }) - }, - - // 清空本地历史 - clearLocal: function () { - this.locals.splice(0, this.locals.length) //UI无反应 this.locals = [] - this.saveCache('', 'locals', []) - }, - - // 删除已保存的 - remove: function (item, index, isRemote, isRandom) { - if (isRemote == null || isRemote == false) { //null != false - localforage.removeItem(item.key, function () { - App.historys.splice(index, 1) - }) - } else { - if (this.isLocalShow) { - this.locals.splice(index, 1) - this.saveCache('', 'locals', this.locals) - return - } - - if (isRandom && (((item || {}).Random || {}).id || 0) <= 0) { - this.randomSubs.splice(index, 1) - return - } - - this.showDelete(true, item, index, isRandom) - } - }, - - // 根据参数注入用例恢复数据 - restoreRandom: function (index, item) { - this.currentRandomItem = item - this.isRandomListShow = false - this.isRandomSubListShow = false - var random = (item || {}).Random || {} - this.randomTestTitle = random.name - this.testRandomCount = random.count - vRandom.value = StringUtil.get(random.config) - - var response = ((item || {}).TestRecord || {}).response - if (StringUtil.isEmpty(response, true) == false) { - this.jsoncon = StringUtil.trim(response) - this.view = 'code' - } - }, - // 根据测试用例/历史记录恢复数据 - restoreRemoteAndTest: function (index, item) { - this.restoreRemote(index, item, true) - }, - // 根据测试用例/历史记录恢复数据 - restoreRemote: function (index, item, test) { - this.currentDocIndex = index - this.currentRemoteItem = item - this.restore((item || {}).Document, ((item || {}).TestRecord || {}).response, true, test) - }, - // 根据历史恢复数据 - restore: function (item, response, isRemote, test) { - this.isEditResponse = false - - item = item || {} - // localforage.getItem(item.key || '', function (err, value) { - var branch = new String(item.url || '/get') - if (branch.startsWith('/') == false) { - branch = '/' + branch - } - - this.type = item.type; - this.urlComment = item.name; - this.requestVersion = item.version; - this.showUrl(false, branch) - - this.showTestCase(false, this.isLocalShow) - vInput.value = StringUtil.get(item.request) - vHeader.value = StringUtil.get(item.header) - vRandom.value = StringUtil.get(item.random) - this.onChange(false) - - if (isRemote) { - this.randoms = [] - this.showRandomList(this.isRandomListShow, item) - } - - if (test) { - this.send(false) - } - else { - if (StringUtil.isEmpty(response, true) == false) { - setTimeout(function () { - App.jsoncon = StringUtil.trim(response) - App.view = 'code' - }, 500) - } - } - - // }) - }, - - // 获取所有保存的json - listHistory: function () { - localforage.iterate(function (value, key, iterationNumber) { - if (key[0] !== '#') { - value.key = key - App.historys.push(value) - } - if (key === '#theme') { - // 设置默认主题 - App.checkedTheme = value - } - }) - }, - - // 导出文本 - exportTxt: function (btnIndex) { - if (btnIndex == null) { - btnIndex = 0 - } - - if (btnIndex == 1 && this.isExportRandom != true) { - this.shareLink(this.isRandomTest) - return - } - - this.isExportShow = false - - if (this.isExportRemote == false) { //下载到本地 - - if (this.isTestCaseShow) { //文档 - saveTextAs('# ' + this.exTxt.name + '\n主页: https://github.com/Tencent/APIJSON' - + '\n\nBASE_URL: ' + this.getBaseUrl() - + '\n\n\n## 测试用例(Markdown格式,可用工具预览) \n\n' + this.getDoc4TestCase() - + '\n\n\n\n\n\n\n\n## 文档(Markdown格式,可用工具预览) \n\n' + doc - , this.exTxt.name + '.txt') - } - else if (this.view == 'markdown' || this.view == 'output') { //model - var clazz = StringUtil.trim(this.exTxt.name) - - var txt = '' //配合下面 +=,实现注释判断,一次全生成,方便测试 - if (clazz.endsWith('.java')) { - txt += CodeUtil.parseJavaBean(docObj, clazz.substring(0, clazz.length - 5), this.database) - } - else if (clazz.endsWith('.swift')) { - txt += CodeUtil.parseSwiftStruct(docObj, clazz.substring(0, clazz.length - 6), this.database) - } - else if (clazz.endsWith('.kt')) { - txt += CodeUtil.parseKotlinDataClass(docObj, clazz.substring(0, clazz.length - 3), this.database) - } - else if (clazz.endsWith('.m')) { - txt += CodeUtil.parseObjectiveCEntity(docObj, clazz.substring(0, clazz.length - 2), this.database) - } - else if (clazz.endsWith('.cs')) { - txt += CodeUtil.parseCSharpEntity(docObj, clazz.substring(0, clazz.length - 3), this.database) - } - else if (clazz.endsWith('.php')) { - txt += CodeUtil.parsePHPEntity(docObj, clazz.substring(0, clazz.length - 4), this.database) - } - else if (clazz.endsWith('.go')) { - txt += CodeUtil.parseGoEntity(docObj, clazz.substring(0, clazz.length - 3), this.database) - } - else if (clazz.endsWith('.cpp')) { - txt += CodeUtil.parseCppStruct(docObj, clazz.substring(0, clazz.length - 4), this.database) - } - else if (clazz.endsWith('.js')) { - txt += CodeUtil.parseJavaScriptEntity(docObj, clazz.substring(0, clazz.length - 3), this.database) - } - else if (clazz.endsWith('.ts')) { - txt += CodeUtil.parseTypeScriptEntity(docObj, clazz.substring(0, clazz.length - 3), this.database) - } - else if (clazz.endsWith('.py')) { - txt += CodeUtil.parsePythonEntity(docObj, clazz.substring(0, clazz.length - 3), this.database) - } - else { - alert('请正确输入对应语言的类名后缀!') - } - - if (StringUtil.isEmpty(txt, true)) { - alert('找不到 ' + clazz + ' 对应的表!请检查数据库中是否存在!\n如果不存在,请重新输入存在的表;\n如果存在,请刷新网页后重试。') - return - } - saveTextAs(txt, clazz) - } - else { - var res = JSON.parse(this.jsoncon) - res = this.removeDebugInfo(res) - - var s = '' - switch (this.language) { - case CodeUtil.LANGUAGE_KOTLIN: - s += '(Kotlin):\n\n' + CodeUtil.parseKotlinResponse('', res, 0, false, ! isSingle) - break; - case CodeUtil.LANGUAGE_JAVA: - s += '(Java):\n\n' + CodeUtil.parseJavaResponse('', res, 0, false, ! isSingle) - break; - case CodeUtil.LANGUAGE_C_SHARP: - s += '(C#):\n\n' + CodeUtil.parseCSharpResponse('', res, 0) - break; - - case CodeUtil.LANGUAGE_SWIFT: - s += '(Swift):\n\n' + CodeUtil.parseSwiftResponse('', res, 0, isSingle) - break; - case CodeUtil.LANGUAGE_OBJECTIVE_C: - s += '(Objective-C):\n\n' + CodeUtil.parseObjectiveCResponse('', res, 0) - break; - - case CodeUtil.LANGUAGE_GO: - s += '(Go):\n\n' + CodeUtil.parseGoResponse('', res, 0) - break; - case CodeUtil.LANGUAGE_C_PLUS_PLUS: - s += '(C++):\n\n' + CodeUtil.parseCppResponse('', res, 0, isSingle) - break; - - case CodeUtil.LANGUAGE_TYPE_SCRIPT: - s += '(TypeScript):\n\n' + CodeUtil.parseTypeScriptResponse('', res, 0, isSingle) - break; - case CodeUtil.LANGUAGE_JAVA_SCRIPT: - s += '(JavaScript):\n\n' + CodeUtil.parseJavaScriptResponse('', res, 0, isSingle) - break; - - case CodeUtil.LANGUAGE_PHP: - s += '(PHP):\n\n' + CodeUtil.parsePHPResponse('', res, 0, isSingle) - break; - case CodeUtil.LANGUAGE_PYTHON: - s += '(Python):\n\n' + CodeUtil.parsePythonResponse('', res, 0, isSingle) - break; - default: - s += ':\n没有生成代码,可能生成代码(封装,解析)的语言配置错误。 \n'; - break; - } - - saveTextAs('# ' + this.exTxt.name + '\n主页: https://github.com/Tencent/APIJSON' - + '\n\n\nURL: ' + StringUtil.get(vUrl.value) - + '\n\n\nHeader:\n' + StringUtil.get(vHeader.value) - + '\n\n\nRequest:\n' + StringUtil.get(vInput.value) - + '\n\n\nResponse:\n' + StringUtil.get(this.jsoncon) - + '\n\n\n## 解析 Response 的代码' + s - , this.exTxt.name + '.txt') - } - } - else { //上传到远程服务器 - var id = this.User == null ? null : this.User.id - if (id == null || id <= 0) { - alert('请先登录!') - return - } - - const isExportRandom = this.isExportRandom - const isEditResponse = this.isEditResponse - const isReleaseRESTful = isExportRandom && btnIndex == 1 && ! isEditResponse - - const method = App.getMethod(); - const methodInfo = isReleaseRESTful ? (CodeUtil.parseUri(method, true) || {}) : {}; - if (isReleaseRESTful) { - var isRestful = methodInfo.isRestful; - var tag = methodInfo.tag; - var table = methodInfo.table; - - if (isRestful) { - alert('请求 URL 格式不是 APIJSON 万能通用接口!必须为 /get/user 这种 /{method}/{tag} 格式!其中 method 只能为 [' + APIJSON_METHODS.join() + '] 中的一个,tag 不能为 Table, Table[] 这种与 APIJSON 简单接口冲突的格式! ') - return - } - if (StringUtil.isEmpty(tag, true)) { - alert('请求 URL 缺少 tag!必须为 /get/user 这种 /{method}/{tag} 格式!其中 method 只能为 [' + APIJSON_METHODS.join() + '] 中的一个,tag 不能为 Table, Table[] 这种与 APIJSON 简单接口冲突的格式! ') - return - } - if (JSONObject.isTableKey(table)) { - alert('请求 URL 中的字符 ' + table + ' 与 APIJSON 简单接口冲突!必须为 /get/user 这种 /{method}/{tag} 格式!其中 method 只能为 [' + APIJSON_METHODS.join() + '] 中的一个,tag 不能为 Table, Table[] 这种与 APIJSON 简单接口冲突的格式! ') - return - } - } - - if ((isExportRandom != true || btnIndex == 1) && StringUtil.isEmpty(this.exTxt.name, true)) { - alert('请输入接口名!') - return - } - - const doc = (this.currentRemoteItem || {}).Document || {} - const tr = (this.currentRemoteItem || {}).TestRecord || {} - const did = isExportRandom && btnIndex == 1 ? null : doc.id - if (isExportRandom && btnIndex <= 0 && did == null) { - alert('请先共享测试用例!') - return - } - - this.isTestCaseShow = false - - const currentAccountId = this.getCurrentAccountId() - const currentResponse = this.view != 'code' || StringUtil.isEmpty(this.jsoncon, true) ? {} : this.removeDebugInfo(JSON.parse(this.jsoncon)); - - const after = isSingle ? this.switchQuote(inputted) : inputted; // this.toDoubleJSON(inputted); - const inputObj = this.getRequest(after, {}); - - var commentObj = null; - if (isExportRandom != true) { - var m = this.getMethod(); - var commentStddObj = null - try { - commentStddObj = JSON.parse(isEditResponse ? tr.standard : doc.standard); - } - catch(e) { - log(e) - } - var code_ = inputObj.code - inputObj.code = null // delete inputObj.code - - commentObj = JSONResponse.updateStandard(commentStddObj, inputObj); - CodeUtil.parseComment(after, docObj == null ? null : docObj['[]'], m, this.database, this.language, isEditResponse != true, commentObj, true); - - inputObj.code = code_ - } - - const code = currentResponse.code; - const thrw = currentResponse.throw; - delete currentResponse.code; //code必须一致 - delete currentResponse.throw; //throw必须一致 - - const isML = this.isMLEnabled; - const stddObj = isML ? JSONResponse.updateStandard({}, currentResponse) : {}; - stddObj.code = code; - stddObj.throw = thrw; - currentResponse.code = code; - currentResponse.throw = thrw; - - var config = vRandom.value; - const mapReq = {}; - const mustKeys = []; - const typeObj = {}; - const refuseKeys = []; - - if (isReleaseRESTful) { - var mapReq2 = {} - - var cfgLines = StringUtil.split(config, '\n', true); - var newCfg = ''; - if (cfgLines != null) { - for (var i = 0; i < cfgLines.length; i++) { - var cfgLine = cfgLines[i]; - var ind = cfgLine == null ? -1 : cfgLine.indexOf(': '); - if (ind <= 0) { - continue; - } - - var cInd = cfgLine.indexOf('//'); - if (cInd >= 0 && cInd <= ind) { - continue; - } - - var k = cfgLine.substring(0, ind).replace(/\//g, '.'); // .trim(); - var ks = StringUtil.split(k, '.') - var p = inputObj; - for (var j = 0; j < ks.length - 1; j ++) { - if (p == null) { - break; - } - - var jk = ks[j]; - p = jk == null ? null : p[jk]; - } - - var v = p == null ? null : p[ks[ks.length - 1]]; - mapReq[k] = v; - mapReq2[k] = v; - - // 智能判断 count, @key 等 - if (k.startsWith('@') || k.endsWith('[].count') || k.endsWith('[].query') || ['format', 'version'].indexOf(k) >= 0) { - refuseKeys.push('!' + k); - } - else { - mustKeys.push(k); - } - - var t = JSONResponse.getType(v); - typeObj[k] = t == 'integer' ? 'NUMBER' : (t == 'number' ? 'DECIMAL' : t.toUpperCase()); - - newCfg += (i <= 0 ? '' : '\n') + k + ': ' + cfgLine.substring(ind+2).trim(); - } - - refuseKeys.push('!'); - config = newCfg; - } - - commentObj = JSONResponse.updateStandard({}, mapReq2); - } - - - var callback = function (randomName, constConfig, constJson) { - // 用现成的测试过的更好,Response 与 Request 严格对应 - // var mapReq = {}; - // if (isExportRandom && btnIndex == 1) { - // - // var mapReq2 = {} - // var cfgLines = StringUtil.split(constConfig, '\n', true); - // if (cfgLines != null) { - // for (var i = 0; i < cfgLines.length; i++) { - // var cfgLine = cfgLines[i]; - // var ind = cfgLine == null ? -1 : cfgLine.indexOf(': '); - // if (ind <= 0) { - // continue; - // } - // - // var k = cfgLine.substring(0, ind).replace(/\//g, '.'); // .trim(); - // var v = cfgLine.substring(ind + 1).trim(); - // try { - // v = JSON.parse(v); - // } - // catch (e) { - // log(e) - // } - // - // mapReq[k] = v - // mapReq2[k] = v - // } - // } - // - // commentObj = JSONResponse.updateStandard({}, mapReq2); - // } - - const extName = App.exTxt.name; - const baseUrl = App.getBaseUrl(); - const url = (isReleaseRESTful ? baseUrl : App.server) + (isExportRandom || isEditResponse || did == null ? '/post' : '/put') - const req = isExportRandom && btnIndex <= 0 ? { - format: false, - 'Random': { - toId: 0, - documentId: did, - count: App.requestCount, - name: App.exTxt.name, - config: config - }, - 'TestRecord': { - 'response': JSON.stringify(currentResponse), - 'standard': isML ? JSON.stringify(stddObj) : null - }, - 'tag': 'Random' - } : { - format: false, - 'Document': isEditResponse ? null : { - 'id': did == null ? undefined : did, - 'testAccountId': currentAccountId, - 'name': extName, - 'type': App.type, - 'url': '/' + method, // 'url': isReleaseRESTful ? ('/' + methodInfo.method + '/' + methodInfo.tag) : ('/' + method), - 'request': JSON.stringify(btnIndex <= 0 ? constJson : mapReq, null, ' '), - 'apijson': btnIndex <= 0 ? undefined : JSON.stringify(constJson, null, ' '), - 'standard': commentObj == null ? null : JSON.stringify(commentObj, null, ' '), - 'header': vHeader.value, - 'detail': App.getExtraComment() || ((App.currentRemoteItem || {}).Document || {}).detail, - }, - 'TestRecord': isEditResponse != true && did != null ? null : { - 'documentId': isEditResponse ? did : undefined, - 'randomId': 0, - 'host': baseUrl, - 'testAccountId': currentAccountId, - 'response': JSON.stringify(isEditResponse ? inputObj : currentResponse), - 'standard': isML || isEditResponse ? JSON.stringify(isEditResponse ? commentObj : stddObj) : undefined, - // 没必要,直接都在请求中说明,查看也方便 'detail': (isEditResponse ? App.getExtraComment() : null) || ((App.currentRemoteItem || {}).TestRecord || {}).detail, - }, - 'tag': isEditResponse ? 'TestRecord' : 'Document' - } - - App.request(true, REQUEST_TYPE_JSON, url, req, {}, function (url, res, err) { - App.onResponse(url, res, err) - - var rpObj = res.data || {} - - if (isExportRandom && btnIndex <= 0) { - if (rpObj.code == CODE_SUCCESS) { - App.randoms = [] - App.showRandomList(true, (App.currentRemoteItem || {}).Document) - } - } - else { - var isPut = url.indexOf('/put') >= 0 - - if (rpObj.code != CODE_SUCCESS) { - if (isPut) { // 修改失败就转为新增 - App.currentRemoteItem = null; - alert('修改失败,请重试(自动转为新增)!' + StringUtil.trim(rpObj.msg)) - } - } - else { - App.remotes = [] - App.showTestCase(true, false) - - if (isPut) { // 修改失败就转为新增 - alert('修改成功') - return - } - - if (isReleaseRESTful) { - var structure = {"MUST": mustKeys.join(), "TYPE": typeObj, "REFUSE": refuseKeys.join()}; - - var reqObj = { - format: false, - Request: { - method: StringUtil.toUpperCase(methodInfo.method), - tag: methodInfo.tag, - structure: JSON.stringify(structure, null, ' '), - detail: extName - }, - tag: 'Request' - }; - - App.request(true, REQUEST_TYPE_JSON, baseUrl + '/post', reqObj, {}, function (url, res, err) { - if (res.data != null && res.data.Request != null && res.data.Request.code == CODE_SUCCESS) { - alert('已自动生成并上传 Request 表校验规则配置:\n' + JSON.stringify(reqObj.Request, null, ' ')) - } - else { - var reqStr = JSON.stringify(reqObj, null, ' '); - console.log('已自动生成,但上传以下 Request 表校验规则配置失败,可能需要手动加表记录:\nPOST ' + baseUrl + '/post' + '\n' + reqStr) - alert('已自动生成,但上传以下 Request 表校验规则配置失败,可能需要手动加表记录,如未自动复制可在控制台复制:\n' + reqStr) - navigator.clipboard.writeText(reqStr); - } - App.onResponse(url, res, err) - }) - } - - //自动生成随机配置(遍历 JSON,对所有可变值生成配置,排除 @key, key@, key() 等固定值) - - const isGenerate = StringUtil.isEmpty(config, true); - if (isGenerate) { - var req = isReleaseRESTful ? mapReq : App.getRequest(vInput.value, {}) - config = StringUtil.trim(App.newRandomConfig(null, '', req)) - - if (StringUtil.isEmpty(config, true)) { - return; - } - } - - App.request(true, REQUEST_TYPE_JSON, (isReleaseRESTful ? baseUrl : App.server) + '/post', { - format: false, - 'Random': { - documentId: rpObj.Document.id, - count: App.requestCount, - name: '默认配置' + (isGenerate ? '(上传测试用例时自动生成)' : ''), - config: config - }, - TestRecord: { - host: baseUrl, - response: '' - }, - 'tag': 'Random' - }, {}, function (url, res, err) { - if (res.data != null && res.data.Random != null && res.data.Random.code == CODE_SUCCESS) { - alert('已' + (isGenerate ? '自动生成并' : '') + '上传随机配置:\n' + config) - App.isRandomListShow = true - } - else { - alert((isGenerate ? '已自动生成,但' : '') + '上传以下随机配置失败:\n' + config) - vRandom.value = config - } - App.onResponse(url, res, err) - }) - } - } - }) - }; - - if (btnIndex == 1) { - // this.parseRandom(inputObj, config, null, true, true, false, callback) - callback(null, null, inputObj) - } - else { - callback(null, null, inputObj) - } - - } - }, - - newRandomConfig: function (path, key, value) { - if (key == null) { - return '' - } - if (path == '' && (key == 'tag' || key == 'version' || key == 'format')) { - return '' - } - - var config = '' - var childPath = path == null || path == '' ? key : path + '/' + key - var prefix = '\n' + childPath + ': ' - - if (value instanceof Array) { - var val - if (value.length <= 0) { - val = '' - } - else { - if (value.length <= 1) { - val = ', ' + JSON.stringify(value) - } - else if (value.length <= 2) { - val = ', ' + JSON.stringify([value[0]]) + ', ' + JSON.stringify([value[1]]) + ', ' + JSON.stringify(value) - } - else { - val = ', ' + JSON.stringify([value[0]]) + ', ' + JSON.stringify([value[value.length - 1]]) + ', ' + JSON.stringify([value[Math.floor(value.length / 2)]]) + ', ' + JSON.stringify(value) - } - } - config += prefix + 'ORDER_IN(undefined, null, []' + val + ')' - } - else if (value instanceof Object) { - for(var k in value) { - var v = value[k] - - var isAPIJSONArray = v instanceof Object && v instanceof Array == false - && k.startsWith('@') == false && (k.endsWith('[]') || k.endsWith('@')) - if (isAPIJSONArray) { - if (k.endsWith('@')) { - delete v.from - delete v.range - } - - prefix = '\n' + (childPath == null || childPath == '' ? '' : childPath + '/') + k + '/' - if (v.hasOwnProperty('page')) { - config += prefix + 'page: ' + 'ORDER_INT(0, 10)' - delete v.page - } - if (v.hasOwnProperty('count')) { - config += prefix + 'count: ' + 'ORDER_IN(undefined, null, 0, 1, 5, 10, 20' - + ([0, 1, 5, 10, 20].indexOf(v.count) >= 0 ? ')' : ', ' + v.count + ')') - delete v.count - } - if (v.hasOwnProperty('query')) { - config += prefix + 'query: ' + 'ORDER_IN(undefined, null, 0, 1, 2)' - delete v.query - } - } - - config += this.newRandomConfig(childPath, k, v) - } - } - else { - //自定义关键词 - if (key.startsWith('@')) { - return config - } - - if (typeof value == 'boolean') { - config += prefix + 'ORDER_IN(undefined, null, false, true)' - } - else if (typeof value == 'number') { - var isId = key == 'id' || key.endsWith('Id') || key.endsWith('_id') || key.endsWith('_ID') - if (isId) { - config += prefix + 'ORDER_IN(undefined, null, ' + value + ')' - if (value >= 1000000000) { //PHP 等语言默认精确到秒 1000000000000) { - config += '\n // 可替代上面的 ' + prefix.substring(1) + 'RANDOM_INT(' + Math.round(0.9 * value) + ', ' + Math.round(1.1 * value) + ')' - } - else { - config += '\n // 可替代上面的 ' + prefix.substring(1) + 'RANDOM_INT(1, ' + (10 * value) + ')' - } - } - else { - var valStr = String(value) - var dotIndex = valStr.indexOf('.') - var hasDot = dotIndex >= 0 - var keep = dotIndex < 0 ? 2 : valStr.length - dotIndex - 1 - - if (value < 0) { - config += prefix + (hasDot ? 'RANDOM_NUM' : 'RANDOM_INT') + '(' + (100 * value) + (hasDot ? ', 0, ' + keep + ')' : ', 0)') - } - else if (value > 0 && value < 1) { // 0-1 比例 - config += prefix + 'RANDOM_NUM(0, 1, ' + keep + ')' - } - else if ((hasDot && value > 0 && value <= 100) || (hasDot != true && value > 5 && value <= 100)) { // 10% 百分比 - config += prefix + (hasDot ? 'RANDOM_NUM(0, 100, ' + keep + ')' : 'RANDOM_INT(0, 100)') - } - else { - config += prefix + (dotIndex < 0 && value <= 10 - ? 'ORDER_INT(0, 10)' - : ((hasDot ? 'RANDOM_NUM' : 'RANDOM_INT') + '(0, ' + 100 * value + (hasDot ? ', ' + keep + ')' : ')')) - ) - var hasDot = String(value).indexOf('.') >= 0 - - if (value < 0) { - config += '\n // 可替代上面的 ' + prefix.substring(1) + (hasDot ? 'RANDOM_NUM' : 'RANDOM_INT') + '(' + (100 * value) + ', 0)' - } - else if (value > 0 && value < 1) { // 0-1 比例 - config += '\n // 可替代上面的 ' + prefix.substring(1) + 'RANDOM_NUM(0, 1)' - } - else if (value >= 0 && value <= 100) { // 10% 百分比 - config += '\n // 可替代上面的 ' + prefix.substring(1) + 'RANDOM_INT(0, 100)' - } - else { - config += '\n // 可替代上面的 ' + prefix.substring(1) + (hasDot != true && value < 10 ? 'ORDER_INT(0, 9)' : ((hasDot ? 'RANDOM_NUM' : 'RANDOM_INT') + '(0, ' + 100 * value + ')')) - } - } - } - } - else if (typeof value == 'string') { - //引用赋值 || 远程函数 || 匹配条件范围 - if (key.endsWith('@') || key.endsWith('()') || key.endsWith('{}')) { - return config - } - - config += prefix + 'ORDER_IN(undefined, null, ""' + (value == '' ? ')' : ', "' + value + '")') - } - else { - config += prefix + 'ORDER_IN(undefined, null' + (value == null ? ')' : ', ' + JSON.stringify(value) + ')') - } - - } - - return config - }, - - - - // 保存配置 - saveConfig: function () { - this.isConfigShow = this.exTxt.index == 8 - - switch (this.exTxt.index) { - case 0: - this.database = CodeUtil.database = this.exTxt.name - this.saveCache('', 'database', this.database) - - doc = null - var item = this.accounts[this.currentAccountIndex] - item.isLoggedIn = false - this.onClickAccount(this.currentAccountIndex, item) - break - case 1: - this.schema = CodeUtil.schema = this.exTxt.name - this.saveCache('', 'schema', this.schema) - - doc = null - var item = this.accounts[this.currentAccountIndex] - item.isLoggedIn = false - this.onClickAccount(this.currentAccountIndex, item) - break - case 2: - this.language = CodeUtil.language = this.exTxt.name - this.saveCache('', 'language', this.language) - - doc = null - this.onChange(false) - break - case 6: - this.server = this.exTxt.name - this.saveCache('', 'server', this.server) - this.logout(true) - break - case 7: - this.types = StringUtil.split(this.exTxt.name) - this.saveCache('', 'types', this.types) - break - case 8: - this.getThirdPartyApiList(this.exTxt.name, function (platform, docUrl, listUrl, itemUrl, url_, res, err) { - var jsonData = (res || {}).data - var isJSONData = jsonData instanceof Object - if (isJSONData == false) { //后面是 URL 才存储;是 JSON 数据则不存储 - App.thirdParty = thirdParty - App.saveCache('', 'thirdParty', App.thirdParty) - } - - const header = App.getHeader(vHeader.value) - - if (platform == PLATFORM_POSTMAN) { - alert('尚未开发 ' + PLATFORM_POSTMAN) - } - else if (platform == PLATFORM_SWAGGER) { - var swaggerCallback = function (url_, res, err) { - if (App.isSyncing) { - alert('正在同步,请等待完成') - return - } - App.isSyncing = true - App.onResponse(url_, res, err) - - var apis = (res.data || {}).paths - if (apis == null) { // || apis.length <= 0) { - App.isSyncing = false - alert('没有查到 Swagger 文档!请开启跨域代理,并检查 URL 是否正确!') - return - } - App.exTxt.button = '...' - - App.uploadTotal = 0 // apis.length || 0 - App.uploadDoneCount = 0 - App.uploadFailCount = 0 - - var item - // var i = 0 - for (var url in apis) { - item = apis[url] - //导致 url 全都是一样的 setTimeout(function () { - if (App.uploadSwaggerApi(url, item, 'get') - || App.uploadSwaggerApi(url, item, 'post') - || App.uploadSwaggerApi(url, item, 'put') - || App.uploadSwaggerApi(url, item, 'delete') - ) {} - // }, 100*i) - // i ++ - } - } - - if (isJSONData) { - swaggerCallback(docUrl, { data: jsonData }, null) - } - else { - App.request(false, REQUEST_TYPE_PARAM, docUrl, {}, header, swaggerCallback) - } - } - else if (platform == PLATFORM_RAP || platform == PLATFORM_YAPI) { - var isRap = platform == PLATFORM_RAP - - var itemCallback = function (url, res, err) { - try { - App.onResponse(url, res, err) - } catch (e) {} - - var data = res.data == null ? null : res.data.data - if (isRap) { - var modules = data == null ? null : data.modules - if (modules != null) { - for (var i = 0; i < modules.length; i++) { - var it = modules[i] || {} - var interfaces = it.interfaces || [] - - for (var j = 0; j < interfaces.length; j++) { - App.uploadRapApi(interfaces[j]) - } - } - } - } - else { - App.uploadYApi(data) - } - } - - if (isJSONData) { - itemCallback(itemUrl, { data: jsonData }, null) - } - else { - App.request(false, REQUEST_TYPE_PARAM, listUrl, {}, header, function (url_, res, err) { - if (App.isSyncing) { - alert('正在同步,请等待完成') - return - } - App.isSyncing = true - App.onResponse(url_, res, err) - - var apis = (res.data || {}).data - if (apis == null) { // || apis.length <= 0) { - App.isSyncing = false - alert('没有查到 ' + (isRap ? 'Rap' : 'YApi') + ' 文档!请开启跨域代理,并检查 URL 是否正确!') - return - } - App.exTxt.button = '...' - - App.uploadTotal = 0 // apis.length || 0 - App.uploadDoneCount = 0 - App.uploadFailCount = 0 - - var item - for (var url in apis) { - item = apis[url] || {} - - var list = (isRap ? [ { _id: item.id } ] : (item == null ? null : item.list)) || [] - for (let i1 = 0; i1 < list.length; i1++) { - var listItem1 = list[i1] - if (listItem1 == null || listItem1._id == null) { - App.log('listItem1 == null || listItem1._id == null >> continue') - continue - } - - App.request(false, REQUEST_TYPE_PARAM, itemUrl + '?id=' + listItem1._id, {}, header, itemCallback) - } - - } - }) - - } - - } - else { - alert('第三方平台只支持 Postman, Swagger, Rap, YApi !') - } - - return true - }) - - break - } - }, - - getThirdPartyApiList: function (thirdParty, listCallback, itemCallback) { - this.parseThirdParty(thirdParty, function (platform, jsonData, docUrl, listUrl, itemUrl) { - var isJSONData = jsonData instanceof Object - - const header = App.getHeader(vHeader.value) - - if (platform == PLATFORM_POSTMAN) { - alert('尚未开发 ' + PLATFORM_POSTMAN) - } - else if (platform == PLATFORM_SWAGGER) { - if (isJSONData) { - listCallback(platform, docUrl, listUrl, itemUrl, itemUrl, { data: jsonData }, null) - } - else { - App.request(false, REQUEST_TYPE_PARAM, docUrl, {}, header, function (url_, res, err) { - if (listCallback != null && listCallback(platform, docUrl, listUrl, itemUrl, url_, res, err)) { - return - } - - if (itemCallback != null) { - itemCallback(platform, docUrl, listUrl, itemUrl, itemUrl, res, err) - } - }) - } - } - else if (platform == PLATFORM_RAP || platform == PLATFORM_YAPI) { - var isRap = platform == PLATFORM_RAP - - if (isJSONData) { - if (listCallback != null && listCallback(platform, docUrl, listUrl, itemUrl, listUrl, {data: [jsonData]}, null)) { - return - } - - if (itemCallback != null) { - itemCallback(platform, docUrl, listUrl, itemUrl, itemUrl, {data: jsonData}, null) - } - } - else { - App.request(false, REQUEST_TYPE_PARAM, listUrl, {}, header, function (url_, res, err) { - if (listCallback != null && listCallback(platform, docUrl, listUrl, itemUrl, url_, res, err)) { - return - } - - var apis = (res.data || {}).data - if (apis == null) { // || apis.length <= 0) { - alert('没有查到 ' + (isRap ? 'Rap' : 'YApi') + ' 文档!请开启跨域代理,并检查 URL 是否正确!YApi/Rap/Swagger 网站的 Cookie 必须粘贴到请求头 Request Header 输入框!') - return - } - - var item - for (var url in apis) { - item = apis[url] || {} - - var list = (isRap ? [ { _id: item.id } ] : (item == null ? null : item.list)) || [] - for (let i1 = 0; i1 < list.length; i1++) { - var listItem1 = list[i1] - if (listItem1 == null || listItem1._id == null) { - App.log('listItem1 == null || listItem1._id == null >> continue') - continue - } - - // var p = listItem1.path == null ? null : StringUtil.noBlank(listItem1.path).replace(/\/\//g, '/') - // if (p == null) { - // continue - // } - - App.request(false, REQUEST_TYPE_PARAM, itemUrl + '?id=' + listItem1._id, {}, header, function (url_, res, err) { - if (itemCallback != null) { - itemCallback(platform, docUrl, listUrl, itemUrl, url_, res, err) - } - }) - } - - } - }) - - } - - } - else { - alert('第三方平台只支持 Postman, Swagger, Rap, YApi !') - } - }) - - }, - - parseThirdParty: function (thirdParty, callback) { - var tp = StringUtil.trim(thirdParty) - var index = tp.indexOf(' ') - var platform = index < 0 ? PLATFORM_SWAGGER : tp.substring(0, index).toUpperCase() - var docUrl = index <= 0 ? tp.trim() : tp.substring(index + 1).trim() - - var jsonData = null - try { - jsonData = JSON.parse(docUrl) - } - catch (e) {} - - var host = this.getBaseUrl() - var listUrl = null - var itemUrl = null - - if (platform == PLATFORM_SWAGGER) { - if (docUrl == '/') { - docUrl += 'v2/api-docs' - } - if (docUrl.startsWith('/')) { - docUrl = host + docUrl - } - } - else if (platform == PLATFORM_RAP || platform == PLATFORM_YAPI) { - var isRap = platform == PLATFORM_RAP - index = docUrl.indexOf(' ') - listUrl = index < 0 ? docUrl + (isRap ? '/repository/joined' : '/api/interface/list_menu') : docUrl.substring(0, index).trim() - itemUrl = index < 0 ? docUrl + (isRap ? '/repository/get' : '/api/interface/get') : docUrl.substring(index + 1).trim() - - if (listUrl.startsWith('/')) { - listUrl = host + listUrl - } - if (itemUrl.startsWith('/')) { - itemUrl = host + itemUrl - } - } - - callback(platform, jsonData, docUrl, listUrl, itemUrl) - }, - - /**上传 Swagger API - * @param url - * @param docItem - * @param method - * @param callback - */ - uploadSwaggerApi: function(url, docItem, method) { - method = method || 'get' - var api = docItem == null ? null : docItem[method] - if (api == null) { - log('postApi', 'api == null >> return') - this.exTxt.button = 'All:' + this.uploadTotal + '\nDone:' + this.uploadDoneCount + '\nFail:' + this.uploadFailCount - return false - } - - this.uploadTotal ++ - - var parameters = api.parameters || [] - var parameters2 = [] - if (parameters != null && parameters.length > 0) { - - for (var k = 0; k < parameters.length; k++) { - var paraItem = parameters[k] || {} - var name = paraItem.name || '' - if (name == 'mock') { - continue - } - - parameters2.push(paraItem) - } - } - - return this.uploadThirdPartyApi(method == 'get' ? REQUEST_TYPE_PARAM : REQUEST_TYPE_JSON - , api.summary, url, parameters2, api.headers, api.description) - }, - - - /**上传 Rap API - * @param docItem - */ - uploadRapApi: function(docItem) { - var api = docItem - if (api == null) { - log('postApi', 'api == null >> return') - this.exTxt.button = 'All:' + this.uploadTotal + '\nDone:' + this.uploadDoneCount + '\nFail:' + this.uploadFailCount - return false - } - - this.uploadTotal ++ - - var type - switch ((api.summary || {}).requestParamsType || '') { - case 'QUERY_PARAMS': - type = REQUEST_TYPE_PARAM - break - case 'BODY_PARAMS': - switch ((api.summary || {}).bodyOption || '') { - case 'FORM_DATA': - type = REQUEST_TYPE_DATA - break - case 'FORM_URLENCODED': - type = REQUEST_TYPE_FORM - break - // case 'RAW': //JSON - default: - type = REQUEST_TYPE_JSON - break - } - break - default: - type = REQUEST_TYPE_JSON - break - } - - var header = '' - - var parameters = api.properties - - var parameters2 = [] - if (parameters != null && parameters.length > 0) { - - for (var k = 0; k < parameters.length; k++) { - - var paraItem = parameters[k] || {} - var name = paraItem.name || '' - if (StringUtil.isEmpty(name, true) || paraItem.scope != 'request') { - continue - } - - var val = paraItem.value - - if (paraItem.pos == 1) { //header - header += (k <= 0 ? '' : '\n') + name + ': ' + (val == null ? '' : val) - + (StringUtil.isEmpty(paraItem.description, true) ? '' : ' // ' + paraItem.description) - continue - } - - //转成和 Swagger 一样的字段及格式 - paraItem.type = paraItem.type == 'Number' ? 'integer' : StringUtil.toLowerCase(paraItem.type) - paraItem.default = val - - parameters2.push(paraItem) - } - } - - return this.uploadThirdPartyApi(type, api.name, api.url, parameters2, header, api.description) - }, - - /**上传 YApi - * @param docItem - */ - uploadYApi: function(docItem) { - var api = docItem - if (api == null) { - log('postApi', 'api == null >> return') - this.exTxt.button = 'All:' + this.uploadTotal + '\nDone:' + this.uploadDoneCount + '\nFail:' + this.uploadFailCount - return false - } - - this.uploadTotal++ - - var headers = api.req_headers || [] - var header = '' - for (var i = 0; i < headers.length; i ++) { - var item = headers[i]; - var name = item == null ? null : item.name - if (name == null) { - continue - } - header += (i <= 0 ? '' : '\n') + name + ': ' + item.value - + (StringUtil.isEmpty(item.description, true) ? '' : ' // ' + item.description) - } - - var typeAndParam = this.parseYApiTypeAndParam(api) - - return this.uploadThirdPartyApi( - typeAndParam.type, api.title, api.path, typeAndParam.param, header - , (StringUtil.trim(api.username) + ': ' + StringUtil.trim(api.title) - + '\n' + (api.up_time == null ? '' : (typeof api.up_time != 'number' ? api.up_time : new Date(1000*api.up_time).toLocaleString())) - + '\nhttp://apijson.cn/yapi/project/1/interface/api/' + api._id - + '\n\n' + (StringUtil.isEmpty(api.markdown, true) ? StringUtil.trim(api.description) : api.markdown.trim().replace(/\\_/g, '_'))) - , api.username - ) - }, - - - parseYApiTypeAndParam: function (api) { - if (api == null) { - return {} - } - - var type - var parameters - switch (api.req_body_type || '') { - case 'form': - type = REQUEST_TYPE_FORM - parameters = api.req_body_form - break - case 'data': - type = REQUEST_TYPE_DATA - parameters = api.req_params - break - case 'query': - type = REQUEST_TYPE_PARAM - parameters = api.req_query - break - default: - type = REQUEST_TYPE_JSON - parameters = api.req_body_other == null ? null : JSON.parse(api.req_body_other) - - var params = parameters.properties || {} - var required = parameters.required || [] - var newParams = [] - for (var k in params) { //TODO 递归里面的子项 - var item = params[k] - item.name = k - item.required = required.indexOf(k) >= 0 - newParams.push(item) - } - parameters = newParams - break - } - - var parameters2 = [] - if (parameters != null && parameters.length > 0) { - //过滤掉无效的,避免多拼接 , 导致 req 不是合法 JSON - for (var k = 0; k < parameters.length; k++) { - var paraItem = parameters[k] || {} - var name = paraItem.name || '' - if (StringUtil.isEmpty(name, true)) { - continue - } - - //转成和 Swagger 一样的字段及格式 - paraItem.url = paraItem.path - - var val = (paraItem.mock || {}).mock - if (val == null && type == 'array') { - val = [] - var it = paraItem.items || {} - var v = it == null ? null : (it.mock || {}).mock - val.push(v) - } - paraItem.default = val - - parameters2.push(paraItem) - } - } - - return { - type: type, - param: parameters2 - } - }, - - //上传第三方平台的 API 至 APIAuto - uploadThirdPartyApi: function(type, name, url, parameters, header, description, creator) { - var req = '{' - - if (parameters != null && parameters.length > 0) { - for (var k = 0; k < parameters.length; k++) { - var paraItem = parameters[k] || {} - var n = paraItem.name || '' //传进来前已过滤,这里只是避免万一为 null 导致后面崩溃 - var t = paraItem.type || '' - var val = paraItem.default - - if (val == undefined) { - if (t == 'boolean') { - val = 'true' - } - if (t == 'integer') { - val = n == 'pageSize' ? '10' : '1' - } - else if (t == 'string') { - val = '""' - } - else if (t == 'object') { - val = '{}' - } - else if (t == 'array') { - val = '[]' - } - else { - var suffix = n.length >= 3 ? n.substring(n.length - 3).toLowerCase() : null - if (suffix == 'dto') { - val = '{}' - } else { - val = 'null' - } - } - } - else if (typeof val == 'string' && (StringUtil.isEmpty(t, true) || t == 'string')) { - val = '"' + val.replace(/"/g, '\\"') + '"' - } - else if (val instanceof Object) { - val = JSON.stringify(val, null, ' ') - } - - req += '\n "' + n + '": ' + val + (k < parameters.length - 1 ? ',' : '') - + ' // ' + (paraItem.required ? '必填。 ' : '') + StringUtil.trim(paraItem.description) - } - - } - - req += '\n}' - - if (StringUtil.isEmpty(description, true) == false) { - req += '\n\n/**\n\n' + StringUtil.trim(description).replace(/\*\//g, '* /') + '\n\n*/' - } - - - var currentAccountId = this.getCurrentAccountId() - this.request(true, REQUEST_TYPE_JSON, this.server + '/post', { - format: false, - 'Document': { - 'creator': creator, - 'testAccountId': currentAccountId, - 'type': type, - 'name': StringUtil.get(name), - 'url': url, - 'request': req, - 'header': StringUtil.isEmpty(header, true) ? null : StringUtil.trim(header) - }, - 'TestRecord': { - 'randomId': 0, - 'host': this.getBaseUrl(), - 'testAccountId': currentAccountId, - 'response': '' - }, - 'tag': 'Document' - }, {}, function (url, res, err) { - //太卡 App.onResponse(url, res, err) - if (res.data != null && res.data.Document != null && res.data.Document.code == CODE_SUCCESS) { - App.uploadDoneCount ++ - } else { - App.uploadFailCount ++ - } - - App.exTxt.button = 'All:' + App.uploadTotal + '\nDone:' + App.uploadDoneCount + '\nFail:' + App.uploadFailCount - if (App.uploadDoneCount + App.uploadFailCount >= App.uploadTotal) { - alert('导入完成') - App.isSyncing = false - App.showTestCase(false, false) - App.remotes = [] - App.showTestCase(true, false) - } - }) - - return true - }, - - // 切换主题 - switchTheme: function (index) { - this.checkedTheme = index - localforage.setItem('#theme', index) - }, - - - // APIJSON <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< - - //格式化日期 - formatDate: function (date) { - if (date == null) { - date = new Date() - } - return date.getFullYear() + '-' + this.fillZero(date.getMonth() + 1) + '-' + this.fillZero(date.getDate()) - }, - //格式化时间 - formatTime: function (date) { - if (date == null) { - date = new Date() - } - return this.fillZero(date.getHours()) + ':' + this.fillZero(date.getMinutes()) - }, - formatDateTime: function (date) { - if (date == null) { - date = new Date() - } - return this.formatDate(date) + ' ' + this.formatTime(date) - }, - //填充0 - fillZero: function (num, n) { - if (num == null) { - num = 0 - } - if (n == null || n <= 0) { - n = 2 - } - var len = num.toString().length; - while(len < n) { - num = "0" + num; - len++; - } - return num; - }, - - - - - - - onClickAccount: function (index, item, callback) { - this.isTestCaseShow = false - - if (this.currentAccountIndex == index) { - if (item == null) { - if (callback != null) { - callback(false, index) - } - } - else { - this.setRememberLogin(item.remember) - this.account = item.phone - this.password = item.password - - if (item.isLoggedIn) { - //logout FIXME 没法自定义退出,浏览器默认根据url来管理session的 - this.logout(false, function (url, res, err) { - App.onResponse(url, res, err) - - item.isLoggedIn = false - App.saveCache(App.getBaseUrl(), 'currentAccountIndex', App.currentAccountIndex) - App.saveCache(App.getBaseUrl(), 'accounts', App.accounts) - - if (callback != null) { - callback(false, index, err) - } - }); - } - else { - //login - this.login(false, function (url, res, err) { - App.onResponse(url, res, err) - - var data = res.data || {} - var user = data.code == CODE_SUCCESS ? data.user : null - if (user == null) { - if (callback != null) { - callback(false, index, err) - } - } - else { - item.name = user.name - item.remember = data.remember - item.isLoggedIn = true - - App.accounts[App.currentAccountIndex] = item - App.saveCache(App.getBaseUrl(), 'currentAccountIndex', App.currentAccountIndex) - App.saveCache(App.getBaseUrl(), 'accounts', App.accounts) - - if (callback != null) { - callback(true, index, err) - } - } - }); - } - - } - - return; - } - - //退出当前账号 - var c = this.currentAccountIndex - var it = c == null || this.accounts == null ? null : this.accounts[c]; - if (it != null) { //切换 BASE_URL后 it = undefined 导致UI操作无法继续 - it.isLoggedIn = false //异步导致账号错位 this.onClickAccount(c, this.accounts[c]) - } - - //切换到这个tab - this.currentAccountIndex = index - - //目前还没做到同一标签页下测试账号切换后,session也跟着切换,所以干脆每次切换tab就重新登录 - if (item != null) { - item.isLoggedIn = false - this.onClickAccount(index, item, callback) - } - else { - if (callback != null) { - callback(false, index) - } - } - }, - - removeAccountTab: function () { - if (this.accounts.length <= 1) { - alert('至少要 1 个测试账号!') - return - } - - this.accounts.splice(this.currentAccountIndex, 1) - if (this.currentAccountIndex >= this.accounts.length) { - this.currentAccountIndex = this.accounts.length - 1 - } - - this.saveCache(this.getBaseUrl(), 'currentAccountIndex', this.currentAccountIndex) - this.saveCache(this.getBaseUrl(), 'accounts', this.accounts) - }, - addAccountTab: function () { - this.showLogin(true, false) - }, - - - //显示远程的测试用例文档 - showTestCase: function (show, isLocal) { - this.isTestCaseShow = show - this.isLocalShow = isLocal - - vOutput.value = show ? '' : (output || '') - this.showDoc() - - if (isLocal) { - this.testCases = this.locals || [] - return - } - this.testCases = this.remotes || [] - - if (show) { - var testCases = this.testCases - var allCount = testCases == null ? 0 : testCases.length - if (allCount > 0) { - var accountIndex = (this.accounts[this.currentAccountIndex] || {}).isLoggedIn ? this.currentAccountIndex : -1 - this.currentAccountIndex = accountIndex //解决 onTestResponse 用 -1 存进去, handleTest 用 currentAccountIndex 取出来为空 - - var tests = this.tests[String(accountIndex)] || {} - if (tests != null && $.isEmptyObject(tests) != true) { - for (var i = 0; i < allCount; i++) { - var item = testCases[i] - if (item == null) { - continue - } - var d = item.Document || {} - this.compareResponse(allCount, testCases, i, item, (tests[d.id] || {})[0], false, accountIndex, true) - } - } - return; - } - - this.isTestCaseShow = false - - var types = this.types - var search = StringUtil.isEmpty(this.testCaseSearch, true) ? null : '%' + StringUtil.trim(this.testCaseSearch) + '%' - var url = this.server + '/get' - var req = { - format: false, - '[]': { - 'count': this.testCaseCount || 100, //200 条测试直接卡死 0, - 'page': this.testCasePage || 0, - 'Document': { - '@order': 'version-,date-', - 'userId': this.User.id, - 'name$': search, - 'url$': search, - '@combine': search == null ? null : 'name$,url$', - 'type{}': types == null || types.length <= 0 ? null : types - }, - 'TestRecord': { - 'documentId@': '/Document/id', - 'userId': this.User.id, - 'testAccountId': this.getCurrentAccountId(), - 'randomId': 0, - '@order': 'date-', - '@column': 'id,userId,documentId,duration,minDuration,maxDuration,response' + (this.isMLEnabled ? ',standard' : ''), - '@having': this.isMLEnabled ? 'length(standard)>2' : null //用 MySQL 5.6 '@having': this.isMLEnabled ? 'json_length(standard)>0' : null - } - }, - '@role': 'LOGIN' - } - - this.onChange(false) - this.request(true, REQUEST_TYPE_JSON, url, req, {}, function (url, res, err) { - App.onResponse(url, res, err) - - var rpObj = res.data - - if (rpObj != null && rpObj.code === CODE_SUCCESS) { - App.isTestCaseShow = true - App.isLocalShow = false - App.testCases = App.remotes = rpObj['[]'] - vOutput.value = show ? '' : (output || '') - App.showDoc() - - //App.onChange(false) - } - }) - } - }, - - //显示远程的随机配置文档 - showRandomList: function (show, item, isSub) { - this.isRandomEditable = false - this.isRandomListShow = show && ! isSub - this.isRandomSubListShow = show && isSub - if (! isSub) { - this.randomSubs = [] - } - - vOutput.value = show ? '' : (output || '') - this.showDoc() - - this.randoms = this.randoms || [] - - if (show && this.isRandomShow && this.randoms.length <= 0 && item != null && item.id != null) { - this.isRandomListShow = false - - var subSearch = StringUtil.isEmpty(this.randomSubSearch, true) - ? null : '%' + StringUtil.trim(this.randomSubSearch) + '%' - var search = isSub ? subSearch : (StringUtil.isEmpty(this.randomSearch, true) - ? null : '%' + StringUtil.trim(this.randomSearch) + '%') - - var url = this.server + '/get' - var req = { - '[]': { - 'count': (isSub ? this.randomSubCount : this.randomCount) || 100, - 'page': (isSub ? this.randomSubPage : this.randomPage) || 0, - 'Random': { - 'toId': isSub ? item.id : 0, - 'documentId': isSub ? null : item.id, - '@order': "date-", - 'name$': search - }, - 'TestRecord': { - 'randomId@': '/Random/id', - 'testAccountId': this.getCurrentAccountId(), - 'host': this.getBaseUrl(), - '@order': 'date-' - }, - '[]': isSub ? null : { - 'count': this.randomSubCount || 100, - 'page': this.randomSubPage || 0, - 'Random': { - 'toId@': '[]/Random/id', - 'documentId': item.id, - '@order': "date-", - 'name$': subSearch - }, - 'TestRecord': { - 'randomId@': '/Random/id', - 'testAccountId': this.getCurrentAccountId(), - 'host': this.getBaseUrl(), - '@order': 'date-' - } - } - } - } - - this.onChange(false) - this.request(true, REQUEST_TYPE_JSON, url, req, {}, function (url, res, err) { - App.onResponse(url, res, err) - - var rpObj = res.data - - if (rpObj != null && rpObj.code === CODE_SUCCESS) { - App.isRandomListShow = ! isSub - App.isRandomSubListShow = isSub - if (isSub) { - if (App.currentRandomItem == null) { - App.currentRandomItem = {} - } - App.randomSubs = App.currentRandomItem.subs = App.currentRandomItem['[]'] = rpObj['[]'] - } - else { - App.randoms = rpObj['[]'] - } - - vOutput.value = show ? '' : (output || '') - App.showDoc() - - //App.onChange(false) - } - }) - } - }, - - - // 设置文档 - showDoc: function () { - if (this.setDoc(doc) == false) { - this.getDoc(function (d) { - App.setDoc(d); - }); - } - }, - - - saveCache: function (url, key, value) { - var cache = this.getCache(url); - cache[key] = value - localStorage.setItem('APIAuto:' + url, JSON.stringify(cache)) - }, - getCache: function (url, key, defaultValue) { - var cache = localStorage.getItem('APIAuto:' + url) - try { - cache = JSON.parse(cache) - } catch(e) { - this.log('login this.send >> try { cache = JSON.parse(cache) } catch(e) {\n' + e.message) - } - cache = cache || {} - var val = key == null ? cache : cache[key] - return val == null && defaultValue != null ? defaultValue : val - }, - - /**登录确认 - */ - confirm: function () { - switch (this.loginType) { - case 'login': - this.login(this.isAdminOperation) - break - case 'register': - this.register(this.isAdminOperation) - break - case 'forget': - this.resetPassword(this.isAdminOperation) - break - } - }, - - showLogin: function (show, isAdmin) { - this.isLoginShow = show - this.isAdminOperation = isAdmin - - if (show != true) { - return - } - - var user = isAdmin ? this.User : null // add account this.accounts[this.currentAccountIndex] - - // alert("showLogin isAdmin = " + isAdmin + "; user = \n" + JSON.stringify(user, null, ' ')) - - if (user == null || StringUtil.isEmpty(user.phone, true)) { - user = { - phone: '13000082001', - password: '123456' - } - } - - this.setRememberLogin(user.remember) - this.account = user.phone - this.password = user.password - }, - - setRememberLogin(remember) { - vRemember.checked = remember || false - }, - - getCurrentAccount: function() { - return this.accounts == null ? null : this.accounts[this.currentAccountIndex] - }, - getCurrentAccountId: function() { - var a = this.getCurrentAccount() - return a != null && a.isLoggedIn ? a.id : null - }, - - /**登录 - */ - login: function (isAdminOperation, callback) { - this.isLoginShow = false - this.isEditResponse = false - - const req = { - type: 0, // 登录方式,非必须 0-密码 1-验证码 - phone: this.account, - password: this.password, - version: 1, // 全局默认版本号,非必须 - remember: vRemember.checked, - format: false, - defaults: isAdminOperation ? undefined : { - '@database': StringUtil.isEmpty(this.database, true) ? undefined : this.database, - '@schema': StringUtil.isEmpty(this.schema, true) ? undefined : this.schema - } - } - - if (isAdminOperation) { - this.request(isAdminOperation, REQUEST_TYPE_JSON, this.server + '/login', req, {}, function (url, res, err) { - if (callback) { - callback(url, res, err) - return - } - - var rpObj = res.data || {} - - if (rpObj.code != CODE_SUCCESS) { - alert('登录失败,请检查网络后重试。\n' + rpObj.msg + '\n详细信息可在浏览器控制台查看。') - App.onResponse(url, res, err) - } - else { - var user = rpObj.user || {} - - if (user.id > 0) { - user.remember = rpObj.remember - user.phone = req.phone - user.password = req.password - App.User = user - } - - //保存User到缓存 - App.saveCache(App.server, 'User', user) - - if (App.currentAccountIndex == null || App.currentAccountIndex < 0) { - App.currentAccountIndex = 0 - } - var item = App.accounts[App.currentAccountIndex] - item.isLoggedIn = false - App.onClickAccount(App.currentAccountIndex, item) //自动登录测试账号 - - if (user.id > 0) { - App.showTestCase(true, false) - } - } - - }) - } - else { - if (callback == null) { - var item - for (var i in this.accounts) { - item = this.accounts[i] - if (item != null && req.phone == item.phone) { - alert(req.phone + ' 已在测试账号中!') - // this.currentAccountIndex = i - item.remember = vRemember.checked - this.onClickAccount(i, item) - return - } - } - } - - this.showUrl(isAdminOperation, '/login') - - vInput.value = JSON.stringify(req, null, ' ') - this.type = REQUEST_TYPE_JSON - this.showTestCase(false, this.isLocalShow) - this.onChange(false) - this.send(isAdminOperation, function (url, res, err) { - if (callback) { - callback(url, res, err) - return - } - - App.onResponse(url, res, err) - - //由login按钮触发,不能通过callback回调来实现以下功能 - var data = res.data || {} - if (data.code == CODE_SUCCESS) { - var user = data.user || {} - App.accounts.push({ - isLoggedIn: true, - id: user.id, - name: user.name, - phone: req.phone, - password: req.password, - remember: data.remember - }) - - var lastItem = App.accounts[App.currentAccountIndex] - if (lastItem != null) { - lastItem.isLoggedIn = false - } - - App.currentAccountIndex = App.accounts.length - 1 - - App.saveCache(App.getBaseUrl(), 'currentAccountIndex', App.currentAccountIndex) - App.saveCache(App.getBaseUrl(), 'accounts', App.accounts) - } - }) - } - }, - - /**注册 - */ - register: function (isAdminOperation) { - this.showUrl(isAdminOperation, '/register') - vInput.value = JSON.stringify( - { - Privacy: { - phone: this.account, - _password: this.password - }, - User: { - name: 'APIJSONUser' - }, - verify: vVerify.value - }, - null, ' ') - this.showTestCase(false, false) - this.onChange(false) - this.send(isAdminOperation, function (url, res, err) { - App.onResponse(url, res, err) - - var rpObj = res.data - - if (rpObj != null && rpObj.code === CODE_SUCCESS) { - alert('注册成功') - - var privacy = rpObj.Privacy || {} - - App.account = privacy.phone - App.loginType = 'login' - } - }) - }, - - /**重置密码 - */ - resetPassword: function (isAdminOperation) { - this.showUrl(isAdminOperation, '/put/password') - vInput.value = JSON.stringify( - { - verify: vVerify.value, - Privacy: { - phone: this.account, - _password: this.password - } - }, - null, ' ') - this.showTestCase(false, this.isLocalShow) - this.onChange(false) - this.send(isAdminOperation, function (url, res, err) { - App.onResponse(url, res, err) - - var rpObj = res.data - - if (rpObj != null && rpObj.code === CODE_SUCCESS) { - alert('重置密码成功') - - var privacy = rpObj.Privacy || {} - - App.account = privacy.phone - App.loginType = 'login' - } - }) - }, - - /**退出 - */ - logout: function (isAdminOperation, callback) { - this.isEditResponse = false - var req = {} - - if (isAdminOperation) { - // alert('logout isAdminOperation this.saveCache(this.server, User, {})') - this.delegateId = null - this.saveCache(this.server, 'delegateId', null) - - this.saveCache(this.server, 'User', {}) - } - - // alert('logout isAdminOperation = ' + isAdminOperation + '; url = ' + url) - if (isAdminOperation) { - this.request(isAdminOperation, REQUEST_TYPE_JSON, this.server + '/logout', req, {}, function (url, res, err) { - if (callback) { - callback(url, res, err) - return - } - - // alert('logout clear admin ') - - App.clearUser() - App.onResponse(url, res, err) - App.showTestCase(false, App.isLocalShow) - }) - } - else { - this.showUrl(isAdminOperation, '/logout') - vInput.value = JSON.stringify(req, null, ' ') - this.type = REQUEST_TYPE_JSON - this.showTestCase(false, this.isLocalShow) - this.onChange(false) - this.send(isAdminOperation, callback) - } - }, - - /**获取验证码 - */ - getVerify: function (isAdminOperation) { - this.showUrl(isAdminOperation, '/post/verify') - var type = this.loginType == 'login' ? 0 : (this.loginType == 'register' ? 1 : 2) - vInput.value = JSON.stringify( - { - type: type, - phone: this.account - }, - null, ' ') - this.showTestCase(false, this.isLocalShow) - this.onChange(false) - this.send(isAdminOperation, function (url, res, err) { - App.onResponse(url, res, err) - - var data = res.data || {} - var obj = data.code == CODE_SUCCESS ? data.verify : null - var verify = obj == null ? null : obj.verify - if (verify != null) { //FIXME isEmpty校验时居然在verify=null! StringUtil.isEmpty(verify, true) == false) { - vVerify.value = verify - } - }) - }, - - clearUser: function () { - this.User.id = 0 - this.Privacy = {} - this.remotes = [] - // 导致刚登录成功就马上退出 this.delegateId = null - this.saveCache(this.server, 'User', this.User) //应该用lastBaseUrl,baseUrl应随watch输入变化重新获取 - // this.saveCache(this.server, 'delegateId', this.delegateId) //应该用lastBaseUrl,baseUrl应随watch输入变化重新获取 - }, - - /**计时回调 - */ - onHandle: function (before) { - this.isDelayShow = false - if (inputted != before) { - clearTimeout(handler); - return; - } - - this.view = 'output'; - vComment.value = ''; - vWarning.value = ''; - // vUrlComment.value = ''; - vOutput.value = 'resolving...'; - - //格式化输入代码 - try { - try { - this.header = this.getHeader(vHeader.value) - } catch (e2) { - this.isHeaderShow = true - vHeader.select() - throw new Error(e2.message) - } - - before = StringUtil.trim(before); - - var afterObj; - var after; - var code = ''; - - if (StringUtil.isEmpty(before)) { - afterObj = {}; - after = ''; - } else { - before = StringUtil.trim(before); // this.toDoubleJSON(StringUtil.trim(before)); - log('onHandle before = \n' + before); - - var json = isSingle ? this.switchQuote(before) : before; - try { - afterObj = jsonlint.parse(json); - after = JSON.stringify(afterObj, null, " "); - before = isSingle ? this.switchQuote(after) : after; - } - catch (e) { - log('main.onHandle', 'try { return jsonlint.parse(before); \n } catch (e) {\n' + e.message) - log('main.onHandle', 'return jsonlint.parse(this.removeComment(before));') - - try { - afterObj = JSON5.parse(json); // jsonlint.parse(this.removeComment(before)); - after = JSON.stringify(afterObj, null, " "); - } catch (e2) { - throw new Error('请求 JSON 格式错误!请检查并编辑请求!\n\n如果JSON中有注释,请 手动删除 或 点击左边的 \'/" 按钮 来去掉。\n\n' + e.message + '\n\n' + e2.message) - } - } - - //关键词let在IE和Safari上不兼容 - if (this.isEditResponse != true) { - try { - code = this.getCode(after); //必须在before还是用 " 时使用,后面用会因为解析 ' 导致失败 - } catch (e) { - code = '\n\n\n建议:\n使用其它浏览器,例如 谷歌Chrome、火狐FireFox 或者 微软Edge, 因为这样能自动生成请求代码.' - + '\nError:\n' + e.message + '\n\n\n'; - } - } - - var selectionStart = vInput.selectionStart - var selectionEnd = vInput.selectionEnd - vInput.value = before - + '\n\n\n ' - + ' \n'; //解决遮挡 - - vInput.selectionStart = selectionStart - vInput.selectionEnd = selectionEnd - vInput.setSelectionRange(selectionStart, selectionEnd) - } - - vSend.disabled = false; - - if (this.isEditResponse != true) { - vOutput.value = output = '登录后点 ↑ 上方左侧最后图标按钮可查看用例列表,点上方右侧中间图标按钮可上传用例并且添加到列表中 ↑ \nOK,请点左上方 [发送请求] 按钮来测试。[点击这里查看视频教程](https://i.youku.com/i/UNTg1NzI1MjQ4MA==/videos?spm=a2hzp.8244740.0.0)' + code; - - this.showDoc() - } - - var docKey = this.isEditResponse ? 'TestRecord' : 'Document'; - var currentItem = (this.currentRemoteItem || {})[docKey] || {} - var detail = currentItem.detail; - var extraComment = this.getExtraComment() - - try { - var standardObj = null; - try { - standardObj = JSON.parse(currentItem.standard); - } catch (e3) { - log(e3) - } - - var isAPIJSONRouter = false; - try { - var apijson = JSON.parse(currentItem.apijson); - isAPIJSONRouter = JSONResponse.isObject(apijson) - } catch (e3) { - log(e3) - } - - var m = this.getMethod(); - var w = isSingle || this.isEditResponse ? '' : StringUtil.trim(CodeUtil.parseComment(after, docObj == null ? null : docObj['[]'], m, this.database, this.language, this.isEditResponse != true, standardObj, null, true, isAPIJSONRouter)); - var c = isSingle ? '' : StringUtil.trim(CodeUtil.parseComment(after, docObj == null ? null : docObj['[]'], m, this.database, this.language, this.isEditResponse != true, standardObj, null, null, isAPIJSONRouter)); - - - //TODO 统计行数,补全到一致 vInput.value.lineNumbers - if (isSingle != true) { - if (afterObj.tag == null) { - m = m == null ? 'GET' : m.toUpperCase() - if (['GETS', 'HEADS', 'POST', 'PUT', 'DELETE'].indexOf(m) >= 0) { - w += ' ! 非开放请求必须设置 tag !例如 "tag": "User"' - c += ' ! 非开放请求必须设置 tag !例如 "tag": "User"' - } - } - - if (StringUtil.isEmpty(detail, true)) { - c += extraComment == null ? '' : ('\n\n/*' + extraComment + '\n*/'); - } else { - c += '\n\n/*' + (extraComment == null ? '' : extraComment + '\n\n') + detail + '\n*/'; - } - } - - - vWarning.value = w - + '\n\n\n ' - + ' \n'; //解决遮挡 - vComment.value = c - + '\n\n\n ' - + ' \n'; //解决遮挡 - - vUrlComment.value = isSingle || StringUtil.isEmpty(this.urlComment, true) - ? '' : vUrl.value + CodeUtil.getComment(this.urlComment, false, ' ') - + ' - ' + (this.requestVersion > 0 ? 'V' + this.requestVersion : 'V*'); - - if (! isSingle) { - var method = this.getMethod(); // m 已经 toUpperCase 了 - var isRestful = ! JSONObject.isAPIJSONPath(method); - if (isRestful != true) { - method = method.toUpperCase(); - } - var apiMap = isRestful ? CodeUtil.thirdPartyApiMap : null; - var api = apiMap == null ? null : apiMap['/' + method]; - var name = api == null ? null : api.name; - if (StringUtil.isEmpty(name, true) == false) { - this.urlComment = name; - vUrlComment.value = vUrl.value + CodeUtil.getComment(this.urlComment, false, ' ') - } - } - - onScrollChanged() - onURLScrollChanged() - } catch (e) { - log('onHandle try { vComment.value = CodeUtil.parseComment >> } catch (e) {\n' + e.message); - } - - if (this.isPreviewEnabled) { - try { - // 去掉前面的 JSON - var raw = StringUtil.trim(isSingle ? vInput.value : vComment.value); - var start = raw.lastIndexOf('\n\/*') - var end = raw.lastIndexOf('\n*\/') - var ct = start < 0 || end <= start ? '' : StringUtil.trim(raw.substring(start + '\n\/*'.length, end)) - - markdownToHTML('```js\n' + (start < 0 || end <= start ? raw : raw.substring(0, start)) + '\n```\n' - + (StringUtil.isEmpty(ct, true) ? '' : ct + '\n\n```js\n' + ct + '\n```\n'), true); - } catch (e3) { - log(e3) - } - } - - if (this.isEditResponse) { - this.view = 'code'; - this.jsoncon = after - } - - } catch(e) { - log(e) - vSend.disabled = true - - this.view = 'error' - this.error = { - msg: e.message - } - } - }, - - - /**输入内容改变 - */ - onChange: function (delay) { - this.setBaseUrl(); - inputted = new String(vInput.value); - vComment.value = ''; - vWarning.value = ''; - // vUrlComment.value = ''; - - clearTimeout(handler); - - this.isDelayShow = delay; - - if (delay) { - handler = setTimeout(function () { - App.onHandle(inputted); - }, 2000); - } else { - this.onHandle(inputted); - } - }, - - /**单双引号切换 - */ - transfer: function () { - isSingle = ! isSingle; - - vInput.value = this.switchQuote(vInput.value); - - this.isTestCaseShow = false - - // // 删除注释 <<<<<<<<<<<<<<<<<<<<< - // - // var input = this.removeComment(vInput.value); - // if (vInput.value != input) { - // vInput.value = input - // } - // - // // 删除注释 >>>>>>>>>>>>>>>>>>>>> - - this.onChange(false); - }, - - /**获取显示的请求类型名称 - */ - getTypeName: function (type) { - var ts = this.types - var t = type || REQUEST_TYPE_JSON - if (ts == null || ts.length <= 1 || (ts.length <= 2 && ts.indexOf(REQUEST_TYPE_PARAM) >= 0 && ts.indexOf(REQUEST_TYPE_GRPC) < 0)) { - return t == REQUEST_TYPE_PARAM ? 'GET' : 'POST' - } - return t - }, - /**请求类型切换 - */ - changeType: function () { - var count = this.types == null ? 0 : this.types.length - if (count > 1) { - var index = this.types.indexOf(this.type) - index++; - this.type = this.types[index % count] - CodeUtil.type = this.type; - } - - var url = StringUtil.get(vUrl.value) - var index = url.indexOf('?') - if (index >= 0) { - var paramObj = getRequestFromURL(url.substring(index), true) - vUrl.value = url.substring(0, index) - if (paramObj != null && $.isEmptyObject(paramObj) == false) { - var originVal = this.getRequest(vInput.value, {}); - var isConflict = false; - - if ($.isEmptyObject(originVal) == false) { - for (var k in paramObj) { - if (originVal.hasOwnProperty(k)) { - isConflict = true; - break; - } - } - } - - if (isConflict) { - vInput.value = JSON.stringify(paramObj, null, ' ') + '\n\n// FIXME 从 URL 上的参数转换过来,需要与下面原来的字段合并为一个 JSON:\n\n' + StringUtil.get(vInput.value) - } - else { - vInput.value = JSON.stringify(Object.assign(originVal, paramObj), null, ' ') - } - } - clearTimeout(handler) //解决 vUrl.value 和 vInput.value 变化导致刷新,而且会把 vInput.value 重置,加上下面 onChange 再刷新就卡死了 - } - - this.onChange(false); - }, - - /** - * 删除注释 - */ - removeComment: function (json) { - var reg = /("([^\\\"]*(\\.)?)*")|('([^\\\']*(\\.)?)*')|(\/{2,}.*?(\r|\n))|(\/\*(\n|.)*?\*\/)/g // 正则表达式 - try { - return new String(json).replace(reg, function(word) { // 去除注释后的文本 - return /^\/{2,}/.test(word) || /^\/\*/.test(word) ? "" : word; - }) - } catch (e) { - log('transfer delete comment in json >> catch \n' + e.message); - } - return json; - }, - - showAndSend: function (branchUrl, req, isAdminOperation, callback) { - this.showUrl(isAdminOperation, branchUrl) - vInput.value = JSON.stringify(req, null, ' ') - this.showTestCase(false, this.isLocalShow) - this.onChange(false) - this.send(isAdminOperation, callback) - }, - - /**发送请求 - */ - send: function(isAdminOperation, callback) { - if (this.isTestCaseShow) { - alert('请先输入请求内容!') - return - } - - if (StringUtil.isEmpty(this.host, true)) { - if (StringUtil.get(vUrl.value).startsWith('http://') != true && StringUtil.get(vUrl.value).startsWith('https://') != true) { - alert('URL 缺少 http:// 或 https:// 前缀,可能不完整或不合法,\n可能使用同域的 Host,很可能访问出错!') - } - } - else { - if (StringUtil.get(vUrl.value).indexOf('://') >= 0) { - alert('URL Host 已经隐藏(固定) 为 \n' + this.host + ' \n将会自动在前面补全,导致 URL 不合法访问出错!\n如果要改 Host,右上角设置 > 显示(编辑)URL Host') - } - } - - this.onHandle(vInput.value) - - clearTimeout(handler) - - if (this.isEditResponse) { - this.onChange(false) - return - } - - var header - try { - header = this.getHeader(vHeader.value) - } catch (e) { - // alert(e.message) - return - } - - var req = this.getRequest(vInput.value, {}) - - var url = this.getUrl() - - vOutput.value = "requesting... \nURL = " + url - this.view = 'output'; - - - this.setBaseUrl() - this.request(isAdminOperation, this.type, url, req, isAdminOperation ? {} : header, callback) - - this.locals = this.locals || [] - if (this.locals.length >= 1000) { //最多1000条,太多会很卡 - this.locals.splice(999, this.locals.length - 999) - } - var method = this.getMethod() - this.locals.unshift({ - 'Document': { - 'userId': this.User.id, - 'name': this.formatDateTime() + ' ' + (this.urlComment || StringUtil.trim(req.tag)), - 'type': this.type, - 'url': '/' + method, - 'request': JSON.stringify(req, null, ' '), - 'header': vHeader.value - } - }) - this.saveCache('', 'locals', this.locals) - }, - - //请求 - request: function (isAdminOperation, type, url, req, header, callback) { - type = type || REQUEST_TYPE_JSON - url = StringUtil.noBlank(url) - - var isDelegate = (isAdminOperation == false && this.isDelegateEnabled) || (isAdminOperation && url.indexOf('://apijson.cn:9090') > 0) - - if (header != null && header.Cookie != null) { - if (isDelegate) { - header['Set-Cookie'] = header.Cookie - delete header.Cookie - } - else { - document.cookie = header.Cookie - } - } - - if (isDelegate && this.delegateId != null && (header == null || header['Apijson-Delegate-Id'] == null)) { - if (header == null) { - header = {}; - } - header['Apijson-Delegate-Id'] = this.delegateId - } - - // axios.defaults.withcredentials = true - axios({ - method: (type == REQUEST_TYPE_PARAM ? 'get' : 'post'), - url: (isDelegate - ? ( - this.server + '/delegate?' + (type == REQUEST_TYPE_GRPC ? '$_type=GRPC&' : '') - + (StringUtil.isEmpty(this.delegateId, true) ? '' : '$_delegate_id=' + this.delegateId + '&') + '$_delegate_url=' + encodeURIComponent(url) - ) : ( - this.isEncodeEnabled ? encodeURI(url) : url - ) - ), - params: (type == REQUEST_TYPE_PARAM || type == REQUEST_TYPE_FORM ? req : null), - data: (type == REQUEST_TYPE_JSON || type == REQUEST_TYPE_GRPC ? req : (type == REQUEST_TYPE_DATA ? toFormData(req) : null)), - headers: header, //Accept-Encoding(HTTP Header 大小写不敏感,SpringBoot 接收后自动转小写)可能导致 Response 乱码 - withCredentials: true, //Cookie 必须要 type == REQUEST_TYPE_JSON - // crossDomain: true - }) - .then(function (res) { - res = res || {} - - if (isDelegate) { - var hs = res.headers || {} - var delegateId = hs['Apijson-Delegate-Id'] || hs['apijson-delegate-id'] - if (delegateId != null && delegateId != App.delegateId) { - App.delegateId = delegateId - App.saveCache(App.server, 'delegateId', delegateId) - } - } - - //any one of then callback throw error will cause it calls then(null) - // if ((res.config || {}).method == 'options') { - // return - // } - log('send >> success:\n' + JSON.stringify(res, null, ' ')) - - //未登录,清空缓存 - if (res.data != null && res.data.code == 407) { - // alert('request res.data != null && res.data.code == 407 >> isAdminOperation = ' + isAdminOperation) - if (isAdminOperation) { - // alert('request App.User = {} App.server = ' + App.server) - - App.clearUser() - } - else { - // alert('request App.accounts[App.currentAccountIndex].isLoggedIn = false ') - - if (App.accounts[App.currentAccountIndex] != null) { - App.accounts[App.currentAccountIndex].isLoggedIn = false - } - } - } - - if (callback != null) { - callback(url, res, null) - return - } - App.onResponse(url, res, null) - }) - .catch(function (err) { - log('send >> error:\n' + err) - if (isAdminOperation) { - App.delegateId = null - } - - if (callback != null) { - callback(url, {}, err) - return - } - App.onResponse(url, {}, err) - }) - }, - - - /**请求回调 - */ - onResponse: function (url, res, err) { - if (res == null) { - res = {} - } - log('onResponse url = ' + url + '\nerr = ' + err + '\nres = \n' + JSON.stringify(res)) - if (err != null) { - vOutput.value = "Response:\nurl = " + url + "\nerror = " + err.message; - } - else { - var data = res.data || {} - if (isSingle && data.code == CODE_SUCCESS) { //不格式化错误的结果 - data = JSONResponse.formatObject(data); - } - this.jsoncon = JSON.stringify(data, null, ' '); - this.view = 'code'; - vOutput.value = ''; - - // 会导致断言用了这个 - // if (this.currentRemoteItem == null) { - // this.currentRemoteItem = {} - // } - // if (this.currentRemoteItem.TestRecord == null) { - // this.currentRemoteItem.TestRecord = {} - // } - // this.currentRemoteItem.TestRecord.response = data - } - }, - - - /**处理复制事件 - * @param event - */ - doOnCopy: function(event) { - var target = event.target; - var selectionStart = target.selectionStart; - var selectionEnd = target.selectionEnd; - - if (target == vUrl) { - try { - var contentType = CONTENT_TYPE_MAP[this.type]; - var json = this.getRequest(vInput.value) - var header = this.getHeader(vHeader.value); - var headerStr = ''; - if (header != null) { - for (var k in header) { - var v = header[k]; - headerStr += '\n' + k + ': ' + StringUtil.get(v); - } - } - - console.log('复制时自动转换:\n' - + `Request URL: ` + vUrl.value + ` -Request Method: ` + (this.type == REQUEST_TYPE_PARAM ? 'GET' : 'POST') + (StringUtil.isEmpty(contentType, true) ? '' : ` -Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : headerStr) - + '\n\n' + JSON.stringify(json)); - } catch (e) { - log(e) - } - } - else if (target == vHeader || target == vRandom) { // key: value 转 { "key": value } - if (selectionStart < 0 || selectionStart <= selectionEnd) { - try { - var selection = selectionStart < 0 ? target.value : StringUtil.get(target.value).substring(selectionStart, selectionEnd); - var lines = StringUtil.split(selection, '\n'); - var json = {}; - - for (var i = 0; i < lines.length; i ++) { - var l = StringUtil.trim(lines[i]) || ''; - if (l.startsWith('//')) { - continue; - } - - var ind = l.lastIndexOf(' //'); - l = ind < 0 ? l : StringUtil.trim(l.substring(0, ind)); - - ind = l.indexOf(':'); - if (ind >= 0) { - var left = target == vHeader ? StringUtil.trim(l.substring(0, ind)) : l.substring(0, ind); - json[left] = StringUtil.trim(l.substring(ind + 1)); - } - } - - if (Object.keys(json).length > 0) { - var txt = JSON.stringify(json) - console.log('复制时自动转换:\n' + txt) - navigator.clipboard.writeText(selection + '\n\n' + txt); - alert('复制内容最后拼接了,控制台 Console 也打印了:\n' + txt); - } - } catch (e) { - log(e) - } - } - } - - }, - - /**处理粘贴事件 - * @param event - */ - doOnPaste: function(event) { - var paste = (event.clipboardData || window.clipboardData || navigator.clipboard).getData('text'); - var target = event.target; - var selectionStart = target.selectionStart; - var selectionEnd = target.selectionEnd; - - if (StringUtil.isNotEmpty(paste, true) && (StringUtil.isEmpty(target.value, true) - || selectionStart <= 0 && selectionEnd >= StringUtil.get(target.value).length)) { - if (target == vUrl) { // TODO 把 Chrome 或 Charles 等抓到的 Response Header 和 Content 自动粘贴到 vUrl, vHeader - try { - if (paste.trim().indexOf('\n') > 0) { // 解决正常的 URL 都粘贴不了 - var contentStart = 0; - var lines = StringUtil.split(paste, '\n'); - var header = ''; - - for (var i = 0; i < lines.length; i++) { - var l = StringUtil.trim(lines[i]); - var ind = l.indexOf(':'); - var left = ind < 0 ? '' : StringUtil.trim(l.substring(0, ind)); - - if (/^[a-zA-Z0-9\- ]+$/g.test(left)) { - var lowerKey = left.toLowerCase(); - var value = l.substring(ind + 1).trim(); - - if (lowerKey == 'host') { - this.setBaseUrl(value.endsWith(':443') ? 'https://' + value.substring(0, value.length - ':443'.length) : 'http://' + value); - event.preventDefault(); - } - else if (lowerKey == 'request method') { - value = value.toUpperCase(); - this.type = value == 'GET' ? 'PARAM' : (value == 'POST' ? 'JSON' : value); - event.preventDefault(); - } - else if (lowerKey == 'content-type') { - var type = vType.value != 'JSON' ? null : CONTENT_VALUE_TYPE_MAP[value]; - if (StringUtil.isEmpty(type, true) != true) { - this.type = type; - event.preventDefault(); - } - } - else if (lowerKey == 'request url') { - vUrl.value = value; - event.preventDefault(); - } - else if (StringUtil.isEmpty(lowerKey, true) || lowerKey.startsWith('accept-') - || lowerKey.startsWith('access-control-') || IGNORE_HEADERS.indexOf(lowerKey) >= 0) { - // 忽略 - } - else { - header += '\n' + left + ': ' + StringUtil.trim(l.substring(ind + 1)); - } - - contentStart += lines[i].length + 1; - } - else { - if (ind <= 0 || StringUtil.isEmpty(l) || l.startsWith('HTTP/') || l.startsWith('HTTPS/')) { // HTTP/1.1 200 - contentStart += lines[i].length + 1; - continue; - } - - var ind = l.indexOf(' '); - var m = ind < 0 ? '' : StringUtil.trim(l.substring(0, ind)); - if (APIJSON_METHODS.indexOf(m.toLowerCase()) >= 0) { // POST /gets HTTP/1.1 - contentStart += lines[i].length + 1; - var t = m.toUpperCase() - this.type = t == 'GET' ? 'PARAM' : (t == 'POST' ? 'JSON' : t); - - l = l.substring(ind).trim(); - ind = l.indexOf(' '); - var url = ind < 0 ? l : l.substring(0, ind); - if (url.length > 0 && url != '/') { - vUrl.value = this.getBaseUrl() + (url.startsWith('/') ? url : '/' + url); - } - - event.preventDefault(); - continue; - } - - var content = StringUtil.trim(paste.substring(contentStart)); - var json = null; - try { - json = JSON5.parse(content); // { "a":1, "b": "c" } - } - catch (e) { - log(e) - try { - json = getRequestFromURL('?' + content, true); // a=1&b=c - } catch (e2) { - log(e2) - } - } - - vInput.value = json == null ? '' : JSON.stringify(json, null, ' '); - event.preventDefault(); - break; - } - - } - - if (StringUtil.isEmpty(header, true) != true) { - vHeader.value = StringUtil.trim(header); - event.preventDefault(); - } - } - } - catch (e) { - log(e) - } - } - else if (target == vHeader || target == vRandom) { // { "key": value } 转 key: value - try { - var json = JSON5.parse(paste); - var newStr = ''; - for (var k in json) { - var v = json[k]; - if (v instanceof Object || v instanceof Array) { - v = JSON.stringify(v); - } - newStr += '\n' + k + ': ' + (target != vHeader && typeof v == 'string' ? "'" + v.replaceAll("'", "\\'") + "'" : StringUtil.get(v)); - } - target.value = StringUtil.trim(newStr); - event.preventDefault(); - } - catch (e) { - log(e) - } - } - else if (target == vInput) { // key: value 转 { "key": value } - try { - try { - JSON5.parse(paste); // 正常的 JSON 就不用转了 - } - catch (e) { - var lines = StringUtil.split(paste, '\n'); - var json = {}; - - for (var i = 0; i < lines.length; i++) { - var l = StringUtil.trim(lines[i]) || ''; - if (l.startsWith('//')) { - continue; - } - - var ind = l.lastIndexOf(' //'); - l = ind < 0 ? l : StringUtil.trim(l.substring(0, ind)); - - ind = l.indexOf(':'); - if (ind >= 0) { - var left = target == vHeader ? StringUtil.trim(l.substring(0, ind)) : l.substring(0, ind); - if (left.indexOf('=') >= 0 || left.indexOf('&') >= 0) { - try { - json = getRequestFromURL('?' + paste, true); - if (Object.keys(json).length > 0) { - break; - } - } catch (e2) { - log(e) - } - } - - json[left] = StringUtil.trim(l.substring(ind + 1)); - } - } - - if (Object.keys(json).length <= 0) { - json = getRequestFromURL('?' + paste, true); - } - - if (Object.keys(json).length > 0) { - vInput.value = JSON.stringify(json, null, ' '); - event.preventDefault(); - } - } - } - catch (e) { - log(e) - } - } - } - - }, - - /**处理按键事件 - * @param event - */ - doOnKeyUp: function (event, type, isFilter, item) { - var keyCode = event.keyCode ? event.keyCode : (event.which ? event.which : event.charCode); - - var obj = event.srcElement ? event.srcElement : event.target; - if ($(obj).attr('id') == 'vUrl') { - vUrlComment.value = '' - this.currentDocItem = null - this.currentRemoteItem = null - } - - if (keyCode == 13) { // enter - if (isFilter) { - this.onFilterChange(type) - return - } - - if (type == null) { - this.send(false); - return - } - - if (type == 'random' || type == 'randomSub') { - - var r = item == null ? null : item.Random - if (r == null || r.id == null) { - alert('请选择有效的选项!item.Random.id == null !') - return - } - - //修改 Random 的 count - this.request(true, REQUEST_TYPE_JSON, this.server + '/put', { - Random: { - id: r.id, - count: r.count, - name: r.name - }, - tag: 'Random' - }, {}, function (url, res, err) { - - var isOk = (res.data || {}).code == CODE_SUCCESS - - var msg = isOk ? '' : ('\nmsg: ' + StringUtil.get((res.data || {}).msg)) - if (err != null) { - msg += '\nerr: ' + err.msg - } - alert('修改' + (isOk ? '成功' : '失败') - + '!\ncount: ' + r.count + '\nname: ' + r.name - + msg - ) - - App.isRandomEditable = !isOk - }) - - return - } - - } - else { - if (isFilter) { - return - } - if (type == 'random' || type == 'randomSub') { - this.isRandomEditable = true - return - } - if (type == 'document' || type == 'testCase') { - return - } - - this.urlComment = ''; - this.requestVersion = ''; - this.onChange(true); - } - }, - - pageDown: function(type) { - type = type || '' - var page - switch (type) { - case 'testCase': - page = this.testCasePage - break - case 'random': - page = this.randomPage - break - case 'randomSub': - page = this.randomSubPage - break - default: - page = this.page - break - } - - if (page == null) { - page = 0 - } - - if (page > 0) { - page -- - switch (type) { - case 'testCase': - this.testCasePage = page - break - case 'random': - this.randomPage = page - break - case 'randomSub': - this.randomSubPage = page - break - default: - this.page = page - break - } - - this.onFilterChange(type) - } - }, - pageUp: function(type) { - type = type || '' - switch (type) { - case 'testCase': - this.testCasePage ++ - break - case 'random': - this.randomPage ++ - break - case 'randomSub': - this.randomSubPage ++ - break - default: - this.page ++ - break - } - this.onFilterChange(type) - }, - onFilterChange: function(type) { - type = type || '' - switch (type) { - case 'testCase': - this.saveCache(this.server, 'testCasePage', this.testCasePage) - this.saveCache(this.server, 'testCaseCount', this.testCaseCount) - - this.remotes = null - this.showTestCase(true, false) - break - case 'random': - this.saveCache(this.server, 'randomPage', this.randomPage) - this.saveCache(this.server, 'randomCount', this.randomCount) - - this.randoms = null - this.showRandomList(true, (this.currentRemoteItem || {}).Document, false) - break - case 'randomSub': - this.saveCache(this.server, 'randomSubPage', this.randomSubPage) - this.saveCache(this.server, 'randomSubCount', this.randomSubCount) - - this.randomSubs = null - this.showRandomList(true, (this.currentRemoteItem || {}).Random, true) - break - default: - docObj = null - doc = null - this.saveCache(this.server, 'page', this.page) - this.saveCache(this.server, 'count', this.count) - // this.saveCache(this.server, 'docObj', null) - // this.saveCache(this.server, 'doc', null) - - this.onChange(false) - - //虽然性能更好,但长时间没反应,用户会觉得未生效 - // this.getDoc(function (d) { - // // vOutput.value = 'resolving...'; - // App.setDoc(d) - // App.onChange(false) - // }); - break - } - }, - - /**转为请求代码 - * @param rq - */ - getCode: function (rq) { - var s = '\n\n\n### 请求代码(自动生成) \n'; - switch (this.language) { - case CodeUtil.LANGUAGE_KOTLIN: - s += '\n#### <= Android-Kotlin: 空对象用 HashMap<String, Any>(),空数组用 ArrayList<Any>()\n' - + '```kotlin \n' - + CodeUtil.parseKotlinRequest(null, JSON.parse(rq), 0, isSingle, false, false, this.type, this.getBaseUrl(), '/' + this.getMethod(), this.urlComment) - + '\n ``` \n注:对象 {} 用 mapOf("key": value),数组 [] 用 listOf(value0, value1)\n'; - break; - case CodeUtil.LANGUAGE_JAVA: - s += '\n#### <= Android-Java: 同名变量需要重命名' - + ' \n ```java \n' - + StringUtil.trim(CodeUtil.parseJavaRequest(null, JSON.parse(rq), 0, isSingle, false, false, this.type, '/' + this.getMethod(), this.urlComment)) - + '\n ``` \n注:' + (isSingle ? '用了 APIJSON 的 JSONRequest, JSONResponse 类,也可使用其它类封装,只要 JSON 有序就行\n' : 'LinkedHashMap<>() 可替换为 fastjson 的 JSONObject(true) 等有序JSON构造方法\n'); - - var serverCode = CodeUtil.parseJavaServer(this.type, '/' + this.getMethod(), this.database, this.schema, JSON.parse(rq), isSingle); - if (StringUtil.isEmpty(serverCode, true) != true) { - s += '\n#### <= Server-Java: RESTful 等非 APIJSON 规范的 API' - + ' \n ```java \n' - + serverCode - + '\n ``` \n注:' + (isSingle ? '分页和排序用了 Mybatis-PageHelper,如不需要可在生成代码基础上修改\n' : '使用 SSM(Spring + SpringMVC + Mybatis) 框架 \n'); - } - break; - case CodeUtil.LANGUAGE_C_SHARP: - s += '\n#### <= Unity3D-C\#: 键值对用 {"key", value}' + - '\n ```csharp \n' - + CodeUtil.parseCSharpRequest(null, JSON.parse(rq), 0) - + '\n ``` \n注:对象 {} 用 new JObject{{"key", value}},数组 [] 用 new JArray{value0, value1}\n'; - break; - - case CodeUtil.LANGUAGE_SWIFT: - s += '\n#### <= iOS-Swift: 空对象用 [ : ]' - + '\n ```swift \n' - + CodeUtil.parseSwiftRequest(null, JSON.parse(rq), 0) - + '\n ``` \n注:对象 {} 用 ["key": value],数组 [] 用 [value0, value1]\n'; - break; - case CodeUtil.LANGUAGE_OBJECTIVE_C: - s += '\n#### <= iOS-Objective-C \n ```objective-c \n' - + CodeUtil.parseObjectiveCRequest(null, JSON.parse(rq)) - + '\n ``` \n'; - break; - - case CodeUtil.LANGUAGE_GO: - s += '\n#### <= Web-Go: 对象 key: value 会被强制排序,每个 key: value 最后都要加逗号 ","' - + ' \n ```go \n' - + CodeUtil.parseGoRequest(null, JSON.parse(rq), 0) - + '\n ``` \n注:对象 {} 用 map[string]interface{} {"key": value},数组 [] 用 []interface{} {value0, value1}\n'; - break; - case CodeUtil.LANGUAGE_C_PLUS_PLUS: - s += '\n#### <= Web-C++: 使用 RapidJSON' - + ' \n ```cpp \n' - + StringUtil.trim(CodeUtil.parseCppRequest(null, JSON.parse(rq), 0, isSingle)) - + '\n ``` \n注:std::string 类型值需要判断 RAPIDJSON_HAS_STDSTRING\n'; - break; - - case CodeUtil.LANGUAGE_PHP: - s += '\n#### <= Web-PHP: 空对象用 (object) ' + (isSingle ? '[]' : 'array()') - + ' \n ```php \n' - + CodeUtil.parsePHPRequest(null, JSON.parse(rq), 0, isSingle) - + '\n ``` \n注:对象 {} 用 ' + (isSingle ? '[\'key\' => value]' : 'array("key" => value)') + ',数组 [] 用 ' + (isSingle ? '[value0, value1]\n' : 'array(value0, value1)\n'); - break; - - case CodeUtil.LANGUAGE_PYTHON: - s += '\n#### <= Web-Python: 注释符用 \'\#\'' - + ' \n ```python \n' - + CodeUtil.parsePythonRequest(null, JSON.parse(rq), 0, isSingle, vInput.value) - + '\n ``` \n注:关键词转换 null: None, false: False, true: True'; - break; - - //以下都不需要解析,直接用左侧的 JSON - case CodeUtil.LANGUAGE_TYPE_SCRIPT: - case CodeUtil.LANGUAGE_JAVA_SCRIPT: - //case CodeUtil.LANGUAGE_PYTHON: - s += '\n#### <= Web-JavaScript/TypeScript: 和左边的请求 JSON 一样 \n'; - break; - default: - s += '\n没有生成代码,可能生成代码(封装,解析)的语言配置错误。\n'; - break; - } - - if (((this.User || {}).id || 0) > 0) { - s += '\n\n#### 开放源码 ' - + '\nAPIJSON 接口测试: https://github.com/TommyLemon/APIAuto ' - + '\nAPIJSON 单元测试: https://github.com/TommyLemon/UnitAuto ' - + '\nAPIJSON 中文文档: https://github.com/vincentCheng/apijson-doc ' - + '\nAPIJSON 英文文档: https://github.com/ruoranw/APIJSONdocs ' - + '\nAPIJSON 官方网站: https://github.com/APIJSON/apijson.cn ' - + '\nAPIJSON -Java版: https://github.com/Tencent/APIJSON ' - + '\nAPIJSON - C# 版: https://github.com/liaozb/APIJSON.NET ' - + '\nAPIJSON - Go 版: https://github.com/j2go/apijson-go ' - + '\nAPIJSON - PHP版: https://github.com/kvnZero/hyperf-APIJSON ' - + '\nAPIJSON -Node版: https://github.com/kevinaskin/apijson-node ' - + '\nAPIJSON -Python: https://github.com/zhangchunlin/uliweb-apijson ' - + '\n感谢热心的作者们的贡献,GitHub 右上角点 ⭐Star 支持下他们吧 ^_^'; - } - - return s; - }, - - - /**显示文档 - * @param d - **/ - setDoc: function (d) { - if (d == null) { //解决死循环 || d == '') { - return false; - } - doc = d; - vOutput.value += ( - '\n\n\n## 文档 \n\n 通用文档见 [APIJSON通用文档](https://github.com/Tencent/APIJSON/blob/master/Document.md#3.2) \n### 数据字典\n自动查数据库表和字段属性来生成 \n\n' + d - + '

关于

' - + '

APIAuto-机器学习 HTTP 接口工具' - + '
机器学习零代码测试、生成代码与静态检查、生成文档与光标悬浮注释' - + '
APIAuto(前端网页工具), APIJSON(后端接口服务) 等提供技术支持' - + '
遵循 Apache-2.0 开源协议' - + '
Copyright © 2016-' + new Date().getFullYear() + ' Tommy Lemon' - + '
粤ICP备18005508号-1' - + '



' - ); - - this.view = 'markdown'; - markdownToHTML(vOutput.value); - return true; - }, - - - /** - * 获取文档 - */ - getDoc: function (callback) { - - var count = this.count || 100 //超过就太卡了 - var page = this.page || 0 - - var search = StringUtil.isEmpty(this.search, true) ? null : '%' + StringUtil.trim(this.search) + '%' - this.request(false, REQUEST_TYPE_JSON, this.getBaseUrl() + '/get', { - format: false, - '@database': StringUtil.isEmpty(this.database, true) ? undefined : this.database, - // '@schema': StringUtil.isEmpty(this.schema, true) ? undefined : this.schema, - 'sql@': { - 'from': 'Access', - 'Access': { - '@column': 'name' - } - }, - 'Access[]': { - 'count': count, - 'page': page, - 'Access': { - '@column': 'name,alias,get,head,gets,heads,post,put,delete', - '@order': 'date-,name+', - 'name()': 'getWithDefault(alias,name)', - 'r0()': 'removeKey(alias)', - 'name$': search, - 'alias$': search, - '@combine': search == null ? null : 'name$,alias$', - } - }, - '[]': { - 'count': count, - 'page': page, - 'Table': this.database == 'SQLSERVER' ? null : { - 'table_schema': this.schema, - 'table_type': 'BASE TABLE', - // 'table_name!$': ['\\_%', 'sys\\_%', 'system\\_%'], - 'table_name$': search, - 'table_comment$': this.database == 'POSTGRESQL' ? null : search, - '@combine': search == null || this.database == 'POSTGRESQL' ? null : 'table_name$,table_comment$', - 'table_name{}@': 'sql', - '@order': 'table_name+', //MySQL 8 SELECT `table_name` 返回的仍然是大写的 TABLE_NAME,需要 AS 一下 - '@column': this.database == 'POSTGRESQL' ? 'table_name' : 'table_name:table_name,table_comment:table_comment' - }, - 'PgClass': this.database != 'POSTGRESQL' ? null : { - 'relname@': '/Table/table_name', - //FIXME 多个 schema 有同名表时数据总是取前面的 不属于 pg_class 表 'nspname': this.schema, - '@column': 'oid;obj_description(oid):table_comment' - }, - 'SysTable': this.database != 'SQLSERVER' ? null : { - 'name!$': [ - '\\_%', - 'sys\\_%', - 'system\\_%' - ], - '@order': 'name+', - '@column': 'name:table_name,object_id' - }, - 'ExtendedProperty': this.database != 'SQLSERVER' ? null : { - '@order': 'name+', - 'major_id@': '/SysTable/object_id', - '@column': 'value:table_comment' - }, - '[]': { - 'count': 0, - 'Column': { - 'table_schema': this.schema, - 'table_name@': this.database != 'SQLSERVER' ? '[]/Table/table_name' : "[]/SysTable/table_name", - "@order": this.database != 'SQLSERVER' ? null : "table_name+", - '@column': this.database == 'POSTGRESQL' || this.database == 'SQLSERVER' //MySQL 8 SELECT `column_name` 返回的仍然是大写的 COLUMN_NAME,需要 AS 一下 - ? 'column_name;data_type;numeric_precision,numeric_scale,character_maximum_length' - : 'column_name:column_name,column_type:column_type,is_nullable:is_nullable,column_comment:column_comment' - }, - 'PgAttribute': this.database != 'POSTGRESQL' ? null : { - 'attrelid@': '[]/PgClass/oid', - 'attname@': '/Column/column_name', - 'attnum>': 0, - '@column': 'col_description(attrelid,attnum):column_comment' - }, - 'SysColumn': this.database != 'SQLSERVER' ? null : { - 'object_id@': '[]/SysTable/object_id', - 'name@': '/Column/column_name', - '@order': 'object_id+', - '@column': 'object_id,column_id' - }, - 'ExtendedProperty': this.database != 'SQLSERVER' ? null : { - '@order': 'major_id+', - 'major_id@': '/SysColumn/object_id', - 'minor_id@': '/SysColumn/column_id', - '@column': 'value:column_comment' - } - } - }, - 'Function[]': { - 'count': count, - 'page': page, - 'Function': { - '@order': 'date-,name+', - '@column': 'name,arguments,demo,detail', - 'demo()': 'getFunctionDemo()', - 'detail()': 'getFunctionDetail()', - 'r0()': 'removeKey(name)', - 'r1()': 'removeKey(arguments)', - 'name$': search, - 'detail$': search, - '@combine': search == null ? null : 'name$,detail$', - } - }, - 'Request[]': { - 'count': count, - 'page': page, - 'Request': { - '@order': 'version-,method-', - '@json': 'structure', - 'tag$': search, - // 界面又不显示这个字段,搜出来莫名其妙 'detail$': search, - // '@combine': search == null ? null : 'tag$,detail$', - } - } - }, {}, function (url, res, err) { - if (err != null || res == null || res.data == null) { - log('getDoc err != null || res == null || res.data == null >> return;'); - callback('') - return; - } - -// log('getDoc docRq.responseText = \n' + docRq.responseText); - docObj = res.data || {}; //避免后面又调用 onChange ,onChange 又调用 getDoc 导致死循环 - - //转为文档格式 - var doc = ''; - var item; - - //[] <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< - var list = docObj == null ? null : docObj['[]']; - CodeUtil.tableList = list; - if (list != null) { - if (DEBUG) { - log('getDoc [] = \n' + format(JSON.stringify(list))); - } - - var table; - var columnList; - var column; - for (var i = 0; i < list.length; i++) { - item = list[i]; - - //Table - table = item == null ? null : (App.database != 'SQLSERVER' ? item.Table : item.SysTable); - if (table == null) { - continue; - } - if (DEBUG) { - log('getDoc [] for i=' + i + ': table = \n' + format(JSON.stringify(table))); - } - - var table_comment = App.database == 'POSTGRESQL' - ? (item.PgClass || {}).table_comment - : (App.database == 'SQLSERVER' - ? (item.ExtendedProperty || {}).table_comment - : table.table_comment - ); - // item.Table.table_name = table.table_name - // item.Table.table_comment = table_comment - - doc += '### ' + (i + 1) + '. ' + CodeUtil.getModelName(table.table_name) + '\n#### 说明: \n' - + App.toMD(table_comment); - - - //Column[] - doc += '\n\n#### 字段: \n 名称 | 类型 | 最大长度 | 详细说明' + - ' \n -------- | ------------ | ------------ | ------------ '; - - columnList = item['[]']; - if (columnList == null) { - continue; - } - if (DEBUG) { - log('getDoc [] for ' + i + ': columnList = \n' + format(JSON.stringify(columnList))); - } - - var name; - var type; - var length; - for (var j = 0; j < columnList.length; j++) { - column = (columnList[j] || {}).Column; - name = column == null ? null : column.column_name; - if (name == null) { - continue; - } - - column.column_type = CodeUtil.getColumnType(column, App.database); - type = CodeUtil.getType4Language(App.language, column.column_type, false); - length = CodeUtil.getMaxLength(column.column_type); - - if (DEBUG) { - log('getDoc [] for j=' + j + ': column = \n' + format(JSON.stringify(column))); - } - - var o = App.database == 'POSTGRESQL' - ? (columnList[j] || {}).PgAttribute - : (App.database == 'SQLSERVER' - ? (columnList[j] || {}).ExtendedProperty - : column - ); - var column_comment = (o || {}).column_comment - - // column.column_comment = column_comment - doc += '\n' + name + ' | ' + type + ' | ' + length + ' | ' + App.toMD(column_comment); - - } - - doc += '\n\n\n'; - - } - - } - - //[] >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> - - - - //Access[] <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< - list = docObj == null ? null : docObj['Access[]']; - if (list != null) { - if (DEBUG) { - log('getDoc Access[] = \n' + format(JSON.stringify(list))); - } - - doc += '\n\n\n\n\n\n\n\n\n### 访问权限\n自动查 Access 表写入的数据来生成\n' - + ' \n 表名 | 允许 get
的角色 | 允许 head
的角色 | 允许 gets
的角色 | 允许 heads
的角色 | 允许 post
的角色 | 允许 put
的角色 | 允许 delete
的角色 | 表名' - + ' \n -------- | --------- | --------- | --------- | --------- | --------- | --------- | --------- | -------- '; - - for (var i = 0; i < list.length; i++) { - item = list[i]; - if (item == null) { - continue; - } - if (DEBUG) { - log('getDoc Access[] for i=' + i + ': item = \n' + format(JSON.stringify(item))); - } - - doc += '\n' + (item.name) //右上角设置指定了 Schema + '(' + item.schema + ')') - + ' | ' + JSONResponse.getShowString(JSON.parse(item.get), 2) - + ' | ' + JSONResponse.getShowString(JSON.parse(item.head), 2) - + ' | ' + JSONResponse.getShowString(JSON.parse(item.gets), 2) - + ' | ' + JSONResponse.getShowString(JSON.parse(item.heads), 2) - + ' | ' + JSONResponse.getShowString(JSON.parse(item.post), 1) - + ' | ' + JSONResponse.getShowString(JSON.parse(item.put), 1) - + ' | ' + JSONResponse.getShowString(JSON.parse(item.delete), 1) - + ' | ' + (item.name); //右上角设置指定了 Schema + '(' + item.schema + ')'); - } - - doc += ' \n 表名 | 允许 get
的角色 | 允许 head
的角色 | 允许 gets
的角色 | 允许 heads
的角色 | 允许 post
的角色 | 允许 put
的角色 | 允许 delete
的角色 | 表名' - - doc += '\n' //避免没数据时表格显示没有网格 - } - - //Access[] >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> - - - //Function[] <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< - list = docObj == null ? null : docObj['Function[]']; - if (list != null) { - if (DEBUG) { - log('getDoc Function[] = \n' + format(JSON.stringify(list))); - } - - doc += '\n\n\n\n\n\n\n\n\n### 远程函数\n自动查 Function 表写入的数据来生成\n' - + ' \n 说明 | 示例' - + ' \n -------- | -------------- '; - - for (var i = 0; i < list.length; i++) { - item = list[i]; - if (item == null) { - continue; - } - if (DEBUG) { - log('getDoc Function[] for i=' + i + ': item = \n' + format(JSON.stringify(item))); - } - - doc += '\n' + item.detail + ' | ' + JSON.stringify(item.demo); - } - - doc += '\n' //避免没数据时表格显示没有网格 - } - - //Function[] >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> - - - //Request[] <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< - list = docObj == null ? null : docObj['Request[]']; - if (list != null) { - if (DEBUG) { - log('getDoc Request[] = \n' + format(JSON.stringify(list))); - } - - doc += '\n\n\n\n\n\n\n\n\n### 非开放请求\n自动查 Request 表写入的数据来生成\n' - + ' \n 版本 | 方法 | 数据和结构' - + ' \n -------- | ------------ | ------------ | ------------ '; - - for (var i = 0; i < list.length; i++) { - item = list[i]; - if (item == null) { - continue; - } - if (DEBUG) { - log('getDoc Request[] for i=' + i + ': item = \n' + format(JSON.stringify(item))); - } - - doc += '\n' + item.version + ' | ' + item.method - + ' | ' + JSON.stringify(App.getStructure(item.structure, item.tag)); - } - - doc += '\n注: \n1.GET,HEAD方法不受限,可传任何 数据、结构。\n2.可在最外层传版本version来指定使用的版本,不传或 version <= 0 则使用最新版。\n\n\n\n\n\n\n'; - } - - - //Request[] >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> - - App.onChange(false); - - - callback(doc); - -// log('getDoc callback(doc); = \n' + doc); - }); - - }, - - // toDoubleJSON: function (json, defaultValue) { - // if (StringUtil.isEmpty(json)) { - // return defaultValue == null ? '{}' : JSON.stringify(defaultValue) - // } - // else if (json.indexOf("'") >= 0) { - // json = json.replace(/'/g, '"'); - // } - // return json; - // }, - - switchQuote: function (before) { - if (before == null) { - return before; - } - - var newBefore = ''; - for (var i = 0; i < before.length; i++) { - var chr = before.substring(i, i + 1); // .charAt(i); - if (chr == '"') { - newBefore += "'"; // chr = "'"; - } - else if (chr == "'") { - newBefore += '"'; // chr = '"'; - } - else { - newBefore += chr; - } - } - return newBefore; - }, - - /**转为Markdown格式 - * @param s - * @return {*} - */ - toMD: function (s) { - if (s == null) { - s = ''; - } - else { - //无效 - s = s.replace(/\|/g, '\|'); - s = s.replace(/\n/g, '
'); - // s = s.replace(/ /g, ' '); - } - - return s; - }, - - /**处理请求结构 - * @param obj - * @param tag - * @return {*} - */ - getStructure: function (obj, tag) { - if (obj == null) { - return null; - } - - log('getStructure tag = ' + tag + '; obj = \n' + format(JSON.stringify(obj))); - - if (obj instanceof Array) { - for (var i = 0; i < obj.length; i++) { - obj[i] = this.getStructure(obj[i]); - } - } - else if (obj instanceof Object) { - var v; - var nk; - for (var k in obj) { - if (k == null || k == '' || k == 'INSERT' || k == 'REMOVE' || k == 'REPLACE' || k == 'UPDATE') { - delete obj[k]; - continue; - } - - v = obj[k]; - if (v == null) { - delete obj[k]; - continue; - } - - if (k == 'DISALLOW') { - nk = '不能传'; - } - else if (k == 'NECESSARY') { - nk = '必须传'; - } - else if (k == 'UNIQUE') { - nk = '不重复'; - } - else if (k == 'VERIFY') { - nk = '满足条件'; - } - else if (k == 'TYPE') { - nk = '满足类型'; - } - else { - nk = null; - } - - if (v instanceof Object) { - v = this.getStructure(v); - } - else if (v === '!') { - v = '非必须传的字段'; - } - - if (nk != null) { - obj[nk] = v; - delete obj[k]; - } - } - - if (tag != null && obj[tag] == null) { //补全省略的Table - var isArrayKey = tag.endsWith(":[]"); //JSONObject.isArrayKey(tag); - var key = isArrayKey ? tag.substring(0, tag.length - 3) : tag; - - if (this.isTableKey(key)) { - if (isArrayKey) { //自动为 tag = Comment:[] 的 { ... } 新增键值对 "Comment[]":[] 为 { "Comment[]":[], ... } - obj[key + "[]"] = []; - } - else { //自动为 tag = Comment 的 { ... } 包一层为 { "Comment": { ... } } - var realObj = {}; - realObj[tag] = obj; - obj = realObj; - } - } - } - - } - - obj.tag = tag; //补全tag - - log('getStructure return obj; = \n' + format(JSON.stringify(obj))); - - return obj; - }, - - /**判断key是否为表名,用CodeUtil里的同名函数会在Safari上报undefined - * @param key - * @return - */ - isTableKey: function (key) { - log('isTableKey typeof key = ' + (typeof key)); - if (key == null) { - return false; - } - return /^[A-Z][A-Za-z0-9_]*$/.test(key); - }, - - log: function (msg) { - // this.log('Main. ' + msg) - }, - - getDoc4TestCase: function () { - var list = this.remotes || [] - var doc = '' - var item - for (var i = 0; i < list.length; i ++) { - item = list[i] == null ? null : list[i].Document - if (item == null || item.name == null) { - continue - } - doc += '\n\n#### ' + (item.version > 0 ? 'V' + item.version : 'V*') + ' ' + item.name + ' ' + item.url - doc += '\n```json\n' + item.request + '\n```\n' - } - return doc - }, - - enableCross: function (enable) { - this.isCrossEnabled = enable - this.crossProcess = enable ? '交叉账号:已开启' : '交叉账号:已关闭' - this.saveCache(this.server, 'isCrossEnabled', enable) - }, - - enableML: function (enable) { - this.isMLEnabled = enable - this.testProcess = enable ? '机器学习:已开启' : '机器学习:已关闭' - this.saveCache(this.server, 'isMLEnabled', enable) - this.remotes = null - this.showTestCase(true, false) - }, - - /**参数注入,动态替换键值对 - * @param show - */ - onClickTestRandom: function () { - this.isRandomTest = true - this.testRandom(! this.isRandomListShow && ! this.isRandomSubListShow, this.isRandomListShow, this.isRandomSubListShow) - }, - testRandom: function (show, testList, testSubList, limit) { - this.isRandomEditable = false - if (testList != true && testSubList != true) { - this.testRandomProcess = '' - this.testRandomWithText(show, null) - } - else { - var baseUrl = StringUtil.trim(this.getBaseUrl()) - if (baseUrl == '') { - alert('请先输入有效的URL!') - return - } - //开放测试 - // if (baseUrl.indexOf('/apijson.cn') >= 0 || baseUrl.indexOf('/39.108.143.172') >= 0) { - // alert('请把URL改成你自己的!\n例如 http://localhost:8080') - // return - // } - // if (baseUrl.indexOf('/apijson.org') >= 0) { - // alert('请把URL改成 http://apijson.cn:8080 或 你自己的!\n例如 http://localhost:8080') - // return - // } - - const list = (testSubList ? this.randomSubs : this.randoms) || [] - var allCount = list.length - doneCount = 0 - - if (allCount <= 0) { - alert('请先获取随机配置\n点击[查看列表]按钮') - return - } - this.testRandomProcess = '正在测试: ' + 0 + '/' + allCount - - if (testSubList) { - this.resetCount(this.currentRandomItem) - } - - var json = this.getRequest(vInput.value, {}) - var url = this.getUrl() - var header = this.getHeader(vHeader.value) - - ORDER_MAP = {} //重置 - - for (var i = 0; i < (limit != null ? limit : list.length); i ++) { //limit限制子项测试个数 - const item = list[i] - const random = item == null ? null : item.Random - if (random == null || random.name == null) { - doneCount ++ - continue - } - this.log('test random = ' + JSON.stringify(random, null, ' ')) - - const index = i - - const itemAllCount = random.count || 0 - allCount += (itemAllCount - 1) - - this.testRandomSingle(show, false, itemAllCount > 1 && ! testSubList, item, this.type, url, json, header, function (url, res, err) { - - doneCount ++ - App.testRandomProcess = doneCount >= allCount ? '' : ('正在测试: ' + doneCount + '/' + allCount) - try { - App.onResponse(url, res, err) - App.log('test App.request >> res.data = ' + JSON.stringify(res.data, null, ' ')) - } catch (e) { - App.log('test App.request >> } catch (e) {\n' + e.message) - } - - App.compareResponse(allCount, list, index, item, res.data, true, App.currentAccountIndex, false, err) - }) - } - } - }, - /**参数注入,动态替换键值对 - * @param show - * @param callback - */ - testRandomSingle: function (show, testList, testSubList, item, type, url, json, header, callback) { - item = item || {} - var random = item.Random = item.Random || {} - var subs = item['[]'] || [] - var existCount = subs.length - subs = existCount <= 0 ? subs : JSON.parse(JSON.stringify(subs)) - - var count = random.count || 0 - var respCount = 0; - - for (var i = 0; i < count; i ++) { - // var constConfig = i < existCount ? ((subs[i] || {}).Random || {}).config : this.getRandomConstConfig(random.config, random.id) //第1遍,把 key : expression 改为 key : value - // var constJson = this.getRandomJSON(JSON.parse(JSON.stringify(json)), constConfig, random.id) //第2遍,用新的 random config 来修改原 json - - const which = i; - var rawConfig = testSubList && i < existCount ? ((subs[i] || {}).Random || {}).config : random.config - this.parseRandom( - JSON.parse(JSON.stringify(json)), rawConfig, random.id - , ! testSubList, testSubList && i >= existCount, testSubList && i >= existCount - , function (randomName, constConfig, constJson) { - - respCount ++; - - if (testSubList) { //在原来已上传的基础上,生成新的 - if (which >= existCount) { - //异步导致顺序错乱 subs.push({ - subs[which] = { - Random: { - id: -i - 1, //表示未上传 - toId: random.id == null ? 1 : random.id, // 1 为了没选择测试用例时避免用 toId 判断子项错误 - userId: random.userId, - documentId: random.documentId, - count: 1, - name: randomName || 'Temp ' + i, - config: constConfig - }, - //不再需要,因为子项里前面一部分就是已上传的,而且这样更准确,交互更直观 - // TestRecord: { //解决子项始终没有对比标准 - // id: 0, //不允许子项撤回 tr.id, //表示未上传 - // userId: random.userId, - // documentId: random.documentId, - // testAccountId: tr.testAccountId, - // randomId: -i - 1, - // response: tr.response, - // standard: tr.standard, - // date: tr.date, - // compare: tr.compare - // } - // }) - }; - } - } - else { - var cb = function (url, res, err) { - if (callback != null) { - callback(url, res, err, random) - } - else { - App.onResponse(url, res, err) - } - }; - - if (show == true) { - vInput.value = JSON.stringify(constJson, null, ' '); - App.send(false, cb); - } - else { - App.request(false, type, url, constJson, header, cb); - } - } - - if (testSubList && respCount >= count) { // && which >= count - 1) { - App.randomSubs = subs - if (App.isRandomListShow == true) { - App.resetCount(item) - item.subs = subs - } - App.testRandom(false, false, true, count) - } - - } - ); - - } //for - - }, - - resetCount: function (randomItem) { - if (randomItem == null) { - this.log('resetCount randomItem == null >> return') - return - } - randomItem.totalCount = 0 - randomItem.whiteCount = 0 - randomItem.greenCount = 0 - randomItem.blueCount = 0 - randomItem.orangeCount = 0 - randomItem.redCount = 0 - }, - - /**参数注入,动态替换键值对 - * @param show - * @param callback - */ - testRandomWithText: function (show, callback) { - try { - var count = this.testRandomCount || 0; - this.isRandomSubListShow = count > 1; - this.testRandomSingle(show, false, this.isRandomSubListShow, { - Random: { - toId: 0, // ((this.currentRandomItem || {}).Random || {}).id || 0, - userId: (this.User || {}).id, - count: count, - name: this.randomTestTitle, - config: vRandom.value - } - }, - this.type, this.getUrl(), this.getRequest(vInput.value, {}), this.getHeader(vHeader.value), callback - ) - } - catch (e) { - log(e) - vSend.disabled = true - - this.view = 'error' - this.error = { - msg: e.message - } - - this.isRandomShow = true - vRandom.select() - } - }, - - /** - * 与 getRandomJSON 合并,返回一个 - * { - * name: 'long 1, long 2', // 自动按 type0 value0, type1, value1 格式 - * config: {}, //const config - * json: {} //const json - * } - */ - /**参数注入,动态替换键值对 - * @param show - * @param callback - */ - parseRandom: function (json, config, randomId, generateJSON, generateConfig, generateName, callback) { - var lines = config == null ? null : config.trim().split('\n') - if (lines == null || lines.length <= 0) { - // return null; - callback(null, null, null); - return - } - json = json || {}; - - baseUrl = this.getBaseUrl(); - - var reqCount = lines.length; //有无效的行 lines.length; //等待次数 - var respCount = 0; - - randomId = randomId || 0; - var randomNameKeys = [] - var constConfigLines = [] //TODO 改为 [{ "rawPath": "User/id", "replacePath": "User/id@", "replaceValue": "RANDOM_INT(1, 10)", "isExpression": true }] ? - - // alert('< json = ' + JSON.stringify(json, null, ' ')) - - for (let i = 0; i < lines.length; i ++) { - const which = i; - const lineItem = lines[i] || ''; - - // remove comment // 解决整体 trim 后第一行 // 被当成正常的 key 路径而不是注释 - const commentIndex = StringUtil.trim(lineItem).startsWith('//') ? 0 : lineItem.lastIndexOf(' //'); // -1; // eval 本身支持注释 eval('1 // test') = 1 lineItem.indexOf(' //'); - const line = commentIndex < 0 ? lineItem : lineItem.substring(0, commentIndex).trim(); - - if (line.length <= 0) { - respCount ++; - if (i >= lines.length - 1 && respCount >= reqCount) { - callback(randomNameKeys.join(', '), constConfigLines.join('\n'), json); - } - continue; - } - - // path User/id key id@ - const index = line.indexOf(': '); //APIJSON Table:alias 前面不会有空格 //致后面就接 { 'a': 1} 报错 Unexpected token ':' lastIndexOf(': '); // indexOf(': '); 可能会有 Comment:to - const p_k = line.substring(0, index); - const bi = -1; //没必要支持,用 before: undefined, after: .. 同样支持替换,反而这样导致不兼容包含空格的 key p_k.indexOf(' '); - const path = bi < 0 ? p_k : p_k.substring(0, bi); // User/id - - const pathKeys = path.split('/') - if (pathKeys == null || pathKeys.length <= 0) { - throw new Error('参数注入 第 ' + (i + 1) + ' 行格式错误!\n字符 ' + path + ' 不符合 JSON 路径的格式 key0/key1/../targetKey !' + - '\n每个随机变量配置都必须按照\n key0/key1/../targetKey replaceKey: value // 注释\n的格式!' + - '\n注意冒号 ": " 左边 0 空格,右边 1 空格!其中 replaceKey 可省略。' + - '\nkey: {} 中最外层常量对象 {} 必须用括号包裹为 ({}),也就是 key: ({}) 这种格式!' + - '\nkey: 多行代码 必须用 function f() { var a = 1; return a; } f() 这种一行代码格式!'); - } - - const lastKeyInPath = pathKeys[pathKeys.length - 1] - const customizeKey = bi > 0; - const key = customizeKey ? p_k.substring(bi + 1) : lastKeyInPath; - if (key == null || key.trim().length <= 0) { - throw new Error('参数注入 第 ' + (i + 1) + ' 行格式错误!\n字符 ' + key + ' 不是合法的 JSON key!' + - '\n每个随机变量配置都必须按照\n key0/key1/../targetKey replaceKey: value // 注释\n的格式!' + - '\n注意冒号 ": " 左边 0 空格,右边 1 空格!其中 replaceKey 可省略。' + - '\nkey: {} 中最外层常量对象 {} 必须用括号包裹为 ({}),也就是 key: ({}) 这种格式!' + - '\nkey: 多行代码 必须用 function f() { var a = 1; return a; } f() 这种一行代码格式!'); - } - - // value RANDOM_DB - const value = line.substring(index + ': '.length); - - var invoke = function (val, which, p_k, pathKeys, key, lastKeyInPath) { - try { - if (generateConfig) { - var configVal; - if (val instanceof Object) { - configVal = JSON.stringify(val); - } - else if (typeof val == 'string') { - configVal = '"' + val + '"'; - } - else { - configVal = val - } - constConfigLines[which] = p_k + ': ' + configVal; - } - - if (generateName) { - var valStr; - if (val instanceof Array) { - valStr = val.length <= 0 ? '[]' : '[..' + val.length + '..]'; - } - else if (val instanceof Object) { - var kl = Object.keys(val).length - valStr = kl <= 0 ? '{}' : '{..' + kl + '..}'; - } - else if (typeof val == 'boolean') { - valStr = '' + val; - } - else { - valStr = new String(val); - if (valStr.length > 13) { - valStr = valStr.substring(0, 5) + '...'; - } - } - randomNameKeys[which] = valStr; - } - - if (generateJSON) { - //先按照单行简单实现 - //替换 JSON 里的键值对 key: value - var parent = json; - var current = null; - for (var j = 0; j < pathKeys.length - 1; j ++) { - current = parent[pathKeys[j]] - if (current == null) { - current = parent[pathKeys[j]] = {} - } - if (parent instanceof Object == false) { - throw new Error('参数注入 第 ' + (i + 1) + ' 行格式错误!路径 ' + path + ' 中' + - ' pathKeys[' + j + '] = ' + pathKeys[j] + ' 在实际请求 JSON 内对应的值不是对象 {} 或 数组 [] !'); - } - parent = current; - } - - if (current == null) { - current = json; - } - // alert('< current = ' + JSON.stringify(current, null, ' ')) - - if (key != lastKeyInPath || current.hasOwnProperty(key) == false) { - delete current[lastKeyInPath]; - } - - current[key] = val; - } - - } - catch (e) { - throw new Error('第 ' + (which + 1) + ' 行随机配置 key: value 后的 value 不合法! \nerr: ' + e.message) - } - - respCount ++; - if (respCount >= reqCount) { - callback(randomNameKeys.join(', '), constConfigLines.join('\n'), json); - } - }; - - - const start = value.indexOf('('); - const end = value.lastIndexOf(')'); - - var request4Db = function(tableName, which, p_k, pathKeys, key, lastKeyInPath, isRandom, isDesc, step) { - // const tableName = JSONResponse.getTableName(pathKeys[pathKeys.length - 2]); - vOutput.value = 'requesting value for ' + tableName + '/' + key + ' from database...'; - - const args = StringUtil.split(value.substring(start + 1, end)) || []; - var min = StringUtil.trim(args[0]); - var max = StringUtil.trim(args[1]); - var table = StringUtil.trim(args[2]) || ''; - var column = StringUtil.trim(args[3]) || ''; - - min = min == '' || min == 'null' || min == 'undefined' ? null : +min; - max = max == '' || max == 'null' || max == 'undefined' ? null : +max; - - if ((table.startsWith('"') && table.endsWith('"')) || (table.startsWith("'") && table.endsWith("'"))) { - table = table.substring(1, table.length - 1); - } - if ((column.startsWith('"') && column.endsWith('"')) || (column.startsWith("'") && column.endsWith("'"))) { - column = column.substring(1, column.length - 1); - } - - const finalTableName = StringUtil.isEmpty(table, true) ? tableName : table; - const finalColumnName = StringUtil.isEmpty(column, true) ? lastKeyInPath : column; - - const tableReq = { - '@column': isRandom ? finalColumnName : ('DISTINCT ' + finalColumnName), - '@order': isRandom ? 'rand()' : (finalColumnName + (isDesc ? '-' : '+')) - }; - tableReq[finalColumnName + '>='] = min; - tableReq[finalColumnName + '<='] = max; - - const req = {}; - const listName = isRandom ? null : finalTableName + '-' + finalColumnName + '[]'; - const orderIndex = isRandom ? null : getOrderIndex(randomId, line, null) - - if (isRandom) { - req[finalTableName] = tableReq; - } - else { - // 从数据库获取时不考虑边界,不会在越界后自动循环 - var listReq = { - count: 1, // count <= 100 ? count : 0, - page: (step*orderIndex) % 100 //暂时先这样,APIJSON 应该改为 count*page <= 10000 //FIXME 上限 100 怎么破,lastKeyInPath 未必是 id - }; - listReq[finalTableName] = tableReq; - req[listName] = listReq; - } - - // reqCount ++; - App.request(true, REQUEST_TYPE_JSON, baseUrl + '/get', req, {}, function (url, res, err) { - // respCount ++; - try { - App.onResponse(url, res, err) - } catch (e) {} - - var data = (res || {}).data || {} - if (data.code != CODE_SUCCESS) { - respCount = -reqCount; - vOutput.value = '参数注入 为第 ' + (which + 1) + ' 行\n ' + p_k + ' \n获取数据库数据 异常:\n' + data.msg; - alert(StringUtil.get(vOutput.value)); - return - // throw new Error('参数注入 为\n ' + tableName + '/' + key + ' \n获取数据库数据 异常:\n' + data.msg) - } - - if (isRandom) { - invoke((data[finalTableName] || {})[finalColumnName], which, p_k, pathKeys, key, lastKeyInPath); - } - else { - var val = (data[listName] || [])[0]; - //越界,重新获取 - if (val == null && orderIndex > 0 && ORDER_MAP[randomId] != null && ORDER_MAP[randomId][line] != null) { - ORDER_MAP[randomId][line] = null; //重置,避免还是在原来基础上叠加 - request4Db(JSONResponse.getTableName(pathKeys[pathKeys.length - 2]), which, p_k, pathKeys, key, lastKeyInPath, false, isDesc, step); - } - else { - invoke(val, which, p_k, pathKeys, key, lastKeyInPath); - } - } - - // var list = data[listName] || []; - //代码变化会导致缓存失效,而且不好判断,数据量大会导致页面很卡 ORDER_MAP[randomId][line].list = list; - // - // if (step == null) { - // invoke('randomIn(' + list.join() + ')'); - // } - // else { - // invoke('orderIn(' + isDesc + ', ' + step*getOrderIndex(randomId, line, list.length) + list.join() + ')'); - // } - - }) - }; - - - - //支持 1, "a" 这种原始值 - // if (start < 0 || end <= start) { //(1) 表示原始值 start*end <= 0 || start >= end) { - // throw new Error('参数注入 第 ' + (i + 1) + ' 行格式错误!字符 ' + value + ' 不是合法的随机函数!'); - // } - - var toEval = value; - if (start > 0 && end > start) { - - var funWithOrder = value.substring(0, start); - var splitIndex = funWithOrder.indexOf('+'); - - var isDesc = false; - if (splitIndex < 0) { // -(1+2) 这种是表达式,不能作为函数 splitIndex <= 0) { - splitIndex = funWithOrder.indexOf('-'); - isDesc = splitIndex > 0; - } - - var fun = splitIndex < 0 ? funWithOrder : funWithOrder.substring(0, splitIndex); - - if ([ORDER_DB, ORDER_IN, ORDER_INT].indexOf(fun) >= 0) { //顺序函数 - var stepStr = splitIndex < 0 ? null : funWithOrder.substring(splitIndex + 1, funWithOrder.length); - var step = stepStr == null || stepStr.length <= 0 ? 1 : +stepStr; //都会自动忽略空格 Number(stepStr); //Number.parseInt(stepStr); //+stepStr; - - if (Number.isSafeInteger(step) != true || step <= 0 - || (StringUtil.isEmpty(stepStr, false) != true && StringUtil.isNumber(stepStr) != true) - ) { - throw new Error('参数注入 第 ' + (i + 1) + ' 行格式错误!路径 ' + path + ' 中字符 ' + stepStr + ' 不符合跨步 step 格式!' - + '\n顺序整数 和 顺序取值 可以通过以下格式配置 升降序 和 跨步:' - + '\n ODER_REAL+step(arg0, arg1...)\n ODER_REAL-step(arg0, arg1...)' - + '\n ODER_INT+step(arg0, arg1...)\n ODER_INT-step(arg0, arg1...)' - + '\n ODER_IN+step(start, end)\n ODER_IN-step(start, end)' - + '\n其中:\n + 为升序,后面没有 step 时可省略;\n - 为降序,不可省略;' + '\n step 为跨步值,类型为 正整数,默认为 1,可省略。' - + '\n+,-,step 前后都不能有空格等其它字符!'); - } - - if (fun == ORDER_DB) { - request4Db(JSONResponse.getTableName(pathKeys[pathKeys.length - 2]), which, p_k, pathKeys, key, lastKeyInPath, false, isDesc, step); //request4Db(key + (isDesc ? '-' : '+'), step); - continue; - } - - toEval = (fun == ORDER_IN ? 'orderIn' : 'orderInt') - + '(' + isDesc + ', ' + step*getOrderIndex( - randomId, line - , fun == ORDER_INT ? 0 : StringUtil.split(value.substring(start + 1, end)).length - ) + ', ' + value.substring(start + 1); - } - else { //随机函数 - fun = funWithOrder; //还原,其它函数不支持 升降序和跨步! - - if (fun == RANDOM_DB) { - request4Db(JSONResponse.getTableName(pathKeys[pathKeys.length - 2]), which, p_k, pathKeys, key, lastKeyInPath, true); //'random()'); - continue; - } - - if (fun == RANDOM_IN) { - toEval = 'randomIn' + value.substring(start); - } - else if (fun == RANDOM_INT) { - toEval = 'randomInt' + value.substring(start); - } - else if (fun == RANDOM_NUM) { - toEval = 'randomNum' + value.substring(start); - } - else if (fun == RANDOM_STR) { - toEval = 'randomStr' + value.substring(start); - } - - } - - } - - invoke(eval(toEval), which, p_k, pathKeys, key, lastKeyInPath); - - // alert('> current = ' + JSON.stringify(current, null, ' ')) - } - - }, - - onClickSend: function () { - this.isRandomTest = false - this.send(false) - }, - onClickTest: function () { - this.isRandomTest = false - this.test(false, this.isCrossEnabled ? -1 : this.currentAccountIndex) - }, - /**回归测试 - * 原理: - 1.遍历所有上传过的测试用例(URL+请求JSON) - 2.逐个发送请求 - 3.对比同一用例的先后两次请求结果,如果不一致,就在列表中标记对应的用例(× 蓝黄红色下载(点击下载两个文件) √)。 - 4.如果这次请求结果正确,就把请求结果保存到和公司开发环境服务器的APIJSON Server,并取消标记 - - compare: 新的请求与上次请求的对比结果 - 0-相同,无颜色; - 1-对象新增字段或数组新增值,绿色; - 2-值改变,蓝色; - 3-对象缺少字段/整数变小数,黄色; - 4-code/值类型 改变,红色; - */ - test: function (isRandom, accountIndex) { - var accounts = this.accounts || [] - // alert('test accountIndex = ' + accountIndex) - var isCrossEnabled = this.isCrossEnabled - if (accountIndex == null) { - accountIndex = -1 //isCrossEnabled ? -1 : 0 - } - if (isCrossEnabled) { - var isCrossDone = accountIndex >= accounts.length - this.crossProcess = isCrossDone ? (isCrossEnabled ? '交叉账号:已开启' : '交叉账号:已关闭') : ('交叉账号: ' + (accountIndex + 1) + '/' + accounts.length) - if (isCrossDone) { - alert('已完成账号交叉测试: 退出登录状态 和 每个账号登录状态') - return - } - } - - var baseUrl = StringUtil.trim(this.getBaseUrl()) - if (baseUrl == '') { - alert('请先输入有效的URL!') - return - } - //开放测试 - // if (baseUrl.indexOf('/apijson.cn') >= 0 || baseUrl.indexOf('/39.108.143.172') >= 0) { - // alert('请把URL改成你自己的!\n例如 http://localhost:8080') - // return - // } - // if (baseUrl.indexOf('/apijson.org') >= 0) { - // alert('请把URL改成 http://apijson.cn:8080 或 你自己的!\n例如 http://localhost:8080') - // return - // } - - const list = this.remotes || [] - const allCount = list.length - doneCount = 0 - - if (allCount <= 0) { - alert('请先获取测试用例文档\n点击[查看共享]图标按钮') - return - } - - if (isCrossEnabled) { - if (accountIndex < 0 && accounts[this.currentAccountIndex] != null) { //退出登录已登录的账号 - accounts[this.currentAccountIndex].isLoggedIn = true - } - var index = accountIndex < 0 ? this.currentAccountIndex : accountIndex - this.onClickAccount(index, accounts[index], function (isLoggedIn, index, err) { - // if (index >= 0 && isLoggedIn == false) { - // alert('第 ' + index + ' 个账号登录失败!' + (err == null ? '' : err.message)) - // App.test(isRandom, accountIndex + 1) - // return - // } - App.showTestCase(true, false) - App.startTest(list, allCount, isRandom, accountIndex) - }) - } - else { - this.startTest(list, allCount, isRandom, accountIndex) - } - }, - - startTest: function (list, allCount, isRandom, accountIndex) { - this.testProcess = '正在测试: ' + 0 + '/' + allCount - - for (var i = 0; i < allCount; i++) { - const item = list[i] - const document = item == null ? null : item.Document - if (document == null || document.name == null) { - doneCount++ - continue - } - if (document.url == '/login' || document.url == '/logout') { //login会导致登录用户改变为默认的但UI上还显示原来的,单独测试OWNER权限时能通过很困惑 - this.log('test document.url == "/login" || document.url == "/logout" >> continue') - doneCount++ - continue - } - this.log('test document = ' + JSON.stringify(document, null, ' ')) - - const index = i - - var header = null - try { - header = this.getHeader(document.header) - } catch (e) { - this.log('test for ' + i + ' >> try { header = this.getHeader(document.header) } catch (e) { \n' + e.message) - } - - this.request(false, document.type, baseUrl + document.url, this.getRequest(document.request, null, true), header, function (url, res, err) { - - try { - App.onResponse(url, res, err) - App.log('test App.request >> res.data = ' + JSON.stringify(res.data, null, ' ')) - } catch (e) { - App.log('test App.request >> } catch (e) {\n' + e.message) - } - - App.compareResponse(allCount, list, index, item, res.data, isRandom, accountIndex, false, err) - }) - } - - }, - - compareResponse: function (allCount, list, index, item, response, isRandom, accountIndex, justRecoverTest, err, ignoreTrend) { - var it = item || {} //请求异步 - var d = (isRandom ? this.currentRemoteItem.Document : it.Document) || {} //请求异步 - var r = isRandom ? it.Random : null //请求异步 - var tr = it.TestRecord || {} //请求异步 - - var bdt = tr.duration || 0 - it.durationBeforeShowStr = bdt <= 0 ? '' : (bdt < 1000 ? bdt + 'ms' : (bdt < 1000*60 ? (bdt/1000).toFixed(1) + 's' : (bdt <= 1000*60*60 ? (bdt/1000/60).toFixed(1) + 'm' : '>1h'))) - try { - var durationInfo = response['time:start|duration|end|parse|sql'] - it.durationInfo = durationInfo - var di = durationInfo.substring(durationInfo.indexOf('\|') + 1) - it.duration = di.substring(0, di.indexOf('\|') || di.length) || 0 - var dt = + it.duration - it.duration = dt - it.durationShowStr = dt <= 0 ? '' : (dt < 1000 ? dt + 'ms' : (dt < 1000*60 ? (dt/1000).toFixed(1) + 's' : (dt <= 1000*60*60 ? (dt/1000/60).toFixed(1) + 'm' : '>1h'))) - var min = tr.minDuration || 20 - var max = tr.maxDuration || 200 - it.durationColor = dt < min ? 'green' : (dt > 2*max ? 'red' : (dt > max + min ? 'orange' : (dt > max ? 'blue' : 'black'))) - it.durationHint = dt < min ? '很快:比以往 [' + min + 'ms, ' + max + 'ms] 最快还更快' : (dt > 2*max ? '非常慢:比以往 [' + min + 'ms, ' + max + 'ms] 最慢的两倍还更慢' - : (dt > max + min ? '比较慢:比以往 [' + min + 'ms, ' + max + 'ms] 最快与最慢之和(平均值两倍)还更慢' - : (dt > max ? '有点慢:比以往 [' + min + 'ms, ' + max + 'ms] 最慢还更慢' : '正常:在以往 [' + min + 'ms, ' + max + 'ms] 最快和最慢之间'))) - } - catch (e) { - log(e) - it.durationShowStr = it.durationShowStr || it.duration - it.durationHint = it.durationHint || '最外层缺少字段 "time:start|duration|end|parse|sql": "1613039123780|10|1613039123790|1|9",无法对比耗时' - } - - if (err != null) { - tr.compare = { - code: JSONResponse.COMPARE_ERROR, //请求出错 - msg: '请求出错!', - path: err.message + '\n\n' - } - } - else { - var standardKey = this.isMLEnabled != true ? 'response' : 'standard' - var standard = StringUtil.isEmpty(tr[standardKey], true) ? null : JSON.parse(tr[standardKey]) - tr.compare = JSONResponse.compareResponse(standard, this.removeDebugInfo(response) || {}, '', this.isMLEnabled, null, null, ignoreTrend) || {} - tr.compare.duration = it.durationHint - } - - this.onTestResponse(allCount, list, index, it, d, r, tr, response, tr.compare || {}, isRandom, accountIndex, justRecoverTest); - }, - - onTestResponse: function(allCount, list, index, it, d, r, tr, response, cmp, isRandom, accountIndex, justRecoverTest) { - tr = tr || {} - tr.compare = cmp; - - it = it || {} - it.compareType = tr.compare.code; - it.hintMessage = tr.compare.path + ' ' + tr.compare.msg; - switch (it.compareType) { - case JSONResponse.COMPARE_ERROR: - it.compareColor = 'red' - it.compareMessage = '请求出错!' - break; - case JSONResponse.COMPARE_NO_STANDARD: - it.compareColor = 'green' - it.compareMessage = '确认正确后点击[对的,纠正]' - break; - case JSONResponse.COMPARE_KEY_MORE: - it.compareColor = 'green' - it.compareMessage = '新增字段/新增值 等' - break; - case JSONResponse.COMPARE_VALUE_CHANGE: - it.compareColor = 'blue' - it.compareMessage = '值改变 等' - break; - case JSONResponse.COMPARE_KEY_LESS: - it.compareColor = 'orange' - it.compareMessage = '缺少字段/整数变小数 等' - break; - case JSONResponse.COMPARE_TYPE_CHANGE: - it.compareColor = 'red' - it.compareMessage = '状态码/异常/值类型 改变等' - break; - default: - it.compareColor = 'white' - it.compareMessage = '查看结果' - break; - } - - if (isRandom) { - r = r || {} - it.Random = r - - this.updateToRandomSummary(it, 1) - } - else { - it.Document = d - } - it.TestRecord = tr - - Vue.set(list, index, it) - - if (justRecoverTest) { - return - } - - doneCount ++ - this.testProcess = doneCount >= allCount ? (this.isMLEnabled ? '机器学习:已开启' : '机器学习:已关闭') : '正在测试: ' + doneCount + '/' + allCount - - this.log('doneCount = ' + doneCount + '; d.name = ' + (isRandom ? r.name : d.name) + '; it.compareType = ' + it.compareType) - - var documentId = isRandom ? r.documentId : d.id - if (this.tests == null) { - this.tests = {} - } - if (this.tests[String(accountIndex)] == null) { - this.tests[String(accountIndex)] = {} - } - - var tests = this.tests[String(accountIndex)] || {} - var t = tests[documentId] - if (t == null) { - t = tests[documentId] = {} - } - t[isRandom ? (r.id > 0 ? r.id : (r.toId + '' + r.id)) : 0] = response - - this.tests[String(accountIndex)] = tests - this.log('tests = ' + JSON.stringify(tests, null, ' ')) - // this.showTestCase(true) - - if (doneCount >= allCount && this.isCrossEnabled && isRandom != true) { - // alert('onTestResponse accountIndex = ' + accountIndex) - //TODO 自动给非 红色 报错的接口跑参数注入 - - this.test(false, accountIndex + 1) - } - }, - - //更新父级总览数据 - updateToRandomSummary: function (item, change) { - var random = item == null || change == null ? null : item.Random - var toId = random == null ? null : random.toId - if (toId != null && toId > 0) { - - for (var i in this.randoms) { - - var toIt = this.randoms[i] - if (toIt != null && toIt.Random != null && toIt.Random.id == toId) { - - var toRandom = toIt.Random - var id = toRandom == null ? 0 : toRandom.id - var count = id == null || id <= 0 ? 0 : toRandom.count - if (count != null && count > 1) { - var key = item.compareColor + 'Count' - if (toIt[key] == null) { - toIt[key] = 0 - } - toIt[key] += change - if (toIt[key] < 0) { - toIt[key] = 0 - } - - if (toIt.totalCount == null) { - toIt.totalCount = 0 - } - toIt.totalCount += change - if (toIt.totalCount < 0) { - toIt.totalCount = 0 - } - } - - Vue.set(this.randoms, i, toIt) - - break; - } - - } - } - }, - - /**移除调试字段 - * @param obj - */ - removeDebugInfo: function (obj) { - if (obj != null) { - delete obj["debug:info|help"] - delete obj["sql:generate|cache|execute|maxExecute"] - delete obj["depth:count|max"] - delete obj["time:start|duration|end"] - delete obj["time:start|duration|end|parse|sql"] - // 保留 delete obj["throw"] - // 保留 delete obj["trace:throw"] - delete obj["trace:stack"] - delete obj["stack"] - } - return obj - }, - - /** - * @param index - * @param item - */ - downloadTest: function (index, item, isRandom) { - item = item || {} - var document; - if (isRandom) { - document = this.currentRemoteItem || {} - } - else { - document = item.Document = item.Document || {} - } - var random = isRandom ? item.Random : null - var testRecord = item.TestRecord = item.TestRecord || {} - - saveTextAs( - '# APIJSON自动化回归测试-前\n主页: https://github.com/Tencent/APIJSON' - + '\n\n接口名称: \n' + (document.version > 0 ? 'V' + document.version : 'V*') + ' ' + document.name - + '\n返回结果: \n' + JSON.stringify(JSON.parse(testRecord.response || '{}'), null, ' ') - , '测试:' + document.name + '-前.txt' - ) - - /** - * 浏览器不允许连续下载,saveTextAs也没有回调。 - * 在第一个文本里加上第二个文本的信息? - * beyond compare会把第一个文件的后面一段与第二个文件匹配, - * 导致必须先删除第一个文件内的后面与第二个文件重复的一段,再重新对比。 - */ - setTimeout(function () { - var tests = App.tests[String(App.currentAccountIndex)] || {} - saveTextAs( - '# APIJSON自动化回归测试-后\n主页: https://github.com/Tencent/APIJSON' - + '\n\n接口名称: \n' + (document.version > 0 ? 'V' + document.version : 'V*') + ' ' + document.name - + '\n返回结果: \n' + JSON.stringify(tests[document.id][isRandom ? random.id : 0] || {}, null, ' ') - , '测试:' + document.name + '-后.txt' - ) - - - if (StringUtil.isEmpty(testRecord.standard, true) == false) { - setTimeout(function () { - saveTextAs( - '# APIJSON自动化回归测试-标准\n主页: https://github.com/Tencent/APIJSON' - + '\n\n接口名称: \n' + (document.version > 0 ? 'V' + document.version : 'V*') + ' ' + document.name - + '\n测试结果: \n' + JSON.stringify(testRecord.compare || '{}', null, ' ') - + '\n测试标准: \n' + JSON.stringify(JSON.parse(testRecord.standard || '{}'), null, ' ') - , '测试:' + document.name + '-标准.txt' - ) - }, 5000) - } - - }, 5000) - - }, - - /** - * @param index - * @param item - */ - handleTest: function (right, index, item, isRandom, isDuration) { - item = item || {} - var random = item.Random = item.Random || {} - var document; - if (isRandom) { - if ((random.count || 0) > 1) { - this.currentRandomIndex = index - // this.currentRandomSubIndex = -1 - this.restoreRandom(index, item) - this.randomSubs = (item.subs || item['[]']) || [] - this.isRandomSubListShow = true - return - } - - this.currentRandomSubIndex = index - document = this.currentRemoteItem || {} - } - else { - this.currentDocIndex = index - this.currentRemoteItem = item - // this.currentRandomIndex = -1 - // this.currentRandomSubIndex = -1 - document = item.Document = item.Document || {} - } - var testRecord = item.TestRecord = item.TestRecord || {} - - var tests = this.tests[String(this.currentAccountIndex)] || {} - var currentResponse = (tests[isRandom ? random.documentId : document.id] || {})[ - isRandom ? (random.id > 0 ? random.id : (random.toId + '' + random.id)) : 0 - ] || {} - - const list = isRandom ? (random.toId == null || random.toId <= 0 ? this.randoms : this.randomSubs) : this.testCases - - var isBefore = item.showType == 'before' - if (right != true) { - item.showType = isBefore ? 'after' : 'before' - Vue.set(list, index, item); - - var res = isBefore ? JSON.stringify(currentResponse) : testRecord.response - - this.view = 'code' - this.jsoncon = res || '' - } - else { - var url - - if (isBefore) { //撤回原来错误提交的校验标准 - if (isDuration) { - alert('撤回上次的耗时需要删除上次的对比标准,请点左边 [错的,撤回] 按钮') - return - } - - url = this.server + '/delete' - const req = { - TestRecord: { - id: testRecord.id, //TODO 权限问题? item.userId, - }, - tag: 'TestRecord' - } - - this.request(true, REQUEST_TYPE_JSON, url, req, {}, function (url, res, err) { - App.onResponse(url, res, err) - - var data = res.data || {} - if (data.code != CODE_SUCCESS && testRecord!= null && testRecord.id != null) { - alert('撤回最新的校验标准 异常:\n' + data.msg) - return - } - - if (isRandom) { - App.updateToRandomSummary(item, -1) - } - - if (isDuration) { - item.durationColor = 'black' - item.durationHint = '正常:在以往最快和最慢之间' - } - else { - item.compareType = JSONResponse.COMPARE_NO_STANDARD - item.compareMessage = '查看结果' - item.compareColor = 'white' - item.hintMessage = '没有校验标准!' - item.TestRecord = null - } - - App.updateTestRecord(0, list, index, item, currentResponse, isRandom, App.currentAccountIndex, true) - }) - } - else { //上传新的校验标准 - // if (isRandom && random.id <= 0) { - // alert('请先上传这个配置!') - // App.currentRandomItem = random - // App.showExport(true, false, true) - // return - // } - var isML = this.isMLEnabled; // 异常分支不合并内容,只记录 code, throw, msg 等关键信息 - - var standard - var stddObj - - var minDuration = testRecord.minDuration - var maxDuration = testRecord.maxDuration - if (isDuration) { - if (item.duration == null) { // 没有获取到 - alert('最外层缺少字段 "time:start|duration|end|parse|sql": "1613039123780|10|1613039123790|1|9",无法对比耗时!') - return - } - else if (maxDuration == null && minDuration == null) { - maxDuration = item.duration - minDuration = Math.round(maxDuration*0.8) - } - else if (maxDuration == null && minDuration != null) { - maxDuration = Math.max(minDuration, item.duration) - testRecord.minDuration = Math.min(minDuration, item.duration) - } - else if (minDuration == null && maxDuration != null) { - minDuration = Math.min(maxDuration, item.duration) - testRecord.maxDuration = Math.max(maxDuration, item.duration) - } - else if (maxDuration > 0 && maxDuration < item.duration) { - maxDuration = item.duration - } - else if (minDuration > 0 && minDuration > item.duration) { - minDuration = item.duration - } - else { // 已经在正常范围中,不需要纠错 - alert('耗时已经在正常范围中,不需要纠错!') - return - } - } - else { - standard = (StringUtil.isEmpty(testRecord.standard, true) ? null : JSON.parse(testRecord.standard)) || {}; - - var code = currentResponse.code; - var thrw = currentResponse.throw; - var msg = currentResponse.msg; - - var hasCode = standard.code != null; - var isCodeChange = standard.code != code; - var exceptions = standard.exceptions || []; - - delete currentResponse.code; //code必须一致 - delete currentResponse.throw; //throw必须一致 - - var find = false; - if (isCodeChange && hasCode) { // 走异常分支 - for (var i = 0; i < exceptions.length; i++) { - var ei = exceptions[i]; - if (ei != null && ei.code == code && ei.throw == thrw) { - find = true; - ei.repeat = (ei.repeat || 0) + 1; // 统计重复出现次数 - break; - } - } - - if (find) { - delete currentResponse.msg; - } - } - - stddObj = isML ? (isCodeChange && hasCode ? standard : JSONResponse.updateStandard(standard, currentResponse)) : {}; - - currentResponse.code = code; - currentResponse.throw = thrw; - - if (isCodeChange) { - if (hasCode != true) { // 走正常分支 - stddObj.code = code; - stddObj.throw = thrw; - } - else { // 走异常分支 - currentResponse.msg = msg; - - if (find != true) { - exceptions.push({ - code: code, - 'throw': thrw, - msg: msg - }) - - stddObj.exceptions = exceptions; - } - } - } - else { - stddObj.repeat = (stddObj.repeat || 0) + 1; // 统计重复出现次数 - } - } - - const isNewRandom = isRandom && random.id <= 0 - - //TODO 先检查是否有重复名称的!让用户确认! - // if (isML != true) { - url = this.server + '/post' - const req = { - Random: isNewRandom != true ? null : { - toId: random.toId, - documentId: random.documentId, - name: random.name, - count: random.count, - config: random.config - }, - TestRecord: isDuration ? Object.assign(testRecord, { - id: undefined, - host: this.getBaseUrl(), - testAccountId: this.getCurrentAccountId(), - duration: item.duration, - minDuration: minDuration, - maxDuration: maxDuration, - compare: JSON.stringify(testRecord.compare || {}), - }) : { - documentId: isNewRandom ? null : (isRandom ? random.documentId : document.id), - randomId: isRandom && ! isNewRandom ? random.id : null, - host: this.getBaseUrl(), - testAccountId: this.getCurrentAccountId(), - compare: JSON.stringify(testRecord.compare || {}), - response: JSON.stringify(currentResponse || {}), - standard: isML ? JSON.stringify(stddObj) : null - }, - tag: isNewRandom ? 'Random' : 'TestRecord' - } - // } - // else { - // url = this.server + '/post/testrecord/ml' - // req = { - // documentId: document.id - // } - // } - - this.request(true, REQUEST_TYPE_JSON, url, req, {}, function (url, res, err) { - App.onResponse(url, res, err) - - var data = res.data || {} - if (data.code != CODE_SUCCESS) { - if (isML) { - alert('机器学习更新标准 异常:\n' + data.msg) - } - } - else { - if (isRandom) { - App.updateToRandomSummary(item, -1) - } - - var testRecord = item.TestRecord || {} - if (isDuration) { - item.durationColor = 'black' - item.durationHint = '正常:在以往最快和最慢之间' - } - else { - item.compareType = JSONResponse.COMPARE_EQUAL - item.compareMessage = '查看结果' - item.compareColor = 'white' - item.hintMessage = '结果正确' - - testRecord.compare = { - code: 0, - msg: '结果正确' - } - testRecord.response = JSON.stringify(currentResponse) - // testRecord.standard = stdd - } - - if (isRandom) { - var r = req == null ? null : req.Random - if (r != null && (data.Random || {}).id != null) { - r.id = data.Random.id - item.Random = r - } - if ((data.TestRecord || {}).id != null) { - testRecord.id = data.TestRecord.id - if (r != null) { - testRecord.randomId = r.id - } - } - } - item.TestRecord = testRecord - - - // if (! isNewRandom) { - // if (isRandom) { - // App.showRandomList(true, App.currentRemoteItem) - // } - // else { - // App.showTestCase(true, false) - // } - // } - - App.updateTestRecord(0, list, index, item, currentResponse, isRandom, true) - } - - }) - - } - } - }, - - updateTestRecord: function (allCount, list, index, item, response, isRandom, ignoreTrend) { - item = item || {} - var doc = (isRandom ? item.Random : item.Document) || {} - - this.request(true, REQUEST_TYPE_JSON, this.server + '/get', { - TestRecord: { - documentId: isRandom ? doc.documentId : doc.id, - randomId: isRandom ? doc.id : null, - testAccountId: this.getCurrentAccountId(), - 'host': this.getBaseUrl(), - '@order': 'date-', - '@column': 'id,userId,testAccountId,documentId,randomId,duration,minDuration,maxDuration,response' + (this.isMLEnabled ? ',standard' : ''), - '@having': this.isMLEnabled ? 'length(standard)>2' : null // '@having': this.isMLEnabled ? 'json_length(standard)>0' : null - } - }, {}, function (url, res, err) { - App.onResponse(url, res, err) - - var data = (res || {}).data || {} - if (data.code != CODE_SUCCESS) { - alert('获取最新的校验标准 异常:\n' + data.msg) - return - } - - item.TestRecord = data.TestRecord - App.compareResponse(allCount, list, index, item, response, isRandom, App.currentAccountIndex, true, err, ignoreTrend); - }) - }, - - //显示详细信息, :data-hint :data, :hint 都报错,只能这样 - setRequestHint: function(index, item, isRandom) { - item = item || {} - var d = isRandom ? item.Random : item.Document; - // var r = d == null ? null : (isRandom ? d.config : d.request); - // this.$refs[isRandom ? 'randomTexts' : 'testCaseTexts'][index].setAttribute('data-hint', r == null ? '' : (isRandom ? r : JSON.stringify(this.getRequest(r), null, ' '))); - - if (isRandom) { - var toId = (d == null ? null : d.toId) || 0 - this.$refs[toId <= 0 ? 'randomTexts' : 'randomSubTexts'][index].setAttribute('data-hint', (d || {}).config == null ? '' : d.config); - } - else { - this.$refs['testCaseTexts'][index].setAttribute('data-hint', StringUtil.isEmpty(d.request, true) ? '' : JSON.stringify(this.getRequest(d.request, {}, true), null, ' ')); - } - }, - - //显示详细信息, :data-hint :data, :hint 都报错,只能这样 - setTestHint: function(index, item, isRandom, isDuration) { - item = item || {}; - var toId = isRandom ? ((item.Random || {}).toId || 0) : 0; - var h = isDuration ? item.durationHint : item.hintMessage; - this.$refs[(isRandom ? (toId <= 0 ? 'testRandomResult' : 'testRandomSubResult') : 'testResult') + (isDuration ? 'Duration' : '') + 'Buttons'][index].setAttribute('data-hint', h || ''); - } - - }, - watch: { - jsoncon: function () { - this.showJsonView() - } - }, - computed: { - theme: function () { - var th = this.themes[this.checkedTheme] - var result = {} - var index = 0; - ['key', 'String', 'Number', 'Boolean', 'Null', 'link-link'].forEach(function(key) { - result[key] = th[index] - index++ - }) - return result - } - }, - created () { - try { //可能URL_BASE是const类型,不允许改,这里是初始化,不能出错 - var url = this.getCache('', 'URL_BASE') - if (StringUtil.isEmpty(url, true) == false) { - URL_BASE = url - } - var database = this.getCache('', 'database') - if (StringUtil.isEmpty(database, true) == false) { - this.database = CodeUtil.database = database - } - var schema = this.getCache('', 'schema') - if (StringUtil.isEmpty(schema, true) == false) { - this.schema = CodeUtil.schema = schema - } - var language = this.getCache('', 'language') - if (StringUtil.isEmpty(language, true) == false) { - this.language = CodeUtil.language = language - } - var types = this.getCache('', 'types') - if (types != null && types.length > 0) { - this.types = types instanceof Array ? types : StringUtil.split(types) - } - var server = this.getCache('', 'server') - if (StringUtil.isEmpty(server, true) == false) { - this.server = server - } - var thirdParty = this.getCache('', 'thirdParty') - if (StringUtil.isEmpty(thirdParty, true) == false) { - this.thirdParty = thirdParty - } - - this.locals = this.getCache('', 'locals', []) - - this.isDelegateEnabled = this.getCache('', 'isDelegateEnabled', this.isDelegateEnabled) - this.isEncodeEnabled = this.getCache('', 'isEncodeEnabled', this.isEncodeEnabled) - //预览了就不能编辑了,点开看会懵 this.isPreviewEnabled = this.getCache('', 'isPreviewEnabled', this.isPreviewEnabled) - this.isHeaderShow = this.getCache('', 'isHeaderShow', this.isHeaderShow) - this.isRandomShow = this.getCache('', 'isRandomShow', this.isRandomShow) - } catch (e) { - console.log('created try { ' + - '\nvar url = this.getCache(, url) ...' + - '\n} catch (e) {\n' + e.message) - } - try { //这里是初始化,不能出错 - var accounts = this.getCache(URL_BASE, 'accounts') - if (accounts != null) { - this.accounts = accounts - this.currentAccountIndex = this.getCache(URL_BASE, 'currentAccountIndex') - } - } catch (e) { - console.log('created try { ' + - '\nvar accounts = this.getCache(URL_BASE, accounts)' + - '\n} catch (e) {\n' + e.message) - } - - try { //可能URL_BASE是const类型,不允许改,这里是初始化,不能出错 - this.User = this.getCache(this.server, 'User', {}) - this.isCrossEnabled = this.getCache(this.server, 'isCrossEnabled', this.isCrossEnabled) - this.isMLEnabled = this.getCache(this.server, 'isMLEnabled', this.isMLEnabled) - this.crossProcess = this.isCrossEnabled ? '交叉账号:已开启' : '交叉账号:已关闭' - this.testProcess = this.isMLEnabled ? '机器学习:已开启' : '机器学习:已关闭' - // this.host = this.getBaseUrl() - this.page = this.getCache(this.server, 'page', this.page) - this.count = this.getCache(this.server, 'count', this.count) - this.testCasePage = this.getCache(this.server, 'testCasePage', this.testCasePage) - this.testCaseCount = this.getCache(this.server, 'testCaseCount', this.testCaseCount) - this.randomPage = this.getCache(this.server, 'randomPage', this.randomPage) - this.randomCount = this.getCache(this.server, 'randomCount', this.randomCount) - this.randomSubPage = this.getCache(this.server, 'randomSubPage', this.randomSubPage) - this.randomSubCount = this.getCache(this.server, 'randomSubCount', this.randomSubCount) - this.delegateId = this.getCache(this.server, 'delegateId', this.delegateId) - - CodeUtil.thirdPartyApiMap = this.getCache(this.thirdParty, 'thirdPartyApiMap') - } catch (e) { - console.log('created try { ' + - '\nthis.User = this.getCache(this.server, User, {})' + - '\n} catch (e) {\n' + e.message) - } - - //无效,只能在index里设置 vUrl.value = this.getCache('', 'URL_BASE') - - this.listHistory() - - var rawReq = getRequestFromURL() - if (rawReq == null || StringUtil.isEmpty(rawReq.type, true)) { - this.transfer() - - if (this.User != null && this.User.id != null && this.User.id > 0) { - setTimeout(function () { - App.showTestCase(true, false) // 本地历史仍然要求登录 this.User == null || this.User.id == null) - }, 1000) - } - } - else { - setTimeout(function () { - isSingle = ! isSingle - - var hasTestArg = false // 避免 http://localhost:63342/APIAuto/index.html?_ijt=fh8di51h7qip2d1s3r3bqn73nt 这种无意义参数 - if (StringUtil.isEmpty(rawReq.type, true) == false) { - hasTestArg = true - App.type = StringUtil.toUpperCase(rawReq.type, true) - if (App.types != null && App.types.indexOf(App.type) < 0) { - App.types.push(App.type) - } - } - - if (StringUtil.isEmpty(rawReq.url, true) == false) { - hasTestArg = true - vUrl.value = StringUtil.trim(rawReq.url) - } - - if (StringUtil.isEmpty(rawReq.json, true) == false) { - hasTestArg = true - vInput.value = StringUtil.trim(rawReq.json) - } - - if (StringUtil.isEmpty(rawReq.header, true) == false) { - hasTestArg = true - vHeader.value = StringUtil.trim(rawReq.header, true) - App.isHeaderShow = true - } - - if (StringUtil.isEmpty(rawReq.random, true) == false) { - hasTestArg = true - vRandom.value = StringUtil.trim(rawReq.random, true) - App.isRandomShow = true - App.isRandomListShow = false - } - - var delayTime = 0 - - // URL 太长导致截断和乱码 - if (StringUtil.isEmpty(rawReq.setting, true) == false) { - var save = rawReq.save == 'true' - try { - var setting = JSON.parse(StringUtil.trim(rawReq.setting, true)) || {} - - if ((setting.count != null && setting.count != App.count) - || (setting.page != null && setting.page != App.page) - || (setting.search != null && setting.search != App.search)) { - delayTime += Math.min(5000, 30*(setting.count) + 1000) - App.setDoc(""); - App.getDoc(function (d) { - App.setDoc(d); - }) - } - - for (var k in setting) { - var v = k == null ? null : setting[k] - if (v == null) { - continue - } - App[k] = v // App.$data[k] = app[k] - - if (save) { - App.saveCache('', k, v) - } - } - - if (setting.isRandomShow && setting.isRandomListShow) { - delayTime += Math.min(5000, (App.isMLEnabled ? 60 : 20)*(setting.randomCount || App.randomCount) + 1000) - App.showRandomList(true, setting.isRandomSubListShow ? App.currentRandomItem : null, setting.isRandomSubListShow) - } - - if (setting.isTestCaseShow) { - delayTime += Math.min(5000, (App.isMLEnabled ? 30 : 10)*(setting.testCaseCount || App.testCaseCount) + 1000) - App.showTestCase(true, setting.isLocalShow) - } - } catch (e) { - log(e) - } - } - - if (hasTestArg) { - vUrlComment.value = "" - vComment.value = "" - vWarning.value = "" - } - - App.onChange(false) - - if (hasTestArg && rawReq.send != "false" && rawReq.send != "null") { - setTimeout(function () { - if (rawReq.send == 'random') { - App.onClickTestRandom() - } else if (App.isTestCaseShow) { - App.onClickTest() - } else { - App.send(false) - } - - var url = vUrl.value || '' - if (rawReq.jump == "true" || rawReq.jump == "null" - || (rawReq.jump != "false" && App.isTestCaseShow != true && rawReq.send != 'random' - && (url.endsWith("/get") || url.endsWith("/head")) - ) - ) { - setTimeout(function () { - window.open(vUrl.value + "/" + encodeURIComponent(JSON.stringify(encode(JSON.parse(vInput.value))))) - }, 2000) - } - }, Math.max(1000, delayTime)) - } - }, 2000) - - } - - - // 快捷键 CTRL + I 格式化 JSON - document.addEventListener('keydown', function(event) { - // alert(event.key) 小写字母 i 而不是 KeyI - // if (event.ctrlKey && event.keyCode === 73) { // KeyI 无效 event.key === 'KeyI' && event.target == vInput){ - if (event.ctrlKey || event.metaKey) { - var target = event.target; - var selectionStart = target.selectionStart; - var selectionEnd = target.selectionEnd; - - // 这里拿不到 clipboardData if (event.keyCode === 86) { - - if (event.keyCode === 73) { // Ctrl + 'I' 格式化 - try { - if (target == vInput) { - var json = JSON.stringify(JSON5.parse(vInput.value), null, ' '); - vInput.value = inputted = isSingle ? App.switchQuote(json) : json; - } - else { - var lines = StringUtil.split(target.value, '\n'); - var newStr = ''; - - for (var i = 0; i < lines.length; i ++) { - var l = StringUtil.trim(lines[i]) || ''; - if (l.startsWith('//')) { - continue; - } - - var ind = l.lastIndexOf(' //'); - l = ind < 0 ? l : StringUtil.trim(l.substring(0, ind)); - - if (target == vHeader || target == vRandom) { - ind = l.indexOf(':'); - if (ind >= 0) { - var left = target == vHeader ? StringUtil.trim(l.substring(0, ind)) : l.substring(0, ind); - l = left + ': ' + StringUtil.trim(l.substring(ind + 1)); - } - } - - if (l.length > 0) { - newStr += '\n' + l; - } - } - - target.value = StringUtil.trim(newStr); - } - } catch (e) { - log(e) - } - } - else if (event.keyCode === 191) { // Ctrl + '/' 注释与取消注释 - try { - var json = StringUtil.get(target.value); - var before = json.substring(0, selectionStart); - var after = json.substring(selectionEnd); - - var ind = before.lastIndexOf('\n'); - var start = ind < 0 ? 0 : ind + 1; - ind = after.indexOf('\n'); - var end = ind < 0 ? json.length : selectionEnd + ind - 1; - - var selection = json.substring(start, end); - var lines = StringUtil.split(selection, '\n'); - - var newStr = json.substring(0, start); - - for (var i = 0; i < lines.length; i ++) { - var l = lines[i] || ''; - if (i > 0) { - newStr += '\n'; - } - - if (StringUtil.trim(l).startsWith('//')) { - var ind = l.indexOf('//'); - var suffix = l.substring(ind + 2); - if (suffix.startsWith(' ')) { - suffix = suffix.substring(2); - selectionEnd -= 2; - } - - newStr += StringUtil.get(l.substring(0, ind)) + StringUtil.get(suffix) - selectionEnd -= 2; - } - else { - newStr += '// ' + l; - selectionEnd += 4; - } - } - - newStr += json.substring(end); - - target.value = newStr; - if (target == vInput) { - inputted = newStr; - } - } catch (e) { - log(e) - } - } - - target.selectionStart = selectionStart; - target.selectionEnd = selectionEnd; - } - }) - - } - }) -})() - -// APIJSON >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> - + +(function () { + Vue.component('vue-item', { + props: ['jsondata', 'theme'], + template: '#item-template' + }) + + Vue.component('vue-outer', { + props: ['jsondata', 'isend', 'path', 'theme'], + template: '#outer-template' + }) + + Vue.component('vue-expand', { + props: [], + template: '#expand-template' + }) + + Vue.component('vue-val', { + props: ['field', 'val', 'isend', 'path', 'theme'], + template: '#val-template' + }) + + Vue.use({ + install: function (Vue, options) { + + // 判断数据类型 + Vue.prototype.getTyp = function (val) { + return toString.call(val).split(']')[0].split(' ')[1] + } + + // 判断是否是对象或者数组,以对下级进行渲染 + Vue.prototype.isObjectArr = function (val) { + return ['Object', 'Array'].indexOf(this.getTyp(val)) > -1 + } + + // 折叠 + Vue.prototype.fold = function ($event) { + var target = Vue.prototype.expandTarget($event) + target.siblings('svg').show() + target.hide().parent().siblings('.expand-view').hide() + target.parent().siblings('.fold-view').show() + } + // 展开 + Vue.prototype.expand = function ($event) { + var target = Vue.prototype.expandTarget($event) + target.siblings('svg').show() + target.hide().parent().siblings('.expand-view').show() + target.parent().siblings('.fold-view').hide() + } + + //获取展开折叠的target + Vue.prototype.expandTarget = function ($event) { + switch($event.target.tagName.toLowerCase()) { + case 'use': + return $($event.target).parent() + case 'label': + return $($event.target).closest('.fold-view').siblings('.expand-wraper').find('.icon-square-plus').first() + default: + return $($event.target) + } + } + + // 格式化值 + Vue.prototype.formatVal = function (val) { + switch(Vue.prototype.getTyp(val)) { + case 'String': + return '"' + val + '"' + case 'Null': + return 'null' + default: + return val + } + } + + // 判断值是否是链接 + Vue.prototype.isaLink = function (val) { + return /^((https|http|ftp|rtsp|mms)?:\/\/)[^\s]+/.test(val) + } + + // 计算对象的长度 + Vue.prototype.objLength = function (obj) { + return Object.keys(obj).length + } + + /**渲染 JSON key:value 项 + * @author TommyLemon + * @param val + * @param key + * @return {boolean} + */ + Vue.prototype.onRenderJSONItem = function (val, key, path) { + if (isSingle || key == null) { + return true + } + if (key == '_$_this_$_') { + // return true + return false + } + + var method = App.getMethod(); + var isRestful = ! JSONObject.isAPIJSONPath(method); + + try { + if (val instanceof Array) { + if (val[0] instanceof Object && (val[0] instanceof Array == false)) { // && JSONObject.isArrayKey(key, null, isRestful)) { + // alert('onRenderJSONItem key = ' + key + '; val = ' + JSON.stringify(val)) + + var ckey = key.substring(0, key.lastIndexOf('[]')); + + var aliaIndex = ckey.indexOf(':'); + var objName = aliaIndex < 0 ? ckey : ckey.substring(0, aliaIndex); + + var firstIndex = objName.indexOf('-'); + var firstKey = firstIndex < 0 ? objName : objName.substring(0, firstIndex); + + for (var i = 0; i < val.length; i++) { + var cPath = (StringUtil.isEmpty(path, false) ? '' : path + '/') + key; + + if (JSONObject.isTableKey(firstKey, val, isRestful)) { + // var newVal = JSON.parse(JSON.stringify(val[i])) + + var newVal = {} + for (var k in val[i]) { + newVal[k] = val[i][k] //提升性能 + delete val[i][k] + } + + val[i]._$_this_$_ = JSON.stringify({ + path: cPath + '/' + i, + table: firstKey + }) + + for (var k in newVal) { + val[i][k] = newVal[k] + } + } + else { + this.onRenderJSONItem(val[i], '' + i, cPath); + } + + // this.$children[i]._$_this_$_ = key + // alert('this.$children[i]._$_this_$_ = ' + this.$children[i]._$_this_$_) + } + } + } + else if (val instanceof Object) { + var aliaIndex = key.indexOf(':'); + var objName = aliaIndex < 0 ? key : key.substring(0, aliaIndex); + + // var newVal = JSON.parse(JSON.stringify(val)) + + var newVal = {} + for (var k in val) { + newVal[k] = val[k] //提升性能 + delete val[k] + } + + val._$_this_$_ = JSON.stringify({ + path: (StringUtil.isEmpty(path, false) ? '' : path + '/') + key, + table: JSONObject.isTableKey(objName, val, isRestful) ? objName : null + }) + + for (var k in newVal) { + val[k] = newVal[k] + } + + // val = Object.assign({ _$_this_$_: objName }, val) //解决多显示一个逗号 , + + // this._$_this_$_ = key TODO 不影响 JSON 的方式,直接在组件读写属性 + // alert('this._$_this_$_ = ' + this._$_this_$_) + } + + + } catch (e) { + alert('onRenderJSONItem try { ... } catch (e) {\n' + e.message) + } + + return true + + } + + + /**显示 Response JSON 的注释 + * @author TommyLemon + * @param val + * @param key + * @param $event + */ + Vue.prototype.setResponseHint = function (val, key, $event) { + console.log('setResponseHint') + this.$refs.responseKey.setAttribute('data-hint', isSingle ? '' : this.getResponseHint(val, key, $event)); + } + /**获取 Response JSON 的注释 + * 方案一: + * 拿到父组件的 key,逐层向下传递 + * 问题:拿不到爷爷组件 "Comment[]": [ { "id": 1, "content": "content1" }, { "id": 2 }... ] + * + * 方案二: + * 改写 jsonon 的 refKey 为 key0/key1/.../refKey + * 问题:遍历,改 key;容易和特殊情况下返回的同样格式的字段冲突 + * + * 方案三: + * 改写 jsonon 的结构,val 里加 .path 或 $.path 之类的隐藏字段 + * 问题:遍历,改 key;容易和特殊情况下返回的同样格式的字段冲突 + * + * @author TommyLemon + * @param val + * @param key + * @param $event + */ + Vue.prototype.getResponseHint = function (val, key, $event) { + // alert('setResponseHint key = ' + key + '; val = ' + JSON.stringify(val)) + + var s = '' + + try { + var standardObj = null; + try { + var currentItem = App.isTestCaseShow ? App.remotes[App.currentDocIndex] : App.currentRemoteItem; + standardObj = JSON.parse(((currentItem || {}).TestRecord || {}).standard); + } catch (e3) { + log(e3) + } + + var path = null + var table = null + var column = null + + var method = App.isTestCaseShow ? ((App.currentRemoteItem || {}).Document || {}).url : App.getMethod(); + var isRestful = ! JSONObject.isAPIJSONPath(method); + + if (val instanceof Object && (val instanceof Array == false)) { + + var parent = $event.currentTarget.parentElement.parentElement + var valString = parent.textContent + + // alert('valString = ' + valString) + + var i = valString.indexOf('"_$_this_$_": "') + if (i >= 0) { + valString = valString.substring(i + '"_$_this_$_": "'.length) + i = valString.indexOf('}"') + if (i >= 0) { + valString = valString.substring(0, i + 1) + // alert('valString = ' + valString) + var _$_this_$_ = JSON.parse(valString) || {} + path = _$_this_$_.path + table = _$_this_$_.table + } + + + var aliaIndex = key == null ? -1 : key.indexOf(':'); + var objName = aliaIndex < 0 ? key : key.substring(0, aliaIndex); + + if (JSONObject.isTableKey(objName, val, isRestful)) { + table = objName + } + else if (JSONObject.isTableKey(table, val, isRestful)) { + column = key + } + + // alert('path = ' + path + '; table = ' + table + '; column = ' + column) + } + } + else { + var parent = $event.currentTarget.parentElement.parentElement + var valString = parent.textContent + + // alert('valString = ' + valString) + + var i = valString.indexOf('"_$_this_$_": "') + if (i >= 0) { + valString = valString.substring(i + '"_$_this_$_": "'.length) + i = valString.indexOf('}"') + if (i >= 0) { + valString = valString.substring(0, i + 1) + // alert('valString = ' + valString) + var _$_this_$_ = JSON.parse(valString) || {} + path = _$_this_$_.path + table = _$_this_$_.table + } + } + + if (val instanceof Array && JSONObject.isArrayKey(key, val, isRestful)) { + var key2 = key == null ? null : key.substring(0, key.lastIndexOf('[]')); + + var aliaIndex = key2 == null ? -1 : key2.indexOf(':'); + var objName = aliaIndex < 0 ? key2 : key2.substring(0, aliaIndex); + + var firstIndex = objName == null ? -1 : objName.indexOf('-'); + var firstKey = firstIndex < 0 ? objName : objName.substring(0, firstIndex); + + // alert('key = ' + key + '; firstKey = ' + firstKey + '; firstIndex = ' + firstIndex) + if (JSONObject.isTableKey(firstKey, null, isRestful)) { + table = firstKey + + var s0 = ''; + if (firstIndex > 0) { + objName = objName.substring(firstIndex + 1); + firstIndex = objName.indexOf('-'); + column = firstIndex < 0 ? objName : objName.substring(0, firstIndex) + + var pathUri = (StringUtil.isEmpty(path) ? '' : path + '/') + key; + + var c = CodeUtil.getCommentFromDoc(docObj == null ? null : docObj['[]'], table, column, method, App.database, App.language, true, false, pathUri.split('/'), isRestful, val, true, standardObj); // this.getResponseHint({}, table, $event + s0 = column + (StringUtil.isEmpty(c, true) ? '' : ': ' + c) + } + + var pathUri = (StringUtil.isEmpty(path) ? '' : path + '/') + (StringUtil.isEmpty(column) ? key : column); + + var c = CodeUtil.getCommentFromDoc(docObj == null ? null : docObj['[]'], table, isRestful ? key : null, method, App.database, App.language, true, false, pathUri.split('/'), isRestful, val, true, standardObj); + s = (StringUtil.isEmpty(path) ? '' : path + '/') + key + ' 中 ' + + ( + StringUtil.isEmpty(c, true) ? '' : table + ': ' + + c + ((StringUtil.isEmpty(s0, true) ? '' : ' - ' + s0) ) + ); + + return s; + } + //导致 key[] 的 hint 显示为 key[]key[] else { + // s = (StringUtil.isEmpty(path) ? '' : path + '/') + key + // } + } + else { + if (isRestful || JSONObject.isTableKey(table)) { + column = key + } + // alert('path = ' + path + '; table = ' + table + '; column = ' + column) + } + } + // alert('setResponseHint table = ' + table + '; column = ' + column) + + var pathUri = (StringUtil.isEmpty(path) ? '' : path + '/') + key; + var c = CodeUtil.getCommentFromDoc(docObj == null ? null : docObj['[]'], table, isRestful ? key : column, method, App.database, App.language, true, false, pathUri.split('/'), isRestful, val, true, standardObj); + + s += pathUri + (StringUtil.isEmpty(c, true) ? '' : ': ' + c) + } + catch (e) { + s += '\n' + e.message + } + + return s; + } + + } + }) + + + var DEBUG = false + + var initJson = {} + +// 主题 [key, String, Number, Boolean, Null, link-link, link-hover] + var themes = [ + ['#92278f', '#3ab54a', '#25aae2', '#f3934e', '#f34e5c', '#717171'], + ['rgb(19, 158, 170)', '#cf9f19', '#ec4040', '#7cc500', 'rgb(211, 118, 126)', 'rgb(15, 189, 170)'], + ['#886', '#25aae2', '#e60fc2', '#f43041', 'rgb(180, 83, 244)', 'rgb(148, 164, 13)'], + ['rgb(97, 97, 102)', '#cf4c74', '#20a0d5', '#cd1bc4', '#c1b8b9', 'rgb(25, 8, 174)'] + ] + + + + +// APIJSON <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + + + function getRequestFromURL(url_, tryParse) { + var url = url_ || window.location.search; + + var index = url == null ? -1 : url.indexOf("?") + if(index < 0) { //判断是否有参数 + return null; + } + + var theRequest = null; + var str = url.substring(index + 1); //从第一个字符开始 因为第0个是?号 获取所有除问号的所有符串 + var arr = str.split("&"); //截除“&”生成一个数组 + + var len = arr == null ? 0 : arr.length; + for(var i = 0; i < len; i++) { + var part = arr[i]; + var ind = part == null ? -1 : part.indexOf("="); + if (ind <= 0) { + continue + } + + if (theRequest == null) { + theRequest = {}; + } + + var v = decodeURIComponent(part.substring(ind+1)); + if (tryParse == true) { + try { + v = JSON.parse(v) + } + catch (e) { + } + } + + theRequest[part.substring(0, ind)] = v; + } + + return theRequest; + } + + + function markdownToHTML(md, isRequest) { + if (editormd == null) { + return; + } + + if (isRequest) { + vRequestMarkdown.innerHTML = ''; + } + else { + vMarkdown.innerHTML = ''; + } + editormd.markdownToHTML(isRequest ? 'vRequestMarkdown' : "vMarkdown", { + markdown : md ,//+ "\r\n" + $("#append-test").text(), + //htmlDecode : true, // 开启 HTML 标签解析,为了安全性,默认不开启 + htmlDecode : "style,script,iframe", // you can filter tags decode + //toc : false, + tocm : true, // Using [TOCM] + //tocContainer : "#custom-toc-container", // 自定义 ToC 容器层 + //gfm : false, + tocDropdown : true, + // markdownSourceCode : true, // 是否保留 Markdown 源码,即是否删除保存源码的 Textarea 标签 + taskList : true, + tex : true, // 默认不解析 + flowChart : true, // 默认不解析 + sequenceDiagram : true, // 默认不解析 + }); + } + + + + var PLATFORM_POSTMAN = 'POSTMAN' + var PLATFORM_SWAGGER = 'SWAGGER' + var PLATFORM_YAPI = 'YAPI' + var PLATFORM_RAP = 'RAP' + + var REQUEST_TYPE_PARAM = 'PARAM' // GET ?a=1&b=c&key=value + var REQUEST_TYPE_FORM = 'FORM' // POST x-www-form-urlencoded + var REQUEST_TYPE_DATA = 'DATA' // POST form-data + var REQUEST_TYPE_JSON = 'JSON' // POST application/json + var REQUEST_TYPE_GRPC = 'GRPC' // POST application/json + + var CONTENT_TYPE_MAP = { + // 'PARAM': 'plain/text', + 'FORM': 'x-www-form-urlencoded', + 'DATA': 'form-data', + 'JSON': 'application/json', + 'GRPC': 'application/json', + } + var CONTENT_VALUE_TYPE_MAP = { + 'plain/text': 'JSON', + 'x-www-form-urlencoded': 'FORM', + 'form-data': 'DATA', + 'application/json': 'JSON' + } + + var IGNORE_HEADERS = ['status code', 'remote address', 'referrer policy', 'connection', 'content-length' + , 'content-type', 'date', 'keep-alive', 'proxy-connection', 'set-cookie', 'vary', 'accept', 'cache-control', 'dnt' + , 'host', 'origin', 'pragma', 'referer', 'user-agent'] + + var RANDOM_DB = 'RANDOM_DB' + var RANDOM_IN = 'RANDOM_IN' + var RANDOM_INT = 'RANDOM_INT' + var RANDOM_NUM = 'RANDOM_NUM' + var RANDOM_STR = 'RANDOM_STR' + + var ORDER_DB = 'ORDER_DB' + var ORDER_IN = 'ORDER_IN' + var ORDER_INT = 'ORDER_INT' + + var ORDER_MAP = {} + + function randomInt(min, max) { + return randomNum(min, max, 0); + } + function randomNum(min, max, precision) { + // 0 居然也会转成 Number.MIN_SAFE_INTEGER !!! + // start = start || Number.MIN_SAFE_INTEGER + // end = end || Number.MAX_SAFE_INTEGER + + if (min == null) { + min = Number.MIN_SAFE_INTEGER + } + if (max == null) { + max = Number.MAX_SAFE_INTEGER + } + if (precision == null) { + precision = 2 + } + + return + ((max - min)*Math.random() + min).toFixed(precision); + } + function randomStr(minLength, maxLength, availableChars) { + return 'Ab_Cd' + randomNum(); + } + function randomIn(...args) { + return args == null || args.length <= 0 ? null : args[randomInt(0, args.length - 1)]; + } + + function orderInt(desc, index, min, max) { + if (min == null) { + min = Number.MIN_SAFE_INTEGER + } + if (max == null) { + max = Number.MAX_SAFE_INTEGER + } + + if (desc) { + return max - index%(max - min + 1) + } + return min + index%(max - min + 1) + } + function orderIn(desc, index, ...args) { + // alert('orderIn index = ' + index + '; args = ' + JSON.stringify(args)); + index = index || 0; + return args == null || args.length <= index ? null : args[desc ? args.length - index : index]; + } + + function getOrderIndex(randomId, line, argCount) { + // alert('randomId = ' + randomId + '; line = ' + line + '; argCount = ' + argCount); + // alert('ORDER_MAP = ' + JSON.stringify(ORDER_MAP, null, ' ')); + + if (randomId == null) { + randomId = 0; + } + if (ORDER_MAP == null) { + ORDER_MAP = {}; + } + if (ORDER_MAP[randomId] == null) { + ORDER_MAP[randomId] = {}; + } + + var orderIndex = ORDER_MAP[randomId][line]; + // alert('orderIndex = ' + orderIndex) + + if (orderIndex == null || orderIndex < -1) { + orderIndex = -1; + } + + orderIndex ++ + orderIndex = argCount == null || argCount <= 0 ? orderIndex : orderIndex%argCount; + ORDER_MAP[randomId][line] = orderIndex; + + // alert('orderIndex = ' + orderIndex) + // alert('ORDER_MAP = ' + JSON.stringify(ORDER_MAP, null, ' ')); + return orderIndex; + } + //这些全局变量不能放在data中,否则会报undefined错误 + + var baseUrl + var inputted + var handler + var docObj + var doc + var output + + var isSingle = true + + var doneCount + +// APIJSON >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + + var App = new Vue({ + el: '#app', + data: { + baseview: 'formater', + view: 'output', + jsoncon: JSON.stringify(initJson), + jsonhtml: initJson, + compressStr: '', + error: {}, + requestVersion: 3, + requestCount: 1, + urlComment: '关联查询 Comment.userId = User.id', + historys: [], + history: {name: '请求0'}, + remotes: [], + locals: [], + testCases: [], + randoms: [], + randomSubs: [], + account: '13000082001', + password: '123456', + accounts: [ + { + 'isLoggedIn': false, + 'name': '测试账号1', + 'phone': '13000082001', + 'password': '123456' + }, + { + 'isLoggedIn': false, + 'name': '测试账号2', + 'phone': '13000082002', + 'password': '123456' + }, + { + 'isLoggedIn': false, + 'name': '测试账号3', + 'phone': '13000082003', + 'password': '123456' + } + ], + currentAccountIndex: 0, + currentDocIndex: -1, + currentRandomIndex: -1, + currentRandomSubIndex: -1, + tests: { '-1':{}, '0':{}, '1':{}, '2': {} }, + crossProcess: '交叉账号:已关闭', + testProcess: '机器学习:已关闭', + randomTestTitle: '参数注入 Random Test', + testRandomCount: 1, + testRandomProcess: '', + compareColor: '#0000', + isLoading: false, + isRandomTest: false, + isDelayShow: false, + isSaveShow: false, + isExportShow: false, + isExportCheckShow: false, + isExportRandom: false, + isTestCaseShow: false, + isHeaderShow: false, + isRandomShow: true, // 默认展示 + isRandomListShow: false, + isRandomSubListShow: false, + isRandomEditable: false, + isLoginShow: false, + isConfigShow: false, + isDeleteShow: false, + currentDocItem: {}, + currentRemoteItem: { + "Document": { + "id": 1560244940013 , + "userId": 82001 , + "testAccountId": 82001 , + "version": 3 , + "name": "测试查询" , + "type": "JSON" , + "url": "/get" , + "date": "2019-06-11 17:22:20.0", +// 导致清空文本后,在说明文档后面重叠显示这个绿色注释 "detail": ` +// 以上 JSON 文本支持 JSON5 格式。清空文本内容可查看规则。 +// 注释可省略。行注释前必须有两个空格;段注释必须在 JSON 下方。 +// +// ## 快捷键 +// Ctrl + I 或 Command + I 格式化 JSON +// +// #### 右上角设置项 > 预览请求输入框,显示对应的预览效果` + }, + "TestRecord": { + "id": 1615135440014 , + "userId": 82001 , + "documentId": 1560244940013 + } + }, + currentRandomItem: {}, + isAdminOperation: false, + loginType: 'login', + isExportRemote: false, + isRegister: false, + isCrossEnabled: false, + isMLEnabled: false, + isDelegateEnabled: false, + isPreviewEnabled: false, + isEncodeEnabled: true, + isEditResponse: false, + isLocalShow: false, + uploadTotal: 0, + uploadDoneCount: 0, + uploadFailCount: 0, + exTxt: { + name: 'APIJSON测试', + label: '发布简单接口', + button: '保存', + index: 0 + }, + themes: themes, + checkedTheme: 0, + isExpand: true, + User: { + id: 0, + name: '', + head: '' + }, + Privacy: { + id: 0, + balance: null //点击更新提示需要判空 0.00 + }, + type: REQUEST_TYPE_JSON, + types: [ REQUEST_TYPE_PARAM, REQUEST_TYPE_JSON], // 很多人喜欢用 GET 接口测试,默认的 JSON 看不懂 , REQUEST_TYPE_FORM, REQUEST_TYPE_DATA, REQUEST_TYPE_GRPC ], //默认展示 + host: '', + database: 'MYSQL', // 查文档必须,除非后端提供默认配置接口 // 用后端默认的,避免用户总是没有配置就问为什么没有生成文档和注释 'MYSQL',// 'POSTGRESQL', + schema: 'sys', // 查文档必须,除非后端提供默认配置接口 // 用后端默认的,避免用户总是没有配置就问为什么没有生成文档和注释 'sys', + server: 'http://apijson.cn:9090/', // Chrome 90+ 跨域问题非常难搞,开发模式启动都不行了 'http://apijson.org:9090/', //apijson.cn + // server: 'http://47.74.39.68:9090/', // apijson.org + thirdParty: 'SWAGGER /v2/api-docs', //apijson.cn + // thirdParty: 'RAP /repository/joined /repository/get', + // thirdParty: 'YAPI /api/interface/list_menu /api/interface/get', + language: CodeUtil.LANGUAGE_KOTLIN, + header: {}, + page: 0, + count: 100, + search: '', + testCasePage: 0, + testCaseCount: 50, + testCaseSearch: '', + randomPage: 0, + randomCount: 50, + randomSearch: '', + randomSubPage: 0, + randomSubCount: 50, + randomSubSearch: '' + }, + methods: { + + // 全部展开 + expandAll: function () { + if (this.view != 'code') { + alert('请先获取正确的JSON Response!') + return + } + + $('.icon-square-min').show() + $('.icon-square-plus').hide() + $('.expand-view').show() + $('.fold-view').hide() + + this.isExpand = true; + }, + + // 全部折叠 + collapseAll: function () { + if (this.view != 'code') { + alert('请先获取正确的JSON Response!') + return + } + + $('.icon-square-min').hide() + $('.icon-square-plus').show() + $('.expand-view').hide() + $('.fold-view').show() + + this.isExpand = false; + }, + + // diff + diffTwo: function () { + var oldJSON = {} + var newJSON = {} + this.view = 'code' + try { + oldJSON = jsonlint.parse(this.jsoncon) + } catch (ex) { + this.view = 'error' + this.error = { + msg: '原 JSON 解析错误\r\n' + ex.message + } + return + } + + try { + newJSON = jsonlint.parse(this.jsoncon) + } catch (ex) { + this.view = 'error' + this.error = { + msg: '新 JSON 解析错误\r\n' + ex.message + } + return + } + + var base = difflib.stringAsLines(JSON.stringify(oldJSON, '', 4)) + var newtxt = difflib.stringAsLines(JSON.stringify(newJSON, '', 4)) + var sm = new difflib.SequenceMatcher(base, newtxt) + var opcodes = sm.get_opcodes() + $('#diffoutput').empty().append(diffview.buildView({ + baseTextLines: base, + newTextLines: newtxt, + opcodes: opcodes, + baseTextName: '原 JSON', + newTextName: '新 JSON', + contextSize: 2, + viewType: 0 + })) + }, + + baseViewToDiff: function () { + this.baseview = 'diff' + this.diffTwo() + }, + + // 回到格式化视图 + baseViewToFormater: function () { + this.baseview = 'formater' + this.view = 'code' + this.showJsonView() + }, + + // 根据json内容变化格式化视图 + showJsonView: function () { + if (this.baseview === 'diff') { + return + } + try { + if (this.jsoncon.trim() === '') { + this.view = 'empty' + } else { + this.view = 'code' + + if (isSingle) { + this.jsonhtml = jsonlint.parse(this.jsoncon) + } + else { + this.jsonhtml = Object.assign({ + _$_this_$_: JSON.stringify({ + path: null, + table: null + }) + }, jsonlint.parse(this.jsoncon)) + } + + } + } catch (ex) { + this.view = 'error' + this.error = { + msg: ex.message + } + } + }, + + + showUrl: function (isAdminOperation, branchUrl) { + if (StringUtil.isEmpty(this.host, true)) { //显示(可编辑)URL Host + if (isAdminOperation != true) { + baseUrl = this.getBaseUrl() + } + vUrl.value = (isAdminOperation ? this.server : baseUrl) + branchUrl + } + else { //隐藏(固定)URL Host + if (isAdminOperation) { + this.host = this.server + } + vUrl.value = branchUrl + } + + vUrlComment.value = isSingle || StringUtil.isEmpty(this.urlComment, true) + ? '' : vUrl.value + CodeUtil.getComment(this.urlComment, false, ' ') + + ' - ' + (this.requestVersion > 0 ? 'V' + this.requestVersion : 'V*'); + }, + + //设置基地址 + setBaseUrl: function () { + if (StringUtil.isEmpty(this.host, true) != true) { + return + } + // 重新拉取文档 + var bu = this.getBaseUrl() + if (baseUrl != bu) { + baseUrl = bu; + doc = null //这个是本地的数据库字典及非开放请求文档 + this.saveCache('', 'URL_BASE', baseUrl) + + //已换成固定的管理系统URL + + // this.remotes = [] + + // var index = baseUrl.indexOf(':') //http://localhost:8080 + // this.server = (index < 0 ? baseUrl : baseUrl.substring(0, baseUrl)) + ':9090' + + } + }, + getUrl: function () { + var url = StringUtil.get(this.host) + new String(vUrl.value) + return url.replace(/ /g, '') + }, + //获取基地址 + getBaseUrl: function () { + var url = new String(vUrl.value).trim() + var length = this.getBaseUrlLength(url) + url = length <= 0 ? '' : url.substring(0, length) + return url == '' ? URL_BASE : url + }, + //获取基地址长度,以://后的第一个/分割baseUrl和method + getBaseUrlLength: function (url_) { + var url = StringUtil.trim(url_) + var index = url.indexOf(' ') + if (index >= 0) { + return index + 1 + } + + index = url.indexOf('://') + return index < 0 ? 0 : index + 3 + url.substring(index + 3).indexOf('/') + }, + //获取操作方法 + getMethod: function () { + var url = new String(vUrl.value).trim() + var index = this.getBaseUrlLength(url) + url = index <= 0 ? url : url.substring(index) + index = url.indexOf("?") + if (index >= 0) { + url = url.substring(0, index) + } + return url.startsWith('/') ? url.substring(1) : url + }, + //获取请求的tag + getTag: function () { + var req = null; + try { + req = this.getRequest(vInput.value); + } catch (e) { + log('main.getTag', 'try { req = this.getRequest(vInput.value); \n } catch (e) {\n' + e.message) + } + return req == null ? null : req.tag + }, + + getRequest: function (json, defaultValue, isRaw) { // JSON5 兜底,减少修改范围 , isSingle) { + var s = isRaw != true && isSingle ? this.switchQuote(json) : json; // this.toDoubleJSON(json, defaultValue); + if (StringUtil.isEmpty(s, true)) { + return defaultValue + } + try { + return jsonlint.parse(s); + } + catch (e) { + log('main.getRequest', 'try { return jsonlint.parse(s); \n } catch (e2) {\n' + e.message) + log('main.getRequest', 'return jsonlint.parse(this.removeComment(s));') + return JSON5.parse(s); // jsonlint.parse(this.removeComment(s)); + } + }, + getExtraComment: function(json) { + var it = json != null ? json : StringUtil.trim(vInput.value); + + var start = it.lastIndexOf('\n\/*'); + var end = it.lastIndexOf('\n*\/'); + + return start < 0 || end <= start ? null : it.substring(start + '\n\/*'.length, end); + }, + + getHeader: function (text) { + var header = {} + var hs = StringUtil.isEmpty(text, true) ? null : StringUtil.split(text, '\n') + + if (hs != null && hs.length > 0) { + var item + for (var i = 0; i < hs.length; i++) { + item = hs[i] || '' + + // 解决整体 trim 后第一行 // 被当成正常的 key 路径而不是注释 + var index = StringUtil.trim(item).startsWith('//') ? 0 : item.lastIndexOf(' //') // 不加空格会导致 http:// 被截断 ('//') //这里只支持单行注释,不用 removeComment 那种带多行的去注释方式 + var item2 = index < 0 ? item : item.substring(0, index) + item2 = item2.trim() + if (item2.length <= 0) { + continue; + } + + index = item2.indexOf(':') + if (index <= 0) { + throw new Error('请求头 Request Header 输入错误!请按照每行 key: value 的格式输入,不要有多余的换行或空格!' + + '\n错误位置: 第 ' + (i + 1) + ' 行' + + '\n错误文本: ' + item) + } + + var val = item2.substring(index + 1, item2.length) + + var ind = val.indexOf('(') //一定要有函数是为了避免里面是一个简短单词和 APIAuto 代码中变量冲突 + if (ind > 0 && val.indexOf(')') > ind) { //不从 0 开始是为了保证是函数,且不是 (1) 这种单纯限制作用域的括号 + try { + val = eval(val) + } + catch (e) { + this.log("getHeader if (hs != null && hs.length > 0) { ... if (ind > 0 && val.indexOf(')') > ind) { ... try { val = eval(val) } catch (e) = " + e.message) + } + } + + header[StringUtil.trim(item2.substring(0, index))] = val + } + } + + return header + }, + + // 分享 APIAuto 特有链接,打开即可还原分享人的 JSON 参数、设置项、搜索关键词、分页数量及页码等配置 + shareLink: function (isRandom) { + var jsonStr = null + if (this.isTestCaseShow != true) { + try { + jsonStr = JSON.stringify(encode(JSON.parse(vInput.value))) + } catch (e) { // 可能包含注释 + log(e) + jsonStr = encode(StringUtil.trim(vInput.value)) + } + } + + // URL 太长导致打不开标签 + var settingStr = null + try { + settingStr = JSON.stringify({ + requestVersion: this.requestVersion, + requestCount: this.requestCount, + isTestCaseShow: this.isTestCaseShow, + // isHeaderShow: this.isHeaderShow, + // isRandomShow: this.isRandomShow, + isRandomListShow: this.isRandomShow ? this.isRandomListShow : undefined, + isRandomSubListShow: this.isRandomListShow ? this.isRandomSubListShow : undefined, + // isRandomEditable: this.isRandomEditable, + isCrossEnabled: this.isCrossEnabled, + isMLEnabled: this.isMLEnabled, + isDelegateEnabled: this.isDelegateEnabled, + isPreviewEnabled: this.isPreviewEnabled, + isEncodeEnabled: this.isEncodeEnabled, + isEditResponse: this.isEditResponse, + isLocalShow: this.isTestCaseShow ? this.isLocalShow : undefined, + page: this.page, + count: this.count, + testCasePage: this.testCasePage, + testCaseCount: this.testCaseCount, + testRandomCount: this.testRandomCount, + randomPage: this.randomPage, + randomCount: this.randomCount, + randomSubPage: this.randomSubPage, + randomSubCount: this.randomSubCount, + host: StringUtil.isEmpty(this.host, true) ? undefined : encodeURIComponent(this.host), + search: StringUtil.isEmpty(this.search, true) ? undefined : encodeURIComponent(this.search), + testCaseSearch: StringUtil.isEmpty(this.testCaseSearch, true) ? undefined : this.testCaseSearch, + randomSearch: StringUtil.isEmpty(this.randomSearch, true) ? undefined : encodeURIComponent(this.randomSearch), + randomSubSearch: StringUtil.isEmpty(this.randomSubSearch, true) ? undefined : encodeURIComponent(this.randomSubSearch) + }) + } catch (e){ + log(e) + } + + var headerStr = this.isTestCaseShow || StringUtil.isEmpty(vHeader.value, true) ? null : encodeURIComponent(StringUtil.trim(vHeader.value)) + var randomStr = this.isTestCaseShow || StringUtil.isEmpty(vRandom.value, true) ? null : encodeURIComponent(StringUtil.trim(vRandom.value)) + + var href = window.location.href || 'http://apijson.cn/api' + var ind = href == null ? -1 : href.indexOf('?') // url 后带参数只能 encodeURIComponent + + // 实测 561059 长度的 URL 都支持,只是输入框显示长度约为 2000 + window.open((ind < 0 ? href : href.substring(0, ind)) + + (this.view != 'code' ? "?send=false" : (isRandom ? "?send=random" : "?send=true")) + + "&type=" + StringUtil.trim(this.type) + + "&url=" + encodeURIComponent(StringUtil.trim(vUrl.value)) + + (StringUtil.isEmpty(jsonStr, true) ? '' : "&json=" + jsonStr) + + (StringUtil.isEmpty(headerStr, true) ? '' : "&header=" + headerStr) + + (StringUtil.isEmpty(randomStr, true) ? '' : "&random=" + randomStr) + + (StringUtil.isEmpty(settingStr, true) ? '' : "&setting=" + settingStr) + ) + }, + + // 显示保存弹窗 + showSave: function (show) { + if (show) { + if (this.isTestCaseShow) { + alert('请先输入请求内容!') + return + } + + var tag = this.getTag() + this.history.name = (this.urlComment || this.getMethod() + (StringUtil.isEmpty(tag, true) ? '' : ' ' + tag)) + ' ' + this.formatTime() //不自定义名称的都是临时的,不需要时间太详细 + } + this.isSaveShow = show + }, + + // 显示导出弹窗 + showExport: function (show, isRemote, isRandom) { + if (show) { + // this.isExportCheckShow = isRemote + + if (isRemote) { //共享测试用例 + this.isExportRandom = isRandom + + // if (isRandom != true) { // 分享搜索关键词和分页信息也挺好 } && this.isTestCaseShow != true) { // 没有拿到列表,没用 + // setTimeout(function () { + // App.shareLink(App.isRandomTest) + // }, 1000) + // } + + if (this.isTestCaseShow) { + alert('请先输入请求内容!') + return + } + + if (this.view == 'error') { // this.view != 'code') { + alert('发现错误,请输入正确的内容!') // alert('请先测试请求,确保是正确可用的!') + return + } + if (isRandom) { + this.exTxt.name = '随机配置 ' + this.formatDateTime() + } + else { + if (this.isEditResponse) { + this.isExportRemote = isRemote + this.exportTxt() + return + } + + // var tag = this.getTag() + this.exTxt.name = this.urlComment || '' // 避免偷懒不输入名称 this.getMethod() + (StringUtil.isEmpty(tag, true) ? '' : ' ' + tag) + } + } + else { //下载到本地 + if (this.isTestCaseShow) { //文档 + this.exTxt.name = 'APIJSON自动化文档 ' + this.formatDateTime() + } + else if (this.view == 'markdown' || this.view == 'output') { + var suffix + switch (this.language) { + case CodeUtil.LANGUAGE_KOTLIN: + suffix = '.kt'; + break; + case CodeUtil.LANGUAGE_JAVA: + suffix = '.java'; + break; + case CodeUtil.LANGUAGE_C_SHARP: + suffix = '.cs'; + break; + + case CodeUtil.LANGUAGE_SWIFT: + suffix = '.swift'; + break; + case CodeUtil.LANGUAGE_OBJECTIVE_C: + suffix = '.h'; + break; + + case CodeUtil.LANGUAGE_GO: + suffix = '.go'; + break; + case CodeUtil.LANGUAGE_C_PLUS_PLUS: + suffix = '.cpp'; + break; + + case CodeUtil.LANGUAGE_TYPE_SCRIPT: + suffix = '.ts'; + break; + case CodeUtil.LANGUAGE_JAVA_SCRIPT: + suffix = '.js'; + break; + + case CodeUtil.LANGUAGE_PHP: + suffix = '.php'; + break; + case CodeUtil.LANGUAGE_PYTHON: + suffix = '.py'; + break; + default: + suffix = '.java'; + break; + } + + this.exTxt.name = 'User' + suffix + alert('自动生成模型代码,可填类名后缀:\n' + + 'Kotlin.kt, Java.java, Swift.swift, Objective-C.m, C#.cs, Go.go,' + + '\nTypeScript.ts, JavaScript.js, PHP.php, Python.py, C++.cpp'); + } + else { + this.exTxt.name = 'APIJSON测试 ' + this.getMethod() + ' ' + this.formatDateTime() + } + } + } + + this.isExportShow = show + this.isExportRemote = isRemote + }, + + // 显示配置弹窗 + showConfig: function (show, index) { + this.isConfigShow = false + if (this.isTestCaseShow) { + if (index == 3 || index == 4 || index == 5 || index == 10) { + this.showTestCase(false, false) + } + } + + if (show) { + this.exTxt.button = index == 8 ? '上传' : '切换' + this.exTxt.index = index + switch (index) { + case 0: + case 1: + case 2: + case 6: + case 7: + case 8: + this.exTxt.name = index == 0 ? this.database : (index == 1 ? this.schema : (index == 2 + ? this.language : (index == 6 ? this.server : (index == 8 ? this.thirdParty : (this.types || []).join())))) + this.isConfigShow = true + + if (index == 0) { + alert('可填数据库:\nMYSQL,POSTGRESQL,SQLSERVER,ORACLE,DB2,SQLITE') + } + else if (index == 2) { + alert('自动生成代码,可填语言:\nKotlin,Java,Swift,Objective-C,C#,Go,\nTypeScript,JavaScript,PHP,Python,C++') + } + else if (index == 7) { + alert('多个类型用 , 隔开,可填类型:\nPARAM(GET ?a=1&b=c&key=value),\nJSON(POST application/json),\nFORM(POST x-www-form-urlencoded),\nDATA(POST form-data),\nGRPC(POST application/json 需要 GRPC 服务开启反射)') + } + else if (index == 8) { + this.isHeaderShow = true + + alert('例如:\nSWAGGER http://apijson.cn:8080/v2/api-docs\nSWAGGER /v2/api-docs // 省略 Host\nSWAGGER / // 省略 Host 和 分支 URL\nRAP /repository/joined /repository/get\nYAPI /api/interface/list_menu /api/interface/get') + + try { + this.getThirdPartyApiList(this.thirdParty, function (platform, docUrl, listUrl, itemUrl, url_, res, err) { + CodeUtil.thirdParty = platform + var data = err != null ? null : (res || {}).data; + var code = data == null ? null : data.errCode || data.errcode || data.err_code + + if (err != null || (code != null && code != 0)) { + App.isHeaderShow = true + App.isRandomShow = false + alert('请把 YApi/Rap/Swagger 等网站的有效 Cookie 粘贴到请求头 Request Header 输入框后再试!') + } + + App.onResponse(url_, res, err) + return false + }, function (platform, docUrl, listUrl, itemUrl, url_, res, err) { + var data = (res || {}).data + var apiMap = CodeUtil.thirdPartyApiMap || {} + + if (platform == PLATFORM_POSTMAN) { + alert('尚未开发 ' + PLATFORM_POSTMAN) + return true + } + else if (platform == PLATFORM_SWAGGER) { + var apis = data == null ? null : data.paths + if (apis != null) { + // var i = 0 + for (var url in apis) { + var item = apis[url] + apiMap[url] = item.post || item.get || item.put || item.delete + } + } + } + else if (platform == PLATFORM_RAP) { + } + else if (platform == PLATFORM_YAPI) { + var api = (data || {}).data + var url = api == null || api.path == null ? null : StringUtil.noBlank(api.path).replace(/\/\//g, '/') + if (StringUtil.isEmpty(url, true)) { + return + } + + var typeAndParam = App.parseYApiTypeAndParam(api) + + var name = StringUtil.trim(api.username) + ': ' + StringUtil.trim(api.title) + apiMap[url] = { + name: name, + request: typeAndParam.param, + response: api.res_body == null ? null : JSON.parse(api.res_body), + detail: name + + '\n' + (api.up_time == null ? '' : (typeof api.up_time != 'number' ? api.up_time : new Date(1000*api.up_time).toLocaleString())) + + '\nhttp://apijson.cn/yapi/project/1/interface/api/' + api._id + + '\n\n' + (StringUtil.isEmpty(api.markdown, true) ? StringUtil.trim(api.description) : api.markdown.trim().replace(/\\_/g, '_')) + } + } + else { + alert('第三方平台只支持 Postman, Swagger, Rap, YApi !') + return true + } + + CodeUtil.thirdPartyApiMap = apiMap + App.saveCache(App.thirdParty, 'thirdPartyApiMap', apiMap); + + return true + }) + } catch (e) { + console.log('created try { ' + + '\nthis.User = this.getCache(this.server, User) || {}' + + '\n} catch (e) {\n' + e.message) + } + + } + break + case 3: + this.host = this.getBaseUrl() + this.showUrl(false, new String(vUrl.value).substring(this.host.length)) //没必要导致必须重新获取 Response,this.onChange(false) + break + case 4: + this.isHeaderShow = show + this.saveCache('', 'isHeaderShow', show) + break + case 5: + this.isRandomShow = show + this.saveCache('', 'isRandomShow', show) + break + case 9: + this.isDelegateEnabled = show + this.saveCache('', 'isDelegateEnabled', show) + break + case 10: + this.isPreviewEnabled = show + this.saveCache('', 'isPreviewEnabled', show) + + this.onChange(false) + break + case 12: + this.isEncodeEnabled = show + this.saveCache('', 'isEncodeEnabled', show) + break + case 11: + var did = ((this.currentRemoteItem || {}).Document || {}).id + if (did == null) { + alert('请先选择一个已上传的用例!') + return + } + + this.isEditResponse = show + // this.saveCache('', 'isEditResponse', show) + + vInput.value = ((this.view != 'code' || StringUtil.isEmpty(this.jsoncon, true) ? null : this.jsoncon) + || (this.currentRemoteItem.TestRecord || {}).response) || '' + + vHeader.value = (this.currentRemoteItem.TestRecord || {}).header || '' + + this.isTestCaseShow = false + this.onChange(false) + break + } + } + else if (index == 3) { + var host = StringUtil.get(this.host) + var branch = new String(vUrl.value) + this.host = '' + vUrl.value = host + branch //保证 showUrl 里拿到的 baseUrl = this.host (http://apijson.cn:8080/put /balance) + this.setBaseUrl() //保证自动化测试等拿到的 baseUrl 是最新的 + this.showUrl(false, branch) //没必要导致必须重新获取 Response,this.onChange(false) + } + else if (index == 4) { + this.isHeaderShow = show + this.saveCache('', 'isHeaderShow', show) + } + else if (index == 5) { + this.isRandomShow = show + this.saveCache('', 'isRandomShow', show) + } + else if (index == 9) { + this.isDelegateEnabled = show + this.saveCache('', 'isDelegateEnabled', show) + } + else if (index == 10) { + this.isPreviewEnabled = show + this.saveCache('', 'isPreviewEnabled', show) + // vRequestMarkdown.innerHTML = '' + } + else if (index == 12) { + this.isEncodeEnabled = show + this.saveCache('', 'isEncodeEnabled', show) + } + else if (index == 11) { + this.isEditResponse = show + // this.saveCache('', 'isEditResponse', show) + + vInput.value = (this.currentRemoteItem.Document || {}).request || '' + vHeader.value = (this.currentRemoteItem.Document || {}).header || '' + + this.isTestCaseShow = false + this.onChange(false) + } + }, + + // 显示删除弹窗 + showDelete: function (show, item, index, isRandom) { + this.isDeleteShow = show + this.isDeleteRandom = isRandom + this.exTxt.name = '请输入' + (isRandom ? '随机配置' : '接口') + '名来确认' + if (isRandom) { + this.currentRandomItem = Object.assign(item, { + index: index + }) + } + else { + this.currentDocItem = Object.assign(item, { + index: index + }) + } + }, + + // 删除接口文档 + deleteDoc: function () { + var isDeleteRandom = this.isDeleteRandom + var item = (isDeleteRandom ? this.currentRandomItem : this.currentDocItem) || {} + var doc = (isDeleteRandom ? item.Random : item.Document) || {} + + var type = isDeleteRandom ? '随机配置' : '接口' + if (doc.id == null) { + alert('未选择' + type + '或' + type + '不存在!') + return + } + if (doc.name != this.exTxt.name) { + alert('输入的' + type + '名和要删除的' + type + '名不匹配!') + return + } + + this.showDelete(false, {}) + + this.isTestCaseShow = false + this.isRandomListShow = false + + var url = this.server + '/delete' + var req = isDeleteRandom ? { + format: false, + 'Random': { + 'id': doc.id + }, + 'tag': 'Random' + } : { + format: false, + 'Document': { + 'id': doc.id + }, + 'tag': 'Document' + } + this.request(true, REQUEST_TYPE_JSON, url, req, {}, function (url, res, err) { + App.onResponse(url, res, err) + + var rpObj = res.data || {} + + if (isDeleteRandom) { + if (rpObj.Random != null && rpObj.Random.code == CODE_SUCCESS) { + if (((item.Random || {}).toId || 0) <= 0) { + App.randoms.splice(item.index, 1) + } + else { + App.randomSubs.splice(item.index, 1) + } + // App.showRandomList(true, App.currentRemoteItem) + } + } else { + if (rpObj.Document != null && rpObj.Document.code == CODE_SUCCESS) { + App.remotes.splice(item.index, 1) + App.showTestCase(true, App.isLocalShow) + } + } + }) + }, + + // 保存当前的JSON + save: function () { + if (this.history.name.trim() === '') { + Helper.alert('名称不能为空!', 'danger') + return + } + var val = { + name: this.history.name, + type: this.type, + url: '/' + this.getMethod(), + request: inputted, + response: this.jsoncon, + header: vHeader.value, + random: vRandom.value + } + var key = String(Date.now()) + localforage.setItem(key, val, function (err, value) { + Helper.alert('保存成功!', 'success') + App.showSave(false) + val.key = key + App.historys.push(val) + }) + }, + + // 清空本地历史 + clearLocal: function () { + this.locals.splice(0, this.locals.length) //UI无反应 this.locals = [] + this.saveCache('', 'locals', []) + }, + + // 删除已保存的 + remove: function (item, index, isRemote, isRandom) { + if (isRemote == null || isRemote == false) { //null != false + localforage.removeItem(item.key, function () { + App.historys.splice(index, 1) + }) + } else { + if (this.isLocalShow) { + this.locals.splice(index, 1) + this.saveCache('', 'locals', this.locals) + return + } + + if (isRandom && (((item || {}).Random || {}).id || 0) <= 0) { + this.randomSubs.splice(index, 1) + return + } + + this.showDelete(true, item, index, isRandom) + } + }, + + // 根据参数注入用例恢复数据 + restoreRandom: function (index, item) { + this.currentRandomItem = item + this.isRandomListShow = false + this.isRandomSubListShow = false + var random = (item || {}).Random || {} + this.randomTestTitle = random.name + this.testRandomCount = random.count + vRandom.value = StringUtil.get(random.config) + + var response = ((item || {}).TestRecord || {}).response + if (StringUtil.isEmpty(response, true) == false) { + this.jsoncon = StringUtil.trim(response) + this.view = 'code' + } + }, + // 根据测试用例/历史记录恢复数据 + restoreRemoteAndTest: function (index, item) { + this.restoreRemote(index, item, true) + }, + // 根据测试用例/历史记录恢复数据 + restoreRemote: function (index, item, test) { + this.currentDocIndex = index + this.currentRemoteItem = item + this.restore((item || {}).Document, ((item || {}).TestRecord || {}).response, true, test) + }, + // 根据历史恢复数据 + restore: function (item, response, isRemote, test) { + this.isEditResponse = false + + item = item || {} + // localforage.getItem(item.key || '', function (err, value) { + var branch = new String(item.url || '/get') + if (branch.startsWith('/') == false) { + branch = '/' + branch + } + + this.type = item.type; + this.urlComment = item.name; + this.requestVersion = item.version; + this.showUrl(false, branch) + + this.showTestCase(false, this.isLocalShow) + vInput.value = StringUtil.get(item.request) + vHeader.value = StringUtil.get(item.header) + vRandom.value = StringUtil.get(item.random) + this.onChange(false) + + if (isRemote) { + this.randoms = [] + this.showRandomList(this.isRandomListShow, item) + } + + if (test) { + this.send(false) + } + else { + if (StringUtil.isEmpty(response, true) == false) { + setTimeout(function () { + App.jsoncon = StringUtil.trim(response) + App.view = 'code' + }, 500) + } + } + + // }) + }, + + // 获取所有保存的json + listHistory: function () { + localforage.iterate(function (value, key, iterationNumber) { + if (key[0] !== '#') { + value.key = key + App.historys.push(value) + } + if (key === '#theme') { + // 设置默认主题 + App.checkedTheme = value + } + }) + }, + + // 导出文本 + exportTxt: function (btnIndex) { + if (btnIndex == null) { + btnIndex = 0 + } + + if (btnIndex == 1 && this.isExportRandom != true) { + this.shareLink(this.isRandomTest) + return + } + + this.isExportShow = false + + if (this.isExportRemote == false) { //下载到本地 + + if (this.isTestCaseShow) { //文档 + saveTextAs('# ' + this.exTxt.name + '\n主页: https://github.com/Tencent/APIJSON' + + '\n\nBASE_URL: ' + this.getBaseUrl() + + '\n\n\n## 测试用例(Markdown格式,可用工具预览) \n\n' + this.getDoc4TestCase() + + '\n\n\n\n\n\n\n\n## 文档(Markdown格式,可用工具预览) \n\n' + doc + , this.exTxt.name + '.txt') + } + else if (this.view == 'markdown' || this.view == 'output') { //model + var clazz = StringUtil.trim(this.exTxt.name) + + var txt = '' //配合下面 +=,实现注释判断,一次全生成,方便测试 + if (clazz.endsWith('.java')) { + txt += CodeUtil.parseJavaBean(docObj, clazz.substring(0, clazz.length - 5), this.database) + } + else if (clazz.endsWith('.swift')) { + txt += CodeUtil.parseSwiftStruct(docObj, clazz.substring(0, clazz.length - 6), this.database) + } + else if (clazz.endsWith('.kt')) { + txt += CodeUtil.parseKotlinDataClass(docObj, clazz.substring(0, clazz.length - 3), this.database) + } + else if (clazz.endsWith('.m')) { + txt += CodeUtil.parseObjectiveCEntity(docObj, clazz.substring(0, clazz.length - 2), this.database) + } + else if (clazz.endsWith('.cs')) { + txt += CodeUtil.parseCSharpEntity(docObj, clazz.substring(0, clazz.length - 3), this.database) + } + else if (clazz.endsWith('.php')) { + txt += CodeUtil.parsePHPEntity(docObj, clazz.substring(0, clazz.length - 4), this.database) + } + else if (clazz.endsWith('.go')) { + txt += CodeUtil.parseGoEntity(docObj, clazz.substring(0, clazz.length - 3), this.database) + } + else if (clazz.endsWith('.cpp')) { + txt += CodeUtil.parseCppStruct(docObj, clazz.substring(0, clazz.length - 4), this.database) + } + else if (clazz.endsWith('.js')) { + txt += CodeUtil.parseJavaScriptEntity(docObj, clazz.substring(0, clazz.length - 3), this.database) + } + else if (clazz.endsWith('.ts')) { + txt += CodeUtil.parseTypeScriptEntity(docObj, clazz.substring(0, clazz.length - 3), this.database) + } + else if (clazz.endsWith('.py')) { + txt += CodeUtil.parsePythonEntity(docObj, clazz.substring(0, clazz.length - 3), this.database) + } + else { + alert('请正确输入对应语言的类名后缀!') + } + + if (StringUtil.isEmpty(txt, true)) { + alert('找不到 ' + clazz + ' 对应的表!请检查数据库中是否存在!\n如果不存在,请重新输入存在的表;\n如果存在,请刷新网页后重试。') + return + } + saveTextAs(txt, clazz) + } + else { + var res = JSON.parse(this.jsoncon) + res = this.removeDebugInfo(res) + + var s = '' + switch (this.language) { + case CodeUtil.LANGUAGE_KOTLIN: + s += '(Kotlin):\n\n' + CodeUtil.parseKotlinResponse('', res, 0, false, ! isSingle) + break; + case CodeUtil.LANGUAGE_JAVA: + s += '(Java):\n\n' + CodeUtil.parseJavaResponse('', res, 0, false, ! isSingle) + break; + case CodeUtil.LANGUAGE_C_SHARP: + s += '(C#):\n\n' + CodeUtil.parseCSharpResponse('', res, 0) + break; + + case CodeUtil.LANGUAGE_SWIFT: + s += '(Swift):\n\n' + CodeUtil.parseSwiftResponse('', res, 0, isSingle) + break; + case CodeUtil.LANGUAGE_OBJECTIVE_C: + s += '(Objective-C):\n\n' + CodeUtil.parseObjectiveCResponse('', res, 0) + break; + + case CodeUtil.LANGUAGE_GO: + s += '(Go):\n\n' + CodeUtil.parseGoResponse('', res, 0) + break; + case CodeUtil.LANGUAGE_C_PLUS_PLUS: + s += '(C++):\n\n' + CodeUtil.parseCppResponse('', res, 0, isSingle) + break; + + case CodeUtil.LANGUAGE_TYPE_SCRIPT: + s += '(TypeScript):\n\n' + CodeUtil.parseTypeScriptResponse('', res, 0, isSingle) + break; + case CodeUtil.LANGUAGE_JAVA_SCRIPT: + s += '(JavaScript):\n\n' + CodeUtil.parseJavaScriptResponse('', res, 0, isSingle) + break; + + case CodeUtil.LANGUAGE_PHP: + s += '(PHP):\n\n' + CodeUtil.parsePHPResponse('', res, 0, isSingle) + break; + case CodeUtil.LANGUAGE_PYTHON: + s += '(Python):\n\n' + CodeUtil.parsePythonResponse('', res, 0, isSingle) + break; + default: + s += ':\n没有生成代码,可能生成代码(封装,解析)的语言配置错误。 \n'; + break; + } + + saveTextAs('# ' + this.exTxt.name + '\n主页: https://github.com/Tencent/APIJSON' + + '\n\n\nURL: ' + StringUtil.get(vUrl.value) + + '\n\n\nHeader:\n' + StringUtil.get(vHeader.value) + + '\n\n\nRequest:\n' + StringUtil.get(vInput.value) + + '\n\n\nResponse:\n' + StringUtil.get(this.jsoncon) + + '\n\n\n## 解析 Response 的代码' + s + , this.exTxt.name + '.txt') + } + } + else { //上传到远程服务器 + var id = this.User == null ? null : this.User.id + if (id == null || id <= 0) { + alert('请先登录!') + return + } + + const isExportRandom = this.isExportRandom + const isEditResponse = this.isEditResponse + const isReleaseRESTful = isExportRandom && btnIndex == 1 && ! isEditResponse + + const method = App.getMethod(); + const methodInfo = isReleaseRESTful ? (CodeUtil.parseUri(method, true) || {}) : {}; + if (isReleaseRESTful) { + var isRestful = methodInfo.isRestful; + var tag = methodInfo.tag; + var table = methodInfo.table; + + if (isRestful) { + alert('请求 URL 格式不是 APIJSON 万能通用接口!必须为 /get/user 这种 /{method}/{tag} 格式!其中 method 只能为 [' + APIJSON_METHODS.join() + '] 中的一个,tag 不能为 Table, Table[] 这种与 APIJSON 简单接口冲突的格式! ') + return + } + if (StringUtil.isEmpty(tag, true)) { + alert('请求 URL 缺少 tag!必须为 /get/user 这种 /{method}/{tag} 格式!其中 method 只能为 [' + APIJSON_METHODS.join() + '] 中的一个,tag 不能为 Table, Table[] 这种与 APIJSON 简单接口冲突的格式! ') + return + } + if (JSONObject.isTableKey(table)) { + alert('请求 URL 中的字符 ' + table + ' 与 APIJSON 简单接口冲突!必须为 /get/user 这种 /{method}/{tag} 格式!其中 method 只能为 [' + APIJSON_METHODS.join() + '] 中的一个,tag 不能为 Table, Table[] 这种与 APIJSON 简单接口冲突的格式! ') + return + } + } + + if ((isExportRandom != true || btnIndex == 1) && StringUtil.isEmpty(this.exTxt.name, true)) { + alert('请输入接口名!') + return + } + + const doc = (this.currentRemoteItem || {}).Document || {} + const tr = (this.currentRemoteItem || {}).TestRecord || {} + const did = isExportRandom && btnIndex == 1 ? null : doc.id + if (isExportRandom && btnIndex <= 0 && did == null) { + alert('请先共享测试用例!') + return + } + + this.isTestCaseShow = false + + const currentAccountId = this.getCurrentAccountId() + const currentResponse = this.view != 'code' || StringUtil.isEmpty(this.jsoncon, true) ? {} : this.removeDebugInfo(JSON.parse(this.jsoncon)); + + const after = isSingle ? this.switchQuote(inputted) : inputted; // this.toDoubleJSON(inputted); + const inputObj = this.getRequest(after, {}); + + var commentObj = null; + if (isExportRandom != true) { + var m = this.getMethod(); + var commentStddObj = null + try { + commentStddObj = JSON.parse(isEditResponse ? tr.standard : doc.standard); + } + catch(e) { + log(e) + } + var code_ = inputObj.code + inputObj.code = null // delete inputObj.code + + commentObj = JSONResponse.updateStandard(commentStddObj, inputObj); + CodeUtil.parseComment(after, docObj == null ? null : docObj['[]'], m, this.database, this.language, isEditResponse != true, commentObj, true); + + inputObj.code = code_ + } + + const code = currentResponse.code; + const thrw = currentResponse.throw; + delete currentResponse.code; //code必须一致 + delete currentResponse.throw; //throw必须一致 + + const isML = this.isMLEnabled; + const stddObj = isML ? JSONResponse.updateStandard({}, currentResponse) : {}; + stddObj.code = code; + stddObj.throw = thrw; + currentResponse.code = code; + currentResponse.throw = thrw; + + var config = vRandom.value; + const mapReq = {}; + const mustKeys = []; + const typeObj = {}; + const refuseKeys = []; + + if (isReleaseRESTful) { + var mapReq2 = {} + + var cfgLines = StringUtil.split(config, '\n', true); + var newCfg = ''; + if (cfgLines != null) { + for (var i = 0; i < cfgLines.length; i++) { + var cfgLine = cfgLines[i]; + var ind = cfgLine == null ? -1 : cfgLine.indexOf(': '); + if (ind <= 0) { + continue; + } + + var cInd = cfgLine.indexOf('//'); + if (cInd >= 0 && cInd <= ind) { + continue; + } + + var k = cfgLine.substring(0, ind).replace(/\//g, '.'); // .trim(); + var ks = StringUtil.split(k, '.') + var p = inputObj; + for (var j = 0; j < ks.length - 1; j ++) { + if (p == null) { + break; + } + + var jk = ks[j]; + p = jk == null ? null : p[jk]; + } + + var v = p == null ? null : p[ks[ks.length - 1]]; + mapReq[k] = v; + mapReq2[k] = v; + + // 智能判断 count, @key 等 + if (k.startsWith('@') || k.endsWith('[].count') || k.endsWith('[].query') || ['format', 'version'].indexOf(k) >= 0) { + refuseKeys.push('!' + k); + } + else { + mustKeys.push(k); + } + + var t = JSONResponse.getType(v); + typeObj[k] = t == 'integer' ? 'NUMBER' : (t == 'number' ? 'DECIMAL' : t.toUpperCase()); + + newCfg += (i <= 0 ? '' : '\n') + k + ': ' + cfgLine.substring(ind+2).trim(); + } + + refuseKeys.push('!'); + config = newCfg; + } + + commentObj = JSONResponse.updateStandard({}, mapReq2); + } + + + var callback = function (randomName, constConfig, constJson) { + // 用现成的测试过的更好,Response 与 Request 严格对应 + // var mapReq = {}; + // if (isExportRandom && btnIndex == 1) { + // + // var mapReq2 = {} + // var cfgLines = StringUtil.split(constConfig, '\n', true); + // if (cfgLines != null) { + // for (var i = 0; i < cfgLines.length; i++) { + // var cfgLine = cfgLines[i]; + // var ind = cfgLine == null ? -1 : cfgLine.indexOf(': '); + // if (ind <= 0) { + // continue; + // } + // + // var k = cfgLine.substring(0, ind).replace(/\//g, '.'); // .trim(); + // var v = cfgLine.substring(ind + 1).trim(); + // try { + // v = JSON.parse(v); + // } + // catch (e) { + // log(e) + // } + // + // mapReq[k] = v + // mapReq2[k] = v + // } + // } + // + // commentObj = JSONResponse.updateStandard({}, mapReq2); + // } + + const extName = App.exTxt.name; + const baseUrl = App.getBaseUrl(); + const url = (isReleaseRESTful ? baseUrl : App.server) + (isExportRandom || isEditResponse || did == null ? '/post' : '/put') + const req = isExportRandom && btnIndex <= 0 ? { + format: false, + 'Random': { + toId: 0, + documentId: did, + count: App.requestCount, + name: App.exTxt.name, + config: config + }, + 'TestRecord': { + 'response': JSON.stringify(currentResponse), + 'standard': isML ? JSON.stringify(stddObj) : null + }, + 'tag': 'Random' + } : { + format: false, + 'Document': isEditResponse ? null : { + 'id': did == null ? undefined : did, + 'testAccountId': currentAccountId, + 'name': extName, + 'type': App.type, + 'url': '/' + method, // 'url': isReleaseRESTful ? ('/' + methodInfo.method + '/' + methodInfo.tag) : ('/' + method), + 'request': JSON.stringify(btnIndex <= 0 ? constJson : mapReq, null, ' '), + 'apijson': btnIndex <= 0 ? undefined : JSON.stringify(constJson, null, ' '), + 'standard': commentObj == null ? null : JSON.stringify(commentObj, null, ' '), + 'header': vHeader.value, + 'detail': App.getExtraComment() || ((App.currentRemoteItem || {}).Document || {}).detail, + }, + 'TestRecord': isEditResponse != true && did != null ? null : { + 'documentId': isEditResponse ? did : undefined, + 'randomId': 0, + 'host': baseUrl, + 'testAccountId': currentAccountId, + 'response': JSON.stringify(isEditResponse ? inputObj : currentResponse), + 'standard': isML || isEditResponse ? JSON.stringify(isEditResponse ? commentObj : stddObj) : undefined, + // 没必要,直接都在请求中说明,查看也方便 'detail': (isEditResponse ? App.getExtraComment() : null) || ((App.currentRemoteItem || {}).TestRecord || {}).detail, + }, + 'tag': isEditResponse ? 'TestRecord' : 'Document' + } + + App.request(true, REQUEST_TYPE_JSON, url, req, {}, function (url, res, err) { + App.onResponse(url, res, err) + + var rpObj = res.data || {} + + if (isExportRandom && btnIndex <= 0) { + if (rpObj.code == CODE_SUCCESS) { + App.randoms = [] + App.showRandomList(true, (App.currentRemoteItem || {}).Document) + } + } + else { + var isPut = url.indexOf('/put') >= 0 + + if (rpObj.code != CODE_SUCCESS) { + if (isPut) { // 修改失败就转为新增 + App.currentRemoteItem = null; + alert('修改失败,请重试(自动转为新增)!' + StringUtil.trim(rpObj.msg)) + } + } + else { + App.remotes = [] + App.showTestCase(true, false) + + if (isPut) { // 修改失败就转为新增 + alert('修改成功') + return + } + + if (isReleaseRESTful) { + var structure = {"MUST": mustKeys.join(), "TYPE": typeObj, "REFUSE": refuseKeys.join()}; + + var reqObj = { + format: false, + Request: { + method: StringUtil.toUpperCase(methodInfo.method), + tag: methodInfo.tag, + structure: JSON.stringify(structure, null, ' '), + detail: extName + }, + tag: 'Request' + }; + + App.request(true, REQUEST_TYPE_JSON, baseUrl + '/post', reqObj, {}, function (url, res, err) { + if (res.data != null && res.data.Request != null && res.data.Request.code == CODE_SUCCESS) { + alert('已自动生成并上传 Request 表校验规则配置:\n' + JSON.stringify(reqObj.Request, null, ' ')) + } + else { + var reqStr = JSON.stringify(reqObj, null, ' '); + console.log('已自动生成,但上传以下 Request 表校验规则配置失败,可能需要手动加表记录:\nPOST ' + baseUrl + '/post' + '\n' + reqStr) + alert('已自动生成,但上传以下 Request 表校验规则配置失败,可能需要手动加表记录,如未自动复制可在控制台复制:\n' + reqStr) + navigator.clipboard.writeText(reqStr); + } + App.onResponse(url, res, err) + }) + } + + //自动生成随机配置(遍历 JSON,对所有可变值生成配置,排除 @key, key@, key() 等固定值) + + const isGenerate = StringUtil.isEmpty(config, true); + if (isGenerate) { + var req = isReleaseRESTful ? mapReq : App.getRequest(vInput.value, {}) + config = StringUtil.trim(App.newRandomConfig(null, '', req)) + + if (StringUtil.isEmpty(config, true)) { + return; + } + } + + App.request(true, REQUEST_TYPE_JSON, (isReleaseRESTful ? baseUrl : App.server) + '/post', { + format: false, + 'Random': { + documentId: rpObj.Document.id, + count: App.requestCount, + name: '默认配置' + (isGenerate ? '(上传测试用例时自动生成)' : ''), + config: config + }, + TestRecord: { + host: baseUrl, + response: '' + }, + 'tag': 'Random' + }, {}, function (url, res, err) { + if (res.data != null && res.data.Random != null && res.data.Random.code == CODE_SUCCESS) { + alert('已' + (isGenerate ? '自动生成并' : '') + '上传随机配置:\n' + config) + App.isRandomListShow = true + } + else { + alert((isGenerate ? '已自动生成,但' : '') + '上传以下随机配置失败:\n' + config) + vRandom.value = config + } + App.onResponse(url, res, err) + }) + } + } + }) + }; + + if (btnIndex == 1) { + // this.parseRandom(inputObj, config, null, true, true, false, callback) + callback(null, null, inputObj) + } + else { + callback(null, null, inputObj) + } + + } + }, + + newRandomConfig: function (path, key, value) { + if (key == null) { + return '' + } + if (path == '' && (key == 'tag' || key == 'version' || key == 'format')) { + return '' + } + + var config = '' + var childPath = path == null || path == '' ? key : path + '/' + key + var prefix = '\n' + childPath + ': ' + + if (value instanceof Array) { + var val + if (value.length <= 0) { + val = '' + } + else { + if (value.length <= 1) { + val = ', ' + JSON.stringify(value) + } + else if (value.length <= 2) { + val = ', ' + JSON.stringify([value[0]]) + ', ' + JSON.stringify([value[1]]) + ', ' + JSON.stringify(value) + } + else { + val = ', ' + JSON.stringify([value[0]]) + ', ' + JSON.stringify([value[value.length - 1]]) + ', ' + JSON.stringify([value[Math.floor(value.length / 2)]]) + ', ' + JSON.stringify(value) + } + } + config += prefix + 'ORDER_IN(undefined, null, []' + val + ')' + } + else if (value instanceof Object) { + for(var k in value) { + var v = value[k] + + var isAPIJSONArray = v instanceof Object && v instanceof Array == false + && k.startsWith('@') == false && (k.endsWith('[]') || k.endsWith('@')) + if (isAPIJSONArray) { + if (k.endsWith('@')) { + delete v.from + delete v.range + } + + prefix = '\n' + (childPath == null || childPath == '' ? '' : childPath + '/') + k + '/' + if (v.hasOwnProperty('page')) { + config += prefix + 'page: ' + 'ORDER_INT(0, 10)' + delete v.page + } + if (v.hasOwnProperty('count')) { + config += prefix + 'count: ' + 'ORDER_IN(undefined, null, 0, 1, 5, 10, 20' + + ([0, 1, 5, 10, 20].indexOf(v.count) >= 0 ? ')' : ', ' + v.count + ')') + delete v.count + } + if (v.hasOwnProperty('query')) { + config += prefix + 'query: ' + 'ORDER_IN(undefined, null, 0, 1, 2)' + delete v.query + } + } + + config += this.newRandomConfig(childPath, k, v) + } + } + else { + //自定义关键词 + if (key.startsWith('@')) { + return config + } + + if (typeof value == 'boolean') { + config += prefix + 'ORDER_IN(undefined, null, false, true)' + } + else if (typeof value == 'number') { + var isId = key == 'id' || key.endsWith('Id') || key.endsWith('_id') || key.endsWith('_ID') + if (isId) { + config += prefix + 'ORDER_IN(undefined, null, ' + value + ')' + if (value >= 1000000000) { //PHP 等语言默认精确到秒 1000000000000) { + config += '\n // 可替代上面的 ' + prefix.substring(1) + 'RANDOM_INT(' + Math.round(0.9 * value) + ', ' + Math.round(1.1 * value) + ')' + } + else { + config += '\n // 可替代上面的 ' + prefix.substring(1) + 'RANDOM_INT(1, ' + (10 * value) + ')' + } + } + else { + var valStr = String(value) + var dotIndex = valStr.indexOf('.') + var hasDot = dotIndex >= 0 + var keep = dotIndex < 0 ? 2 : valStr.length - dotIndex - 1 + + if (value < 0) { + config += prefix + (hasDot ? 'RANDOM_NUM' : 'RANDOM_INT') + '(' + (100 * value) + (hasDot ? ', 0, ' + keep + ')' : ', 0)') + } + else if (value > 0 && value < 1) { // 0-1 比例 + config += prefix + 'RANDOM_NUM(0, 1, ' + keep + ')' + } + else if ((hasDot && value > 0 && value <= 100) || (hasDot != true && value > 5 && value <= 100)) { // 10% 百分比 + config += prefix + (hasDot ? 'RANDOM_NUM(0, 100, ' + keep + ')' : 'RANDOM_INT(0, 100)') + } + else { + config += prefix + (dotIndex < 0 && value <= 10 + ? 'ORDER_INT(0, 10)' + : ((hasDot ? 'RANDOM_NUM' : 'RANDOM_INT') + '(0, ' + 100 * value + (hasDot ? ', ' + keep + ')' : ')')) + ) + var hasDot = String(value).indexOf('.') >= 0 + + if (value < 0) { + config += '\n // 可替代上面的 ' + prefix.substring(1) + (hasDot ? 'RANDOM_NUM' : 'RANDOM_INT') + '(' + (100 * value) + ', 0)' + } + else if (value > 0 && value < 1) { // 0-1 比例 + config += '\n // 可替代上面的 ' + prefix.substring(1) + 'RANDOM_NUM(0, 1)' + } + else if (value >= 0 && value <= 100) { // 10% 百分比 + config += '\n // 可替代上面的 ' + prefix.substring(1) + 'RANDOM_INT(0, 100)' + } + else { + config += '\n // 可替代上面的 ' + prefix.substring(1) + (hasDot != true && value < 10 ? 'ORDER_INT(0, 9)' : ((hasDot ? 'RANDOM_NUM' : 'RANDOM_INT') + '(0, ' + 100 * value + ')')) + } + } + } + } + else if (typeof value == 'string') { + //引用赋值 || 远程函数 || 匹配条件范围 + if (key.endsWith('@') || key.endsWith('()') || key.endsWith('{}')) { + return config + } + + config += prefix + 'ORDER_IN(undefined, null, ""' + (value == '' ? ')' : ', "' + value + '")') + } + else { + config += prefix + 'ORDER_IN(undefined, null' + (value == null ? ')' : ', ' + JSON.stringify(value) + ')') + } + + } + + return config + }, + + + + // 保存配置 + saveConfig: function () { + this.isConfigShow = this.exTxt.index == 8 + + switch (this.exTxt.index) { + case 0: + this.database = CodeUtil.database = this.exTxt.name + this.saveCache('', 'database', this.database) + + doc = null + var item = this.accounts[this.currentAccountIndex] + item.isLoggedIn = false + this.onClickAccount(this.currentAccountIndex, item) + break + case 1: + this.schema = CodeUtil.schema = this.exTxt.name + this.saveCache('', 'schema', this.schema) + + doc = null + var item = this.accounts[this.currentAccountIndex] + item.isLoggedIn = false + this.onClickAccount(this.currentAccountIndex, item) + break + case 2: + this.language = CodeUtil.language = this.exTxt.name + this.saveCache('', 'language', this.language) + + doc = null + this.onChange(false) + break + case 6: + this.server = this.exTxt.name + this.saveCache('', 'server', this.server) + this.logout(true) + break + case 7: + this.types = StringUtil.split(this.exTxt.name) + this.saveCache('', 'types', this.types) + break + case 8: + this.getThirdPartyApiList(this.exTxt.name, function (platform, docUrl, listUrl, itemUrl, url_, res, err) { + var jsonData = (res || {}).data + var isJSONData = jsonData instanceof Object + if (isJSONData == false) { //后面是 URL 才存储;是 JSON 数据则不存储 + App.thirdParty = thirdParty + App.saveCache('', 'thirdParty', App.thirdParty) + } + + const header = App.getHeader(vHeader.value) + + if (platform == PLATFORM_POSTMAN) { + alert('尚未开发 ' + PLATFORM_POSTMAN) + } + else if (platform == PLATFORM_SWAGGER) { + var swaggerCallback = function (url_, res, err) { + if (App.isSyncing) { + alert('正在同步,请等待完成') + return + } + App.isSyncing = true + App.onResponse(url_, res, err) + + var apis = (res.data || {}).paths + if (apis == null) { // || apis.length <= 0) { + App.isSyncing = false + alert('没有查到 Swagger 文档!请开启跨域代理,并检查 URL 是否正确!') + return + } + App.exTxt.button = '...' + + App.uploadTotal = 0 // apis.length || 0 + App.uploadDoneCount = 0 + App.uploadFailCount = 0 + + var item + // var i = 0 + for (var url in apis) { + item = apis[url] + //导致 url 全都是一样的 setTimeout(function () { + if (App.uploadSwaggerApi(url, item, 'get') + || App.uploadSwaggerApi(url, item, 'post') + || App.uploadSwaggerApi(url, item, 'put') + || App.uploadSwaggerApi(url, item, 'delete') + ) {} + // }, 100*i) + // i ++ + } + } + + if (isJSONData) { + swaggerCallback(docUrl, { data: jsonData }, null) + } + else { + App.request(false, REQUEST_TYPE_PARAM, docUrl, {}, header, swaggerCallback) + } + } + else if (platform == PLATFORM_RAP || platform == PLATFORM_YAPI) { + var isRap = platform == PLATFORM_RAP + + var itemCallback = function (url, res, err) { + try { + App.onResponse(url, res, err) + } catch (e) {} + + var data = res.data == null ? null : res.data.data + if (isRap) { + var modules = data == null ? null : data.modules + if (modules != null) { + for (var i = 0; i < modules.length; i++) { + var it = modules[i] || {} + var interfaces = it.interfaces || [] + + for (var j = 0; j < interfaces.length; j++) { + App.uploadRapApi(interfaces[j]) + } + } + } + } + else { + App.uploadYApi(data) + } + } + + if (isJSONData) { + itemCallback(itemUrl, { data: jsonData }, null) + } + else { + App.request(false, REQUEST_TYPE_PARAM, listUrl, {}, header, function (url_, res, err) { + if (App.isSyncing) { + alert('正在同步,请等待完成') + return + } + App.isSyncing = true + App.onResponse(url_, res, err) + + var apis = (res.data || {}).data + if (apis == null) { // || apis.length <= 0) { + App.isSyncing = false + alert('没有查到 ' + (isRap ? 'Rap' : 'YApi') + ' 文档!请开启跨域代理,并检查 URL 是否正确!') + return + } + App.exTxt.button = '...' + + App.uploadTotal = 0 // apis.length || 0 + App.uploadDoneCount = 0 + App.uploadFailCount = 0 + + var item + for (var url in apis) { + item = apis[url] || {} + + var list = (isRap ? [ { _id: item.id } ] : (item == null ? null : item.list)) || [] + for (let i1 = 0; i1 < list.length; i1++) { + var listItem1 = list[i1] + if (listItem1 == null || listItem1._id == null) { + App.log('listItem1 == null || listItem1._id == null >> continue') + continue + } + + App.request(false, REQUEST_TYPE_PARAM, itemUrl + '?id=' + listItem1._id, {}, header, itemCallback) + } + + } + }) + + } + + } + else { + alert('第三方平台只支持 Postman, Swagger, Rap, YApi !') + } + + return true + }) + + break + } + }, + + getThirdPartyApiList: function (thirdParty, listCallback, itemCallback) { + this.parseThirdParty(thirdParty, function (platform, jsonData, docUrl, listUrl, itemUrl) { + var isJSONData = jsonData instanceof Object + + const header = App.getHeader(vHeader.value) + + if (platform == PLATFORM_POSTMAN) { + alert('尚未开发 ' + PLATFORM_POSTMAN) + } + else if (platform == PLATFORM_SWAGGER) { + if (isJSONData) { + listCallback(platform, docUrl, listUrl, itemUrl, itemUrl, { data: jsonData }, null) + } + else { + App.request(false, REQUEST_TYPE_PARAM, docUrl, {}, header, function (url_, res, err) { + if (listCallback != null && listCallback(platform, docUrl, listUrl, itemUrl, url_, res, err)) { + return + } + + if (itemCallback != null) { + itemCallback(platform, docUrl, listUrl, itemUrl, itemUrl, res, err) + } + }) + } + } + else if (platform == PLATFORM_RAP || platform == PLATFORM_YAPI) { + var isRap = platform == PLATFORM_RAP + + if (isJSONData) { + if (listCallback != null && listCallback(platform, docUrl, listUrl, itemUrl, listUrl, {data: [jsonData]}, null)) { + return + } + + if (itemCallback != null) { + itemCallback(platform, docUrl, listUrl, itemUrl, itemUrl, {data: jsonData}, null) + } + } + else { + App.request(false, REQUEST_TYPE_PARAM, listUrl, {}, header, function (url_, res, err) { + if (listCallback != null && listCallback(platform, docUrl, listUrl, itemUrl, url_, res, err)) { + return + } + + var apis = (res.data || {}).data + if (apis == null) { // || apis.length <= 0) { + alert('没有查到 ' + (isRap ? 'Rap' : 'YApi') + ' 文档!请开启跨域代理,并检查 URL 是否正确!YApi/Rap/Swagger 网站的 Cookie 必须粘贴到请求头 Request Header 输入框!') + return + } + + var item + for (var url in apis) { + item = apis[url] || {} + + var list = (isRap ? [ { _id: item.id } ] : (item == null ? null : item.list)) || [] + for (let i1 = 0; i1 < list.length; i1++) { + var listItem1 = list[i1] + if (listItem1 == null || listItem1._id == null) { + App.log('listItem1 == null || listItem1._id == null >> continue') + continue + } + + // var p = listItem1.path == null ? null : StringUtil.noBlank(listItem1.path).replace(/\/\//g, '/') + // if (p == null) { + // continue + // } + + App.request(false, REQUEST_TYPE_PARAM, itemUrl + '?id=' + listItem1._id, {}, header, function (url_, res, err) { + if (itemCallback != null) { + itemCallback(platform, docUrl, listUrl, itemUrl, url_, res, err) + } + }) + } + + } + }) + + } + + } + else { + alert('第三方平台只支持 Postman, Swagger, Rap, YApi !') + } + }) + + }, + + parseThirdParty: function (thirdParty, callback) { + var tp = StringUtil.trim(thirdParty) + var index = tp.indexOf(' ') + var platform = index < 0 ? PLATFORM_SWAGGER : tp.substring(0, index).toUpperCase() + var docUrl = index <= 0 ? tp.trim() : tp.substring(index + 1).trim() + + var jsonData = null + try { + jsonData = JSON.parse(docUrl) + } + catch (e) {} + + var host = this.getBaseUrl() + var listUrl = null + var itemUrl = null + + if (platform == PLATFORM_SWAGGER) { + if (docUrl == '/') { + docUrl += 'v2/api-docs' + } + if (docUrl.startsWith('/')) { + docUrl = host + docUrl + } + } + else if (platform == PLATFORM_RAP || platform == PLATFORM_YAPI) { + var isRap = platform == PLATFORM_RAP + index = docUrl.indexOf(' ') + listUrl = index < 0 ? docUrl + (isRap ? '/repository/joined' : '/api/interface/list_menu') : docUrl.substring(0, index).trim() + itemUrl = index < 0 ? docUrl + (isRap ? '/repository/get' : '/api/interface/get') : docUrl.substring(index + 1).trim() + + if (listUrl.startsWith('/')) { + listUrl = host + listUrl + } + if (itemUrl.startsWith('/')) { + itemUrl = host + itemUrl + } + } + + callback(platform, jsonData, docUrl, listUrl, itemUrl) + }, + + /**上传 Swagger API + * @param url + * @param docItem + * @param method + * @param callback + */ + uploadSwaggerApi: function(url, docItem, method) { + method = method || 'get' + var api = docItem == null ? null : docItem[method] + if (api == null) { + log('postApi', 'api == null >> return') + this.exTxt.button = 'All:' + this.uploadTotal + '\nDone:' + this.uploadDoneCount + '\nFail:' + this.uploadFailCount + return false + } + + this.uploadTotal ++ + + var parameters = api.parameters || [] + var parameters2 = [] + if (parameters != null && parameters.length > 0) { + + for (var k = 0; k < parameters.length; k++) { + var paraItem = parameters[k] || {} + var name = paraItem.name || '' + if (name == 'mock') { + continue + } + + parameters2.push(paraItem) + } + } + + return this.uploadThirdPartyApi(method == 'get' ? REQUEST_TYPE_PARAM : REQUEST_TYPE_JSON + , api.summary, url, parameters2, api.headers, api.description) + }, + + + /**上传 Rap API + * @param docItem + */ + uploadRapApi: function(docItem) { + var api = docItem + if (api == null) { + log('postApi', 'api == null >> return') + this.exTxt.button = 'All:' + this.uploadTotal + '\nDone:' + this.uploadDoneCount + '\nFail:' + this.uploadFailCount + return false + } + + this.uploadTotal ++ + + var type + switch ((api.summary || {}).requestParamsType || '') { + case 'QUERY_PARAMS': + type = REQUEST_TYPE_PARAM + break + case 'BODY_PARAMS': + switch ((api.summary || {}).bodyOption || '') { + case 'FORM_DATA': + type = REQUEST_TYPE_DATA + break + case 'FORM_URLENCODED': + type = REQUEST_TYPE_FORM + break + // case 'RAW': //JSON + default: + type = REQUEST_TYPE_JSON + break + } + break + default: + type = REQUEST_TYPE_JSON + break + } + + var header = '' + + var parameters = api.properties + + var parameters2 = [] + if (parameters != null && parameters.length > 0) { + + for (var k = 0; k < parameters.length; k++) { + + var paraItem = parameters[k] || {} + var name = paraItem.name || '' + if (StringUtil.isEmpty(name, true) || paraItem.scope != 'request') { + continue + } + + var val = paraItem.value + + if (paraItem.pos == 1) { //header + header += (k <= 0 ? '' : '\n') + name + ': ' + (val == null ? '' : val) + + (StringUtil.isEmpty(paraItem.description, true) ? '' : ' // ' + paraItem.description) + continue + } + + //转成和 Swagger 一样的字段及格式 + paraItem.type = paraItem.type == 'Number' ? 'integer' : StringUtil.toLowerCase(paraItem.type) + paraItem.default = val + + parameters2.push(paraItem) + } + } + + return this.uploadThirdPartyApi(type, api.name, api.url, parameters2, header, api.description) + }, + + /**上传 YApi + * @param docItem + */ + uploadYApi: function(docItem) { + var api = docItem + if (api == null) { + log('postApi', 'api == null >> return') + this.exTxt.button = 'All:' + this.uploadTotal + '\nDone:' + this.uploadDoneCount + '\nFail:' + this.uploadFailCount + return false + } + + this.uploadTotal++ + + var headers = api.req_headers || [] + var header = '' + for (var i = 0; i < headers.length; i ++) { + var item = headers[i]; + var name = item == null ? null : item.name + if (name == null) { + continue + } + header += (i <= 0 ? '' : '\n') + name + ': ' + item.value + + (StringUtil.isEmpty(item.description, true) ? '' : ' // ' + item.description) + } + + var typeAndParam = this.parseYApiTypeAndParam(api) + + return this.uploadThirdPartyApi( + typeAndParam.type, api.title, api.path, typeAndParam.param, header + , (StringUtil.trim(api.username) + ': ' + StringUtil.trim(api.title) + + '\n' + (api.up_time == null ? '' : (typeof api.up_time != 'number' ? api.up_time : new Date(1000*api.up_time).toLocaleString())) + + '\nhttp://apijson.cn/yapi/project/1/interface/api/' + api._id + + '\n\n' + (StringUtil.isEmpty(api.markdown, true) ? StringUtil.trim(api.description) : api.markdown.trim().replace(/\\_/g, '_'))) + , api.username + ) + }, + + + parseYApiTypeAndParam: function (api) { + if (api == null) { + return {} + } + + var type + var parameters + switch (api.req_body_type || '') { + case 'form': + type = REQUEST_TYPE_FORM + parameters = api.req_body_form + break + case 'data': + type = REQUEST_TYPE_DATA + parameters = api.req_params + break + case 'query': + type = REQUEST_TYPE_PARAM + parameters = api.req_query + break + default: + type = REQUEST_TYPE_JSON + parameters = api.req_body_other == null ? null : JSON.parse(api.req_body_other) + + var params = parameters.properties || {} + var required = parameters.required || [] + var newParams = [] + for (var k in params) { //TODO 递归里面的子项 + var item = params[k] + item.name = k + item.required = required.indexOf(k) >= 0 + newParams.push(item) + } + parameters = newParams + break + } + + var parameters2 = [] + if (parameters != null && parameters.length > 0) { + //过滤掉无效的,避免多拼接 , 导致 req 不是合法 JSON + for (var k = 0; k < parameters.length; k++) { + var paraItem = parameters[k] || {} + var name = paraItem.name || '' + if (StringUtil.isEmpty(name, true)) { + continue + } + + //转成和 Swagger 一样的字段及格式 + paraItem.url = paraItem.path + + var val = (paraItem.mock || {}).mock + if (val == null && type == 'array') { + val = [] + var it = paraItem.items || {} + var v = it == null ? null : (it.mock || {}).mock + val.push(v) + } + paraItem.default = val + + parameters2.push(paraItem) + } + } + + return { + type: type, + param: parameters2 + } + }, + + //上传第三方平台的 API 至 APIAuto + uploadThirdPartyApi: function(type, name, url, parameters, header, description, creator) { + var req = '{' + + if (parameters != null && parameters.length > 0) { + for (var k = 0; k < parameters.length; k++) { + var paraItem = parameters[k] || {} + var n = paraItem.name || '' //传进来前已过滤,这里只是避免万一为 null 导致后面崩溃 + var t = paraItem.type || '' + var val = paraItem.default + + if (val == undefined) { + if (t == 'boolean') { + val = 'true' + } + if (t == 'integer') { + val = n == 'pageSize' ? '10' : '1' + } + else if (t == 'string') { + val = '""' + } + else if (t == 'object') { + val = '{}' + } + else if (t == 'array') { + val = '[]' + } + else { + var suffix = n.length >= 3 ? n.substring(n.length - 3).toLowerCase() : null + if (suffix == 'dto') { + val = '{}' + } else { + val = 'null' + } + } + } + else if (typeof val == 'string' && (StringUtil.isEmpty(t, true) || t == 'string')) { + val = '"' + val.replace(/"/g, '\\"') + '"' + } + else if (val instanceof Object) { + val = JSON.stringify(val, null, ' ') + } + + req += '\n "' + n + '": ' + val + (k < parameters.length - 1 ? ',' : '') + + ' // ' + (paraItem.required ? '必填。 ' : '') + StringUtil.trim(paraItem.description) + } + + } + + req += '\n}' + + if (StringUtil.isEmpty(description, true) == false) { + req += '\n\n/**\n\n' + StringUtil.trim(description).replace(/\*\//g, '* /') + '\n\n*/' + } + + + var currentAccountId = this.getCurrentAccountId() + this.request(true, REQUEST_TYPE_JSON, this.server + '/post', { + format: false, + 'Document': { + 'creator': creator, + 'testAccountId': currentAccountId, + 'type': type, + 'name': StringUtil.get(name), + 'url': url, + 'request': req, + 'header': StringUtil.isEmpty(header, true) ? null : StringUtil.trim(header) + }, + 'TestRecord': { + 'randomId': 0, + 'host': this.getBaseUrl(), + 'testAccountId': currentAccountId, + 'response': '' + }, + 'tag': 'Document' + }, {}, function (url, res, err) { + //太卡 App.onResponse(url, res, err) + if (res.data != null && res.data.Document != null && res.data.Document.code == CODE_SUCCESS) { + App.uploadDoneCount ++ + } else { + App.uploadFailCount ++ + } + + App.exTxt.button = 'All:' + App.uploadTotal + '\nDone:' + App.uploadDoneCount + '\nFail:' + App.uploadFailCount + if (App.uploadDoneCount + App.uploadFailCount >= App.uploadTotal) { + alert('导入完成') + App.isSyncing = false + App.showTestCase(false, false) + App.remotes = [] + App.showTestCase(true, false) + } + }) + + return true + }, + + // 切换主题 + switchTheme: function (index) { + this.checkedTheme = index + localforage.setItem('#theme', index) + }, + + + // APIJSON <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + + //格式化日期 + formatDate: function (date) { + if (date == null) { + date = new Date() + } + return date.getFullYear() + '-' + this.fillZero(date.getMonth() + 1) + '-' + this.fillZero(date.getDate()) + }, + //格式化时间 + formatTime: function (date) { + if (date == null) { + date = new Date() + } + return this.fillZero(date.getHours()) + ':' + this.fillZero(date.getMinutes()) + }, + formatDateTime: function (date) { + if (date == null) { + date = new Date() + } + return this.formatDate(date) + ' ' + this.formatTime(date) + }, + //填充0 + fillZero: function (num, n) { + if (num == null) { + num = 0 + } + if (n == null || n <= 0) { + n = 2 + } + var len = num.toString().length; + while(len < n) { + num = "0" + num; + len++; + } + return num; + }, + + + + + + + onClickAccount: function (index, item, callback) { + this.isTestCaseShow = false + + if (this.currentAccountIndex == index) { + if (item == null) { + if (callback != null) { + callback(false, index) + } + } + else { + this.setRememberLogin(item.remember) + this.account = item.phone + this.password = item.password + + if (item.isLoggedIn) { + //logout FIXME 没法自定义退出,浏览器默认根据url来管理session的 + this.logout(false, function (url, res, err) { + App.onResponse(url, res, err) + + item.isLoggedIn = false + App.saveCache(App.getBaseUrl(), 'currentAccountIndex', App.currentAccountIndex) + App.saveCache(App.getBaseUrl(), 'accounts', App.accounts) + + if (callback != null) { + callback(false, index, err) + } + }); + } + else { + //login + this.login(false, function (url, res, err) { + App.onResponse(url, res, err) + + var data = res.data || {} + var user = data.code == CODE_SUCCESS ? data.user : null + if (user == null) { + if (callback != null) { + callback(false, index, err) + } + } + else { + item.name = user.name + item.remember = data.remember + item.isLoggedIn = true + + App.accounts[App.currentAccountIndex] = item + App.saveCache(App.getBaseUrl(), 'currentAccountIndex', App.currentAccountIndex) + App.saveCache(App.getBaseUrl(), 'accounts', App.accounts) + + if (callback != null) { + callback(true, index, err) + } + } + }); + } + + } + + return; + } + + //退出当前账号 + var c = this.currentAccountIndex + var it = c == null || this.accounts == null ? null : this.accounts[c]; + if (it != null) { //切换 BASE_URL后 it = undefined 导致UI操作无法继续 + it.isLoggedIn = false //异步导致账号错位 this.onClickAccount(c, this.accounts[c]) + } + + //切换到这个tab + this.currentAccountIndex = index + + //目前还没做到同一标签页下测试账号切换后,session也跟着切换,所以干脆每次切换tab就重新登录 + if (item != null) { + item.isLoggedIn = false + this.onClickAccount(index, item, callback) + } + else { + if (callback != null) { + callback(false, index) + } + } + }, + + removeAccountTab: function () { + if (this.accounts.length <= 1) { + alert('至少要 1 个测试账号!') + return + } + + this.accounts.splice(this.currentAccountIndex, 1) + if (this.currentAccountIndex >= this.accounts.length) { + this.currentAccountIndex = this.accounts.length - 1 + } + + this.saveCache(this.getBaseUrl(), 'currentAccountIndex', this.currentAccountIndex) + this.saveCache(this.getBaseUrl(), 'accounts', this.accounts) + }, + addAccountTab: function () { + this.showLogin(true, false) + }, + + + //显示远程的测试用例文档 + showTestCase: function (show, isLocal) { + this.isTestCaseShow = show + this.isLocalShow = isLocal + + vOutput.value = show ? '' : (output || '') + this.showDoc() + + if (isLocal) { + this.testCases = this.locals || [] + return + } + this.testCases = this.remotes || [] + + if (show) { + var testCases = this.testCases + var allCount = testCases == null ? 0 : testCases.length + if (allCount > 0) { + var accountIndex = (this.accounts[this.currentAccountIndex] || {}).isLoggedIn ? this.currentAccountIndex : -1 + this.currentAccountIndex = accountIndex //解决 onTestResponse 用 -1 存进去, handleTest 用 currentAccountIndex 取出来为空 + + var tests = this.tests[String(accountIndex)] || {} + if (tests != null && $.isEmptyObject(tests) != true) { + for (var i = 0; i < allCount; i++) { + var item = testCases[i] + if (item == null) { + continue + } + var d = item.Document || {} + this.compareResponse(allCount, testCases, i, item, (tests[d.id] || {})[0], false, accountIndex, true) + } + } + return; + } + + this.isTestCaseShow = false + + var types = this.types + var search = StringUtil.isEmpty(this.testCaseSearch, true) ? null : '%' + StringUtil.trim(this.testCaseSearch) + '%' + var url = this.server + '/get' + var req = { + format: false, + '[]': { + 'count': this.testCaseCount || 100, //200 条测试直接卡死 0, + 'page': this.testCasePage || 0, + 'Document': { + '@order': 'version-,date-', + 'userId': this.User.id, + 'name$': search, + 'url$': search, + '@combine': search == null ? null : 'name$,url$', + 'type{}': types == null || types.length <= 0 ? null : types + }, + 'TestRecord': { + 'documentId@': '/Document/id', + 'userId': this.User.id, + 'testAccountId': this.getCurrentAccountId(), + 'randomId': 0, + '@order': 'date-', + '@column': 'id,userId,documentId,duration,minDuration,maxDuration,response' + (this.isMLEnabled ? ',standard' : ''), + '@having': this.isMLEnabled ? 'length(standard)>2' : null //用 MySQL 5.6 '@having': this.isMLEnabled ? 'json_length(standard)>0' : null + } + }, + '@role': 'LOGIN' + } + + this.onChange(false) + this.request(true, REQUEST_TYPE_JSON, url, req, {}, function (url, res, err) { + App.onResponse(url, res, err) + + var rpObj = res.data + + if (rpObj != null && rpObj.code === CODE_SUCCESS) { + App.isTestCaseShow = true + App.isLocalShow = false + App.testCases = App.remotes = rpObj['[]'] + vOutput.value = show ? '' : (output || '') + App.showDoc() + + //App.onChange(false) + } + }) + } + }, + + //显示远程的随机配置文档 + showRandomList: function (show, item, isSub) { + this.isRandomEditable = false + this.isRandomListShow = show && ! isSub + this.isRandomSubListShow = show && isSub + if (! isSub) { + this.randomSubs = [] + } + + vOutput.value = show ? '' : (output || '') + this.showDoc() + + this.randoms = this.randoms || [] + + if (show && this.isRandomShow && this.randoms.length <= 0 && item != null && item.id != null) { + this.isRandomListShow = false + + var subSearch = StringUtil.isEmpty(this.randomSubSearch, true) + ? null : '%' + StringUtil.trim(this.randomSubSearch) + '%' + var search = isSub ? subSearch : (StringUtil.isEmpty(this.randomSearch, true) + ? null : '%' + StringUtil.trim(this.randomSearch) + '%') + + var url = this.server + '/get' + var req = { + '[]': { + 'count': (isSub ? this.randomSubCount : this.randomCount) || 100, + 'page': (isSub ? this.randomSubPage : this.randomPage) || 0, + 'Random': { + 'toId': isSub ? item.id : 0, + 'documentId': isSub ? null : item.id, + '@order': "date-", + 'name$': search + }, + 'TestRecord': { + 'randomId@': '/Random/id', + 'testAccountId': this.getCurrentAccountId(), + 'host': this.getBaseUrl(), + '@order': 'date-' + }, + '[]': isSub ? null : { + 'count': this.randomSubCount || 100, + 'page': this.randomSubPage || 0, + 'Random': { + 'toId@': '[]/Random/id', + 'documentId': item.id, + '@order': "date-", + 'name$': subSearch + }, + 'TestRecord': { + 'randomId@': '/Random/id', + 'testAccountId': this.getCurrentAccountId(), + 'host': this.getBaseUrl(), + '@order': 'date-' + } + } + } + } + + this.onChange(false) + this.request(true, REQUEST_TYPE_JSON, url, req, {}, function (url, res, err) { + App.onResponse(url, res, err) + + var rpObj = res.data + + if (rpObj != null && rpObj.code === CODE_SUCCESS) { + App.isRandomListShow = ! isSub + App.isRandomSubListShow = isSub + if (isSub) { + if (App.currentRandomItem == null) { + App.currentRandomItem = {} + } + App.randomSubs = App.currentRandomItem.subs = App.currentRandomItem['[]'] = rpObj['[]'] + } + else { + App.randoms = rpObj['[]'] + } + + vOutput.value = show ? '' : (output || '') + App.showDoc() + + //App.onChange(false) + } + }) + } + }, + + + // 设置文档 + showDoc: function () { + if (this.setDoc(doc) == false) { + this.getDoc(function (d) { + App.setDoc(d); + }); + } + }, + + + saveCache: function (url, key, value) { + var cache = this.getCache(url); + cache[key] = value + localStorage.setItem('APIAuto:' + url, JSON.stringify(cache)) + }, + getCache: function (url, key, defaultValue) { + var cache = localStorage.getItem('APIAuto:' + url) + try { + cache = JSON.parse(cache) + } catch(e) { + this.log('login this.send >> try { cache = JSON.parse(cache) } catch(e) {\n' + e.message) + } + cache = cache || {} + var val = key == null ? cache : cache[key] + return val == null && defaultValue != null ? defaultValue : val + }, + + /**登录确认 + */ + confirm: function () { + switch (this.loginType) { + case 'login': + this.login(this.isAdminOperation) + break + case 'register': + this.register(this.isAdminOperation) + break + case 'forget': + this.resetPassword(this.isAdminOperation) + break + } + }, + + showLogin: function (show, isAdmin) { + this.isLoginShow = show + this.isAdminOperation = isAdmin + + if (show != true) { + return + } + + var user = isAdmin ? this.User : null // add account this.accounts[this.currentAccountIndex] + + // alert("showLogin isAdmin = " + isAdmin + "; user = \n" + JSON.stringify(user, null, ' ')) + + if (user == null || StringUtil.isEmpty(user.phone, true)) { + user = { + phone: '13000082001', + password: '123456' + } + } + + this.setRememberLogin(user.remember) + this.account = user.phone + this.password = user.password + }, + + setRememberLogin(remember) { + vRemember.checked = remember || false + }, + + getCurrentAccount: function() { + return this.accounts == null ? null : this.accounts[this.currentAccountIndex] + }, + getCurrentAccountId: function() { + var a = this.getCurrentAccount() + return a != null && a.isLoggedIn ? a.id : null + }, + + /**登录 + */ + login: function (isAdminOperation, callback) { + this.isLoginShow = false + this.isEditResponse = false + + const req = { + type: 0, // 登录方式,非必须 0-密码 1-验证码 + phone: this.account, + password: this.password, + version: 1, // 全局默认版本号,非必须 + remember: vRemember.checked, + format: false, + defaults: isAdminOperation ? undefined : { + '@database': StringUtil.isEmpty(this.database, true) ? undefined : this.database, + '@schema': StringUtil.isEmpty(this.schema, true) ? undefined : this.schema + } + } + + if (isAdminOperation) { + this.request(isAdminOperation, REQUEST_TYPE_JSON, this.server + '/login', req, {}, function (url, res, err) { + if (callback) { + callback(url, res, err) + return + } + + var rpObj = res.data || {} + + if (rpObj.code != CODE_SUCCESS) { + alert('登录失败,请检查网络后重试。\n' + rpObj.msg + '\n详细信息可在浏览器控制台查看。') + App.onResponse(url, res, err) + } + else { + var user = rpObj.user || {} + + if (user.id > 0) { + user.remember = rpObj.remember + user.phone = req.phone + user.password = req.password + App.User = user + } + + //保存User到缓存 + App.saveCache(App.server, 'User', user) + + if (App.currentAccountIndex == null || App.currentAccountIndex < 0) { + App.currentAccountIndex = 0 + } + var item = App.accounts[App.currentAccountIndex] + item.isLoggedIn = false + App.onClickAccount(App.currentAccountIndex, item) //自动登录测试账号 + + if (user.id > 0) { + App.showTestCase(true, false) + } + } + + }) + } + else { + if (callback == null) { + var item + for (var i in this.accounts) { + item = this.accounts[i] + if (item != null && req.phone == item.phone) { + alert(req.phone + ' 已在测试账号中!') + // this.currentAccountIndex = i + item.remember = vRemember.checked + this.onClickAccount(i, item) + return + } + } + } + + this.showUrl(isAdminOperation, '/login') + + vInput.value = JSON.stringify(req, null, ' ') + this.type = REQUEST_TYPE_JSON + this.showTestCase(false, this.isLocalShow) + this.onChange(false) + this.send(isAdminOperation, function (url, res, err) { + if (callback) { + callback(url, res, err) + return + } + + App.onResponse(url, res, err) + + //由login按钮触发,不能通过callback回调来实现以下功能 + var data = res.data || {} + if (data.code == CODE_SUCCESS) { + var user = data.user || {} + App.accounts.push({ + isLoggedIn: true, + id: user.id, + name: user.name, + phone: req.phone, + password: req.password, + remember: data.remember + }) + + var lastItem = App.accounts[App.currentAccountIndex] + if (lastItem != null) { + lastItem.isLoggedIn = false + } + + App.currentAccountIndex = App.accounts.length - 1 + + App.saveCache(App.getBaseUrl(), 'currentAccountIndex', App.currentAccountIndex) + App.saveCache(App.getBaseUrl(), 'accounts', App.accounts) + } + }) + } + }, + + /**注册 + */ + register: function (isAdminOperation) { + this.showUrl(isAdminOperation, '/register') + vInput.value = JSON.stringify( + { + Privacy: { + phone: this.account, + _password: this.password + }, + User: { + name: 'APIJSONUser' + }, + verify: vVerify.value + }, + null, ' ') + this.showTestCase(false, false) + this.onChange(false) + this.send(isAdminOperation, function (url, res, err) { + App.onResponse(url, res, err) + + var rpObj = res.data + + if (rpObj != null && rpObj.code === CODE_SUCCESS) { + alert('注册成功') + + var privacy = rpObj.Privacy || {} + + App.account = privacy.phone + App.loginType = 'login' + } + }) + }, + + /**重置密码 + */ + resetPassword: function (isAdminOperation) { + this.showUrl(isAdminOperation, '/put/password') + vInput.value = JSON.stringify( + { + verify: vVerify.value, + Privacy: { + phone: this.account, + _password: this.password + } + }, + null, ' ') + this.showTestCase(false, this.isLocalShow) + this.onChange(false) + this.send(isAdminOperation, function (url, res, err) { + App.onResponse(url, res, err) + + var rpObj = res.data + + if (rpObj != null && rpObj.code === CODE_SUCCESS) { + alert('重置密码成功') + + var privacy = rpObj.Privacy || {} + + App.account = privacy.phone + App.loginType = 'login' + } + }) + }, + + /**退出 + */ + logout: function (isAdminOperation, callback) { + this.isEditResponse = false + var req = {} + + if (isAdminOperation) { + // alert('logout isAdminOperation this.saveCache(this.server, User, {})') + this.delegateId = null + this.saveCache(this.server, 'delegateId', null) + + this.saveCache(this.server, 'User', {}) + } + + // alert('logout isAdminOperation = ' + isAdminOperation + '; url = ' + url) + if (isAdminOperation) { + this.request(isAdminOperation, REQUEST_TYPE_JSON, this.server + '/logout', req, {}, function (url, res, err) { + if (callback) { + callback(url, res, err) + return + } + + // alert('logout clear admin ') + + App.clearUser() + App.onResponse(url, res, err) + App.showTestCase(false, App.isLocalShow) + }) + } + else { + this.showUrl(isAdminOperation, '/logout') + vInput.value = JSON.stringify(req, null, ' ') + this.type = REQUEST_TYPE_JSON + this.showTestCase(false, this.isLocalShow) + this.onChange(false) + this.send(isAdminOperation, callback) + } + }, + + /**获取验证码 + */ + getVerify: function (isAdminOperation) { + this.showUrl(isAdminOperation, '/post/verify') + var type = this.loginType == 'login' ? 0 : (this.loginType == 'register' ? 1 : 2) + vInput.value = JSON.stringify( + { + type: type, + phone: this.account + }, + null, ' ') + this.showTestCase(false, this.isLocalShow) + this.onChange(false) + this.send(isAdminOperation, function (url, res, err) { + App.onResponse(url, res, err) + + var data = res.data || {} + var obj = data.code == CODE_SUCCESS ? data.verify : null + var verify = obj == null ? null : obj.verify + if (verify != null) { //FIXME isEmpty校验时居然在verify=null! StringUtil.isEmpty(verify, true) == false) { + vVerify.value = verify + } + }) + }, + + clearUser: function () { + this.User.id = 0 + this.Privacy = {} + this.remotes = [] + // 导致刚登录成功就马上退出 this.delegateId = null + this.saveCache(this.server, 'User', this.User) //应该用lastBaseUrl,baseUrl应随watch输入变化重新获取 + // this.saveCache(this.server, 'delegateId', this.delegateId) //应该用lastBaseUrl,baseUrl应随watch输入变化重新获取 + }, + + /**计时回调 + */ + onHandle: function (before) { + this.isDelayShow = false + if (inputted != before) { + clearTimeout(handler); + return; + } + + this.view = 'output'; + vComment.value = ''; + vWarning.value = ''; + // vUrlComment.value = ''; + vOutput.value = 'resolving...'; + + //格式化输入代码 + try { + try { + this.header = this.getHeader(vHeader.value) + } catch (e2) { + this.isHeaderShow = true + vHeader.select() + throw new Error(e2.message) + } + + before = StringUtil.trim(before); + + var afterObj; + var after; + var code = ''; + + if (StringUtil.isEmpty(before)) { + afterObj = {}; + after = ''; + } else { + before = StringUtil.trim(before); // this.toDoubleJSON(StringUtil.trim(before)); + log('onHandle before = \n' + before); + + var json = isSingle ? this.switchQuote(before) : before; + try { + afterObj = jsonlint.parse(json); + after = JSON.stringify(afterObj, null, " "); + before = isSingle ? this.switchQuote(after) : after; + } + catch (e) { + log('main.onHandle', 'try { return jsonlint.parse(before); \n } catch (e) {\n' + e.message) + log('main.onHandle', 'return jsonlint.parse(this.removeComment(before));') + + try { + afterObj = JSON5.parse(json); // jsonlint.parse(this.removeComment(before)); + after = JSON.stringify(afterObj, null, " "); + } catch (e2) { + throw new Error('请求 JSON 格式错误!请检查并编辑请求!\n\n如果JSON中有注释,请 手动删除 或 点击左边的 \'/" 按钮 来去掉。\n\n' + e.message + '\n\n' + e2.message) + } + } + + //关键词let在IE和Safari上不兼容 + if (this.isEditResponse != true) { + try { + code = this.getCode(after); //必须在before还是用 " 时使用,后面用会因为解析 ' 导致失败 + } catch (e) { + code = '\n\n\n建议:\n使用其它浏览器,例如 谷歌Chrome、火狐FireFox 或者 微软Edge, 因为这样能自动生成请求代码.' + + '\nError:\n' + e.message + '\n\n\n'; + } + } + + var selectionStart = vInput.selectionStart + var selectionEnd = vInput.selectionEnd + vInput.value = before + + '\n\n\n ' + + ' \n'; //解决遮挡 + + vInput.selectionStart = selectionStart + vInput.selectionEnd = selectionEnd + vInput.setSelectionRange(selectionStart, selectionEnd) + } + + vSend.disabled = false; + + if (this.isEditResponse != true) { + vOutput.value = output = '登录后点 ↑ 上方左侧最后图标按钮可查看用例列表,点上方右侧中间图标按钮可上传用例并且添加到列表中 ↑ \nOK,请点左上方 [发送请求] 按钮来测试。[点击这里查看视频教程](https://i.youku.com/i/UNTg1NzI1MjQ4MA==/videos?spm=a2hzp.8244740.0.0)' + code; + + this.showDoc() + } + + var docKey = this.isEditResponse ? 'TestRecord' : 'Document'; + var currentItem = (this.currentRemoteItem || {})[docKey] || {} + var detail = currentItem.detail; + var extraComment = this.getExtraComment() + + try { + var standardObj = null; + try { + standardObj = JSON.parse(currentItem.standard); + } catch (e3) { + log(e3) + } + + var isAPIJSONRouter = false; + try { + var apijson = JSON.parse(currentItem.apijson); + isAPIJSONRouter = JSONResponse.isObject(apijson) + } catch (e3) { + log(e3) + } + + var m = this.getMethod(); + var w = isSingle || this.isEditResponse ? '' : StringUtil.trim(CodeUtil.parseComment(after, docObj == null ? null : docObj['[]'], m, this.database, this.language, this.isEditResponse != true, standardObj, null, true, isAPIJSONRouter)); + var c = isSingle ? '' : StringUtil.trim(CodeUtil.parseComment(after, docObj == null ? null : docObj['[]'], m, this.database, this.language, this.isEditResponse != true, standardObj, null, null, isAPIJSONRouter)); + + + //TODO 统计行数,补全到一致 vInput.value.lineNumbers + if (isSingle != true) { + if (afterObj.tag == null) { + m = m == null ? 'GET' : m.toUpperCase() + if (['GETS', 'HEADS', 'POST', 'PUT', 'DELETE'].indexOf(m) >= 0) { + w += ' ! 非开放请求必须设置 tag !例如 "tag": "User"' + c += ' ! 非开放请求必须设置 tag !例如 "tag": "User"' + } + } + + if (StringUtil.isEmpty(detail, true)) { + c += extraComment == null ? '' : ('\n\n/*' + extraComment + '\n*/'); + } else { + c += '\n\n/*' + (extraComment == null ? '' : extraComment + '\n\n') + detail + '\n*/'; + } + } + + + vWarning.value = w + + '\n\n\n ' + + ' \n'; //解决遮挡 + vComment.value = c + + '\n\n\n ' + + ' \n'; //解决遮挡 + + vUrlComment.value = isSingle || StringUtil.isEmpty(this.urlComment, true) + ? '' : vUrl.value + CodeUtil.getComment(this.urlComment, false, ' ') + + ' - ' + (this.requestVersion > 0 ? 'V' + this.requestVersion : 'V*'); + + if (! isSingle) { + var method = this.getMethod(); // m 已经 toUpperCase 了 + var isRestful = ! JSONObject.isAPIJSONPath(method); + if (isRestful != true) { + method = method.toUpperCase(); + } + var apiMap = isRestful ? CodeUtil.thirdPartyApiMap : null; + var api = apiMap == null ? null : apiMap['/' + method]; + var name = api == null ? null : api.name; + if (StringUtil.isEmpty(name, true) == false) { + this.urlComment = name; + vUrlComment.value = vUrl.value + CodeUtil.getComment(this.urlComment, false, ' ') + } + } + + onScrollChanged() + onURLScrollChanged() + } catch (e) { + log('onHandle try { vComment.value = CodeUtil.parseComment >> } catch (e) {\n' + e.message); + } + + if (this.isPreviewEnabled) { + try { + // 去掉前面的 JSON + var raw = StringUtil.trim(isSingle ? vInput.value : vComment.value); + var start = raw.lastIndexOf('\n\/*') + var end = raw.lastIndexOf('\n*\/') + var ct = start < 0 || end <= start ? '' : StringUtil.trim(raw.substring(start + '\n\/*'.length, end)) + + markdownToHTML('```js\n' + (start < 0 || end <= start ? raw : raw.substring(0, start)) + '\n```\n' + + (StringUtil.isEmpty(ct, true) ? '' : ct + '\n\n```js\n' + ct + '\n```\n'), true); + } catch (e3) { + log(e3) + } + } + + if (this.isEditResponse) { + this.view = 'code'; + this.jsoncon = after + } + + } catch(e) { + log(e) + vSend.disabled = true + + this.view = 'error' + this.error = { + msg: e.message + } + } + }, + + + /**输入内容改变 + */ + onChange: function (delay) { + this.setBaseUrl(); + inputted = new String(vInput.value); + vComment.value = ''; + vWarning.value = ''; + // vUrlComment.value = ''; + + clearTimeout(handler); + + this.isDelayShow = delay; + + if (delay) { + handler = setTimeout(function () { + App.onHandle(inputted); + }, 2000); + } else { + this.onHandle(inputted); + } + }, + + /**单双引号切换 + */ + transfer: function () { + isSingle = ! isSingle; + + vInput.value = this.switchQuote(vInput.value); + + this.isTestCaseShow = false + + // // 删除注释 <<<<<<<<<<<<<<<<<<<<< + // + // var input = this.removeComment(vInput.value); + // if (vInput.value != input) { + // vInput.value = input + // } + // + // // 删除注释 >>>>>>>>>>>>>>>>>>>>> + + this.onChange(false); + }, + + /**获取显示的请求类型名称 + */ + getTypeName: function (type) { + var ts = this.types + var t = type || REQUEST_TYPE_JSON + if (ts == null || ts.length <= 1 || (ts.length <= 2 && ts.indexOf(REQUEST_TYPE_PARAM) >= 0 && ts.indexOf(REQUEST_TYPE_GRPC) < 0)) { + return t == REQUEST_TYPE_PARAM ? 'GET' : 'POST' + } + return t + }, + /**请求类型切换 + */ + changeType: function () { + var count = this.types == null ? 0 : this.types.length + if (count > 1) { + var index = this.types.indexOf(this.type) + index++; + this.type = this.types[index % count] + CodeUtil.type = this.type; + } + + var url = StringUtil.get(vUrl.value) + var index = url.indexOf('?') + if (index >= 0) { + var paramObj = getRequestFromURL(url.substring(index), true) + vUrl.value = url.substring(0, index) + if (paramObj != null && $.isEmptyObject(paramObj) == false) { + var originVal = this.getRequest(vInput.value, {}); + var isConflict = false; + + if ($.isEmptyObject(originVal) == false) { + for (var k in paramObj) { + if (originVal.hasOwnProperty(k)) { + isConflict = true; + break; + } + } + } + + if (isConflict) { + vInput.value = JSON.stringify(paramObj, null, ' ') + '\n\n// FIXME 从 URL 上的参数转换过来,需要与下面原来的字段合并为一个 JSON:\n\n' + StringUtil.get(vInput.value) + } + else { + vInput.value = JSON.stringify(Object.assign(originVal, paramObj), null, ' ') + } + } + clearTimeout(handler) //解决 vUrl.value 和 vInput.value 变化导致刷新,而且会把 vInput.value 重置,加上下面 onChange 再刷新就卡死了 + } + + this.onChange(false); + }, + + /** + * 删除注释 + */ + removeComment: function (json) { + var reg = /("([^\\\"]*(\\.)?)*")|('([^\\\']*(\\.)?)*')|(\/{2,}.*?(\r|\n))|(\/\*(\n|.)*?\*\/)/g // 正则表达式 + try { + return new String(json).replace(reg, function(word) { // 去除注释后的文本 + return /^\/{2,}/.test(word) || /^\/\*/.test(word) ? "" : word; + }) + } catch (e) { + log('transfer delete comment in json >> catch \n' + e.message); + } + return json; + }, + + showAndSend: function (branchUrl, req, isAdminOperation, callback) { + this.showUrl(isAdminOperation, branchUrl) + vInput.value = JSON.stringify(req, null, ' ') + this.showTestCase(false, this.isLocalShow) + this.onChange(false) + this.send(isAdminOperation, callback) + }, + + /**发送请求 + */ + send: function(isAdminOperation, callback) { + if (this.isTestCaseShow) { + alert('请先输入请求内容!') + return + } + + if (StringUtil.isEmpty(this.host, true)) { + if (StringUtil.get(vUrl.value).startsWith('http://') != true && StringUtil.get(vUrl.value).startsWith('https://') != true) { + alert('URL 缺少 http:// 或 https:// 前缀,可能不完整或不合法,\n可能使用同域的 Host,很可能访问出错!') + } + } + else { + if (StringUtil.get(vUrl.value).indexOf('://') >= 0) { + alert('URL Host 已经隐藏(固定) 为 \n' + this.host + ' \n将会自动在前面补全,导致 URL 不合法访问出错!\n如果要改 Host,右上角设置 > 显示(编辑)URL Host') + } + } + + this.onHandle(vInput.value) + + clearTimeout(handler) + + if (this.isEditResponse) { + this.onChange(false) + return + } + + var header + try { + header = this.getHeader(vHeader.value) + } catch (e) { + // alert(e.message) + return + } + + var req = this.getRequest(vInput.value, {}) + + var url = this.getUrl() + + vOutput.value = "requesting... \nURL = " + url + this.view = 'output'; + + + this.setBaseUrl() + this.request(isAdminOperation, this.type, url, req, isAdminOperation ? {} : header, callback) + + this.locals = this.locals || [] + if (this.locals.length >= 1000) { //最多1000条,太多会很卡 + this.locals.splice(999, this.locals.length - 999) + } + var method = this.getMethod() + this.locals.unshift({ + 'Document': { + 'userId': this.User.id, + 'name': this.formatDateTime() + ' ' + (this.urlComment || StringUtil.trim(req.tag)), + 'type': this.type, + 'url': '/' + method, + 'request': JSON.stringify(req, null, ' '), + 'header': vHeader.value + } + }) + this.saveCache('', 'locals', this.locals) + }, + + //请求 + request: function (isAdminOperation, type, url, req, header, callback) { + this.isLoading = true + + type = type || REQUEST_TYPE_JSON + url = StringUtil.noBlank(url) + + var isDelegate = (isAdminOperation == false && this.isDelegateEnabled) || (isAdminOperation && url.indexOf('://apijson.cn:9090') > 0) + + if (header != null && header.Cookie != null) { + if (isDelegate) { + header['Set-Cookie'] = header.Cookie + delete header.Cookie + } + else { + document.cookie = header.Cookie + } + } + + if (isDelegate && this.delegateId != null && (header == null || header['Apijson-Delegate-Id'] == null)) { + if (header == null) { + header = {}; + } + header['Apijson-Delegate-Id'] = this.delegateId + } + + // axios.defaults.withcredentials = true + axios({ + method: (type == REQUEST_TYPE_PARAM ? 'get' : 'post'), + url: (isDelegate + ? ( + this.server + '/delegate?' + (type == REQUEST_TYPE_GRPC ? '$_type=GRPC&' : '') + + (StringUtil.isEmpty(this.delegateId, true) ? '' : '$_delegate_id=' + this.delegateId + '&') + '$_delegate_url=' + encodeURIComponent(url) + ) : ( + this.isEncodeEnabled ? encodeURI(url) : url + ) + ), + params: (type == REQUEST_TYPE_PARAM || type == REQUEST_TYPE_FORM ? req : null), + data: (type == REQUEST_TYPE_JSON || type == REQUEST_TYPE_GRPC ? req : (type == REQUEST_TYPE_DATA ? toFormData(req) : null)), + headers: header, //Accept-Encoding(HTTP Header 大小写不敏感,SpringBoot 接收后自动转小写)可能导致 Response 乱码 + withCredentials: true, //Cookie 必须要 type == REQUEST_TYPE_JSON + // crossDomain: true + }) + .then(function (res) { + App.isLoading = false + + res = res || {} + + if (isDelegate) { + var hs = res.headers || {} + var delegateId = hs['Apijson-Delegate-Id'] || hs['apijson-delegate-id'] + if (delegateId != null && delegateId != App.delegateId) { + App.delegateId = delegateId + App.saveCache(App.server, 'delegateId', delegateId) + } + } + + //any one of then callback throw error will cause it calls then(null) + // if ((res.config || {}).method == 'options') { + // return + // } + log('send >> success:\n' + JSON.stringify(res, null, ' ')) + + //未登录,清空缓存 + if (res.data != null && res.data.code == 407) { + // alert('request res.data != null && res.data.code == 407 >> isAdminOperation = ' + isAdminOperation) + if (isAdminOperation) { + // alert('request App.User = {} App.server = ' + App.server) + + App.clearUser() + } + else { + // alert('request App.accounts[App.currentAccountIndex].isLoggedIn = false ') + + if (App.accounts[App.currentAccountIndex] != null) { + App.accounts[App.currentAccountIndex].isLoggedIn = false + } + } + } + + if (callback != null) { + callback(url, res, null) + return + } + App.onResponse(url, res, null) + }) + .catch(function (err) { + log('send >> error:\n' + err) + if (isAdminOperation) { + App.delegateId = null + } + + if (callback != null) { + callback(url, {}, err) + return + } + App.onResponse(url, {}, err) + }) + }, + + + /**请求回调 + */ + onResponse: function (url, res, err) { + if (res == null) { + res = {} + } + log('onResponse url = ' + url + '\nerr = ' + err + '\nres = \n' + JSON.stringify(res)) + if (err != null) { + vOutput.value = "Response:\nurl = " + url + "\nerror = " + err.message; + } + else { + var data = res.data || {} + if (isSingle && data.code == CODE_SUCCESS) { //不格式化错误的结果 + data = JSONResponse.formatObject(data); + } + this.jsoncon = JSON.stringify(data, null, ' '); + this.view = 'code'; + vOutput.value = ''; + + // 会导致断言用了这个 + // if (this.currentRemoteItem == null) { + // this.currentRemoteItem = {} + // } + // if (this.currentRemoteItem.TestRecord == null) { + // this.currentRemoteItem.TestRecord = {} + // } + // this.currentRemoteItem.TestRecord.response = data + } + }, + + + /**处理复制事件 + * @param event + */ + doOnCopy: function(event) { + var target = event.target; + var selectionStart = target.selectionStart; + var selectionEnd = target.selectionEnd; + + if (target == vUrl) { + try { + var contentType = CONTENT_TYPE_MAP[this.type]; + var json = this.getRequest(vInput.value) + var header = this.getHeader(vHeader.value); + var headerStr = ''; + if (header != null) { + for (var k in header) { + var v = header[k]; + headerStr += '\n' + k + ': ' + StringUtil.get(v); + } + } + + console.log('复制时自动转换:\n' + + `Request URL: ` + vUrl.value + ` +Request Method: ` + (this.type == REQUEST_TYPE_PARAM ? 'GET' : 'POST') + (StringUtil.isEmpty(contentType, true) ? '' : ` +Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : headerStr) + + '\n\n' + JSON.stringify(json)); + } catch (e) { + log(e) + } + } + else if (target == vHeader || target == vRandom) { // key: value 转 { "key": value } + if (selectionStart < 0 || selectionStart <= selectionEnd) { + try { + var selection = selectionStart < 0 ? target.value : StringUtil.get(target.value).substring(selectionStart, selectionEnd); + var lines = StringUtil.split(selection, '\n'); + var json = {}; + + for (var i = 0; i < lines.length; i ++) { + var l = StringUtil.trim(lines[i]) || ''; + if (l.startsWith('//')) { + continue; + } + + var ind = l.lastIndexOf(' //'); + l = ind < 0 ? l : StringUtil.trim(l.substring(0, ind)); + + ind = l.indexOf(':'); + if (ind >= 0) { + var left = target == vHeader ? StringUtil.trim(l.substring(0, ind)) : l.substring(0, ind); + json[left] = StringUtil.trim(l.substring(ind + 1)); + } + } + + if (Object.keys(json).length > 0) { + var txt = JSON.stringify(json) + console.log('复制时自动转换:\n' + txt) + navigator.clipboard.writeText(selection + '\n\n' + txt); + alert('复制内容最后拼接了,控制台 Console 也打印了:\n' + txt); + } + } catch (e) { + log(e) + } + } + } + + }, + + /**处理粘贴事件 + * @param event + */ + doOnPaste: function(event) { + var paste = (event.clipboardData || window.clipboardData || navigator.clipboard).getData('text'); + var target = event.target; + var selectionStart = target.selectionStart; + var selectionEnd = target.selectionEnd; + + if (StringUtil.isNotEmpty(paste, true) && (StringUtil.isEmpty(target.value, true) + || selectionStart <= 0 && selectionEnd >= StringUtil.get(target.value).length)) { + if (target == vUrl) { // TODO 把 Chrome 或 Charles 等抓到的 Response Header 和 Content 自动粘贴到 vUrl, vHeader + try { + if (paste.trim().indexOf('\n') > 0) { // 解决正常的 URL 都粘贴不了 + var contentStart = 0; + var lines = StringUtil.split(paste, '\n'); + var header = ''; + + for (var i = 0; i < lines.length; i++) { + var l = StringUtil.trim(lines[i]); + var ind = l.indexOf(':'); + var left = ind < 0 ? '' : StringUtil.trim(l.substring(0, ind)); + + if (/^[a-zA-Z0-9\- ]+$/g.test(left)) { + var lowerKey = left.toLowerCase(); + var value = l.substring(ind + 1).trim(); + + if (lowerKey == 'host') { + this.setBaseUrl(value.endsWith(':443') ? 'https://' + value.substring(0, value.length - ':443'.length) : 'http://' + value); + event.preventDefault(); + } + else if (lowerKey == 'request method') { + value = value.toUpperCase(); + this.type = value == 'GET' ? 'PARAM' : (value == 'POST' ? 'JSON' : value); + event.preventDefault(); + } + else if (lowerKey == 'content-type') { + var type = vType.value != 'JSON' ? null : CONTENT_VALUE_TYPE_MAP[value]; + if (StringUtil.isEmpty(type, true) != true) { + this.type = type; + event.preventDefault(); + } + } + else if (lowerKey == 'request url') { + vUrl.value = value; + event.preventDefault(); + } + else if (StringUtil.isEmpty(lowerKey, true) || lowerKey.startsWith('accept-') + || lowerKey.startsWith('access-control-') || IGNORE_HEADERS.indexOf(lowerKey) >= 0) { + // 忽略 + } + else { + header += '\n' + left + ': ' + StringUtil.trim(l.substring(ind + 1)); + } + + contentStart += lines[i].length + 1; + } + else { + if (ind <= 0 || StringUtil.isEmpty(l) || l.startsWith('HTTP/') || l.startsWith('HTTPS/')) { // HTTP/1.1 200 + contentStart += lines[i].length + 1; + continue; + } + + var ind = l.indexOf(' '); + var m = ind < 0 ? '' : StringUtil.trim(l.substring(0, ind)); + if (APIJSON_METHODS.indexOf(m.toLowerCase()) >= 0) { // POST /gets HTTP/1.1 + contentStart += lines[i].length + 1; + var t = m.toUpperCase() + this.type = t == 'GET' ? 'PARAM' : (t == 'POST' ? 'JSON' : t); + + l = l.substring(ind).trim(); + ind = l.indexOf(' '); + var url = ind < 0 ? l : l.substring(0, ind); + if (url.length > 0 && url != '/') { + vUrl.value = this.getBaseUrl() + (url.startsWith('/') ? url : '/' + url); + } + + event.preventDefault(); + continue; + } + + var content = StringUtil.trim(paste.substring(contentStart)); + var json = null; + try { + json = JSON5.parse(content); // { "a":1, "b": "c" } + } + catch (e) { + log(e) + try { + json = getRequestFromURL('?' + content, true); // a=1&b=c + } catch (e2) { + log(e2) + } + } + + vInput.value = json == null ? '' : JSON.stringify(json, null, ' '); + event.preventDefault(); + break; + } + + } + + if (StringUtil.isEmpty(header, true) != true) { + vHeader.value = StringUtil.trim(header); + event.preventDefault(); + } + } + } + catch (e) { + log(e) + } + } + else if (target == vHeader || target == vRandom) { // { "key": value } 转 key: value + try { + var json = JSON5.parse(paste); + var newStr = ''; + for (var k in json) { + var v = json[k]; + if (v instanceof Object || v instanceof Array) { + v = JSON.stringify(v); + } + newStr += '\n' + k + ': ' + (target != vHeader && typeof v == 'string' ? "'" + v.replaceAll("'", "\\'") + "'" : StringUtil.get(v)); + } + target.value = StringUtil.trim(newStr); + event.preventDefault(); + } + catch (e) { + log(e) + } + } + else if (target == vInput) { // key: value 转 { "key": value } + try { + try { + JSON5.parse(paste); // 正常的 JSON 就不用转了 + } + catch (e) { + var lines = StringUtil.split(paste, '\n'); + var json = {}; + + for (var i = 0; i < lines.length; i++) { + var l = StringUtil.trim(lines[i]) || ''; + if (l.startsWith('//')) { + continue; + } + + var ind = l.lastIndexOf(' //'); + l = ind < 0 ? l : StringUtil.trim(l.substring(0, ind)); + + ind = l.indexOf(':'); + if (ind >= 0) { + var left = target == vHeader ? StringUtil.trim(l.substring(0, ind)) : l.substring(0, ind); + if (left.indexOf('=') >= 0 || left.indexOf('&') >= 0) { + try { + json = getRequestFromURL('?' + paste, true); + if (Object.keys(json).length > 0) { + break; + } + } catch (e2) { + log(e) + } + } + + json[left] = StringUtil.trim(l.substring(ind + 1)); + } + } + + if (Object.keys(json).length <= 0) { + json = getRequestFromURL('?' + paste, true); + } + + if (Object.keys(json).length > 0) { + vInput.value = JSON.stringify(json, null, ' '); + event.preventDefault(); + } + } + } + catch (e) { + log(e) + } + } + } + + }, + + /**处理按键事件 + * @param event + */ + doOnKeyUp: function (event, type, isFilter, item) { + var keyCode = event.keyCode ? event.keyCode : (event.which ? event.which : event.charCode); + + var obj = event.srcElement ? event.srcElement : event.target; + if ($(obj).attr('id') == 'vUrl') { + vUrlComment.value = '' + this.currentDocItem = null + this.currentRemoteItem = null + } + + if (keyCode == 13) { // enter + if (isFilter) { + this.onFilterChange(type) + return + } + + if (type == null) { + this.send(false); + return + } + + if (type == 'random' || type == 'randomSub') { + + var r = item == null ? null : item.Random + if (r == null || r.id == null) { + alert('请选择有效的选项!item.Random.id == null !') + return + } + + //修改 Random 的 count + this.request(true, REQUEST_TYPE_JSON, this.server + '/put', { + Random: { + id: r.id, + count: r.count, + name: r.name + }, + tag: 'Random' + }, {}, function (url, res, err) { + + var isOk = (res.data || {}).code == CODE_SUCCESS + + var msg = isOk ? '' : ('\nmsg: ' + StringUtil.get((res.data || {}).msg)) + if (err != null) { + msg += '\nerr: ' + err.msg + } + alert('修改' + (isOk ? '成功' : '失败') + + '!\ncount: ' + r.count + '\nname: ' + r.name + + msg + ) + + App.isRandomEditable = !isOk + }) + + return + } + + } + else { + if (isFilter) { + return + } + if (type == 'random' || type == 'randomSub') { + this.isRandomEditable = true + return + } + if (type == 'document' || type == 'testCase') { + return + } + + this.urlComment = ''; + this.requestVersion = ''; + this.onChange(true); + } + }, + + pageDown: function(type) { + type = type || '' + var page + switch (type) { + case 'testCase': + page = this.testCasePage + break + case 'random': + page = this.randomPage + break + case 'randomSub': + page = this.randomSubPage + break + default: + page = this.page + break + } + + if (page == null) { + page = 0 + } + + if (page > 0) { + page -- + switch (type) { + case 'testCase': + this.testCasePage = page + break + case 'random': + this.randomPage = page + break + case 'randomSub': + this.randomSubPage = page + break + default: + this.page = page + break + } + + this.onFilterChange(type) + } + }, + pageUp: function(type) { + type = type || '' + switch (type) { + case 'testCase': + this.testCasePage ++ + break + case 'random': + this.randomPage ++ + break + case 'randomSub': + this.randomSubPage ++ + break + default: + this.page ++ + break + } + this.onFilterChange(type) + }, + onFilterChange: function(type) { + type = type || '' + switch (type) { + case 'testCase': + this.saveCache(this.server, 'testCasePage', this.testCasePage) + this.saveCache(this.server, 'testCaseCount', this.testCaseCount) + + this.remotes = null + this.showTestCase(true, false) + break + case 'random': + this.saveCache(this.server, 'randomPage', this.randomPage) + this.saveCache(this.server, 'randomCount', this.randomCount) + + this.randoms = null + this.showRandomList(true, (this.currentRemoteItem || {}).Document, false) + break + case 'randomSub': + this.saveCache(this.server, 'randomSubPage', this.randomSubPage) + this.saveCache(this.server, 'randomSubCount', this.randomSubCount) + + this.randomSubs = null + this.showRandomList(true, (this.currentRemoteItem || {}).Random, true) + break + default: + docObj = null + doc = null + this.saveCache(this.server, 'page', this.page) + this.saveCache(this.server, 'count', this.count) + // this.saveCache(this.server, 'docObj', null) + // this.saveCache(this.server, 'doc', null) + + this.onChange(false) + + //虽然性能更好,但长时间没反应,用户会觉得未生效 + // this.getDoc(function (d) { + // // vOutput.value = 'resolving...'; + // App.setDoc(d) + // App.onChange(false) + // }); + break + } + }, + + /**转为请求代码 + * @param rq + */ + getCode: function (rq) { + var s = '\n\n\n### 请求代码(自动生成) \n'; + switch (this.language) { + case CodeUtil.LANGUAGE_KOTLIN: + s += '\n#### <= Android-Kotlin: 空对象用 HashMap<String, Any>(),空数组用 ArrayList<Any>()\n' + + '```kotlin \n' + + CodeUtil.parseKotlinRequest(null, JSON.parse(rq), 0, isSingle, false, false, this.type, this.getBaseUrl(), '/' + this.getMethod(), this.urlComment) + + '\n ``` \n注:对象 {} 用 mapOf("key": value),数组 [] 用 listOf(value0, value1)\n'; + break; + case CodeUtil.LANGUAGE_JAVA: + s += '\n#### <= Android-Java: 同名变量需要重命名' + + ' \n ```java \n' + + StringUtil.trim(CodeUtil.parseJavaRequest(null, JSON.parse(rq), 0, isSingle, false, false, this.type, '/' + this.getMethod(), this.urlComment)) + + '\n ``` \n注:' + (isSingle ? '用了 APIJSON 的 JSONRequest, JSONResponse 类,也可使用其它类封装,只要 JSON 有序就行\n' : 'LinkedHashMap<>() 可替换为 fastjson 的 JSONObject(true) 等有序JSON构造方法\n'); + + var serverCode = CodeUtil.parseJavaServer(this.type, '/' + this.getMethod(), this.database, this.schema, JSON.parse(rq), isSingle); + if (StringUtil.isEmpty(serverCode, true) != true) { + s += '\n#### <= Server-Java: RESTful 等非 APIJSON 规范的 API' + + ' \n ```java \n' + + serverCode + + '\n ``` \n注:' + (isSingle ? '分页和排序用了 Mybatis-PageHelper,如不需要可在生成代码基础上修改\n' : '使用 SSM(Spring + SpringMVC + Mybatis) 框架 \n'); + } + break; + case CodeUtil.LANGUAGE_C_SHARP: + s += '\n#### <= Unity3D-C\#: 键值对用 {"key", value}' + + '\n ```csharp \n' + + CodeUtil.parseCSharpRequest(null, JSON.parse(rq), 0) + + '\n ``` \n注:对象 {} 用 new JObject{{"key", value}},数组 [] 用 new JArray{value0, value1}\n'; + break; + + case CodeUtil.LANGUAGE_SWIFT: + s += '\n#### <= iOS-Swift: 空对象用 [ : ]' + + '\n ```swift \n' + + CodeUtil.parseSwiftRequest(null, JSON.parse(rq), 0) + + '\n ``` \n注:对象 {} 用 ["key": value],数组 [] 用 [value0, value1]\n'; + break; + case CodeUtil.LANGUAGE_OBJECTIVE_C: + s += '\n#### <= iOS-Objective-C \n ```objective-c \n' + + CodeUtil.parseObjectiveCRequest(null, JSON.parse(rq)) + + '\n ``` \n'; + break; + + case CodeUtil.LANGUAGE_GO: + s += '\n#### <= Web-Go: 对象 key: value 会被强制排序,每个 key: value 最后都要加逗号 ","' + + ' \n ```go \n' + + CodeUtil.parseGoRequest(null, JSON.parse(rq), 0) + + '\n ``` \n注:对象 {} 用 map[string]interface{} {"key": value},数组 [] 用 []interface{} {value0, value1}\n'; + break; + case CodeUtil.LANGUAGE_C_PLUS_PLUS: + s += '\n#### <= Web-C++: 使用 RapidJSON' + + ' \n ```cpp \n' + + StringUtil.trim(CodeUtil.parseCppRequest(null, JSON.parse(rq), 0, isSingle)) + + '\n ``` \n注:std::string 类型值需要判断 RAPIDJSON_HAS_STDSTRING\n'; + break; + + case CodeUtil.LANGUAGE_PHP: + s += '\n#### <= Web-PHP: 空对象用 (object) ' + (isSingle ? '[]' : 'array()') + + ' \n ```php \n' + + CodeUtil.parsePHPRequest(null, JSON.parse(rq), 0, isSingle) + + '\n ``` \n注:对象 {} 用 ' + (isSingle ? '[\'key\' => value]' : 'array("key" => value)') + ',数组 [] 用 ' + (isSingle ? '[value0, value1]\n' : 'array(value0, value1)\n'); + break; + + case CodeUtil.LANGUAGE_PYTHON: + s += '\n#### <= Web-Python: 注释符用 \'\#\'' + + ' \n ```python \n' + + CodeUtil.parsePythonRequest(null, JSON.parse(rq), 0, isSingle, vInput.value) + + '\n ``` \n注:关键词转换 null: None, false: False, true: True'; + break; + + //以下都不需要解析,直接用左侧的 JSON + case CodeUtil.LANGUAGE_TYPE_SCRIPT: + case CodeUtil.LANGUAGE_JAVA_SCRIPT: + //case CodeUtil.LANGUAGE_PYTHON: + s += '\n#### <= Web-JavaScript/TypeScript: 和左边的请求 JSON 一样 \n'; + break; + default: + s += '\n没有生成代码,可能生成代码(封装,解析)的语言配置错误。\n'; + break; + } + + if (((this.User || {}).id || 0) > 0) { + s += '\n\n#### 开放源码 ' + + '\nAPIJSON 接口测试: https://github.com/TommyLemon/APIAuto ' + + '\nAPIJSON 单元测试: https://github.com/TommyLemon/UnitAuto ' + + '\nAPIJSON 中文文档: https://github.com/vincentCheng/apijson-doc ' + + '\nAPIJSON 英文文档: https://github.com/ruoranw/APIJSONdocs ' + + '\nAPIJSON 官方网站: https://github.com/APIJSON/apijson.cn ' + + '\nAPIJSON -Java版: https://github.com/Tencent/APIJSON ' + + '\nAPIJSON - C# 版: https://github.com/liaozb/APIJSON.NET ' + + '\nAPIJSON - Go 版: https://github.com/j2go/apijson-go ' + + '\nAPIJSON - PHP版: https://github.com/kvnZero/hyperf-APIJSON ' + + '\nAPIJSON -Node版: https://github.com/kevinaskin/apijson-node ' + + '\nAPIJSON -Python: https://github.com/zhangchunlin/uliweb-apijson ' + + '\n感谢热心的作者们的贡献,GitHub 右上角点 ⭐Star 支持下他们吧 ^_^'; + } + + return s; + }, + + + /**显示文档 + * @param d + **/ + setDoc: function (d) { + if (d == null) { //解决死循环 || d == '') { + return false; + } + doc = d; + vOutput.value += ( + '\n\n\n## 文档 \n\n 通用文档见 [APIJSON通用文档](https://github.com/Tencent/APIJSON/blob/master/Document.md#3.2) \n### 数据字典\n自动查数据库表和字段属性来生成 \n\n' + d + + '

关于

' + + '

APIAuto-机器学习 HTTP 接口工具' + + '
机器学习零代码测试、生成代码与静态检查、生成文档与光标悬浮注释' + + '
APIAuto(前端网页工具), APIJSON(后端接口服务) 等提供技术支持' + + '
遵循 Apache-2.0 开源协议' + + '
Copyright © 2016-' + new Date().getFullYear() + ' Tommy Lemon' + + '
粤ICP备18005508号-1' + + '



' + ); + + this.view = 'markdown'; + markdownToHTML(vOutput.value); + return true; + }, + + + /** + * 获取文档 + */ + getDoc: function (callback) { + + var count = this.count || 100 //超过就太卡了 + var page = this.page || 0 + + var search = StringUtil.isEmpty(this.search, true) ? null : '%' + StringUtil.trim(this.search) + '%' + this.request(false, REQUEST_TYPE_JSON, this.getBaseUrl() + '/get', { + format: false, + '@database': StringUtil.isEmpty(this.database, true) ? undefined : this.database, + // '@schema': StringUtil.isEmpty(this.schema, true) ? undefined : this.schema, + 'sql@': { + 'from': 'Access', + 'Access': { + '@column': 'name' + } + }, + 'Access[]': { + 'count': count, + 'page': page, + 'Access': { + '@column': 'name,alias,get,head,gets,heads,post,put,delete', + '@order': 'date-,name+', + 'name()': 'getWithDefault(alias,name)', + 'r0()': 'removeKey(alias)', + 'name$': search, + 'alias$': search, + '@combine': search == null ? null : 'name$,alias$', + } + }, + '[]': { + 'count': count, + 'page': page, + 'Table': this.database == 'SQLSERVER' ? null : { + 'table_schema': this.schema, + 'table_type': 'BASE TABLE', + // 'table_name!$': ['\\_%', 'sys\\_%', 'system\\_%'], + 'table_name$': search, + 'table_comment$': this.database == 'POSTGRESQL' ? null : search, + '@combine': search == null || this.database == 'POSTGRESQL' ? null : 'table_name$,table_comment$', + 'table_name{}@': 'sql', + '@order': 'table_name+', //MySQL 8 SELECT `table_name` 返回的仍然是大写的 TABLE_NAME,需要 AS 一下 + '@column': this.database == 'POSTGRESQL' ? 'table_name' : 'table_name:table_name,table_comment:table_comment' + }, + 'PgClass': this.database != 'POSTGRESQL' ? null : { + 'relname@': '/Table/table_name', + //FIXME 多个 schema 有同名表时数据总是取前面的 不属于 pg_class 表 'nspname': this.schema, + '@column': 'oid;obj_description(oid):table_comment' + }, + 'SysTable': this.database != 'SQLSERVER' ? null : { + 'name!$': [ + '\\_%', + 'sys\\_%', + 'system\\_%' + ], + '@order': 'name+', + '@column': 'name:table_name,object_id' + }, + 'ExtendedProperty': this.database != 'SQLSERVER' ? null : { + '@order': 'name+', + 'major_id@': '/SysTable/object_id', + '@column': 'value:table_comment' + }, + '[]': { + 'count': 0, + 'Column': { + 'table_schema': this.schema, + 'table_name@': this.database != 'SQLSERVER' ? '[]/Table/table_name' : "[]/SysTable/table_name", + "@order": this.database != 'SQLSERVER' ? null : "table_name+", + '@column': this.database == 'POSTGRESQL' || this.database == 'SQLSERVER' //MySQL 8 SELECT `column_name` 返回的仍然是大写的 COLUMN_NAME,需要 AS 一下 + ? 'column_name;data_type;numeric_precision,numeric_scale,character_maximum_length' + : 'column_name:column_name,column_type:column_type,is_nullable:is_nullable,column_comment:column_comment' + }, + 'PgAttribute': this.database != 'POSTGRESQL' ? null : { + 'attrelid@': '[]/PgClass/oid', + 'attname@': '/Column/column_name', + 'attnum>': 0, + '@column': 'col_description(attrelid,attnum):column_comment' + }, + 'SysColumn': this.database != 'SQLSERVER' ? null : { + 'object_id@': '[]/SysTable/object_id', + 'name@': '/Column/column_name', + '@order': 'object_id+', + '@column': 'object_id,column_id' + }, + 'ExtendedProperty': this.database != 'SQLSERVER' ? null : { + '@order': 'major_id+', + 'major_id@': '/SysColumn/object_id', + 'minor_id@': '/SysColumn/column_id', + '@column': 'value:column_comment' + } + } + }, + 'Function[]': { + 'count': count, + 'page': page, + 'Function': { + '@order': 'date-,name+', + '@column': 'name,arguments,demo,detail', + 'demo()': 'getFunctionDemo()', + 'detail()': 'getFunctionDetail()', + 'r0()': 'removeKey(name)', + 'r1()': 'removeKey(arguments)', + 'name$': search, + 'detail$': search, + '@combine': search == null ? null : 'name$,detail$', + } + }, + 'Request[]': { + 'count': count, + 'page': page, + 'Request': { + '@order': 'version-,method-', + '@json': 'structure', + 'tag$': search, + // 界面又不显示这个字段,搜出来莫名其妙 'detail$': search, + // '@combine': search == null ? null : 'tag$,detail$', + } + } + }, {}, function (url, res, err) { + if (err != null || res == null || res.data == null) { + log('getDoc err != null || res == null || res.data == null >> return;'); + callback('') + return; + } + +// log('getDoc docRq.responseText = \n' + docRq.responseText); + docObj = res.data || {}; //避免后面又调用 onChange ,onChange 又调用 getDoc 导致死循环 + + //转为文档格式 + var doc = ''; + var item; + + //[] <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + var list = docObj == null ? null : docObj['[]']; + CodeUtil.tableList = list; + if (list != null) { + if (DEBUG) { + log('getDoc [] = \n' + format(JSON.stringify(list))); + } + + var table; + var columnList; + var column; + for (var i = 0; i < list.length; i++) { + item = list[i]; + + //Table + table = item == null ? null : (App.database != 'SQLSERVER' ? item.Table : item.SysTable); + if (table == null) { + continue; + } + if (DEBUG) { + log('getDoc [] for i=' + i + ': table = \n' + format(JSON.stringify(table))); + } + + var table_comment = App.database == 'POSTGRESQL' + ? (item.PgClass || {}).table_comment + : (App.database == 'SQLSERVER' + ? (item.ExtendedProperty || {}).table_comment + : table.table_comment + ); + // item.Table.table_name = table.table_name + // item.Table.table_comment = table_comment + + doc += '### ' + (i + 1) + '. ' + CodeUtil.getModelName(table.table_name) + '\n#### 说明: \n' + + App.toMD(table_comment); + + + //Column[] + doc += '\n\n#### 字段: \n 名称 | 类型 | 最大长度 | 详细说明' + + ' \n -------- | ------------ | ------------ | ------------ '; + + columnList = item['[]']; + if (columnList == null) { + continue; + } + if (DEBUG) { + log('getDoc [] for ' + i + ': columnList = \n' + format(JSON.stringify(columnList))); + } + + var name; + var type; + var length; + for (var j = 0; j < columnList.length; j++) { + column = (columnList[j] || {}).Column; + name = column == null ? null : column.column_name; + if (name == null) { + continue; + } + + column.column_type = CodeUtil.getColumnType(column, App.database); + type = CodeUtil.getType4Language(App.language, column.column_type, false); + length = CodeUtil.getMaxLength(column.column_type); + + if (DEBUG) { + log('getDoc [] for j=' + j + ': column = \n' + format(JSON.stringify(column))); + } + + var o = App.database == 'POSTGRESQL' + ? (columnList[j] || {}).PgAttribute + : (App.database == 'SQLSERVER' + ? (columnList[j] || {}).ExtendedProperty + : column + ); + var column_comment = (o || {}).column_comment + + // column.column_comment = column_comment + doc += '\n' + name + ' | ' + type + ' | ' + length + ' | ' + App.toMD(column_comment); + + } + + doc += '\n\n\n'; + + } + + } + + //[] >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + + + + //Access[] <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + list = docObj == null ? null : docObj['Access[]']; + if (list != null) { + if (DEBUG) { + log('getDoc Access[] = \n' + format(JSON.stringify(list))); + } + + doc += '\n\n\n\n\n\n\n\n\n### 访问权限\n自动查 Access 表写入的数据来生成\n' + + ' \n 表名 | 允许 get
的角色 | 允许 head
的角色 | 允许 gets
的角色 | 允许 heads
的角色 | 允许 post
的角色 | 允许 put
的角色 | 允许 delete
的角色 | 表名' + + ' \n -------- | --------- | --------- | --------- | --------- | --------- | --------- | --------- | -------- '; + + for (var i = 0; i < list.length; i++) { + item = list[i]; + if (item == null) { + continue; + } + if (DEBUG) { + log('getDoc Access[] for i=' + i + ': item = \n' + format(JSON.stringify(item))); + } + + doc += '\n' + (item.name) //右上角设置指定了 Schema + '(' + item.schema + ')') + + ' | ' + JSONResponse.getShowString(JSON.parse(item.get), 2) + + ' | ' + JSONResponse.getShowString(JSON.parse(item.head), 2) + + ' | ' + JSONResponse.getShowString(JSON.parse(item.gets), 2) + + ' | ' + JSONResponse.getShowString(JSON.parse(item.heads), 2) + + ' | ' + JSONResponse.getShowString(JSON.parse(item.post), 1) + + ' | ' + JSONResponse.getShowString(JSON.parse(item.put), 1) + + ' | ' + JSONResponse.getShowString(JSON.parse(item.delete), 1) + + ' | ' + (item.name); //右上角设置指定了 Schema + '(' + item.schema + ')'); + } + + doc += ' \n 表名 | 允许 get
的角色 | 允许 head
的角色 | 允许 gets
的角色 | 允许 heads
的角色 | 允许 post
的角色 | 允许 put
的角色 | 允许 delete
的角色 | 表名' + + doc += '\n' //避免没数据时表格显示没有网格 + } + + //Access[] >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + + + //Function[] <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + list = docObj == null ? null : docObj['Function[]']; + if (list != null) { + if (DEBUG) { + log('getDoc Function[] = \n' + format(JSON.stringify(list))); + } + + doc += '\n\n\n\n\n\n\n\n\n### 远程函数\n自动查 Function 表写入的数据来生成\n' + + ' \n 说明 | 示例' + + ' \n -------- | -------------- '; + + for (var i = 0; i < list.length; i++) { + item = list[i]; + if (item == null) { + continue; + } + if (DEBUG) { + log('getDoc Function[] for i=' + i + ': item = \n' + format(JSON.stringify(item))); + } + + doc += '\n' + item.detail + ' | ' + JSON.stringify(item.demo); + } + + doc += '\n' //避免没数据时表格显示没有网格 + } + + //Function[] >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + + + //Request[] <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + list = docObj == null ? null : docObj['Request[]']; + if (list != null) { + if (DEBUG) { + log('getDoc Request[] = \n' + format(JSON.stringify(list))); + } + + doc += '\n\n\n\n\n\n\n\n\n### 非开放请求\n自动查 Request 表写入的数据来生成\n' + + ' \n 版本 | 方法 | 数据和结构' + + ' \n -------- | ------------ | ------------ | ------------ '; + + for (var i = 0; i < list.length; i++) { + item = list[i]; + if (item == null) { + continue; + } + if (DEBUG) { + log('getDoc Request[] for i=' + i + ': item = \n' + format(JSON.stringify(item))); + } + + doc += '\n' + item.version + ' | ' + item.method + + ' | ' + JSON.stringify(App.getStructure(item.structure, item.tag)); + } + + doc += '\n注: \n1.GET,HEAD方法不受限,可传任何 数据、结构。\n2.可在最外层传版本version来指定使用的版本,不传或 version <= 0 则使用最新版。\n\n\n\n\n\n\n'; + } + + + //Request[] >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + + App.onChange(false); + + + callback(doc); + +// log('getDoc callback(doc); = \n' + doc); + }); + + }, + + // toDoubleJSON: function (json, defaultValue) { + // if (StringUtil.isEmpty(json)) { + // return defaultValue == null ? '{}' : JSON.stringify(defaultValue) + // } + // else if (json.indexOf("'") >= 0) { + // json = json.replace(/'/g, '"'); + // } + // return json; + // }, + + switchQuote: function (before) { + if (before == null) { + return before; + } + + var newBefore = ''; + for (var i = 0; i < before.length; i++) { + var chr = before.substring(i, i + 1); // .charAt(i); + if (chr == '"') { + newBefore += "'"; // chr = "'"; + } + else if (chr == "'") { + newBefore += '"'; // chr = '"'; + } + else { + newBefore += chr; + } + } + return newBefore; + }, + + /**转为Markdown格式 + * @param s + * @return {*} + */ + toMD: function (s) { + if (s == null) { + s = ''; + } + else { + //无效 + s = s.replace(/\|/g, '\|'); + s = s.replace(/\n/g, '
'); + // s = s.replace(/ /g, ' '); + } + + return s; + }, + + /**处理请求结构 + * @param obj + * @param tag + * @return {*} + */ + getStructure: function (obj, tag) { + if (obj == null) { + return null; + } + + log('getStructure tag = ' + tag + '; obj = \n' + format(JSON.stringify(obj))); + + if (obj instanceof Array) { + for (var i = 0; i < obj.length; i++) { + obj[i] = this.getStructure(obj[i]); + } + } + else if (obj instanceof Object) { + var v; + var nk; + for (var k in obj) { + if (k == null || k == '' || k == 'INSERT' || k == 'REMOVE' || k == 'REPLACE' || k == 'UPDATE') { + delete obj[k]; + continue; + } + + v = obj[k]; + if (v == null) { + delete obj[k]; + continue; + } + + if (k == 'DISALLOW') { + nk = '不能传'; + } + else if (k == 'NECESSARY') { + nk = '必须传'; + } + else if (k == 'UNIQUE') { + nk = '不重复'; + } + else if (k == 'VERIFY') { + nk = '满足条件'; + } + else if (k == 'TYPE') { + nk = '满足类型'; + } + else { + nk = null; + } + + if (v instanceof Object) { + v = this.getStructure(v); + } + else if (v === '!') { + v = '非必须传的字段'; + } + + if (nk != null) { + obj[nk] = v; + delete obj[k]; + } + } + + if (tag != null && obj[tag] == null) { //补全省略的Table + var isArrayKey = tag.endsWith(":[]"); //JSONObject.isArrayKey(tag); + var key = isArrayKey ? tag.substring(0, tag.length - 3) : tag; + + if (this.isTableKey(key)) { + if (isArrayKey) { //自动为 tag = Comment:[] 的 { ... } 新增键值对 "Comment[]":[] 为 { "Comment[]":[], ... } + obj[key + "[]"] = []; + } + else { //自动为 tag = Comment 的 { ... } 包一层为 { "Comment": { ... } } + var realObj = {}; + realObj[tag] = obj; + obj = realObj; + } + } + } + + } + + obj.tag = tag; //补全tag + + log('getStructure return obj; = \n' + format(JSON.stringify(obj))); + + return obj; + }, + + /**判断key是否为表名,用CodeUtil里的同名函数会在Safari上报undefined + * @param key + * @return + */ + isTableKey: function (key) { + log('isTableKey typeof key = ' + (typeof key)); + if (key == null) { + return false; + } + return /^[A-Z][A-Za-z0-9_]*$/.test(key); + }, + + log: function (msg) { + // this.log('Main. ' + msg) + }, + + getDoc4TestCase: function () { + var list = this.remotes || [] + var doc = '' + var item + for (var i = 0; i < list.length; i ++) { + item = list[i] == null ? null : list[i].Document + if (item == null || item.name == null) { + continue + } + doc += '\n\n#### ' + (item.version > 0 ? 'V' + item.version : 'V*') + ' ' + item.name + ' ' + item.url + doc += '\n```json\n' + item.request + '\n```\n' + } + return doc + }, + + enableCross: function (enable) { + this.isCrossEnabled = enable + this.crossProcess = enable ? '交叉账号:已开启' : '交叉账号:已关闭' + this.saveCache(this.server, 'isCrossEnabled', enable) + }, + + enableML: function (enable) { + this.isMLEnabled = enable + this.testProcess = enable ? '机器学习:已开启' : '机器学习:已关闭' + this.saveCache(this.server, 'isMLEnabled', enable) + this.remotes = null + this.showTestCase(true, false) + }, + + /**参数注入,动态替换键值对 + * @param show + */ + onClickTestRandom: function () { + this.isRandomTest = true + this.testRandom(! this.isRandomListShow && ! this.isRandomSubListShow, this.isRandomListShow, this.isRandomSubListShow) + }, + testRandom: function (show, testList, testSubList, limit) { + this.isRandomEditable = false + if (testList != true && testSubList != true) { + this.testRandomProcess = '' + this.testRandomWithText(show, null) + } + else { + var baseUrl = StringUtil.trim(this.getBaseUrl()) + if (baseUrl == '') { + alert('请先输入有效的URL!') + return + } + //开放测试 + // if (baseUrl.indexOf('/apijson.cn') >= 0 || baseUrl.indexOf('/39.108.143.172') >= 0) { + // alert('请把URL改成你自己的!\n例如 http://localhost:8080') + // return + // } + // if (baseUrl.indexOf('/apijson.org') >= 0) { + // alert('请把URL改成 http://apijson.cn:8080 或 你自己的!\n例如 http://localhost:8080') + // return + // } + + const list = (testSubList ? this.randomSubs : this.randoms) || [] + var allCount = list.length + doneCount = 0 + + if (allCount <= 0) { + alert('请先获取随机配置\n点击[查看列表]按钮') + return + } + this.testRandomProcess = '正在测试: ' + 0 + '/' + allCount + + if (testSubList) { + this.resetCount(this.currentRandomItem) + } + + var json = this.getRequest(vInput.value, {}) + var url = this.getUrl() + var header = this.getHeader(vHeader.value) + + ORDER_MAP = {} //重置 + + for (var i = 0; i < (limit != null ? limit : list.length); i ++) { //limit限制子项测试个数 + const item = list[i] + const random = item == null ? null : item.Random + if (random == null || random.name == null) { + doneCount ++ + continue + } + this.log('test random = ' + JSON.stringify(random, null, ' ')) + + const index = i + + const itemAllCount = random.count || 0 + allCount += (itemAllCount - 1) + + this.testRandomSingle(show, false, itemAllCount > 1 && ! testSubList, item, this.type, url, json, header, function (url, res, err) { + + doneCount ++ + App.testRandomProcess = doneCount >= allCount ? '' : ('正在测试: ' + doneCount + '/' + allCount) + try { + App.onResponse(url, res, err) + App.log('test App.request >> res.data = ' + JSON.stringify(res.data, null, ' ')) + } catch (e) { + App.log('test App.request >> } catch (e) {\n' + e.message) + } + + App.compareResponse(allCount, list, index, item, res.data, true, App.currentAccountIndex, false, err) + }) + } + } + }, + /**参数注入,动态替换键值对 + * @param show + * @param callback + */ + testRandomSingle: function (show, testList, testSubList, item, type, url, json, header, callback) { + item = item || {} + var random = item.Random = item.Random || {} + var subs = item['[]'] || [] + var existCount = subs.length + subs = existCount <= 0 ? subs : JSON.parse(JSON.stringify(subs)) + + var count = random.count || 0 + var respCount = 0; + + for (var i = 0; i < count; i ++) { + // var constConfig = i < existCount ? ((subs[i] || {}).Random || {}).config : this.getRandomConstConfig(random.config, random.id) //第1遍,把 key : expression 改为 key : value + // var constJson = this.getRandomJSON(JSON.parse(JSON.stringify(json)), constConfig, random.id) //第2遍,用新的 random config 来修改原 json + + const which = i; + var rawConfig = testSubList && i < existCount ? ((subs[i] || {}).Random || {}).config : random.config + this.parseRandom( + JSON.parse(JSON.stringify(json)), rawConfig, random.id + , ! testSubList, testSubList && i >= existCount, testSubList && i >= existCount + , function (randomName, constConfig, constJson) { + + respCount ++; + + if (testSubList) { //在原来已上传的基础上,生成新的 + if (which >= existCount) { + //异步导致顺序错乱 subs.push({ + subs[which] = { + Random: { + id: -i - 1, //表示未上传 + toId: random.id == null ? 1 : random.id, // 1 为了没选择测试用例时避免用 toId 判断子项错误 + userId: random.userId, + documentId: random.documentId, + count: 1, + name: randomName || 'Temp ' + i, + config: constConfig + }, + //不再需要,因为子项里前面一部分就是已上传的,而且这样更准确,交互更直观 + // TestRecord: { //解决子项始终没有对比标准 + // id: 0, //不允许子项撤回 tr.id, //表示未上传 + // userId: random.userId, + // documentId: random.documentId, + // testAccountId: tr.testAccountId, + // randomId: -i - 1, + // response: tr.response, + // standard: tr.standard, + // date: tr.date, + // compare: tr.compare + // } + // }) + }; + } + } + else { + var cb = function (url, res, err) { + if (callback != null) { + callback(url, res, err, random) + } + else { + App.onResponse(url, res, err) + } + }; + + if (show == true) { + vInput.value = JSON.stringify(constJson, null, ' '); + App.send(false, cb); + } + else { + App.request(false, type, url, constJson, header, cb); + } + } + + if (testSubList && respCount >= count) { // && which >= count - 1) { + App.randomSubs = subs + if (App.isRandomListShow == true) { + App.resetCount(item) + item.subs = subs + } + App.testRandom(false, false, true, count) + } + + } + ); + + } //for + + }, + + resetCount: function (randomItem) { + if (randomItem == null) { + this.log('resetCount randomItem == null >> return') + return + } + randomItem.totalCount = 0 + randomItem.whiteCount = 0 + randomItem.greenCount = 0 + randomItem.blueCount = 0 + randomItem.orangeCount = 0 + randomItem.redCount = 0 + }, + + /**参数注入,动态替换键值对 + * @param show + * @param callback + */ + testRandomWithText: function (show, callback) { + try { + var count = this.testRandomCount || 0; + this.isRandomSubListShow = count > 1; + this.testRandomSingle(show, false, this.isRandomSubListShow, { + Random: { + toId: 0, // ((this.currentRandomItem || {}).Random || {}).id || 0, + userId: (this.User || {}).id, + count: count, + name: this.randomTestTitle, + config: vRandom.value + } + }, + this.type, this.getUrl(), this.getRequest(vInput.value, {}), this.getHeader(vHeader.value), callback + ) + } + catch (e) { + log(e) + vSend.disabled = true + + this.view = 'error' + this.error = { + msg: e.message + } + + this.isRandomShow = true + vRandom.select() + } + }, + + /** + * 与 getRandomJSON 合并,返回一个 + * { + * name: 'long 1, long 2', // 自动按 type0 value0, type1, value1 格式 + * config: {}, //const config + * json: {} //const json + * } + */ + /**参数注入,动态替换键值对 + * @param show + * @param callback + */ + parseRandom: function (json, config, randomId, generateJSON, generateConfig, generateName, callback) { + var lines = config == null ? null : config.trim().split('\n') + if (lines == null || lines.length <= 0) { + // return null; + callback(null, null, null); + return + } + json = json || {}; + + baseUrl = this.getBaseUrl(); + + var reqCount = lines.length; //有无效的行 lines.length; //等待次数 + var respCount = 0; + + randomId = randomId || 0; + var randomNameKeys = [] + var constConfigLines = [] //TODO 改为 [{ "rawPath": "User/id", "replacePath": "User/id@", "replaceValue": "RANDOM_INT(1, 10)", "isExpression": true }] ? + + // alert('< json = ' + JSON.stringify(json, null, ' ')) + + for (let i = 0; i < lines.length; i ++) { + const which = i; + const lineItem = lines[i] || ''; + + // remove comment // 解决整体 trim 后第一行 // 被当成正常的 key 路径而不是注释 + const commentIndex = StringUtil.trim(lineItem).startsWith('//') ? 0 : lineItem.lastIndexOf(' //'); // -1; // eval 本身支持注释 eval('1 // test') = 1 lineItem.indexOf(' //'); + const line = commentIndex < 0 ? lineItem : lineItem.substring(0, commentIndex).trim(); + + if (line.length <= 0) { + respCount ++; + if (i >= lines.length - 1 && respCount >= reqCount) { + callback(randomNameKeys.join(', '), constConfigLines.join('\n'), json); + } + continue; + } + + // path User/id key id@ + const index = line.indexOf(': '); //APIJSON Table:alias 前面不会有空格 //致后面就接 { 'a': 1} 报错 Unexpected token ':' lastIndexOf(': '); // indexOf(': '); 可能会有 Comment:to + const p_k = line.substring(0, index); + const bi = -1; //没必要支持,用 before: undefined, after: .. 同样支持替换,反而这样导致不兼容包含空格的 key p_k.indexOf(' '); + const path = bi < 0 ? p_k : p_k.substring(0, bi); // User/id + + const pathKeys = path.split('/') + if (pathKeys == null || pathKeys.length <= 0) { + throw new Error('参数注入 第 ' + (i + 1) + ' 行格式错误!\n字符 ' + path + ' 不符合 JSON 路径的格式 key0/key1/../targetKey !' + + '\n每个随机变量配置都必须按照\n key0/key1/../targetKey replaceKey: value // 注释\n的格式!' + + '\n注意冒号 ": " 左边 0 空格,右边 1 空格!其中 replaceKey 可省略。' + + '\nkey: {} 中最外层常量对象 {} 必须用括号包裹为 ({}),也就是 key: ({}) 这种格式!' + + '\nkey: 多行代码 必须用 function f() { var a = 1; return a; } f() 这种一行代码格式!'); + } + + const lastKeyInPath = pathKeys[pathKeys.length - 1] + const customizeKey = bi > 0; + const key = customizeKey ? p_k.substring(bi + 1) : lastKeyInPath; + if (key == null || key.trim().length <= 0) { + throw new Error('参数注入 第 ' + (i + 1) + ' 行格式错误!\n字符 ' + key + ' 不是合法的 JSON key!' + + '\n每个随机变量配置都必须按照\n key0/key1/../targetKey replaceKey: value // 注释\n的格式!' + + '\n注意冒号 ": " 左边 0 空格,右边 1 空格!其中 replaceKey 可省略。' + + '\nkey: {} 中最外层常量对象 {} 必须用括号包裹为 ({}),也就是 key: ({}) 这种格式!' + + '\nkey: 多行代码 必须用 function f() { var a = 1; return a; } f() 这种一行代码格式!'); + } + + // value RANDOM_DB + const value = line.substring(index + ': '.length); + + var invoke = function (val, which, p_k, pathKeys, key, lastKeyInPath) { + try { + if (generateConfig) { + var configVal; + if (val instanceof Object) { + configVal = JSON.stringify(val); + } + else if (typeof val == 'string') { + configVal = '"' + val + '"'; + } + else { + configVal = val + } + constConfigLines[which] = p_k + ': ' + configVal; + } + + if (generateName) { + var valStr; + if (val instanceof Array) { + valStr = val.length <= 0 ? '[]' : '[..' + val.length + '..]'; + } + else if (val instanceof Object) { + var kl = Object.keys(val).length + valStr = kl <= 0 ? '{}' : '{..' + kl + '..}'; + } + else if (typeof val == 'boolean') { + valStr = '' + val; + } + else { + valStr = new String(val); + if (valStr.length > 13) { + valStr = valStr.substring(0, 5) + '...'; + } + } + randomNameKeys[which] = valStr; + } + + if (generateJSON) { + //先按照单行简单实现 + //替换 JSON 里的键值对 key: value + var parent = json; + var current = null; + for (var j = 0; j < pathKeys.length - 1; j ++) { + current = parent[pathKeys[j]] + if (current == null) { + current = parent[pathKeys[j]] = {} + } + if (parent instanceof Object == false) { + throw new Error('参数注入 第 ' + (i + 1) + ' 行格式错误!路径 ' + path + ' 中' + + ' pathKeys[' + j + '] = ' + pathKeys[j] + ' 在实际请求 JSON 内对应的值不是对象 {} 或 数组 [] !'); + } + parent = current; + } + + if (current == null) { + current = json; + } + // alert('< current = ' + JSON.stringify(current, null, ' ')) + + if (key != lastKeyInPath || current.hasOwnProperty(key) == false) { + delete current[lastKeyInPath]; + } + + current[key] = val; + } + + } + catch (e) { + throw new Error('第 ' + (which + 1) + ' 行随机配置 key: value 后的 value 不合法! \nerr: ' + e.message) + } + + respCount ++; + if (respCount >= reqCount) { + callback(randomNameKeys.join(', '), constConfigLines.join('\n'), json); + } + }; + + + const start = value.indexOf('('); + const end = value.lastIndexOf(')'); + + var request4Db = function(tableName, which, p_k, pathKeys, key, lastKeyInPath, isRandom, isDesc, step) { + // const tableName = JSONResponse.getTableName(pathKeys[pathKeys.length - 2]); + vOutput.value = 'requesting value for ' + tableName + '/' + key + ' from database...'; + + const args = StringUtil.split(value.substring(start + 1, end)) || []; + var min = StringUtil.trim(args[0]); + var max = StringUtil.trim(args[1]); + var table = StringUtil.trim(args[2]) || ''; + var column = StringUtil.trim(args[3]) || ''; + + min = min == '' || min == 'null' || min == 'undefined' ? null : +min; + max = max == '' || max == 'null' || max == 'undefined' ? null : +max; + + if ((table.startsWith('"') && table.endsWith('"')) || (table.startsWith("'") && table.endsWith("'"))) { + table = table.substring(1, table.length - 1); + } + if ((column.startsWith('"') && column.endsWith('"')) || (column.startsWith("'") && column.endsWith("'"))) { + column = column.substring(1, column.length - 1); + } + + const finalTableName = StringUtil.isEmpty(table, true) ? tableName : table; + const finalColumnName = StringUtil.isEmpty(column, true) ? lastKeyInPath : column; + + const tableReq = { + '@column': isRandom ? finalColumnName : ('DISTINCT ' + finalColumnName), + '@order': isRandom ? 'rand()' : (finalColumnName + (isDesc ? '-' : '+')) + }; + tableReq[finalColumnName + '>='] = min; + tableReq[finalColumnName + '<='] = max; + + const req = {}; + const listName = isRandom ? null : finalTableName + '-' + finalColumnName + '[]'; + const orderIndex = isRandom ? null : getOrderIndex(randomId, line, null) + + if (isRandom) { + req[finalTableName] = tableReq; + } + else { + // 从数据库获取时不考虑边界,不会在越界后自动循环 + var listReq = { + count: 1, // count <= 100 ? count : 0, + page: (step*orderIndex) % 100 //暂时先这样,APIJSON 应该改为 count*page <= 10000 //FIXME 上限 100 怎么破,lastKeyInPath 未必是 id + }; + listReq[finalTableName] = tableReq; + req[listName] = listReq; + } + + // reqCount ++; + App.request(true, REQUEST_TYPE_JSON, baseUrl + '/get', req, {}, function (url, res, err) { + // respCount ++; + try { + App.onResponse(url, res, err) + } catch (e) {} + + var data = (res || {}).data || {} + if (data.code != CODE_SUCCESS) { + respCount = -reqCount; + vOutput.value = '参数注入 为第 ' + (which + 1) + ' 行\n ' + p_k + ' \n获取数据库数据 异常:\n' + data.msg; + alert(StringUtil.get(vOutput.value)); + return + // throw new Error('参数注入 为\n ' + tableName + '/' + key + ' \n获取数据库数据 异常:\n' + data.msg) + } + + if (isRandom) { + invoke((data[finalTableName] || {})[finalColumnName], which, p_k, pathKeys, key, lastKeyInPath); + } + else { + var val = (data[listName] || [])[0]; + //越界,重新获取 + if (val == null && orderIndex > 0 && ORDER_MAP[randomId] != null && ORDER_MAP[randomId][line] != null) { + ORDER_MAP[randomId][line] = null; //重置,避免还是在原来基础上叠加 + request4Db(JSONResponse.getTableName(pathKeys[pathKeys.length - 2]), which, p_k, pathKeys, key, lastKeyInPath, false, isDesc, step); + } + else { + invoke(val, which, p_k, pathKeys, key, lastKeyInPath); + } + } + + // var list = data[listName] || []; + //代码变化会导致缓存失效,而且不好判断,数据量大会导致页面很卡 ORDER_MAP[randomId][line].list = list; + // + // if (step == null) { + // invoke('randomIn(' + list.join() + ')'); + // } + // else { + // invoke('orderIn(' + isDesc + ', ' + step*getOrderIndex(randomId, line, list.length) + list.join() + ')'); + // } + + }) + }; + + + + //支持 1, "a" 这种原始值 + // if (start < 0 || end <= start) { //(1) 表示原始值 start*end <= 0 || start >= end) { + // throw new Error('参数注入 第 ' + (i + 1) + ' 行格式错误!字符 ' + value + ' 不是合法的随机函数!'); + // } + + var toEval = value; + if (start > 0 && end > start) { + + var funWithOrder = value.substring(0, start); + var splitIndex = funWithOrder.indexOf('+'); + + var isDesc = false; + if (splitIndex < 0) { // -(1+2) 这种是表达式,不能作为函数 splitIndex <= 0) { + splitIndex = funWithOrder.indexOf('-'); + isDesc = splitIndex > 0; + } + + var fun = splitIndex < 0 ? funWithOrder : funWithOrder.substring(0, splitIndex); + + if ([ORDER_DB, ORDER_IN, ORDER_INT].indexOf(fun) >= 0) { //顺序函数 + var stepStr = splitIndex < 0 ? null : funWithOrder.substring(splitIndex + 1, funWithOrder.length); + var step = stepStr == null || stepStr.length <= 0 ? 1 : +stepStr; //都会自动忽略空格 Number(stepStr); //Number.parseInt(stepStr); //+stepStr; + + if (Number.isSafeInteger(step) != true || step <= 0 + || (StringUtil.isEmpty(stepStr, false) != true && StringUtil.isNumber(stepStr) != true) + ) { + throw new Error('参数注入 第 ' + (i + 1) + ' 行格式错误!路径 ' + path + ' 中字符 ' + stepStr + ' 不符合跨步 step 格式!' + + '\n顺序整数 和 顺序取值 可以通过以下格式配置 升降序 和 跨步:' + + '\n ODER_REAL+step(arg0, arg1...)\n ODER_REAL-step(arg0, arg1...)' + + '\n ODER_INT+step(arg0, arg1...)\n ODER_INT-step(arg0, arg1...)' + + '\n ODER_IN+step(start, end)\n ODER_IN-step(start, end)' + + '\n其中:\n + 为升序,后面没有 step 时可省略;\n - 为降序,不可省略;' + '\n step 为跨步值,类型为 正整数,默认为 1,可省略。' + + '\n+,-,step 前后都不能有空格等其它字符!'); + } + + if (fun == ORDER_DB) { + request4Db(JSONResponse.getTableName(pathKeys[pathKeys.length - 2]), which, p_k, pathKeys, key, lastKeyInPath, false, isDesc, step); //request4Db(key + (isDesc ? '-' : '+'), step); + continue; + } + + toEval = (fun == ORDER_IN ? 'orderIn' : 'orderInt') + + '(' + isDesc + ', ' + step*getOrderIndex( + randomId, line + , fun == ORDER_INT ? 0 : StringUtil.split(value.substring(start + 1, end)).length + ) + ', ' + value.substring(start + 1); + } + else { //随机函数 + fun = funWithOrder; //还原,其它函数不支持 升降序和跨步! + + if (fun == RANDOM_DB) { + request4Db(JSONResponse.getTableName(pathKeys[pathKeys.length - 2]), which, p_k, pathKeys, key, lastKeyInPath, true); //'random()'); + continue; + } + + if (fun == RANDOM_IN) { + toEval = 'randomIn' + value.substring(start); + } + else if (fun == RANDOM_INT) { + toEval = 'randomInt' + value.substring(start); + } + else if (fun == RANDOM_NUM) { + toEval = 'randomNum' + value.substring(start); + } + else if (fun == RANDOM_STR) { + toEval = 'randomStr' + value.substring(start); + } + + } + + } + + invoke(eval(toEval), which, p_k, pathKeys, key, lastKeyInPath); + + // alert('> current = ' + JSON.stringify(current, null, ' ')) + } + + }, + + onClickSend: function () { + this.isRandomTest = false + this.send(false) + }, + onClickTest: function () { + this.isRandomTest = false + this.test(false, this.isCrossEnabled ? -1 : this.currentAccountIndex) + }, + /**回归测试 + * 原理: + 1.遍历所有上传过的测试用例(URL+请求JSON) + 2.逐个发送请求 + 3.对比同一用例的先后两次请求结果,如果不一致,就在列表中标记对应的用例(× 蓝黄红色下载(点击下载两个文件) √)。 + 4.如果这次请求结果正确,就把请求结果保存到和公司开发环境服务器的APIJSON Server,并取消标记 + + compare: 新的请求与上次请求的对比结果 + 0-相同,无颜色; + 1-对象新增字段或数组新增值,绿色; + 2-值改变,蓝色; + 3-对象缺少字段/整数变小数,黄色; + 4-code/值类型 改变,红色; + */ + test: function (isRandom, accountIndex) { + var accounts = this.accounts || [] + // alert('test accountIndex = ' + accountIndex) + var isCrossEnabled = this.isCrossEnabled + if (accountIndex == null) { + accountIndex = -1 //isCrossEnabled ? -1 : 0 + } + if (isCrossEnabled) { + var isCrossDone = accountIndex >= accounts.length + this.crossProcess = isCrossDone ? (isCrossEnabled ? '交叉账号:已开启' : '交叉账号:已关闭') : ('交叉账号: ' + (accountIndex + 1) + '/' + accounts.length) + if (isCrossDone) { + alert('已完成账号交叉测试: 退出登录状态 和 每个账号登录状态') + return + } + } + + var baseUrl = StringUtil.trim(this.getBaseUrl()) + if (baseUrl == '') { + alert('请先输入有效的URL!') + return + } + //开放测试 + // if (baseUrl.indexOf('/apijson.cn') >= 0 || baseUrl.indexOf('/39.108.143.172') >= 0) { + // alert('请把URL改成你自己的!\n例如 http://localhost:8080') + // return + // } + // if (baseUrl.indexOf('/apijson.org') >= 0) { + // alert('请把URL改成 http://apijson.cn:8080 或 你自己的!\n例如 http://localhost:8080') + // return + // } + + const list = this.remotes || [] + const allCount = list.length + doneCount = 0 + + if (allCount <= 0) { + alert('请先获取测试用例文档\n点击[查看共享]图标按钮') + return + } + + if (isCrossEnabled) { + if (accountIndex < 0 && accounts[this.currentAccountIndex] != null) { //退出登录已登录的账号 + accounts[this.currentAccountIndex].isLoggedIn = true + } + var index = accountIndex < 0 ? this.currentAccountIndex : accountIndex + this.onClickAccount(index, accounts[index], function (isLoggedIn, index, err) { + // if (index >= 0 && isLoggedIn == false) { + // alert('第 ' + index + ' 个账号登录失败!' + (err == null ? '' : err.message)) + // App.test(isRandom, accountIndex + 1) + // return + // } + App.showTestCase(true, false) + App.startTest(list, allCount, isRandom, accountIndex) + }) + } + else { + this.startTest(list, allCount, isRandom, accountIndex) + } + }, + + startTest: function (list, allCount, isRandom, accountIndex) { + this.testProcess = '正在测试: ' + 0 + '/' + allCount + + for (var i = 0; i < allCount; i++) { + const item = list[i] + const document = item == null ? null : item.Document + if (document == null || document.name == null) { + doneCount++ + continue + } + if (document.url == '/login' || document.url == '/logout') { //login会导致登录用户改变为默认的但UI上还显示原来的,单独测试OWNER权限时能通过很困惑 + this.log('test document.url == "/login" || document.url == "/logout" >> continue') + doneCount++ + continue + } + this.log('test document = ' + JSON.stringify(document, null, ' ')) + + const index = i + + var header = null + try { + header = this.getHeader(document.header) + } catch (e) { + this.log('test for ' + i + ' >> try { header = this.getHeader(document.header) } catch (e) { \n' + e.message) + } + + this.request(false, document.type, baseUrl + document.url, this.getRequest(document.request, null, true), header, function (url, res, err) { + + try { + App.onResponse(url, res, err) + App.log('test App.request >> res.data = ' + JSON.stringify(res.data, null, ' ')) + } catch (e) { + App.log('test App.request >> } catch (e) {\n' + e.message) + } + + App.compareResponse(allCount, list, index, item, res.data, isRandom, accountIndex, false, err) + }) + } + + }, + + compareResponse: function (allCount, list, index, item, response, isRandom, accountIndex, justRecoverTest, err, ignoreTrend) { + var it = item || {} //请求异步 + var d = (isRandom ? this.currentRemoteItem.Document : it.Document) || {} //请求异步 + var r = isRandom ? it.Random : null //请求异步 + var tr = it.TestRecord || {} //请求异步 + + var bdt = tr.duration || 0 + it.durationBeforeShowStr = bdt <= 0 ? '' : (bdt < 1000 ? bdt + 'ms' : (bdt < 1000*60 ? (bdt/1000).toFixed(1) + 's' : (bdt <= 1000*60*60 ? (bdt/1000/60).toFixed(1) + 'm' : '>1h'))) + try { + var durationInfo = response['time:start|duration|end|parse|sql'] + it.durationInfo = durationInfo + var di = durationInfo.substring(durationInfo.indexOf('\|') + 1) + it.duration = di.substring(0, di.indexOf('\|') || di.length) || 0 + var dt = + it.duration + it.duration = dt + it.durationShowStr = dt <= 0 ? '' : (dt < 1000 ? dt + 'ms' : (dt < 1000*60 ? (dt/1000).toFixed(1) + 's' : (dt <= 1000*60*60 ? (dt/1000/60).toFixed(1) + 'm' : '>1h'))) + var min = tr.minDuration || 20 + var max = tr.maxDuration || 200 + it.durationColor = dt < min ? 'green' : (dt > 2*max ? 'red' : (dt > max + min ? 'orange' : (dt > max ? 'blue' : 'black'))) + it.durationHint = dt < min ? '很快:比以往 [' + min + 'ms, ' + max + 'ms] 最快还更快' : (dt > 2*max ? '非常慢:比以往 [' + min + 'ms, ' + max + 'ms] 最慢的两倍还更慢' + : (dt > max + min ? '比较慢:比以往 [' + min + 'ms, ' + max + 'ms] 最快与最慢之和(平均值两倍)还更慢' + : (dt > max ? '有点慢:比以往 [' + min + 'ms, ' + max + 'ms] 最慢还更慢' : '正常:在以往 [' + min + 'ms, ' + max + 'ms] 最快和最慢之间'))) + } + catch (e) { + log(e) + it.durationShowStr = it.durationShowStr || it.duration + it.durationHint = it.durationHint || '最外层缺少字段 "time:start|duration|end|parse|sql": "1613039123780|10|1613039123790|1|9",无法对比耗时' + } + + if (err != null) { + tr.compare = { + code: JSONResponse.COMPARE_ERROR, //请求出错 + msg: '请求出错!', + path: err.message + '\n\n' + } + } + else { + var standardKey = this.isMLEnabled != true ? 'response' : 'standard' + var standard = StringUtil.isEmpty(tr[standardKey], true) ? null : JSON.parse(tr[standardKey]) + tr.compare = JSONResponse.compareResponse(standard, this.removeDebugInfo(response) || {}, '', this.isMLEnabled, null, null, ignoreTrend) || {} + tr.compare.duration = it.durationHint + } + + this.onTestResponse(allCount, list, index, it, d, r, tr, response, tr.compare || {}, isRandom, accountIndex, justRecoverTest); + }, + + onTestResponse: function(allCount, list, index, it, d, r, tr, response, cmp, isRandom, accountIndex, justRecoverTest) { + tr = tr || {} + tr.compare = cmp; + + it = it || {} + it.compareType = tr.compare.code; + it.hintMessage = tr.compare.path + ' ' + tr.compare.msg; + switch (it.compareType) { + case JSONResponse.COMPARE_ERROR: + it.compareColor = 'red' + it.compareMessage = '请求出错!' + break; + case JSONResponse.COMPARE_NO_STANDARD: + it.compareColor = 'green' + it.compareMessage = '确认正确后点击[对的,纠正]' + break; + case JSONResponse.COMPARE_KEY_MORE: + it.compareColor = 'green' + it.compareMessage = '新增字段/新增值 等' + break; + case JSONResponse.COMPARE_VALUE_CHANGE: + it.compareColor = 'blue' + it.compareMessage = '值改变 等' + break; + case JSONResponse.COMPARE_KEY_LESS: + it.compareColor = 'orange' + it.compareMessage = '缺少字段/整数变小数 等' + break; + case JSONResponse.COMPARE_TYPE_CHANGE: + it.compareColor = 'red' + it.compareMessage = '状态码/异常/值类型 改变等' + break; + default: + it.compareColor = 'white' + it.compareMessage = '查看结果' + break; + } + + if (isRandom) { + r = r || {} + it.Random = r + + this.updateToRandomSummary(it, 1) + } + else { + it.Document = d + } + it.TestRecord = tr + + Vue.set(list, index, it) + + if (justRecoverTest) { + return + } + + doneCount ++ + this.testProcess = doneCount >= allCount ? (this.isMLEnabled ? '机器学习:已开启' : '机器学习:已关闭') : '正在测试: ' + doneCount + '/' + allCount + + this.log('doneCount = ' + doneCount + '; d.name = ' + (isRandom ? r.name : d.name) + '; it.compareType = ' + it.compareType) + + var documentId = isRandom ? r.documentId : d.id + if (this.tests == null) { + this.tests = {} + } + if (this.tests[String(accountIndex)] == null) { + this.tests[String(accountIndex)] = {} + } + + var tests = this.tests[String(accountIndex)] || {} + var t = tests[documentId] + if (t == null) { + t = tests[documentId] = {} + } + t[isRandom ? (r.id > 0 ? r.id : (r.toId + '' + r.id)) : 0] = response + + this.tests[String(accountIndex)] = tests + this.log('tests = ' + JSON.stringify(tests, null, ' ')) + // this.showTestCase(true) + + if (doneCount >= allCount && this.isCrossEnabled && isRandom != true) { + // alert('onTestResponse accountIndex = ' + accountIndex) + //TODO 自动给非 红色 报错的接口跑参数注入 + + this.test(false, accountIndex + 1) + } + }, + + //更新父级总览数据 + updateToRandomSummary: function (item, change) { + var random = item == null || change == null ? null : item.Random + var toId = random == null ? null : random.toId + if (toId != null && toId > 0) { + + for (var i in this.randoms) { + + var toIt = this.randoms[i] + if (toIt != null && toIt.Random != null && toIt.Random.id == toId) { + + var toRandom = toIt.Random + var id = toRandom == null ? 0 : toRandom.id + var count = id == null || id <= 0 ? 0 : toRandom.count + if (count != null && count > 1) { + var key = item.compareColor + 'Count' + if (toIt[key] == null) { + toIt[key] = 0 + } + toIt[key] += change + if (toIt[key] < 0) { + toIt[key] = 0 + } + + if (toIt.totalCount == null) { + toIt.totalCount = 0 + } + toIt.totalCount += change + if (toIt.totalCount < 0) { + toIt.totalCount = 0 + } + } + + Vue.set(this.randoms, i, toIt) + + break; + } + + } + } + }, + + /**移除调试字段 + * @param obj + */ + removeDebugInfo: function (obj) { + if (obj != null) { + delete obj["debug:info|help"] + delete obj["sql:generate|cache|execute|maxExecute"] + delete obj["depth:count|max"] + delete obj["time:start|duration|end"] + delete obj["time:start|duration|end|parse|sql"] + // 保留 delete obj["throw"] + // 保留 delete obj["trace:throw"] + delete obj["trace:stack"] + delete obj["stack"] + } + return obj + }, + + /** + * @param index + * @param item + */ + downloadTest: function (index, item, isRandom) { + item = item || {} + var document; + if (isRandom) { + document = this.currentRemoteItem || {} + } + else { + document = item.Document = item.Document || {} + } + var random = isRandom ? item.Random : null + var testRecord = item.TestRecord = item.TestRecord || {} + + saveTextAs( + '# APIJSON自动化回归测试-前\n主页: https://github.com/Tencent/APIJSON' + + '\n\n接口名称: \n' + (document.version > 0 ? 'V' + document.version : 'V*') + ' ' + document.name + + '\n返回结果: \n' + JSON.stringify(JSON.parse(testRecord.response || '{}'), null, ' ') + , '测试:' + document.name + '-前.txt' + ) + + /** + * 浏览器不允许连续下载,saveTextAs也没有回调。 + * 在第一个文本里加上第二个文本的信息? + * beyond compare会把第一个文件的后面一段与第二个文件匹配, + * 导致必须先删除第一个文件内的后面与第二个文件重复的一段,再重新对比。 + */ + setTimeout(function () { + var tests = App.tests[String(App.currentAccountIndex)] || {} + saveTextAs( + '# APIJSON自动化回归测试-后\n主页: https://github.com/Tencent/APIJSON' + + '\n\n接口名称: \n' + (document.version > 0 ? 'V' + document.version : 'V*') + ' ' + document.name + + '\n返回结果: \n' + JSON.stringify(tests[document.id][isRandom ? random.id : 0] || {}, null, ' ') + , '测试:' + document.name + '-后.txt' + ) + + + if (StringUtil.isEmpty(testRecord.standard, true) == false) { + setTimeout(function () { + saveTextAs( + '# APIJSON自动化回归测试-标准\n主页: https://github.com/Tencent/APIJSON' + + '\n\n接口名称: \n' + (document.version > 0 ? 'V' + document.version : 'V*') + ' ' + document.name + + '\n测试结果: \n' + JSON.stringify(testRecord.compare || '{}', null, ' ') + + '\n测试标准: \n' + JSON.stringify(JSON.parse(testRecord.standard || '{}'), null, ' ') + , '测试:' + document.name + '-标准.txt' + ) + }, 5000) + } + + }, 5000) + + }, + + /** + * @param index + * @param item + */ + handleTest: function (right, index, item, isRandom, isDuration) { + item = item || {} + var random = item.Random = item.Random || {} + var document; + if (isRandom) { + if ((random.count || 0) > 1) { + this.currentRandomIndex = index + // this.currentRandomSubIndex = -1 + this.restoreRandom(index, item) + this.randomSubs = (item.subs || item['[]']) || [] + this.isRandomSubListShow = true + return + } + + this.currentRandomSubIndex = index + document = this.currentRemoteItem || {} + } + else { + this.currentDocIndex = index + this.currentRemoteItem = item + // this.currentRandomIndex = -1 + // this.currentRandomSubIndex = -1 + document = item.Document = item.Document || {} + } + var testRecord = item.TestRecord = item.TestRecord || {} + + var tests = this.tests[String(this.currentAccountIndex)] || {} + var currentResponse = (tests[isRandom ? random.documentId : document.id] || {})[ + isRandom ? (random.id > 0 ? random.id : (random.toId + '' + random.id)) : 0 + ] || {} + + const list = isRandom ? (random.toId == null || random.toId <= 0 ? this.randoms : this.randomSubs) : this.testCases + + var isBefore = item.showType == 'before' + if (right != true) { + item.showType = isBefore ? 'after' : 'before' + Vue.set(list, index, item); + + var res = isBefore ? JSON.stringify(currentResponse) : testRecord.response + + this.view = 'code' + this.jsoncon = res || '' + } + else { + var url + + if (isBefore) { //撤回原来错误提交的校验标准 + if (isDuration) { + alert('撤回上次的耗时需要删除上次的对比标准,请点左边 [错的,撤回] 按钮') + return + } + + url = this.server + '/delete' + const req = { + TestRecord: { + id: testRecord.id, //TODO 权限问题? item.userId, + }, + tag: 'TestRecord' + } + + this.request(true, REQUEST_TYPE_JSON, url, req, {}, function (url, res, err) { + App.onResponse(url, res, err) + + var data = res.data || {} + if (data.code != CODE_SUCCESS && testRecord!= null && testRecord.id != null) { + alert('撤回最新的校验标准 异常:\n' + data.msg) + return + } + + if (isRandom) { + App.updateToRandomSummary(item, -1) + } + + if (isDuration) { + item.durationColor = 'black' + item.durationHint = '正常:在以往最快和最慢之间' + } + else { + item.compareType = JSONResponse.COMPARE_NO_STANDARD + item.compareMessage = '查看结果' + item.compareColor = 'white' + item.hintMessage = '没有校验标准!' + item.TestRecord = null + } + + App.updateTestRecord(0, list, index, item, currentResponse, isRandom, App.currentAccountIndex, true) + }) + } + else { //上传新的校验标准 + // if (isRandom && random.id <= 0) { + // alert('请先上传这个配置!') + // App.currentRandomItem = random + // App.showExport(true, false, true) + // return + // } + var isML = this.isMLEnabled; // 异常分支不合并内容,只记录 code, throw, msg 等关键信息 + + var standard + var stddObj + + var minDuration = testRecord.minDuration + var maxDuration = testRecord.maxDuration + if (isDuration) { + if (item.duration == null) { // 没有获取到 + alert('最外层缺少字段 "time:start|duration|end|parse|sql": "1613039123780|10|1613039123790|1|9",无法对比耗时!') + return + } + else if (maxDuration == null && minDuration == null) { + maxDuration = item.duration + minDuration = Math.round(maxDuration*0.8) + } + else if (maxDuration == null && minDuration != null) { + maxDuration = Math.max(minDuration, item.duration) + testRecord.minDuration = Math.min(minDuration, item.duration) + } + else if (minDuration == null && maxDuration != null) { + minDuration = Math.min(maxDuration, item.duration) + testRecord.maxDuration = Math.max(maxDuration, item.duration) + } + else if (maxDuration > 0 && maxDuration < item.duration) { + maxDuration = item.duration + } + else if (minDuration > 0 && minDuration > item.duration) { + minDuration = item.duration + } + else { // 已经在正常范围中,不需要纠错 + alert('耗时已经在正常范围中,不需要纠错!') + return + } + } + else { + standard = (StringUtil.isEmpty(testRecord.standard, true) ? null : JSON.parse(testRecord.standard)) || {}; + + var code = currentResponse.code; + var thrw = currentResponse.throw; + var msg = currentResponse.msg; + + var hasCode = standard.code != null; + var isCodeChange = standard.code != code; + var exceptions = standard.exceptions || []; + + delete currentResponse.code; //code必须一致 + delete currentResponse.throw; //throw必须一致 + + var find = false; + if (isCodeChange && hasCode) { // 走异常分支 + for (var i = 0; i < exceptions.length; i++) { + var ei = exceptions[i]; + if (ei != null && ei.code == code && ei.throw == thrw) { + find = true; + ei.repeat = (ei.repeat || 0) + 1; // 统计重复出现次数 + break; + } + } + + if (find) { + delete currentResponse.msg; + } + } + + stddObj = isML ? (isCodeChange && hasCode ? standard : JSONResponse.updateStandard(standard, currentResponse)) : {}; + + currentResponse.code = code; + currentResponse.throw = thrw; + + if (isCodeChange) { + if (hasCode != true) { // 走正常分支 + stddObj.code = code; + stddObj.throw = thrw; + } + else { // 走异常分支 + currentResponse.msg = msg; + + if (find != true) { + exceptions.push({ + code: code, + 'throw': thrw, + msg: msg + }) + + stddObj.exceptions = exceptions; + } + } + } + else { + stddObj.repeat = (stddObj.repeat || 0) + 1; // 统计重复出现次数 + } + } + + const isNewRandom = isRandom && random.id <= 0 + + //TODO 先检查是否有重复名称的!让用户确认! + // if (isML != true) { + url = this.server + '/post' + const req = { + Random: isNewRandom != true ? null : { + toId: random.toId, + documentId: random.documentId, + name: random.name, + count: random.count, + config: random.config + }, + TestRecord: isDuration ? Object.assign(testRecord, { + id: undefined, + host: this.getBaseUrl(), + testAccountId: this.getCurrentAccountId(), + duration: item.duration, + minDuration: minDuration, + maxDuration: maxDuration, + compare: JSON.stringify(testRecord.compare || {}), + }) : { + documentId: isNewRandom ? null : (isRandom ? random.documentId : document.id), + randomId: isRandom && ! isNewRandom ? random.id : null, + host: this.getBaseUrl(), + testAccountId: this.getCurrentAccountId(), + compare: JSON.stringify(testRecord.compare || {}), + response: JSON.stringify(currentResponse || {}), + standard: isML ? JSON.stringify(stddObj) : null + }, + tag: isNewRandom ? 'Random' : 'TestRecord' + } + // } + // else { + // url = this.server + '/post/testrecord/ml' + // req = { + // documentId: document.id + // } + // } + + this.request(true, REQUEST_TYPE_JSON, url, req, {}, function (url, res, err) { + App.onResponse(url, res, err) + + var data = res.data || {} + if (data.code != CODE_SUCCESS) { + if (isML) { + alert('机器学习更新标准 异常:\n' + data.msg) + } + } + else { + if (isRandom) { + App.updateToRandomSummary(item, -1) + } + + var testRecord = item.TestRecord || {} + if (isDuration) { + item.durationColor = 'black' + item.durationHint = '正常:在以往最快和最慢之间' + } + else { + item.compareType = JSONResponse.COMPARE_EQUAL + item.compareMessage = '查看结果' + item.compareColor = 'white' + item.hintMessage = '结果正确' + + testRecord.compare = { + code: 0, + msg: '结果正确' + } + testRecord.response = JSON.stringify(currentResponse) + // testRecord.standard = stdd + } + + if (isRandom) { + var r = req == null ? null : req.Random + if (r != null && (data.Random || {}).id != null) { + r.id = data.Random.id + item.Random = r + } + if ((data.TestRecord || {}).id != null) { + testRecord.id = data.TestRecord.id + if (r != null) { + testRecord.randomId = r.id + } + } + } + item.TestRecord = testRecord + + + // if (! isNewRandom) { + // if (isRandom) { + // App.showRandomList(true, App.currentRemoteItem) + // } + // else { + // App.showTestCase(true, false) + // } + // } + + App.updateTestRecord(0, list, index, item, currentResponse, isRandom, true) + } + + }) + + } + } + }, + + updateTestRecord: function (allCount, list, index, item, response, isRandom, ignoreTrend) { + item = item || {} + var doc = (isRandom ? item.Random : item.Document) || {} + + this.request(true, REQUEST_TYPE_JSON, this.server + '/get', { + TestRecord: { + documentId: isRandom ? doc.documentId : doc.id, + randomId: isRandom ? doc.id : null, + testAccountId: this.getCurrentAccountId(), + 'host': this.getBaseUrl(), + '@order': 'date-', + '@column': 'id,userId,testAccountId,documentId,randomId,duration,minDuration,maxDuration,response' + (this.isMLEnabled ? ',standard' : ''), + '@having': this.isMLEnabled ? 'length(standard)>2' : null // '@having': this.isMLEnabled ? 'json_length(standard)>0' : null + } + }, {}, function (url, res, err) { + App.onResponse(url, res, err) + + var data = (res || {}).data || {} + if (data.code != CODE_SUCCESS) { + alert('获取最新的校验标准 异常:\n' + data.msg) + return + } + + item.TestRecord = data.TestRecord + App.compareResponse(allCount, list, index, item, response, isRandom, App.currentAccountIndex, true, err, ignoreTrend); + }) + }, + + //显示详细信息, :data-hint :data, :hint 都报错,只能这样 + setRequestHint: function(index, item, isRandom) { + item = item || {} + var d = isRandom ? item.Random : item.Document; + // var r = d == null ? null : (isRandom ? d.config : d.request); + // this.$refs[isRandom ? 'randomTexts' : 'testCaseTexts'][index].setAttribute('data-hint', r == null ? '' : (isRandom ? r : JSON.stringify(this.getRequest(r), null, ' '))); + + if (isRandom) { + var toId = (d == null ? null : d.toId) || 0 + this.$refs[toId <= 0 ? 'randomTexts' : 'randomSubTexts'][index].setAttribute('data-hint', (d || {}).config == null ? '' : d.config); + } + else { + this.$refs['testCaseTexts'][index].setAttribute('data-hint', StringUtil.isEmpty(d.request, true) ? '' : JSON.stringify(this.getRequest(d.request, {}, true), null, ' ')); + } + }, + + //显示详细信息, :data-hint :data, :hint 都报错,只能这样 + setTestHint: function(index, item, isRandom, isDuration) { + item = item || {}; + var toId = isRandom ? ((item.Random || {}).toId || 0) : 0; + var h = isDuration ? item.durationHint : item.hintMessage; + this.$refs[(isRandom ? (toId <= 0 ? 'testRandomResult' : 'testRandomSubResult') : 'testResult') + (isDuration ? 'Duration' : '') + 'Buttons'][index].setAttribute('data-hint', h || ''); + } + + }, + watch: { + jsoncon: function () { + this.showJsonView() + } + }, + computed: { + theme: function () { + var th = this.themes[this.checkedTheme] + var result = {} + var index = 0; + ['key', 'String', 'Number', 'Boolean', 'Null', 'link-link'].forEach(function(key) { + result[key] = th[index] + index++ + }) + return result + } + }, + created () { + try { //可能URL_BASE是const类型,不允许改,这里是初始化,不能出错 + var url = this.getCache('', 'URL_BASE') + if (StringUtil.isEmpty(url, true) == false) { + URL_BASE = url + } + var database = this.getCache('', 'database') + if (StringUtil.isEmpty(database, true) == false) { + this.database = CodeUtil.database = database + } + var schema = this.getCache('', 'schema') + if (StringUtil.isEmpty(schema, true) == false) { + this.schema = CodeUtil.schema = schema + } + var language = this.getCache('', 'language') + if (StringUtil.isEmpty(language, true) == false) { + this.language = CodeUtil.language = language + } + var types = this.getCache('', 'types') + if (types != null && types.length > 0) { + this.types = types instanceof Array ? types : StringUtil.split(types) + } + var server = this.getCache('', 'server') + if (StringUtil.isEmpty(server, true) == false) { + this.server = server + } + var thirdParty = this.getCache('', 'thirdParty') + if (StringUtil.isEmpty(thirdParty, true) == false) { + this.thirdParty = thirdParty + } + + this.locals = this.getCache('', 'locals', []) + + this.isDelegateEnabled = this.getCache('', 'isDelegateEnabled', this.isDelegateEnabled) + this.isEncodeEnabled = this.getCache('', 'isEncodeEnabled', this.isEncodeEnabled) + //预览了就不能编辑了,点开看会懵 this.isPreviewEnabled = this.getCache('', 'isPreviewEnabled', this.isPreviewEnabled) + this.isHeaderShow = this.getCache('', 'isHeaderShow', this.isHeaderShow) + this.isRandomShow = this.getCache('', 'isRandomShow', this.isRandomShow) + } catch (e) { + console.log('created try { ' + + '\nvar url = this.getCache(, url) ...' + + '\n} catch (e) {\n' + e.message) + } + try { //这里是初始化,不能出错 + var accounts = this.getCache(URL_BASE, 'accounts') + if (accounts != null) { + this.accounts = accounts + this.currentAccountIndex = this.getCache(URL_BASE, 'currentAccountIndex') + } + } catch (e) { + console.log('created try { ' + + '\nvar accounts = this.getCache(URL_BASE, accounts)' + + '\n} catch (e) {\n' + e.message) + } + + try { //可能URL_BASE是const类型,不允许改,这里是初始化,不能出错 + this.User = this.getCache(this.server, 'User', {}) + this.isCrossEnabled = this.getCache(this.server, 'isCrossEnabled', this.isCrossEnabled) + this.isMLEnabled = this.getCache(this.server, 'isMLEnabled', this.isMLEnabled) + this.crossProcess = this.isCrossEnabled ? '交叉账号:已开启' : '交叉账号:已关闭' + this.testProcess = this.isMLEnabled ? '机器学习:已开启' : '机器学习:已关闭' + // this.host = this.getBaseUrl() + this.page = this.getCache(this.server, 'page', this.page) + this.count = this.getCache(this.server, 'count', this.count) + this.testCasePage = this.getCache(this.server, 'testCasePage', this.testCasePage) + this.testCaseCount = this.getCache(this.server, 'testCaseCount', this.testCaseCount) + this.randomPage = this.getCache(this.server, 'randomPage', this.randomPage) + this.randomCount = this.getCache(this.server, 'randomCount', this.randomCount) + this.randomSubPage = this.getCache(this.server, 'randomSubPage', this.randomSubPage) + this.randomSubCount = this.getCache(this.server, 'randomSubCount', this.randomSubCount) + this.delegateId = this.getCache(this.server, 'delegateId', this.delegateId) + + CodeUtil.thirdPartyApiMap = this.getCache(this.thirdParty, 'thirdPartyApiMap') + } catch (e) { + console.log('created try { ' + + '\nthis.User = this.getCache(this.server, User, {})' + + '\n} catch (e) {\n' + e.message) + } + + //无效,只能在index里设置 vUrl.value = this.getCache('', 'URL_BASE') + + this.listHistory() + + var rawReq = getRequestFromURL() + if (rawReq == null || StringUtil.isEmpty(rawReq.type, true)) { + this.transfer() + + if (this.User != null && this.User.id != null && this.User.id > 0) { + setTimeout(function () { + App.showTestCase(true, false) // 本地历史仍然要求登录 this.User == null || this.User.id == null) + }, 1000) + } + } + else { + setTimeout(function () { + isSingle = ! isSingle + + var hasTestArg = false // 避免 http://localhost:63342/APIAuto/index.html?_ijt=fh8di51h7qip2d1s3r3bqn73nt 这种无意义参数 + if (StringUtil.isEmpty(rawReq.type, true) == false) { + hasTestArg = true + App.type = StringUtil.toUpperCase(rawReq.type, true) + if (App.types != null && App.types.indexOf(App.type) < 0) { + App.types.push(App.type) + } + } + + if (StringUtil.isEmpty(rawReq.url, true) == false) { + hasTestArg = true + vUrl.value = StringUtil.trim(rawReq.url) + } + + if (StringUtil.isEmpty(rawReq.json, true) == false) { + hasTestArg = true + vInput.value = StringUtil.trim(rawReq.json) + } + + if (StringUtil.isEmpty(rawReq.header, true) == false) { + hasTestArg = true + vHeader.value = StringUtil.trim(rawReq.header, true) + App.isHeaderShow = true + } + + if (StringUtil.isEmpty(rawReq.random, true) == false) { + hasTestArg = true + vRandom.value = StringUtil.trim(rawReq.random, true) + App.isRandomShow = true + App.isRandomListShow = false + } + + var delayTime = 0 + + // URL 太长导致截断和乱码 + if (StringUtil.isEmpty(rawReq.setting, true) == false) { + var save = rawReq.save == 'true' + try { + var setting = JSON.parse(StringUtil.trim(rawReq.setting, true)) || {} + + if ((setting.count != null && setting.count != App.count) + || (setting.page != null && setting.page != App.page) + || (setting.search != null && setting.search != App.search)) { + delayTime += Math.min(5000, 30*(setting.count) + 1000) + App.setDoc(""); + App.getDoc(function (d) { + App.setDoc(d); + }) + } + + for (var k in setting) { + var v = k == null ? null : setting[k] + if (v == null) { + continue + } + App[k] = v // App.$data[k] = app[k] + + if (save) { + App.saveCache('', k, v) + } + } + + if (setting.isRandomShow && setting.isRandomListShow) { + delayTime += Math.min(5000, (App.isMLEnabled ? 60 : 20)*(setting.randomCount || App.randomCount) + 1000) + App.showRandomList(true, setting.isRandomSubListShow ? App.currentRandomItem : null, setting.isRandomSubListShow) + } + + if (setting.isTestCaseShow) { + delayTime += Math.min(5000, (App.isMLEnabled ? 30 : 10)*(setting.testCaseCount || App.testCaseCount) + 1000) + App.showTestCase(true, setting.isLocalShow) + } + } catch (e) { + log(e) + } + } + + if (hasTestArg) { + vUrlComment.value = "" + vComment.value = "" + vWarning.value = "" + } + + App.onChange(false) + + if (hasTestArg && rawReq.send != "false" && rawReq.send != "null") { + setTimeout(function () { + if (rawReq.send == 'random') { + App.onClickTestRandom() + } else if (App.isTestCaseShow) { + App.onClickTest() + } else { + App.send(false) + } + + var url = vUrl.value || '' + if (rawReq.jump == "true" || rawReq.jump == "null" + || (rawReq.jump != "false" && App.isTestCaseShow != true && rawReq.send != 'random' + && (url.endsWith("/get") || url.endsWith("/head")) + ) + ) { + setTimeout(function () { + window.open(vUrl.value + "/" + encodeURIComponent(JSON.stringify(encode(JSON.parse(vInput.value))))) + }, 2000) + } + }, Math.max(1000, delayTime)) + } + }, 2000) + + } + + + // 快捷键 CTRL + I 格式化 JSON + document.addEventListener('keydown', function(event) { + // alert(event.key) 小写字母 i 而不是 KeyI + // if (event.ctrlKey && event.keyCode === 73) { // KeyI 无效 event.key === 'KeyI' && event.target == vInput){ + if (event.ctrlKey || event.metaKey) { + var target = event.target; + var selectionStart = target.selectionStart; + var selectionEnd = target.selectionEnd; + + // 这里拿不到 clipboardData if (event.keyCode === 86) { + + if (event.keyCode === 73) { // Ctrl + 'I' 格式化 + try { + if (target == vInput) { + var json = JSON.stringify(JSON5.parse(vInput.value), null, ' '); + vInput.value = inputted = isSingle ? App.switchQuote(json) : json; + } + else { + var lines = StringUtil.split(target.value, '\n'); + var newStr = ''; + + for (var i = 0; i < lines.length; i ++) { + var l = StringUtil.trim(lines[i]) || ''; + if (l.startsWith('//')) { + continue; + } + + var ind = l.lastIndexOf(' //'); + l = ind < 0 ? l : StringUtil.trim(l.substring(0, ind)); + + if (target == vHeader || target == vRandom) { + ind = l.indexOf(':'); + if (ind >= 0) { + var left = target == vHeader ? StringUtil.trim(l.substring(0, ind)) : l.substring(0, ind); + l = left + ': ' + StringUtil.trim(l.substring(ind + 1)); + } + } + + if (l.length > 0) { + newStr += '\n' + l; + } + } + + target.value = StringUtil.trim(newStr); + } + } catch (e) { + log(e) + } + } + else if (event.keyCode === 191) { // Ctrl + '/' 注释与取消注释 + try { + var json = StringUtil.get(target.value); + var before = json.substring(0, selectionStart); + var after = json.substring(selectionEnd); + + var ind = before.lastIndexOf('\n'); + var start = ind < 0 ? 0 : ind + 1; + ind = after.indexOf('\n'); + var end = ind < 0 ? json.length : selectionEnd + ind - 1; + + var selection = json.substring(start, end); + var lines = StringUtil.split(selection, '\n'); + + var newStr = json.substring(0, start); + + for (var i = 0; i < lines.length; i ++) { + var l = lines[i] || ''; + if (i > 0) { + newStr += '\n'; + } + + if (StringUtil.trim(l).startsWith('//')) { + var ind = l.indexOf('//'); + var suffix = l.substring(ind + 2); + if (suffix.startsWith(' ')) { + suffix = suffix.substring(2); + selectionEnd -= 2; + } + + newStr += StringUtil.get(l.substring(0, ind)) + StringUtil.get(suffix) + selectionEnd -= 2; + } + else { + newStr += '// ' + l; + selectionEnd += 4; + } + } + + newStr += json.substring(end); + + target.value = newStr; + if (target == vInput) { + inputted = newStr; + } + } catch (e) { + log(e) + } + } + + target.selectionStart = selectionStart; + target.selectionEnd = selectionEnd; + } + }) + + } + }) +})() + +// APIJSON >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + From 015a11f9a245d3ed3d1a7a0d626df53124fe28d0 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sat, 2 Jul 2022 07:57:26 +0800 Subject: [PATCH 574/818] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E5=85=BC=E5=AE=B9=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apijson/JSONResponse.js | 22 +++++++++++----------- apijson/StringUtil.js | 4 ++++ index.html | 2 +- js/main.js | 15 +++++++++------ 4 files changed, 25 insertions(+), 18 deletions(-) diff --git a/apijson/JSONResponse.js b/apijson/JSONResponse.js index ed52690..a6e2fb5 100644 --- a/apijson/JSONResponse.js +++ b/apijson/JSONResponse.js @@ -150,7 +150,7 @@ var JSONResponse = { * @param fullName * @return {@link #formatKey(String, boolean, boolean, boolean)} formatColon = true, formatAt = true, formatHyphen = true, firstCase = true */ - getVariableName(fullName, listSuffix) { + getVariableName: function(fullName, listSuffix) { if (JSONObject.isArrayKey(fullName)) { fullName = StringUtil.addSuffix(fullName.substring(0, fullName.length - 2), listSuffix || "list"); } @@ -161,7 +161,7 @@ var JSONResponse = { * @param key empty ? "list" : key + "List" 且首字母小写 * @return {@link #formatKey(String, boolean, boolean, boolean)} formatColon = false, formatAt = true, formatHyphen = true, firstCase = true */ - formatArrayKey(key) { + formatArrayKey: function(key) { if (JSONObject.isArrayKey(key)) { key = StringUtil.addSuffix(key.substring(0, key.length - 2), "list"); } @@ -177,7 +177,7 @@ var JSONResponse = { * @param key name 或 name:alias * @return {@link #formatKey(String, boolean, boolean, boolean)} formatColon = false, formatAt = true, formatHyphen = false, firstCase = true */ - formatObjectKey(key) { + formatObjectKey: function(key) { var index = key == null ? -1 : key.indexOf(":"); if (index >= 0) { return key.substring(index + 1); //不处理自定义的 @@ -190,7 +190,7 @@ var JSONResponse = { * @param fullName name 或 name:alias * @return {@link #formatKey(String, boolean, boolean, boolean)} formatColon = false, formatAt = true, formatHyphen = false, firstCase = false */ - formatOtherKey(fullName) { + formatOtherKey: function(fullName) { return JSONResponse.formatKey(fullName, false, true, false, false); //节约性能,除了关键词 @key ,一般都符合变量命名规范,不符合也原样返回便于调试 }, @@ -202,7 +202,7 @@ var JSONResponse = { * @param firstCase 第一个单词首字母小写,后面的首字母大写, Ab => ab ; A-b-Cd => aBCd * @return name => name; name:alias => alias */ - formatKey(fullName, formatAlias, formatAt, formatHyphen, firstCase, formatUnderline, formatFunChar) { + formatKey: function(fullName, formatAlias, formatAt, formatHyphen, firstCase, formatUnderline, formatFunChar) { if (fullName == null) { log(JSONResponse.TAG, "formatKey fullName == null >> return null;"); return null; @@ -231,7 +231,7 @@ var JSONResponse = { * @param key * @return */ - formatAt(key) { + formatAt: function(key) { var k = key.startsWith("@") ? key.substring(1) : key; return k; //由 formatFunChar 实现去掉末尾的 @ k.endsWith("@") ? k.substring(0, k.length - 1) : k; }, @@ -239,7 +239,7 @@ var JSONResponse = { * @param key * @return */ - formatAlias(key) { + formatAlias: function(key) { var index = key.indexOf(":"); return index < 0 ? key : key.substring(0, index) + 'As' + StringUtil.firstCase(key.substring(index + 1), true); }, @@ -248,7 +248,7 @@ var JSONResponse = { * @param key * @return */ - formatHyphen(key, firstCase) { + formatHyphen: function(key, firstCase) { var first = true; var index; @@ -272,7 +272,7 @@ var JSONResponse = { * @param key * @return */ - formatUnderline(key, firstCase) { + formatUnderline: function(key, firstCase) { var first = true; var index; @@ -296,7 +296,7 @@ var JSONResponse = { * @param key * @return */ - formatFunChar(key) { + formatFunChar: function(key) { var name = key.replace(/@/g, 'At'); name = name.replace(/{}/g, 'In') name = name.replace(/}{/g, 'Exists') @@ -1489,7 +1489,7 @@ var JSONResponse = { return StringUtil.isEmpty(folder, true) ? name : folder + divider + name; }, - getShowString(arr, lineItemCount) { + getShowString: function(arr, lineItemCount) { if (arr == null || arr.length <= 0) { return ''; } diff --git a/apijson/StringUtil.js b/apijson/StringUtil.js index 06b03c7..a910ae5 100644 --- a/apijson/StringUtil.js +++ b/apijson/StringUtil.js @@ -167,6 +167,10 @@ var StringUtil = { isNumber: function (s) { return typeof s == 'string' && /^[0-9]+$/.test(s); + }, + + join: function (arr, separator) { + return arr == null ? '' : arr.join(separator) } } diff --git a/index.html b/index.html index 0bea75d..31cd89a 100755 --- a/index.html +++ b/index.html @@ -194,7 +194,7 @@ + - @@ -442,11 +442,11 @@ - + diff --git a/js/main.js b/js/main.js index 35eab5e..389f141 100755 --- a/js/main.js +++ b/js/main.js @@ -945,7 +945,7 @@ } vUrlComment.value = isSingle || StringUtil.isEmpty(this.urlComment, true) - ? '' : vUrl.value + CodeUtil.getComment(this.urlComment, false, ' ') + ? '' : vUrl.value + CodeUtil.getComment(this.urlComment, false, ' ') + ' - ' + (this.requestVersion > 0 ? 'V' + this.requestVersion : 'V*'); }, @@ -4109,7 +4109,7 @@ + ' \n'; //解决遮挡 vUrlComment.value = isSingle || StringUtil.isEmpty(this.urlComment, true) - ? '' : vUrl.value + CodeUtil.getComment(this.urlComment, false, ' ') + ? '' : vUrl.value + CodeUtil.getComment(this.urlComment, false, ' ') + ' - ' + (this.requestVersion > 0 ? 'V' + this.requestVersion : 'V*'); if (! isSingle) { @@ -4123,7 +4123,7 @@ var name = api == null ? null : api.name; if (StringUtil.isEmpty(name, true) == false) { this.urlComment = name; - vUrlComment.value = vUrl.value + CodeUtil.getComment(this.urlComment, false, ' ') + vUrlComment.value = vUrl.value + CodeUtil.getComment(this.urlComment, false, ' ') } } From c9bba17cd25a9aeca79b00b79f5de44440338cd8 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sun, 6 Nov 2022 03:09:45 +0800 Subject: [PATCH 635/818] =?UTF-8?q?=E8=87=AA=E5=8A=A8=E9=9D=99=E6=80=81?= =?UTF-8?q?=E6=A3=80=E6=9F=A5=EF=BC=9A=E5=AE=8C=E5=96=84=E5=AF=B9=20APIJSO?= =?UTF-8?q?N=20=E8=BF=9C=E7=A8=8B=E5=87=BD=E6=95=B0=E7=9A=84=E9=9D=99?= =?UTF-8?q?=E6=80=81=E6=A3=80=E6=9F=A5=E5=92=8C=E8=87=AA=E5=8A=A8=E6=B3=A8?= =?UTF-8?q?=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apijson/CodeUtil.js | 100 +++++++++++++++++++++++++++++++++++++++++--- js/main.js | 51 +++++++++++----------- 2 files changed, 121 insertions(+), 30 deletions(-) diff --git a/apijson/CodeUtil.js b/apijson/CodeUtil.js index ced1153..e5dedce 100644 --- a/apijson/CodeUtil.js +++ b/apijson/CodeUtil.js @@ -49,12 +49,14 @@ var CodeUtil = { database: 'MYSQL', schema: 'sys', language: 'Kotlin', + functionList: [], + requestList: [], tableList: [], thirdParty: 'YAPI', thirdPartyApiMap: null, // {} - /**生成JSON的注释 TODO 提取 // 单行注释,补充到 TestRecord 的 standard 中,文档也是有版本的 + /**生成JSON的注释 * @param reqStr //已格式化的JSON String * @param tableList * @param method @@ -5878,6 +5880,82 @@ var CodeUtil = { }, DATABASE_KEYS: ['MYSQL', 'POSTGRESQL', 'SQLSERVER', 'ORACLE', 'DB2', 'DAMENG', 'CLICKHOUSE', 'SQLITE', 'TDENGINE'], + getComment4Function: function (funCallStr, method) { + var start = funCallStr == null ? -1 : funCallStr.indexOf('(') + if (start <= 0 || funCallStr.endsWith(')') != true) { + throw new Error('远程函数调用格式非法!必须为 fun(arg0,arg1..) 这种形式!不允许多余的空格!') + } + + var fun = funCallStr.substring(0, start) + if (StringUtil.isName(fun) != true) { + throw new Error('远程函数名称 ' + fun + ' 非法!必须为大小写英文字母开头且其它字符只能是字母/下划线/数字!') + } + + var funObj = CodeUtil.getFunctionFromList(fun, method) + if (funObj == null) { + throw new Error('远程函数 ' + fun + ' 非法!只能传后端 Function 表中配置的!') + } + + // 不做校验,似乎怎么写都是对的 + var argStr = funCallStr.substring(start + 1, funCallStr.length - 1) + var args = StringUtil.isEmpty(argStr) ? null : StringUtil.split(argStr) + var argLen = args == null ? 0 : args.length + + // if (args != null) { + // for (var i = 0; i < args.length; i++) { + // var a = args[i] + // if (a.startsWith("'") && a.endsWith("'")) { + // continue + // } + // + // if (a.startsWith('`') && a.endsWith('`')) { + // a = a.substring(1, a.length - 1) + // if (StringUtil.isName(a) != true) { + // throw new Error('远程函数名称 ' + fun + ' 非法!必须为大小写英文字母开头且其它字符只能是字母/下划线/数字!') + // } + // } + // } + // } + + var allowArgStr = funObj.arguments + var allowArgs = StringUtil.isEmpty(allowArgStr) ? null : StringUtil.split(allowArgStr) + var allowArgLen = allowArgs == null ? 0 : allowArgs.length + if (argLen != allowArgLen) { + throw new Error('远程函数参数数量 ' + argLen + ' 非法!必须是 ' + allowArgLen + ' 个!格式为 ' + fun + '(' + StringUtil.trim(allowArgStr) + ')') + } + + return funObj.rawDetail || funObj.detail + }, + + getFunctionFromList: function (name, method) { + if (StringUtil.isEmpty(name)) { + return null + } + + var functionMap = CodeUtil.functionMap; + var funObj = functionMap == null ? null : functionMap[name] + if (funObj != null) { + return funObj; + } + + var functionList = CodeUtil.functionList; + if (functionList != null) { + for (var i = 0; i < functionList.length; i++) { + var f = functionList[i]; + if (f != null && f.name == name) { + if (functionMap == null) { + functionMap = {}; + } + functionMap[name] = f; + CodeUtil.functionMap = functionMap; + return f; + } + } + } + + return null; + }, + /**获取请求JSON的注释 * @param tableList * @param name @@ -5898,7 +5976,7 @@ var CodeUtil = { var valuesIsNotInteger = typeOfValue != 'integer'; // var valuesIsNotNumber = valuesIsNotInteger && typeOfValue != 'number'; var valuesIsNotBoolean = typeOfValue != 'boolean'; - var isValueNotEmpty = valuesIsNotString ? (typeOfValue != 'array' ? value != null : value.length > 0) : StringUtil.isEmpty(value, true) != true; + var isValueNotEmpty = valuesIsNotString ? (typeOfValue != 'array' ? value != null : value.length > 0) : StringUtil.isNotEmpty(value, true); var extraComment = ''; if (isAPIJSONRouter) { @@ -5981,7 +6059,7 @@ var CodeUtil = { } } - if (isRestful != true && key != null && key.endsWith("()")) { // 方法,查询完后处理,先用一个Map保存? + if (isRestful != true && key != null && key.endsWith('()')) { // 方法,查询完后处理,先用一个Map保存? if (['GET', 'HEAD'].indexOf(method) < 0) { return ' ! 远程函数只能用于 GET,HEAD 请求!!'; } @@ -6000,6 +6078,15 @@ var CodeUtil = { } } + var c = '' + if (StringUtil.isNotEmpty(value)) { // isValueNotEmpty 居然不对 + try { + c = CodeUtil.getComment4Function(value, method) + } catch (e) { + return ' ! ' + e.message + } + } + if (isWarning) { return ' '; } @@ -6012,10 +6099,11 @@ var CodeUtil = { priority = ' < 在解析所在对象后滞后执行'; } else { - priority = ',执行时机在解析所在对象后,解析子对象前,可以在 () 前用 + - 设置优先级,例如 key-() 优先执行'; + priority = ' < 执行时机在解析所在对象后,解析子对象前,可以在 () 前用 + - 设置优先级,例如 key-() 优先执行'; } - return CodeUtil.getComment('远程函数' + (isValueNotEmpty ? ',触发调用后端对应的方法/函数' + priority : ',例如 "isContain(praiseUserIdList,userId)"'), false, ' '); + return CodeUtil.getComment('远程函数' + (isValueNotEmpty ? (StringUtil.isEmpty(c, true) ? '' : ':' + c) + priority + : ',例如 "isContain(praiseUserIdList,userId)"'), false, ' '); } @@ -6490,7 +6578,7 @@ var CodeUtil = { } - // if (isRestful != true && onlyTableAndColumn != true && columnName != null && columnName.endsWith("()")) { // 方法,查询完后处理,先用一个Map保存? + // if (isRestful != true && onlyTableAndColumn != true && columnName != null && columnName.endsWith('()')) { // 方法,查询完后处理,先用一个Map保存? // if (['GET', 'HEAD'].indexOf(method) < 0) { // return ' ! 远程函数只能用于 GET,HEAD 请求!!'; // } diff --git a/js/main.js b/js/main.js index 389f141..acca02a 100755 --- a/js/main.js +++ b/js/main.js @@ -5237,11 +5237,9 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea 'page': page, 'Function': { '@order': 'date-,name+', - '@column': 'name,arguments,demo,detail', + '@column': 'name,arguments,demo,detail,detail:rawDetail', 'demo()': 'getFunctionDemo()', 'detail()': 'getFunctionDetail()', - 'r0()': 'removeKey(name)', - 'r1()': 'removeKey(arguments)', 'name$': search, 'detail$': search, '@combine': search == null ? null : 'name$,detail$', @@ -5277,24 +5275,21 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea //转为文档格式 var doc = ''; - var item; //[] <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< var list = docObj == null ? null : docObj['[]']; + var map = {}; CodeUtil.tableList = list; if (list != null) { if (DEBUG) { log('getDoc [] = \n' + format(JSON.stringify(list))); } - var table; - var columnList; - var column; for (var i = 0; i < list.length; i++) { - item = list[i]; + var item = list[i]; //Table - table = item == null ? null : (App.database != 'SQLSERVER' ? item.Table : item.SysTable); + var table = item == null ? null : (App.database != 'SQLSERVER' ? item.Table : item.SysTable); if (table == null) { continue; } @@ -5313,7 +5308,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea var schema = table.table_schema var modelName = CodeUtil.getModelName(table.table_name) - var baseUrl = App.getBaseUrl() + map[schema + '.' + modelName] = table // TODO 对 isAPIJSON 和 isRESTful 生成不一样的 doc += '\n### ' + (i + 1) + '. ' + modelName @@ -5328,7 +5323,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea doc += '\n\n 名称 | 类型 | 最大长度 | 详细说明' + ' \n -------- | ------------ | ------------ | ------------ '; - columnList = item['[]']; + var columnList = item['[]']; if (columnList == null) { continue; } @@ -5336,19 +5331,16 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea log('getDoc [] for ' + i + ': columnList = \n' + format(JSON.stringify(columnList))); } - var name; - var type; - var length; for (var j = 0; j < columnList.length; j++) { - column = (columnList[j] || {}).Column; - name = column == null ? null : column.column_name; + var column = (columnList[j] || {}).Column; + var name = column == null ? null : column.column_name; if (name == null) { continue; } column.column_type = CodeUtil.getColumnType(column, App.database); - type = CodeUtil.getType4Language(App.language, column.column_type, false); - length = CodeUtil.getMaxLength(column.column_type); + var type = CodeUtil.getType4Language(App.language, column.column_type, false); + var length = CodeUtil.getMaxLength(column.column_type); if (DEBUG) { log('getDoc [] for j=' + j + ': column = \n' + format(JSON.stringify(column))); @@ -5373,13 +5365,14 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea } } - + CodeUtil.tableMap = map; //[] >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> //Access[] <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< list = docObj == null ? null : docObj['Access[]']; + CodeUtil.accessList = list; if (list != null) { if (DEBUG) { log('getDoc Access[] = \n' + format(JSON.stringify(list))); @@ -5390,7 +5383,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea + ' \n -------- | --------- | --------- | --------- | --------- | --------- | --------- | --------- | -------- '; for (var i = 0; i < list.length; i++) { - item = list[i]; + var item = list[i]; if (item == null) { continue; } @@ -5398,6 +5391,8 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea log('getDoc Access[] for i=' + i + ': item = \n' + format(JSON.stringify(item))); } + map[item.schema + '.' + item.name] = item + doc += '\n' + (item.name) //右上角设置指定了 Schema + '(' + item.schema + ')') + ' | ' + JSONResponse.getShowString(JSON.parse(item.get), 2) + ' | ' + JSONResponse.getShowString(JSON.parse(item.head), 2) @@ -5413,12 +5408,13 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea doc += '\n' //避免没数据时表格显示没有网格 } - + CodeUtil.accessMap = map; //Access[] >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> //Function[] <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< list = docObj == null ? null : docObj['Function[]']; + CodeUtil.functionList = list; if (list != null) { if (DEBUG) { log('getDoc Function[] = \n' + format(JSON.stringify(list))); @@ -5429,7 +5425,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea + ' \n -------- | -------------- '; for (var i = 0; i < list.length; i++) { - item = list[i]; + var item = list[i]; if (item == null) { continue; } @@ -5437,6 +5433,8 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea log('getDoc Function[] for i=' + i + ': item = \n' + format(JSON.stringify(item))); } + map[item.name] = item + var demoStr = JSON.stringify(item.demo) // doc += '\n' + item.detail + ' | ' + ' >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> //Request[] <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< list = docObj == null ? null : docObj['Request[]']; + map = {}; + CodeUtil.requestList = list; if (list != null) { if (DEBUG) { log('getDoc Request[] = \n' + format(JSON.stringify(list))); @@ -5462,7 +5462,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea + ' \n -------- | ------------ | ------------ | ------------ | ------------ '; for (var i = 0; i < list.length; i++) { - item = list[i]; + var item = list[i]; if (item == null) { continue; } @@ -5470,6 +5470,8 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea log('getDoc Request[] for i=' + i + ': item = \n' + format(JSON.stringify(item))); } + map[item.version + '.' + item.method + '.' + item.tag] = item + var jsonStr = JSON.stringify(App.getStructure(false, null, item.structure, item.method, item.tag, item.version)) doc += '\n' + item.version + ' | ' + item.method + ' | ' + item.tag @@ -5478,6 +5480,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea doc += '\n注: \n1.GET,HEAD方法不受限,可传任何 数据、结构。\n2.可在最外层传版本version来指定使用的版本,不传或 version <= 0 则使用最新版。\n\n\n\n\n\n\n'; } + CodeUtil.requestMap = map; //Request[] >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> From c3842d83af05d633b8533174aa40ae597b4dd323 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sun, 6 Nov 2022 03:39:17 +0800 Subject: [PATCH 636/818] =?UTF-8?q?=E8=87=AA=E5=8A=A8=E9=9D=99=E6=80=81?= =?UTF-8?q?=E6=A3=80=E6=9F=A5=EF=BC=9A=E8=A7=A3=E5=86=B3=E6=8A=8A=20@key()?= =?UTF-8?q?=20=E5=AD=98=E5=82=A8=E8=BF=87=E7=A8=8B=E8=AF=AF=E5=BD=93?= =?UTF-8?q?=E6=88=90=20key()=20=E8=BF=9C=E7=A8=8B=E5=87=BD=E6=95=B0?= =?UTF-8?q?=EF=BC=9B=E6=B5=8B=E8=AF=95=E7=94=A8=E4=BE=8B=E5=88=97=E8=A1=A8?= =?UTF-8?q?=EF=BC=9A=E8=A7=A3=E5=86=B3=E4=B8=80=E6=97=A6=E5=88=86=E9=A1=B5?= =?UTF-8?q?=E6=95=B0=E9=87=8F=E6=88=96=E9=A1=B5=E7=A0=81=E9=94=99=E4=BA=86?= =?UTF-8?q?=EF=BC=8C=E5=B0=B1=E5=8F=AA=E8=83=BD=E6=B8=85=E7=BC=93=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apijson/CodeUtil.js | 29 +++++++++++++++++------------ js/main.js | 5 +++++ 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/apijson/CodeUtil.js b/apijson/CodeUtil.js index e5dedce..12a31ac 100644 --- a/apijson/CodeUtil.js +++ b/apijson/CodeUtil.js @@ -5881,6 +5881,10 @@ var CodeUtil = { DATABASE_KEYS: ['MYSQL', 'POSTGRESQL', 'SQLSERVER', 'ORACLE', 'DB2', 'DAMENG', 'CLICKHOUSE', 'SQLITE', 'TDENGINE'], getComment4Function: function (funCallStr, method) { + if (typeof funCallStr != 'string') { + return '远程函数 value 必须是 String 类型!'; + } + var start = funCallStr == null ? -1 : funCallStr.indexOf('(') if (start <= 0 || funCallStr.endsWith(')') != true) { throw new Error('远程函数调用格式非法!必须为 fun(arg0,arg1..) 这种形式!不允许多余的空格!') @@ -6059,25 +6063,26 @@ var CodeUtil = { } } - if (isRestful != true && key != null && key.endsWith('()')) { // 方法,查询完后处理,先用一个Map保存? + if (isRestful != true && key != null && key.startsWith('@') != true && key.endsWith('()')) { // 方法,查询完后处理,先用一个Map保存? if (['GET', 'HEAD'].indexOf(method) < 0) { return ' ! 远程函数只能用于 GET,HEAD 请求!!'; } if (value != null && valuesIsNotString) { - return ' ! value必须是String类型!'; - } - if (value != null) { - var startIndex = value.indexOf("("); - if (startIndex <= 0 || value.endsWith(")") == false) { - return ' ! value必须符合 fun(arg0,arg1..) 这种格式!且不要有任何多余的空格!'; - } - var fun = value.substring(0, startIndex); - if (StringUtil.isName(fun) != true) { - return '! 函数名' + fun + '不合法!value必须符合 fun(arg0,arg1..) 这种格式!且不要有任何多余的空格!'; - } + return ' ! 远程函数 value 必须是 String 类型!'; } + // if (value != null) { + // var startIndex = value.indexOf("("); + // if (startIndex <= 0 || value.endsWith(")") == false) { + // return ' ! 远程函数 value 必须符合 fun(arg0,arg1..) 这种格式!且不要有任何多余的空格!'; + // } + // var fun = value.substring(0, startIndex); + // if (StringUtil.isName(fun) != true) { + // return '! 函数名' + fun + '不合法!value 必须符合 fun(arg0,arg1..) 这种格式!且不要有任何多余的空格!'; + // } + // } + var c = '' if (StringUtil.isNotEmpty(value)) { // isValueNotEmpty 居然不对 try { diff --git a/js/main.js b/js/main.js index acca02a..479c28c 100755 --- a/js/main.js +++ b/js/main.js @@ -3391,6 +3391,11 @@ this.showCompare4TestCaseList(show) //this.onChange(false) + } else if (IS_BROWSER) { // 解决一旦错了,就只能清缓存 + this.testCaseCount = 50 + this.testCasePage = 0 + this.saveCache(this.server, 'testCasePage', this.testCasePage) + this.saveCache(this.server, 'testCaseCount', this.testCaseCount) } }, From c2218370e569797739f4b3a3bb2ec8c5d4d3771c Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sun, 6 Nov 2022 04:00:04 +0800 Subject: [PATCH 637/818] =?UTF-8?q?=E8=87=AA=E5=8A=A8=E7=94=9F=E6=88=90=20?= =?UTF-8?q?APIJSON=EF=BC=9A=E5=90=88=E5=B9=B6=E5=90=8C=20URL=20=E7=9A=84?= =?UTF-8?q?=E8=AF=B7=E6=B1=82=20JSON=EF=BC=8C=E8=80=8C=E4=B8=8D=E6=98=AF?= =?UTF-8?q?=E6=9B=BF=E4=BB=A3=EF=BC=8C=E5=BF=AB=E9=80=9F=E6=9E=84=E5=BB=BA?= =?UTF-8?q?=E5=A4=8D=E5=88=B6=E5=A4=9A=E8=A1=A8=E6=9F=A5=E8=AF=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apijson/CodeUtil.js | 2 +- js/main.js | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/apijson/CodeUtil.js b/apijson/CodeUtil.js index 12a31ac..330f3c3 100644 --- a/apijson/CodeUtil.js +++ b/apijson/CodeUtil.js @@ -6715,7 +6715,7 @@ var CodeUtil = { return ' ! value必须是String或Array类型!'; } - fun = '匹配 选项/条件' + (isValueNotEmpty ? '' : ',例如 ' + (valuesIsNotString ? '[1, 2, 3] ["%c%", "S%", "%end"] 等' : '">100" "%2=0;<=100000" 等')); + fun = (valuesIsNotString ? '匹配选项' : '匹配条件') + (isValueNotEmpty ? '' : ',例如 ' + (valuesIsNotString ? '[1, 2, 3] ["%c%", "S%", "%end"] 等' : '">100" "%2=0;<=100000" 等')); key = columnName.substring(0, columnName.length - 2); verifyType = false; diff --git a/js/main.js b/js/main.js index 479c28c..a425b18 100755 --- a/js/main.js +++ b/js/main.js @@ -5844,6 +5844,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea } } + vInput.value = '' this.showCRUD( '/' + StringUtil.toLowerCase(method) + (isSingle ? '/' + tag + (version == null ? '' : '?version=' + version) : '') , isSingle ? this.switchQuote(jsonStr) : jsonStr @@ -5851,6 +5852,18 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea }, showCRUD: function (url, json) { + if (url == this.getBranchUrl()) { + var origin = this.getRequest(vInput.value) + if (origin != null && Object.keys(origin).length > 0) { + json = this.getRequest(json) + if (json == null || Object.keys(json).length <= 0 + || (json instanceof Array != true && json instanceof Object)) { + json = Object.assign(origin, json) + json = JSON.stringify(json, null, ' ') + } + } + } + this.type = REQUEST_TYPE_JSON this.showUrl(false, url) this.urlComment = '' From f40376b8bc597408011df469249561c0a38b546b Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sun, 6 Nov 2022 05:59:43 +0800 Subject: [PATCH 638/818] =?UTF-8?q?=E8=87=AA=E5=8A=A8=E7=94=9F=E6=88=90=20?= =?UTF-8?q?APIJSON=EF=BC=9A=E6=96=B0=E5=A2=9E=E6=94=AF=E6=8C=81=20Access?= =?UTF-8?q?=20=E8=A1=A8=E4=B8=AD=E9=85=8D=E7=BD=AE=E7=9A=84=E8=A1=A8?= =?UTF-8?q?=E5=A2=9E=E5=88=A0=E6=94=B9=E6=9F=A5=E8=A7=92=E8=89=B2=E6=9D=83?= =?UTF-8?q?=E9=99=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- js/main.js | 263 ++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 188 insertions(+), 75 deletions(-) diff --git a/js/main.js b/js/main.js index a425b18..b54e880 100755 --- a/js/main.js +++ b/js/main.js @@ -5140,8 +5140,6 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea 'Access': { '@column': 'name,alias,get,head,gets,heads,post,put,delete', '@order': 'date-,name+', - 'name()': 'getWithDefault(alias,name)', - 'r0()': 'removeKey(alias)', 'name$': search, 'alias$': search, '@combine': search == null ? null : 'name$,alias$', @@ -5276,14 +5274,73 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea } // log('getDoc docRq.responseText = \n' + docRq.responseText); - docObj = res.data || {}; //避免后面又调用 onChange ,onChange 又调用 getDoc 导致死循环 + docObj = res.data || {}; //避免后面又调用 onChange ,onChange 又调用 getDoc 导致死循环 - //转为文档格式 + var map = {}; + + //Access[] <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< + var ad = '' + list = docObj == null ? null : docObj['Access[]']; + CodeUtil.accessList = list; + if (list != null) { + if (DEBUG) { + log('getDoc Access[] = \n' + format(JSON.stringify(list))); + } + + ad += '\n\n\n\n\n\n\n\n\n### 访问权限\n自动查 Access 表写入的数据来生成\n' + + ' \n 表名 | 允许 post
的角色 | 允许 put
的角色 | 允许 delete
的角色 | 允许 get
的角色 | 允许 head
的角色 | 允许 gets
的角色 | 允许 heads
的角色 | 表名' + + ' \n -------- | --------- | --------- | --------- | --------- | --------- | --------- | --------- | -------- '; + + for (var i = 0; i < list.length; i++) { + var item = list[i]; + if (item == null) { + continue; + } + if (DEBUG) { + log('getDoc Access[] for i=' + i + ': item = \n' + format(JSON.stringify(item))); + } + + var name = StringUtil.isEmpty(item.alias, true) ? StringUtil.firstCase(item.name, true) : item.alias + map[StringUtil.toLowerCase(item.schema) + '.' + StringUtil.toLowerCase(item.name)] = item + + function getShowString(method, lineItemCount) { + var roles = item[method] == null ? null : JSON.parse(item[method]) + var rs = [] + if (roles != null) { + var schemaStr = StringUtil.isEmpty(item.schema) ? 'null' : "'" + item.schema + "'" + for (var j = 0; j < roles.length; j++) { + var r = roles[j] || '' + rs.push('
' + r + '') + } + } + return JSONResponse.getShowString(rs, lineItemCount) + } + + ad += '\n' + (name) //右上角设置指定了 Schema + '(' + item.schema + ')') + + ' | ' + getShowString('post', 1) + + ' | ' + getShowString('put', 1) + + ' | ' + getShowString('delete', 1) + + ' | ' + getShowString('get', 2) + + ' | ' + getShowString('head', 2) + + ' | ' + getShowString('gets', 2) + + ' | ' + getShowString('heads', 2) + + ' | ' + (name); //右上角设置指定了 Schema + '(' + item.schema + ')'); + } + + ad += ' \n 表名 | 允许 post
的角色 | 允许 put
的角色 | 允许 delete
的角色 | 允许 get
的角色 | 允许 head
的角色 | 允许 gets
的角色 | 允许 heads
的角色 | 表名' + + ad += '\n' //避免没数据时表格显示没有网格 + } + var accessMap = CodeUtil.accessMap = map; + //Access[] >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + + + //转为文档格式 var doc = ''; //[] <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< var list = docObj == null ? null : docObj['[]']; - var map = {}; + map = {}; CodeUtil.tableList = list; if (list != null) { if (DEBUG) { @@ -5312,10 +5369,10 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea // item.Table.table_comment = table_comment var schema = table.table_schema - var modelName = CodeUtil.getModelName(table.table_name) - map[schema + '.' + modelName] = table - // TODO 对 isAPIJSON 和 isRESTful 生成不一样的 + var modelName = App.getModelName(i) + map[StringUtil.toLowerCase(schema) + '.' + StringUtil.toLowerCase(modelName)] = table + // TODO 对 isAPIJSON 和 isRESTful 生成不一样的 doc += '\n### ' + (i + 1) + '. ' + modelName + (StringUtil.isEmpty(schema, true) ? '' : ': { @schema: ' + schema + ' }') + ' - GET' @@ -5373,49 +5430,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea CodeUtil.tableMap = map; //[] >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> - - - //Access[] <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< - list = docObj == null ? null : docObj['Access[]']; - CodeUtil.accessList = list; - if (list != null) { - if (DEBUG) { - log('getDoc Access[] = \n' + format(JSON.stringify(list))); - } - - doc += '\n\n\n\n\n\n\n\n\n### 访问权限\n自动查 Access 表写入的数据来生成\n' - + ' \n 表名 | 允许 get
的角色 | 允许 head
的角色 | 允许 gets
的角色 | 允许 heads
的角色 | 允许 post
的角色 | 允许 put
的角色 | 允许 delete
的角色 | 表名' - + ' \n -------- | --------- | --------- | --------- | --------- | --------- | --------- | --------- | -------- '; - - for (var i = 0; i < list.length; i++) { - var item = list[i]; - if (item == null) { - continue; - } - if (DEBUG) { - log('getDoc Access[] for i=' + i + ': item = \n' + format(JSON.stringify(item))); - } - - map[item.schema + '.' + item.name] = item - - doc += '\n' + (item.name) //右上角设置指定了 Schema + '(' + item.schema + ')') - + ' | ' + JSONResponse.getShowString(JSON.parse(item.get), 2) - + ' | ' + JSONResponse.getShowString(JSON.parse(item.head), 2) - + ' | ' + JSONResponse.getShowString(JSON.parse(item.gets), 2) - + ' | ' + JSONResponse.getShowString(JSON.parse(item.heads), 2) - + ' | ' + JSONResponse.getShowString(JSON.parse(item.post), 1) - + ' | ' + JSONResponse.getShowString(JSON.parse(item.put), 1) - + ' | ' + JSONResponse.getShowString(JSON.parse(item.delete), 1) - + ' | ' + (item.name); //右上角设置指定了 Schema + '(' + item.schema + ')'); - } - - doc += ' \n 表名 | 允许 get
的角色 | 允许 head
的角色 | 允许 gets
的角色 | 允许 heads
的角色 | 允许 post
的角色 | 允许 put
的角色 | 允许 delete
的角色 | 表名' - - doc += '\n' //避免没数据时表格显示没有网格 - } - CodeUtil.accessMap = map; - //Access[] >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> - + doc += ad; //Function[] <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< list = docObj == null ? null : docObj['Function[]']; @@ -5522,7 +5537,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea if (list != null) { for (var i = 0; i < list.length; i++) { var table = this.getTableObj(i) - if (table != null && CodeUtil.getModelName(table.table_name) == modelName + if (table != null && this.getModelName(i) == modelName && (schemaName == null || table.table_schema == schemaName)) { return list[i]['[]'] } @@ -5549,7 +5564,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea if (list != null) { for (var i = 0; i < list.length; i++) { var table = this.getTableObj(i) - if (table != null && CodeUtil.getModelName(table.table_name) == modelName + if (table != null && this.getModelName(i) == modelName && (schemaName == null || table.table_schema == schemaName)) { return table } @@ -5572,6 +5587,10 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea getColumnObj(columnList, columnIndex) { return columnList == null ? null : (columnList[columnIndex] || {})[this.getColumnKey()]; }, + getAccessObj(index) { + var list = docObj == null ? null : docObj['Access[]'] + return list == null ? null : list[index]; + }, getFunctionObj(index) { var list = docObj == null ? null : docObj['Function[]'] return list == null ? null : list[index]; @@ -5625,15 +5644,35 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea }, getModelName(tableIndex) { var table = this.getTableObj(tableIndex) - return table == null ? '' : CodeUtil.getModelName(table.table_name) + var table_name = table == null ? null : table.table_name + + var accessMap = table_name == null ? null : CodeUtil.accessMap + var access = accessMap == null ? null : accessMap[StringUtil.toLowerCase(table.table_schema) + '.' + StringUtil.toLowerCase(table_name)] + var alias = access == null ? null : access.alias + + return StringUtil.isEmpty(alias, true) ? StringUtil.firstCase(table_name, true) : alias }, + getModelNameByTableName(tableName, schemaName) { + var table = this.getTableByName(tableName, schemaName) + var table_name = table == null ? null : table.table_name - onClickPost: function (tableIndex, modelName) { - modelName = modelName || this.getModelName(tableIndex) + var accessMap = table_name == null ? null : CodeUtil.accessMap + var access = accessMap == null ? null : accessMap[StringUtil.toLowerCase(table.table_schema) + '.' + StringUtil.toLowerCase(table_name)] + var alias = access == null ? null : access.alias + + return StringUtil.isEmpty(alias, true) ? StringUtil.firstCase(table_name, true) : alias + }, + + onClickPost: function (tableIndex, modelName, schemaName, role) { + this.handleClickPost(this.getColumnList(tableIndex), modelName || this.getModelName(tableIndex), schemaName, role) + }, + handleClickPost: function (columnList, modelName, schemaName, role) { + if (columnList == null) { + columnList = this.getColumnListWithModelName(modelName, schemaName) + } var tbl = {} - var columnList = this.getColumnList(tableIndex) if (columnList != null && columnList.length > 0) { for (var j = 0; j < columnList.length; j++) { var column = this.getColumnObj(columnList, j) @@ -5653,6 +5692,13 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea } } + if (StringUtil.isNotEmpty(schemaName, true)) { + tbl['@schema'] = schemaName + } + if (StringUtil.isNotEmpty(role, true)) { + tbl['@role'] = role + } + var json = isSingle ? tbl : {} if (! isSingle) { json[modelName] = tbl @@ -5662,17 +5708,26 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea var s = JSON.stringify(json, null, ' ') - this.showCRUD('/post' + (isSingle ? '/' + modelName : ''), isSingle ? this.switchQuote(s) : s) + var isSchemaEmpty = StringUtil.isEmpty(schemaName, true) + var isRoleEmpty = StringUtil.isEmpty(role, true) + + this.showCRUD('/post' + (isSingle ? '/' + modelName + + (isSchemaEmpty && isRoleEmpty ? '' : '?' + (isSchemaEmpty ? '' : '&@schema=' + schemaName) + (isRoleEmpty ? '' : '&@role=' + role)) + : ''), isSingle ? this.switchQuote(s) : s) }, - onClickGet: function (tableIndex, modelName) { - modelName = modelName || this.getModelName(tableIndex) + onClickGet: function (tableIndex, modelName, schemaName, role) { + this.handleClickGet(this.getColumnList(tableIndex), modelName || this.getModelName(tableIndex), schemaName, role) + }, + handleClickGet: function (columnList, modelName, schemaName, role) { + if (columnList == null) { + columnList = this.getColumnListWithModelName(modelName, schemaName) + } var idName = 'id' var userIdName = 'userId' var dateName = 'date' var s = '' - var columnList = this.getColumnList(tableIndex) if (columnList != null && columnList.length > 0) { for (var j = 0; j < columnList.length; j++) { var column = this.getColumnObj(columnList, j) @@ -5698,24 +5753,29 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea var arrName = modelName + '[]' - this.showCRUD('/get' + (isSingle ? '/' + arrName + '?total@=' + arrName + '/total' + '&info@=' + arrName + '/info' : ''), + this.showCRUD('/get' + (isSingle ? '/' + arrName + '?total@=' + arrName + '/total' + '&info@=' + arrName + '/info' + + (StringUtil.isEmpty(schemaName, true) ? '' : '&@schema=' + schemaName) + (StringUtil.isEmpty(role, true) ? '' : '&@role=' + role): ''), isSingle ? `{ - '` + modelName + `': { + '` + modelName + `': {` + (StringUtil.isEmpty(role, true) ? '' : ` + '@role': '` + role + "',") + (StringUtil.isEmpty(schemaName, true) ? '' : ` + '@schema': '` + schemaName + "',") + ` '@column': '` + s + `', '@order': '` + idName + `-', // '@group': '` + userIdName + `', '` + idName + `>': 10, // '@column': '` + userIdName + `;avg(` + idName + `)', - '` + dateName + `{}': '!=null' // '@having': 'avg(` + idName + `)>10', + '` + dateName + `{}': '!=null' // '@having': 'avg(` + idName + `)>10' }, 'count': 10, 'page': 0, 'query': 2 }` : `{ "` + modelName + `[]": { - "` + modelName + `": { + "` + modelName + `": {` + (StringUtil.isEmpty(role, true) ? '' : ` + "@role": "` + role + '",') + (StringUtil.isEmpty(schemaName, true) ? '' : ` + "@schema": "` + schemaName + '",') + ` "@column": "` + s + `", "@order": "` + idName + `-", // "@group": "` + userIdName + `", "` + idName + `>": 10, // "@column": "` + userIdName + `;avg(` + idName + `)", - "` + dateName + `{}": "!=null" // "@having": "avg(` + idName + `)>10", + "` + dateName + `{}": "!=null" // "@having": "avg(` + idName + `)>10" }, "count": 10, "page": 0, @@ -5727,8 +5787,13 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea }`) }, - onClickPut: function (tableIndex, modelName) { - modelName = modelName || this.getModelName(tableIndex) + onClickPut: function (tableIndex, modelName, schemaName, role) { + this.handleClickPut(this.getColumnList(tableIndex), modelName || this.getModelName(tableIndex), schemaName, role) + }, + handleClickPut: function (columnList, modelName, schemaName, role) { + if (columnList == null) { + columnList = this.getColumnListWithModelName(modelName, schemaName) + } var tbl = { "id{}": [ @@ -5742,7 +5807,6 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea ] } - var columnList = this.getColumnList(tableIndex) if (columnList != null && columnList.length > 0) { for (var j = 0; j < columnList.length; j++) { var column = this.getColumnObj(columnList, j) @@ -5762,6 +5826,13 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea } } + if (StringUtil.isNotEmpty(schemaName, true)) { + tbl['@schema'] = schemaName + } + if (StringUtil.isNotEmpty(role, true)) { + tbl['@role'] = role + } + var json = isSingle ? tbl : {} if (! isSingle) { json[modelName] = tbl @@ -5771,18 +5842,37 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea var s = JSON.stringify(json, null, ' ') - this.showCRUD('/put' + (isSingle ? '/' + modelName + '[]' : ''), isSingle ? this.switchQuote(s) : s) + var isSchemaEmpty = StringUtil.isEmpty(schemaName, true) + var isRoleEmpty = StringUtil.isEmpty(role, true) + + this.showCRUD('/put' + (isSingle ? '/' + modelName + '[]' + + (isSchemaEmpty && isRoleEmpty ? '' : '?' + (isSchemaEmpty ? '' : '&@schema=' + schemaName) + (isRoleEmpty ? '' : '&@role=' + role)) + : ''), isSingle ? this.switchQuote(s) : s) }, - onClickDelete: function (tableIndex, modelName) { - modelName = modelName || this.getModelName(tableIndex) + onClickDelete: function (tableIndex, modelName, schemaName, role) { + this.handleClickDelete(this.getColumnList(tableIndex), modelName || this.getModelName(tableIndex), schemaName, role) + }, + handleClickDelete: function (columnList, modelName, schemaName, role) { + if (columnList == null) { + columnList = this.getColumnListWithModelName(modelName, schemaName) + } - this.showCRUD('/delete' + (isSingle ? '/' + modelName : ''), + var isSchemaEmpty = StringUtil.isEmpty(schemaName, true) + var isRoleEmpty = StringUtil.isEmpty(role, true) + + this.showCRUD('/delete' + (isSingle ? '/' + modelName + + (isSchemaEmpty && isRoleEmpty ? '' : '?' + (isSchemaEmpty ? '' : '&@schema=' + schemaName) + (isRoleEmpty ? '' : '&@role=' + role)) + : ''), isSingle ? `{ - 'id': 1 + 'id': 1` + (StringUtil.isEmpty(schemaName, true) ? '' : `, + '@schema': '` + schemaName + "'") + (StringUtil.isEmpty(role, true) ? '' : `, + '@role': '` + role + "'") + ` }` : `{ "` + modelName + `": { - "id": 1 + "id": 1` + (StringUtil.isEmpty(schemaName, true) ? '' : `, + "@schema": "` + schemaName + '"') + (StringUtil.isEmpty(role, true) ? '' : `, + "@role": "` + role + '"') + ` }, "tag": "` + modelName + `", "@explain": true @@ -5823,6 +5913,29 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea }`) }, + onClickAccess: function (index, model, schema, method, role) { + if (StringUtil.isEmpty(model, true) || StringUtil.isEmpty(schema, true) || StringUtil.isEmpty(method, true) || StringUtil.isEmpty(role, true)) { + // var access = this.getAccessObj(index) + // model = this.getModelNameByTableName() + } + + method = StringUtil.toLowerCase(method) + switch (method) { + case 'get': + this.handleClickGet(null, model, schema, role) + break + case 'post': + this.handleClickPost(null, model, schema, role) + break + case 'put': + this.handleClickPut(null, model, schema, role) + break + case 'delete': + this.handleClickDelete(null, model, schema, role) + break + } + }, + onClickFunction: function (index, demo) { if (StringUtil.isEmpty(demo, true)) { var fun = this.getFunctionObj(index) From 28e48bd7c66d39bec96681af53cc3afdf344bcbf Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sun, 6 Nov 2022 06:20:05 +0800 Subject: [PATCH 639/818] =?UTF-8?q?=E8=87=AA=E5=8A=A8=E7=94=9F=E6=88=90=20?= =?UTF-8?q?APIJSON=EF=BC=9A=E6=96=B0=E5=A2=9E=E6=94=AF=E6=8C=81=20GETS,=20?= =?UTF-8?q?HEAD,=20HEADS?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- js/main.js | 98 ++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 69 insertions(+), 29 deletions(-) diff --git a/js/main.js b/js/main.js index b54e880..0e64c56 100755 --- a/js/main.js +++ b/js/main.js @@ -5375,10 +5375,13 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea // TODO 对 isAPIJSON 和 isRESTful 生成不一样的 doc += '\n### ' + (i + 1) + '. ' + modelName + (StringUtil.isEmpty(schema, true) ? '' : ': { @schema: ' + schema + ' }') - + ' - GET' - + ' POST' + + ' - POST' + ' PUT' + ' DELETE' + + ' GET' + + ' GETS' + + ' HEAD' + + ' HEADS' + '\n' + App.toMD(table_comment); //Column[] @@ -5707,13 +5710,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea } var s = JSON.stringify(json, null, ' ') - - var isSchemaEmpty = StringUtil.isEmpty(schemaName, true) - var isRoleEmpty = StringUtil.isEmpty(role, true) - - this.showCRUD('/post' + (isSingle ? '/' + modelName - + (isSchemaEmpty && isRoleEmpty ? '' : '?' + (isSchemaEmpty ? '' : '&@schema=' + schemaName) + (isRoleEmpty ? '' : '&@role=' + role)) - : ''), isSingle ? this.switchQuote(s) : s) + this.showCRUD('/post' + (isSingle ? '/' + modelName : ''), isSingle ? this.switchQuote(s) : s) }, onClickGet: function (tableIndex, modelName, schemaName, role) { @@ -5753,16 +5750,15 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea var arrName = modelName + '[]' - this.showCRUD('/get' + (isSingle ? '/' + arrName + '?total@=' + arrName + '/total' + '&info@=' + arrName + '/info' - + (StringUtil.isEmpty(schemaName, true) ? '' : '&@schema=' + schemaName) + (StringUtil.isEmpty(role, true) ? '' : '&@role=' + role): ''), + this.showCRUD('/get' + (isSingle ? '/' + arrName + '?total@=' + arrName + '/total' + '&info@=' + arrName + '/info' : ''), isSingle ? `{ '` + modelName + `': {` + (StringUtil.isEmpty(role, true) ? '' : ` '@role': '` + role + "',") + (StringUtil.isEmpty(schemaName, true) ? '' : ` '@schema': '` + schemaName + "',") + ` '@column': '` + s + `', - '@order': '` + idName + `-', // '@group': '` + userIdName + `', - '` + idName + `>': 10, // '@column': '` + userIdName + `;avg(` + idName + `)', - '` + dateName + `{}': '!=null' // '@having': 'avg(` + idName + `)>10' + '@order': '` + idName + `-', // '@group': '` + userIdName + `', + '` + idName + `>': 10, // '@column': '` + userIdName + `;avg(` + idName + `)', + '` + dateName + `{}': '!=null' // '@having': 'avg(` + idName + `)>10' }, 'count': 10, 'page': 0, @@ -5773,9 +5769,9 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea "@role": "` + role + '",') + (StringUtil.isEmpty(schemaName, true) ? '' : ` "@schema": "` + schemaName + '",') + ` "@column": "` + s + `", - "@order": "` + idName + `-", // "@group": "` + userIdName + `", - "` + idName + `>": 10, // "@column": "` + userIdName + `;avg(` + idName + `)", - "` + dateName + `{}": "!=null" // "@having": "avg(` + idName + `)>10" + "@order": "` + idName + `-", // "@group": "` + userIdName + `", + "` + idName + `>": 10, // "@column": "` + userIdName + `;avg(` + idName + `)", + "` + dateName + `{}": "!=null" // "@having": "avg(` + idName + `)>10" }, "count": 10, "page": 0, @@ -5841,19 +5837,16 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea } var s = JSON.stringify(json, null, ' ') - - var isSchemaEmpty = StringUtil.isEmpty(schemaName, true) - var isRoleEmpty = StringUtil.isEmpty(role, true) - - this.showCRUD('/put' + (isSingle ? '/' + modelName + '[]' - + (isSchemaEmpty && isRoleEmpty ? '' : '?' + (isSchemaEmpty ? '' : '&@schema=' + schemaName) + (isRoleEmpty ? '' : '&@role=' + role)) - : ''), isSingle ? this.switchQuote(s) : s) + this.showCRUD('/put' + (isSingle ? '/' + modelName + '[]' : ''), isSingle ? this.switchQuote(s) : s) }, onClickDelete: function (tableIndex, modelName, schemaName, role) { this.handleClickDelete(this.getColumnList(tableIndex), modelName || this.getModelName(tableIndex), schemaName, role) }, handleClickDelete: function (columnList, modelName, schemaName, role) { + this.handleClickGetsOrDelete(false, columnList, modelName, schemaName, role) + }, + handleClickGetsOrDelete: function (isGets, columnList, modelName, schemaName, role) { if (columnList == null) { columnList = this.getColumnListWithModelName(modelName, schemaName) } @@ -5861,9 +5854,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea var isSchemaEmpty = StringUtil.isEmpty(schemaName, true) var isRoleEmpty = StringUtil.isEmpty(role, true) - this.showCRUD('/delete' + (isSingle ? '/' + modelName - + (isSchemaEmpty && isRoleEmpty ? '' : '?' + (isSchemaEmpty ? '' : '&@schema=' + schemaName) + (isRoleEmpty ? '' : '&@role=' + role)) - : ''), + this.showCRUD((isGets ? '/gets' : '/delete') + (isSingle ? '/' + modelName : ''), isSingle ? `{ 'id': 1` + (StringUtil.isEmpty(schemaName, true) ? '' : `, '@schema': '` + schemaName + "'") + (StringUtil.isEmpty(role, true) ? '' : `, @@ -5879,6 +5870,46 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea }`) }, + onClickGets: function (tableIndex, modelName, schemaName, role) { + this.handleClickGets(this.getColumnList(tableIndex), modelName || this.getModelName(tableIndex), schemaName, role) + }, + handleClickGets: function (columnList, modelName, schemaName, role) { + this.handleClickGetsOrDelete(true, columnList, modelName, schemaName, role) + }, + + onClickHead: function (tableIndex, modelName, schemaName, role) { + this.handleClickHead(this.getColumnList(tableIndex), modelName || this.getModelName(tableIndex), schemaName, role) + }, + handleClickHead: function (columnList, modelName, schemaName, role) { + this.handleClickHeadOrHeads(false, columnList, modelName, schemaName, role) + }, + onClickHeads: function (tableIndex, modelName, schemaName, role) { + this.handleClickHeads(this.getColumnList(tableIndex), modelName || this.getModelName(tableIndex), schemaName, role) + }, + handleClickHeads: function (columnList, modelName, schemaName, role) { + this.handleClickHeadOrHeads(true, columnList, modelName, schemaName, role) + }, + handleClickHeadOrHeads: function (isHeads, columnList, modelName, schemaName, role) { + if (columnList == null) { + columnList = this.getColumnListWithModelName(modelName, schemaName) + } + + this.showCRUD((isHeads ? '/heads' : '/head') + (isSingle ? '/' + modelName : ''), + isSingle ? `{ + 'userId': 82001` + (StringUtil.isEmpty(schemaName, true) ? '' : `, + '@schema': '` + schemaName + "'") + (StringUtil.isEmpty(role, true) ? '' : `, + '@role': '` + role + "'") + ` +}` : `{ + "` + modelName + `": { + "userId": 82001` + (StringUtil.isEmpty(schemaName, true) ? '' : `, + "@schema": "` + schemaName + '"') + (StringUtil.isEmpty(role, true) ? '' : `, + "@role": "` + role + '"') + ` + }, + "tag": "` + modelName + `", + "@explain": true +}`) + }, + onClickColumn: function (tableIndex, modelName, columnIndex, columnName) { modelName = modelName || this.getModelName(tableIndex) if (StringUtil.isEmpty(columnName, true)) { @@ -5892,7 +5923,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea isSingle ? `{ '` + modelName + `': { '@column': 'DISTINCT ` + columnName + `', - '@order': '` + columnName + `+', // '@order': 'id-' + '@order': '` + columnName + `+', // '@order': 'id-' }, 'count': 0, 'page': 0, @@ -5901,7 +5932,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea "` + modelName + '-' + columnName + `[]": { "` + modelName + `": { "@column": "DISTINCT ` + columnName + `", - "@order": "` + columnName + `+", // "@order": "id-" + "@order": "` + columnName + `+", // "@order": "id-" }, "count": 0, "page": 0, @@ -5924,6 +5955,15 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea case 'get': this.handleClickGet(null, model, schema, role) break + case 'gets': + this.handleClickGets(null, model, schema, role) + break + case 'head': + this.handleClickHead(null, model, schema, role) + break + case 'heads': + this.handleClickHeads(null, model, schema, role) + break case 'post': this.handleClickPost(null, model, schema, role) break From 01eed1d332a66f2698239699af3fe4fb9dfb528d Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sun, 6 Nov 2022 06:51:56 +0800 Subject: [PATCH 640/818] =?UTF-8?q?=E8=87=AA=E5=8A=A8=E7=94=9F=E6=88=90?= =?UTF-8?q?=E6=96=87=E6=A1=A3=EF=BC=9A=E4=BC=98=E5=8C=96=20Access=20?= =?UTF-8?q?=E8=A1=A8=E8=A7=92=E8=89=B2=E6=9D=83=E9=99=90=E8=A1=A8=E6=A0=BC?= =?UTF-8?q?=E7=9A=84=E6=8E=92=E7=89=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- js/main.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/js/main.js b/js/main.js index 0e64c56..d662b49 100755 --- a/js/main.js +++ b/js/main.js @@ -5138,7 +5138,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea 'count': count, 'page': page, 'Access': { - '@column': 'name,alias,get,head,gets,heads,post,put,delete', + '@column': 'name,alias,post,put,delete,get,gets,head,heads', '@order': 'date-,name+', 'name$': search, 'alias$': search, @@ -5288,7 +5288,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea } ad += '\n\n\n\n\n\n\n\n\n### 访问权限\n自动查 Access 表写入的数据来生成\n' - + ' \n 表名 | 允许 post
的角色 | 允许 put
的角色 | 允许 delete
的角色 | 允许 get
的角色 | 允许 head
的角色 | 允许 gets
的角色 | 允许 heads
的角色 | 表名' + + ' \n 表名 | 允许 POST
的角色 | 允许 PUT
的角色 | 允许 DELETE
的角色 | 允许 GET
的角色 | 允许 GETS
的角色 | 允许 HEAD
的角色 | 允许 HEADS
的角色 | 表名' + ' \n -------- | --------- | --------- | --------- | --------- | --------- | --------- | --------- | -------- '; for (var i = 0; i < list.length; i++) { @@ -5321,13 +5321,17 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea + ' | ' + getShowString('put', 1) + ' | ' + getShowString('delete', 1) + ' | ' + getShowString('get', 2) - + ' | ' + getShowString('head', 2) + ' | ' + getShowString('gets', 2) + + ' | ' + getShowString('head', 2) + ' | ' + getShowString('heads', 2) + ' | ' + (name); //右上角设置指定了 Schema + '(' + item.schema + ')'); + + if (i % 5 == 4) { + ad += ' \n **表名** | **允许 POST**
**的角色** | **允许 PUT**
**的角色** | **允许 DELETE**
**的角色** | **允许 GET**
**的角色** | **允许 GETS**
**的角色** | **允许 HEAD**
**的角色** | **允许 HEADS**
**的角色** | 表名' + } } - ad += ' \n 表名 | 允许 post
的角色 | 允许 put
的角色 | 允许 delete
的角色 | 允许 get
的角色 | 允许 head
的角色 | 允许 gets
的角色 | 允许 heads
的角色 | 表名' + // ad += ' \n 表名 | 允许 post
的角色 | 允许 put
的角色 | 允许 delete
的角色 | 允许 get
的角色 | 允许 gets
的角色 | 允许 head
的角色 | 允许 heads
的角色 | 表名' ad += '\n' //避免没数据时表格显示没有网格 } From 4c5bf02b166de886825a5283e0d1b20d7e968070 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Tue, 8 Nov 2022 00:17:58 +0800 Subject: [PATCH 641/818] =?UTF-8?q?=E5=BF=AB=E6=8D=B7=E9=94=AE=EF=BC=9A?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=AF=B9=E5=9B=9E=E8=BD=A6=E5=92=8C=E5=88=A0?= =?UTF-8?q?=E9=99=A4=E7=9A=84=E8=87=AA=E5=8A=A8=E9=80=82=E9=85=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- js/main.js | 93 +++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 85 insertions(+), 8 deletions(-) diff --git a/js/main.js b/js/main.js index d662b49..1321fe0 100755 --- a/js/main.js +++ b/js/main.js @@ -8380,7 +8380,84 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea document.addEventListener('keydown', function(event) { // alert(event.key) 小写字母 i 而不是 KeyI // if (event.ctrlKey && event.keyCode === 73) { // KeyI 无效 event.key === 'KeyI' && event.target == vInput){ - if (event.ctrlKey || event.metaKey) { + var isEnter = event.keyCode === 13 + var isDel = event.keyCode === 8 || event.keyCode === 46 // backspace 和 del + if (isEnter || isDel) { // enter || delete + var target = event.target + if (target == vUrl) { + } + else { + var selectionStart = target.selectionStart; + var selectionEnd = target.selectionEnd; + + var text = StringUtil.get(target.value); + var before = text.substring(0, selectionStart); + var after = text.substring(selectionEnd); + + var firstIndex = isEnter ? after.indexOf('\n') : -1; + var firstLine = firstIndex <= 0 ? '' : after.substring(0, firstIndex); + var tfl = firstLine.trimLeft(); + + // var lastLineStart = isEnter && tfl.length > 0 ? -1 : before.lastIndexOf('\n') + 1; + var lastLineStart = before.lastIndexOf('\n') + 1; + var lastLine = lastLineStart < 0 ? '' : before.substring(lastLineStart); + + var prefixEnd = 0; + for (var i = 0; i < lastLine.length; i++) { + if (lastLine.charAt(i).trim().length > 0) { + if (isDel) { + prefixEnd = 0; + } + break; + } + + prefixEnd += 1; + } + + + var prefix = prefixEnd <= 0 ? '' : lastLine.substring(0, prefixEnd); + + var hasPadding = false; + var hasComma = false; + if (isEnter) { + var tll = lastLine.trimRight(); + hasPadding = tll.endsWith('{') || tll.endsWith('[') + + tll = before.trimRight(); + hasComma = tfl.length <= 0 && tll.endsWith(',') != true && (tll.endsWith('{') || tll.endsWith('[')) != true; + if (hasComma) { + for (var i = before.length; i >= 0; i--) { + if (before.charAt(i).trim().length > 0) { + break; + } + + selectionStart -= 1; + } + + before = tll + ','; + selectionStart += 1; + } + } + + if (prefix.length > 0) { + if (isEnter) { + target.value = before + '\n' + prefix + (hasPadding ? ' ' : '') + + (tfl.startsWith('}') || tfl.startsWith(']') ? after + : (hasPadding ? tfl.trimLeft() : tfl) + '\n' + after.substring(firstIndex + 1) + ); + + target.selectionEnd = target.selectionStart = selectionStart + prefix.length + 1 + (hasComma ? 1 : 0) + (hasPadding ? 4 : 0); + event.preventDefault(); + } + else if (isDel) { + target.value = (selectionStart == selectionEnd ? StringUtil.get(before.substring(0, lastLineStart - 1) + ' ') : before) + after; + target.selectionEnd = target.selectionStart = selectionStart == selectionEnd ? lastLineStart - 1 : selectionStart; + event.preventDefault(); + } + } + } + } + else if (event.ctrlKey || event.metaKey) { var target = event.target; var selectionStart = target.selectionStart; var selectionEnd = target.selectionEnd; @@ -8427,19 +8504,19 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea } else if (event.keyCode === 191) { // Ctrl + '/' 注释与取消注释 try { - var json = StringUtil.get(target.value); - var before = json.substring(0, selectionStart); - var after = json.substring(selectionEnd); + var text = StringUtil.get(target.value); + var before = text.substring(0, selectionStart); + var after = text.substring(selectionEnd); var ind = before.lastIndexOf('\n'); var start = ind < 0 ? 0 : ind + 1; ind = after.indexOf('\n'); - var end = ind < 0 ? json.length : selectionEnd + ind - 1; + var end = ind < 0 ? text.length : selectionEnd + ind - 1; - var selection = json.substring(start, end); + var selection = text.substring(start, end); var lines = StringUtil.split(selection, '\n'); - var newStr = json.substring(0, start); + var newStr = text.substring(0, start); var commentSign = '//' var commentSignLen = commentSign.length @@ -8470,7 +8547,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea } } - newStr += json.substring(end); + newStr += text.substring(end); target.value = newStr; if (target == vInput) { From 9653c1c185d9ad2ce585973082244c2cb23898d3 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Tue, 8 Nov 2022 00:37:46 +0800 Subject: [PATCH 642/818] =?UTF-8?q?=E5=BF=AB=E6=8D=B7=E9=94=AE=EF=BC=9A=20?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=94=AF=E6=8C=81=20Ctrl=20+=20D=20=E5=88=A0?= =?UTF-8?q?=E9=99=A4=E8=A1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- js/main.js | 36 +++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/js/main.js b/js/main.js index 1321fe0..79ea27e 100755 --- a/js/main.js +++ b/js/main.js @@ -8380,8 +8380,10 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea document.addEventListener('keydown', function(event) { // alert(event.key) 小写字母 i 而不是 KeyI // if (event.ctrlKey && event.keyCode === 73) { // KeyI 无效 event.key === 'KeyI' && event.target == vInput){ - var isEnter = event.keyCode === 13 - var isDel = event.keyCode === 8 || event.keyCode === 46 // backspace 和 del + + var keyCode = event.keyCode + var isEnter = keyCode === 13 + var isDel = keyCode === 8 || keyCode === 46 // backspace 和 del if (isEnter || isDel) { // enter || delete var target = event.target if (target == vUrl) { @@ -8454,6 +8456,10 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea target.selectionEnd = target.selectionStart = selectionStart == selectionEnd ? lastLineStart - 1 : selectionStart; event.preventDefault(); } + + if (target == vInput) { + inputted = target.value; + } } } } @@ -8462,9 +8468,9 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea var selectionStart = target.selectionStart; var selectionEnd = target.selectionEnd; - // 这里拿不到 clipboardData if (event.keyCode === 86) { + // 这里拿不到 clipboardData if (keyCode === 86) { - if (event.keyCode === 73) { // Ctrl + 'I' 格式化 + if (keyCode === 73) { // Ctrl + 'I' 格式化 try { if (target == vInput) { var json = JSON.stringify(JSON5.parse(vInput.value), null, ' '); @@ -8502,7 +8508,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea log(e) } } - else if (event.keyCode === 191) { // Ctrl + '/' 注释与取消注释 + else if (keyCode === 191) { // Ctrl + '/' 注释与取消注释 try { var text = StringUtil.get(target.value); var before = text.substring(0, selectionStart); @@ -8557,6 +8563,26 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea log(e) } } + else if (keyCode == 68) { // Ctrl + 'D' 删除行 + try { + var text = StringUtil.get(target.value); + var before = text.substring(0, selectionStart); + var after = text.substring(selectionEnd); + + var lastIndex = before.lastIndexOf('\n'); + var firstIndex = after.indexOf('\n'); + + target.value = (lastIndex < 0 ? '' : before.substring(0, lastIndex)) + '\n' + after.substring(firstIndex + 1); + selectionEnd = selectionStart = lastIndex + 1; + event.preventDefault(); + + if (target == vInput) { + inputted = newStr; + } + } catch (e) { + log(e) + } + } target.selectionStart = selectionStart; target.selectionEnd = selectionEnd; From 61c56ac15d9b4ce1ec2cf1c8dfd87b26b29ee9b5 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Tue, 8 Nov 2022 01:05:26 +0800 Subject: [PATCH 643/818] =?UTF-8?q?=E5=BF=AB=E6=8D=B7=E9=94=AE=EF=BC=9A=20?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=94=AF=E6=8C=81=20Tab=20=E5=9C=A8=E6=9C=80?= =?UTF-8?q?=E5=89=8D=E9=9D=A2=E5=8A=A0=204=20=E4=B8=AA=E7=A9=BA=E6=A0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apijson/CodeUtil.js | 8 +++--- js/main.js | 65 ++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 64 insertions(+), 9 deletions(-) diff --git a/apijson/CodeUtil.js b/apijson/CodeUtil.js index 330f3c3..d1e60a2 100644 --- a/apijson/CodeUtil.js +++ b/apijson/CodeUtil.js @@ -6137,7 +6137,8 @@ var CodeUtil = { else if (value instanceof Object) { if ((isReq != true || isRestful != true) && StringUtil.isEmpty(key, true)) { if (names == null || names.length <= 0) { - return isReq != true || isWarning ? '' : ' ' + CodeUtil.getComment('根对象,可在内部加 format,tag,version,@role,@database,@schema,@datasource,@explain,@cache 等全局关键词键值对', false, ' '); + return isReq != true || isWarning ? '' : ' ' + CodeUtil.getComment('根对象,可在内部加 Table:{}, []:{} 等' + + '或 format,tag,version,@role,@database,@schema,@datasource,@explain,@cache 等全局关键词键值对', false, ' '); } // 解决 APIJSON 批量 POST/PUT "Table[]": [{ key:value }] 中 {} 不显示注释 @@ -6170,7 +6171,7 @@ var CodeUtil = { return CodeUtil.getComment('子查询,里面必须有 "from":Table, Table:{} < ' + CodeUtil.getCommentFromDoc(tableList, objName, key.substring(0, key.length - 1), method, database, language, isReq != true || isRestful, isReq, pathKeys, isRestful, value, null, null, true, isWarning), false, ' ') + extraComment; } - return CodeUtil.getComment('子查询,可在内部加 from,range 或 数组关键词 等键值对,需要被下面的表字段相关 key 引用赋值', false, ' ') + extraComment; + return CodeUtil.getComment('子查询,可在内部加 Table:{} 或 from,range 或 数组关键词 等键值对,需要被下面的表字段相关 key 引用赋值', false, ' ') + extraComment; } if (isRestful != true && JSONObject.isArrayKey(key)) { @@ -6191,7 +6192,8 @@ var CodeUtil = { var firstIndex = objName.indexOf('-'); var firstKey = firstIndex < 0 ? objName : objName.substring(0, firstIndex); alias = alias.length <= 0 ? '' : '新建别名: ' + alias + ' < '; - return CodeUtil.getComment((JSONObject.isTableKey(firstKey) ? '提取' + objName + ' < ' : '') + alias + '数组,可在内部加 count,page,query,join 等关键词键值对', false, ' ') + extraComment; + return CodeUtil.getComment((JSONObject.isTableKey(firstKey) ? '提取' + objName + ' < ' : '') + alias + + '数组,可在内部加 Table:{}, []:{} 等或 count,page,query,compat,join 等关键词键值对', false, ' ') + extraComment; } var aliaIndex = key.indexOf(':'); diff --git a/js/main.js b/js/main.js index 79ea27e..efa3630 100755 --- a/js/main.js +++ b/js/main.js @@ -8379,13 +8379,13 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea // 快捷键 CTRL + I 格式化 JSON document.addEventListener('keydown', function(event) { // alert(event.key) 小写字母 i 而不是 KeyI - // if (event.ctrlKey && event.keyCode === 73) { // KeyI 无效 event.key === 'KeyI' && event.target == vInput){ + var target = event.target; var keyCode = event.keyCode var isEnter = keyCode === 13 var isDel = keyCode === 8 || keyCode === 46 // backspace 和 del + if (isEnter || isDel) { // enter || delete - var target = event.target if (target == vUrl) { } else { @@ -8463,8 +8463,55 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea } } } + else if (keyCode === 9) { // Tab 加空格 + try { + var selectionStart = target.selectionStart; + var selectionEnd = target.selectionEnd; + + var text = StringUtil.get(target.value); + var before = text.substring(0, selectionStart); + var after = text.substring(selectionEnd); + + var ind = before.lastIndexOf('\n'); + var start = ind < 0 ? 0 : ind + 1; + ind = after.indexOf('\n'); + var end = ind < 0 ? text.length : selectionEnd + ind - 1; + + var selection = text.substring(start, end); + var lines = StringUtil.split(selection, '\n'); + + var newStr = text.substring(0, start); + + var prefix = ' '; + var prefixLen = prefix.length; + for (var i = 0; i < lines.length; i ++) { + var l = lines[i] || ''; + if (i > 0) { + newStr += '\n'; + } + + newStr += prefix + l; + if (i <= 0) { + selectionStart += prefixLen; + } + selectionEnd += prefixLen; + } + + newStr += text.substring(end); + + target.value = newStr; + event.preventDefault(); + if (target == vInput) { + inputted = newStr; + } + + target.selectionStart = selectionStart; + target.selectionEnd = selectionEnd; + } catch (e) { + log(e) + } + } else if (event.ctrlKey || event.metaKey) { - var target = event.target; var selectionStart = target.selectionStart; var selectionEnd = target.selectionEnd; @@ -8538,17 +8585,23 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea var suffix = l.substring(ind + commentSignLen); if (suffix.startsWith(' ')) { suffix = suffix.substring(1); - selectionStart -= 1; + if (i <= 0) { + selectionStart -= 1; + } selectionEnd -= 1; } newStr += StringUtil.get(l.substring(0, ind)) + StringUtil.get(suffix) - selectionStart -= commentSignLen; + if (i <= 0) { + selectionStart -= commentSignLen; + } selectionEnd -= commentSignLen; } else { newStr += commentSign + ' ' + l; - selectionStart += commentSignLen + 1; + if (i <= 0) { + selectionStart += commentSignLen + 1; + } selectionEnd += commentSignLen + 1; } } From ec3d6088b0f7c2549414b0c0565bcfb9fe37f2bd Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Tue, 8 Nov 2022 01:25:06 +0800 Subject: [PATCH 644/818] =?UTF-8?q?=E5=BF=AB=E6=8D=B7=E9=94=AE=EF=BC=9A?= =?UTF-8?q?=E5=9C=A8=E5=AF=B9=E8=B1=A1=E5=86=85=E5=9B=9E=E8=BD=A6=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E7=94=9F=E6=88=90=E7=A9=BA=E9=94=AE=E5=80=BC=E5=AF=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- js/main.js | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/js/main.js b/js/main.js index efa3630..dd59166 100755 --- a/js/main.js +++ b/js/main.js @@ -8421,8 +8421,16 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea var hasPadding = false; var hasComma = false; + var hasNewKey = null; if (isEnter) { var tll = lastLine.trimRight(); + if (tll.endsWith('[') || tfl.startsWith(']')) { + hasNewKey = false; + } + else if (tfl.startsWith('}') || tll.indexOf('":') > 1 || tll.indexOf("':") > 1) { + hasNewKey = true; + } + hasPadding = tll.endsWith('{') || tll.endsWith('[') tll = before.trimRight(); @@ -8439,16 +8447,20 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea before = tll + ','; selectionStart += 1; } + + if (hasNewKey == null) { + hasNewKey = tll.endsWith('{'); + } } if (prefix.length > 0) { if (isEnter) { target.value = before + '\n' + prefix + (hasPadding ? ' ' : '') - + (tfl.startsWith('}') || tfl.startsWith(']') ? after + + (hasNewKey ? (isSingle ? "'': null," : '"": null,') : '') + (tfl.startsWith('}') || tfl.startsWith(']') ? after : (hasPadding ? tfl.trimLeft() : tfl) + '\n' + after.substring(firstIndex + 1) ); - target.selectionEnd = target.selectionStart = selectionStart + prefix.length + 1 + (hasComma ? 1 : 0) + (hasPadding ? 4 : 0); + target.selectionEnd = target.selectionStart = selectionStart + prefix.length + 1 + (hasComma ? 1 : 0) + (hasNewKey ? 1 : 0) + (hasPadding ? 4 : 0); event.preventDefault(); } else if (isDel) { From 0b650a58c2d69784b4146e94d38511456ade4e84 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Tue, 8 Nov 2022 05:35:22 +0800 Subject: [PATCH 645/818] =?UTF-8?q?=E8=87=AA=E5=8A=A8=E8=A1=A5=E5=85=A8?= =?UTF-8?q?=E5=8F=82=E6=95=B0=EF=BC=9A=E6=96=B0=E5=A2=9E=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E8=A1=A5=E5=85=A8=20APIJSON=20=E7=9A=84?= =?UTF-8?q?=E5=85=B3=E9=94=AE=E8=AF=8D=E3=80=81=E5=AD=97=E6=AE=B5=E5=90=8D?= =?UTF-8?q?=E3=80=81=E8=A1=A8=E5=90=8D=E7=AD=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.html | 17 ++++ js/main.js | 260 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 273 insertions(+), 4 deletions(-) diff --git a/index.html b/index.html index a4cff1e..28b028e 100755 --- a/index.html +++ b/index.html @@ -293,6 +293,18 @@ + + + + + + + + + + + +
@@ -600,6 +612,10 @@ + + @@ -867,6 +883,7 @@ var vType = document.getElementById("vType"); var vSend = document.getElementById("vSend"); + var vOption = document.getElementById("vOption"); var vInput = document.getElementById("vInput"); var vWarning = document.getElementById("vWarning"); var vComment = document.getElementById("vComment"); diff --git a/js/main.js b/js/main.js index dd59166..320b2f4 100755 --- a/js/main.js +++ b/js/main.js @@ -641,6 +641,7 @@ } //这些全局变量不能放在data中,否则会报undefined错误 + var baseUrl var inputted var handler @@ -650,6 +651,9 @@ var isSingle = true + var currentTarget = vInput; + var selectionStart = 0; + var selectionEnd = 0; // APIJSON >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> @@ -665,6 +669,8 @@ requestVersion: 3, requestCount: 1, urlComment: '一对多关联查询 Comment.userId = User.id', + selectIndex: 0, + options: [], // [{name:"id", type: "integer", comment:"主键"}, {name:"name", type: "string", comment:"用户名称"}], historys: [], history: {name: '请求0'}, remotes: [], @@ -714,6 +720,7 @@ isExportShow: false, isExportCheckShow: false, isExportRandom: false, + isOptionListShow: false, isTestCaseShow: false, isHeaderShow: false, isRandomShow: true, // 默认展示 @@ -1168,6 +1175,35 @@ }, + selectInput: function (target, item, index, isDone) { + currentTarget = target; + // 失去焦点后拿不到有效值 + // var selectionStart = target.selectionStart; + // var selectionEnd = target.selectionEnd; + + var text = StringUtil.get(target.value); + var before = text.substring(0, selectionStart); + var after = text.substring(selectionEnd); + + var name = StringUtil.get(item.name); + target.value = before + name + after + if (target == vInput) { + inputted = target.value; + } + + if (isDone) { + this.options = []; + + target.focus(); + selectionStart = target.selectionStart = selectionEnd + 3; + selectionEnd = target.selectionEnd = selectionStart + 4 + // vOption.focusout() + } else { + target.selectionStart = selectionStart; + selectionEnd = target.selectionEnd = selectionStart + name.length; + } + }, + // 显示保存弹窗 showSave: function (show) { if (show) { @@ -4804,6 +4840,12 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea */ doOnKeyUp: function (event, type, isFilter, item) { var keyCode = event.keyCode ? event.keyCode : (event.which ? event.which : event.charCode); + if (type == 'option') { + if (keyCode == 13) { + this.selectInput(vInput, item); + } + return + } var obj = event.srcElement ? event.srcElement : event.target; if ($(obj).attr('id') == 'vUrl') { @@ -8376,6 +8418,149 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea } + function showOptions(target, text, before, after) { + currentTarget = target; + selectionStart = target.selectionStart; + selectionEnd = target.selectionEnd; + App.options = [] + + var posX = 0, posY = 0; + + var event = window.event; + if (event.pageX || event.pageY) { + posX = event.pageX; + posY = event.pageY; + } + else if (event.clientX || event.clientY) { + posX = event.clientX + document.documentElement.scrollLeft + document.body.scrollLeft; + posY = event.clientY + document.documentElement.scrollTop + document.body.scrollTop; + } + else if (target.offsetHeight || target.offsetWidth) { + // posX = target.offsetHeight; + // posY = target.offsetWidth; + } + + vOption.style.left = posX + 'px'; + vOption.style.top = posY + 'px'; + + var table = null; + var isArrayKey = false; + var isSubqueryKey = false; + while (before != null && before.length > 0) { + var lastIndex = before.lastIndexOf('{'); + before = before.substring(0, lastIndex).trimRight(); + if (before.endsWith(':')) { + before = before.substring(0, before.length - 1).trimRight(); + var endsWithDoubleQuote = before.endsWith('"') + if (endsWithDoubleQuote || before.endsWith("'")) { + before = before.substring(0, before.length - 1); + lastIndex = before.lastIndexOf('\n'); + var lastLine = before.substring(lastIndex + 1, before.length); + var ind = lastLine.lastIndexOf(endsWithDoubleQuote ? '"' : "'"); + table = ind < 0 ? null : lastLine.substring(ind + 1, lastLine.length); + if (App.isTableKey(table)) { + break; + } + if (table != null && table.endsWith('[]')) { + isArrayKey = true; + break; + } + if (table != null && table.endsWith('@')) { + isSubqueryKey = true; + break; + } + + before = lastIndex <= 0 ? '' : before.substring(0, lastIndex); + } + } + } + + App.selectIndex = 0; + App.options = [ + {name:"@column", type: "string", comment:"返回字段"}, + {name:"@from@", type: "object", comment:"数据来源"}, + {name:"@group", type: "string", comment:"分组方式"}, + {name:"@having", type: "string", comment:"聚合函数"}, + {name:"@order", type: "string", comment:"排序方式"}, + {name:"@combine", type: "string", comment:"条件组合"}, + {name:"@raw", type: "string", comment:"原始SQL片段"}, + {name:"@json", type: "string", comment:"转为JSON"}, + {name:"@null", type: "string", comment:"NULL值字段"}, + {name:"@cast", type: "string", comment:"类型转换"}, + {name:"@schema", type: "string", comment:"集合空间(数据库名/模式)"}, + {name:"@database", type: "string", comment:"数据库类型"}, + {name:"@datasource", type: "string", comment:"跨数据源"}, + {name:"@role", type: "string", comment:"来访角色"}, + {name:"@cache", type: "string", comment:"缓存方式"}, + {name:"@explain", type: "string", comment:"性能分析"}, + ]; + + if (isArrayKey) { + App.options = [ + {name:"count", type: "integer", comment:"每页数量"}, + {name:"page", type: "integer", comment:"分页页码"}, + {name:"query", type: "integer", comment:"查询内容"}, + {name:"compat", type: "boolean", comment:"兼容统计"}, + {name:"join", type: "string", comment:"联表查询"}, + ]; + } + else if (isSubqueryKey) { + App.options = [ + {name:"from", type: "string", comment:"主表名称"}, + {name:"count", type: "integer", comment:"每页数量"}, + {name:"page", type: "integer", comment:"分页页码"}, + {name:"range", type: "string", comment:"比较范围"}, + {name:"join", type: "string", comment:"联表查询"}, + ]; + } + else if (App.isTableKey(table)) { + var columnList = App.getColumnListWithModelName(table); + if (columnList != null) { + for (var j = 0; j < columnList.length; j++) { + var column = App.getColumnObj(columnList, j) + var name = column == null ? null : column.column_name; + if (StringUtil.isEmpty(name, true)) { + continue; + } + + App.options.push({ + name: name, + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, column.column_type), + comment: column.column_comment + }) + } + } + } + else { + App.options.push([ + {name:"format", type: "string", comment:"格式化"}, + {name:"tag", type: "string", comment:"请求标识"}, + {name:"version", type: "string", comment:"请求版本"}, + ]) + } + + if (App.isTableKey(table) != true) { + var tableList = docObj['[]'] + if (tableList != null) { + for (var j = 0; j < tableList.length; j++) { + var tableObj = App.getTableObj(j); + var name = tableObj == null ? null : App.getModelNameByTableName(tableObj.table_name); + if (StringUtil.isEmpty(name, true)) { + continue; + } + + App.options.push({ + name: name, + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, 'object'), + comment: tableObj.table_comment + }) + } + } + } + + vOption.focus(); + } + // 快捷键 CTRL + I 格式化 JSON document.addEventListener('keydown', function(event) { // alert(event.key) 小写字母 i 而不是 KeyI @@ -8385,10 +8570,73 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea var isEnter = keyCode === 13 var isDel = keyCode === 8 || keyCode === 46 // backspace 和 del - if (isEnter || isDel) { // enter || delete + if (keyCode === 27) { // ESC + if (document.activeElement == vOption || App.options.length > 0) { + App.options = []; + target.focus(); + } + } + else if (keyCode === 40 || keyCode === 38) { // 方向键 上 和 下 + if (keyCode === 38) { + if (App.selectIndex > 0) { + App.selectIndex -- + App.selectInput(vInput, App.options[App.selectIndex], App.selectIndex) + } + } else if (App.selectIndex < App.options.length - 1) { + App.selectIndex ++ + App.selectInput(vInput, App.options[App.selectIndex], App.selectIndex) + } + + // var options = document.activeElement == vOption || App.options.length > 0 ? App.options : null; // vOption.options : null; + // if (options != null) { + // for (var i = 0; i < options.length; i++) { + // var opt = options[i] + // if (opt != null && (opt.selected || i == App.selectIndex)) { + // if (keyCode === 38) { + // if (i > 0) { + // opt.selected = false + // options[i - 1].selected = true + // App.selectInput(vInput, App.options[i - 1], i - 1) + // } + // } else { + // if (i < options.length - 1) { + // opt.selected = false + // options[i + 1].selected = true + // App.selectInput(vInput, App.options[i + 1], i + 1) + // } + // } + // + // break + // } + // } + + event.preventDefault(); + // } + } + else if (isEnter || isDel) { // enter || delete + if (document.activeElement == vOption || App.options.length > 0) { // hasFocus is undefined vOption.hasFocus()) { + if (currentTarget == null) { + currentTarget = vInput; + } + + var options = vOption.options || App.options + if (options != null) { + for (var i = 0; i < options.length; i++) { + var opt = options[i] + if (opt != null && (opt.selected || i == App.selectIndex)) { + App.selectInput(currentTarget, App.options[i], i, true); + break; + } + } + } + + event.preventDefault(); + return; + } + if (target == vUrl) { } - else { + else if (target != vOption) { var selectionStart = target.selectionStart; var selectionEnd = target.selectionEnd; @@ -8424,10 +8672,10 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea var hasNewKey = null; if (isEnter) { var tll = lastLine.trimRight(); - if (tll.endsWith('[') || tfl.startsWith(']')) { + if (tll.endsWith('[') || tfl.startsWith(']') || tfl.startsWith('}')) { hasNewKey = false; } - else if (tfl.startsWith('}') || tll.indexOf('":') > 1 || tll.indexOf("':") > 1) { + else if (tll.indexOf('":') > 1 || tll.indexOf("':") > 1) { hasNewKey = true; } @@ -8462,6 +8710,10 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea target.selectionEnd = target.selectionStart = selectionStart + prefix.length + 1 + (hasComma ? 1 : 0) + (hasNewKey ? 1 : 0) + (hasPadding ? 4 : 0); event.preventDefault(); + + if (hasNewKey) { + showOptions(target, text, before, after); + } } else if (isDel) { target.value = (selectionStart == selectionEnd ? StringUtil.get(before.substring(0, lastLineStart - 1) + ' ') : before) + after; From 693dc6363f82e331f8c0aa7ef956a908cc78e7e3 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Tue, 8 Nov 2022 07:38:06 +0800 Subject: [PATCH 646/818] =?UTF-8?q?=E8=87=AA=E5=8A=A8=E8=A1=A5=E5=85=A8?= =?UTF-8?q?=E5=8F=82=E6=95=B0=EF=BC=9A=E5=AE=8C=E5=96=84=E8=A1=A5=E5=85=A8?= =?UTF-8?q?=20APIJSON=20key=20=E5=AF=B9=E5=BA=94=E7=9A=84=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- js/main.js | 734 +++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 549 insertions(+), 185 deletions(-) diff --git a/js/main.js b/js/main.js index 320b2f4..7ef562e 100755 --- a/js/main.js +++ b/js/main.js @@ -652,6 +652,7 @@ var isSingle = true var currentTarget = vInput; + var isInputValue = false; var selectionStart = 0; var selectionEnd = 0; @@ -1175,8 +1176,9 @@ }, - selectInput: function (target, item, index, isDone) { + selectInput: function (target, item, index, isDone, isValue) { currentTarget = target; + isInputValue = isValue; // 失去焦点后拿不到有效值 // var selectionStart = target.selectionStart; // var selectionEnd = target.selectionEnd; @@ -1185,8 +1187,8 @@ var before = text.substring(0, selectionStart); var after = text.substring(selectionEnd); - var name = StringUtil.get(item.name); - target.value = before + name + after + var name = item == null ? '' : StringUtil.get(item.name); + target.value = text = before + name + after if (target == vInput) { inputted = target.value; } @@ -1195,9 +1197,13 @@ this.options = []; target.focus(); - selectionStart = target.selectionStart = selectionEnd + 3; - selectionEnd = target.selectionEnd = selectionStart + 4 + selectionStart = target.selectionStart = selectionEnd + (isValue ? 1 : 3); + selectionEnd = target.selectionEnd = selectionStart + (isValue ? 0 : 4) // vOption.focusout() + + if (isValue != true) { + App.showOptions(target, text, before + name + (isSingle ? "'" : '"') + ': ', after.substring(3), true); + } } else { target.selectionStart = selectionStart; selectionEnd = target.selectionEnd = selectionStart + name.length; @@ -4211,7 +4217,7 @@ onChange: function (delay) { this.setBaseUrl(); - if (IS_NODE) { + if (IS_NODE || document.activeElement == vOption || this.options.length > 0) { return; } @@ -8210,6 +8216,497 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea } }) + }, + + showOptions: function(target, text, before, after, isValue) { + currentTarget = target; + isInputValue = isValue; + selectionStart = target.selectionStart; + selectionEnd = target.selectionEnd; + App.options = [] + + var posX = 0, posY = 0; + + var event = window.event; + if (event.pageX || event.pageY) { + posX = event.pageX; + posY = event.pageY; + } + else if (event.clientX || event.clientY) { + posX = event.clientX + document.documentElement.scrollLeft + document.body.scrollLeft; + posY = event.clientY + document.documentElement.scrollTop + document.body.scrollTop; + } + else if (target.offsetHeight || target.offsetWidth) { + // posX = target.offsetHeight; + // posY = target.offsetWidth; + } + + vOption.style.left = posX + 'px'; + vOption.style.top = posY + 'px'; + + var quote = isSingle ? "'" : '"'; + + var table = null; + var isArrayKey = false; + var isSubqueryKey = false; + + var prev = before; + while (prev != null && prev.length > 0) { + var lastIndex = prev.lastIndexOf('{'); + prev = prev.substring(0, lastIndex).trimRight(); + + if (prev.endsWith(':')) { + prev = prev.substring(0, prev.length - 1).trimRight(); + var endsWithDoubleQuote = prev.endsWith('"') + + if (endsWithDoubleQuote || prev.endsWith("'")) { + prev = prev.substring(0, prev.length - 1); + lastIndex = prev.lastIndexOf('\n'); + + var lastLine = prev.substring(lastIndex + 1, prev.length); + var ind = lastLine.lastIndexOf(endsWithDoubleQuote ? '"' : "'"); + table = ind < 0 ? null : lastLine.substring(ind + 1, lastLine.length); + + if (App.isTableKey(table)) { + break; + } + if (table != null && table.endsWith('[]')) { + isArrayKey = true; + break; + } + if (table != null && table.endsWith('@')) { + isSubqueryKey = true; + break; + } + + prev = lastIndex <= 0 ? '' : prev.substring(0, lastIndex); + } + } + } + + if (isValue) { + var lastIndex = before.lastIndexOf('\n'); + var lastLine = before.substring(lastIndex + 1, before.length); + lastIndex = lastLine.lastIndexOf(':'); + lastLine = lastIndex < 0 ? '' : lastLine.substring(0, lastIndex).trim(); + + var endsWithDoubleQuote = lastLine.endsWith('"') + if (endsWithDoubleQuote || lastLine.endsWith("'")) { + lastLine = lastLine.substring(0, lastLine.length - 1); + } + var ind = lastLine.lastIndexOf(endsWithDoubleQuote ? '"' : "'"); + var key = ind < 0 ? null : lastLine.substring(ind + 1, lastLine.length); + + var isArrayKey = JSONObject.isArrayKey(key) + if (isArrayKey || App.isTableKey(key)) { + table = key; + if (isArrayKey) { + ind = key.indexOf('-'); + if (ind < 0) { + ind = key.indexOf(':'); + } + table = key.substring(0, ind < 0 ? key.length - 2 : ind); + } + + App.options = [{ + name: "{}", + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "varchar"), + comment: (isArrayKey ? '数组 < ' + table + ': ' : '') + StringUtil.trim((App.getTableByModelName(table) || {}).table_comment) + }] + } + else { + switch (key) { + case '@from@': + App.options = [{ + name: "{}", + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "object"), + comment: '数据来源' + }]; + break; + case '@combine': + case '@raw': + var isRaw = key == '@raw'; + + var end = before.lastIndexOf('{'); + var start = after.indexOf('}'); + var s = (end < 0 ? before : before.substring(end)) + after.substring(0, start + 1); + var json = App.getRequest(s, {}); + + var ks = ''; + var first = true; + for (var k in json) { + if (StringUtil.isNotEmpty(k, true)) { + App.options.push({ + name: quote + k + quote, + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "string"), + comment: isRaw ? '原始SQL片段' : '条件组合' + }); + + ks += (first ? '' : (isRaw ? ',' : ' & ')) + k; + first = false; + } + }; + + if (StringUtil.isNotEmpty(ks, true)) { + App.options.push({ + name: quote + ks + quote, + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "string"), + comment: isRaw ? '原始SQL片段' : '条件组合' + }); + } + break; + case '@schema': + var schemas = StringUtil.split(App.schema); + if (schemas != null) { + for (var i = 0; i < schemas.length; i++) { + var sch = schemas[i]; + if (StringUtil.isNotEmpty(sch, true)) { + App.options.push({ + name: quote + sch + quote, + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "string"), + comment: '集合空间(数据库名/模式)' + }); + } + } + } + break; + case '@database': + App.options = [{ + name: isSingle ? "'MYSQL'" : '"MYSQL"', + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "string"), + comment: 'MySQL' + },{ + name: isSingle ? "'POSTGRESQL'" : '"POSTGRESQL"', + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "string"), + comment: 'PostgreSQL' + },{ + name: isSingle ? "'SQLSERVER'" : '"SQLSERVER"', + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "string"), + comment: 'SQLServer' + },{ + name: isSingle ? "'ORACLE'" : '"ORACLE"', + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "string"), + comment: 'Oracle' + },{ + name: isSingle ? "'DB2'" : '"DB2"', + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "string"), + comment: 'DB2' + },{ + name: isSingle ? "'DAMENG'" : '"DAMENG"', + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "string"), + comment: '达梦数据库' + },{ + name: isSingle ? "'CLICKHOUSE'" : '"CLICKHOUSE"', + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "string"), + comment: 'ClickHouse' + },{ + name: isSingle ? "'SQLITE'" : '"SQLITE"', + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "string"), + comment: 'SQLite' + },{ + name: isSingle ? "'TDENGINE'" : '"TDENGINE"', + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "string"), + comment: 'TDengine' + }]; + break; + case '@role': + App.options = [{ + name: isSingle ? "'UNKNOWN'" : '"UNKNOWN"', + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "string"), + comment: '来访角色: 未登录' + },{ + name: isSingle ? "'LOGIN'" : '"LOGIN"', + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "string"), + comment: '来访角色: 已登录' + },{ + name: isSingle ? "'CIRCLE'" : '"CIRCLE"', + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "string"), + comment: '来访角色: 圈子成员' + },{ + name: isSingle ? "'CONTACT'" : '"CONTACT"', + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "string"), + comment: '来访角色: 联系人' + },{ + name: isSingle ? "'OWNER'" : '"OWNER"', + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "string"), + comment: '来访角色: 拥有者' + },{ + name: isSingle ? "'ADMIN'" : '"ADMIN"', + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "string"), + comment: '来访角色: 管理员' + }]; + break; + case '@cache': + App.options = [{ + name: "0", + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "int"), + comment: '缓存方式: 全部' + },{ + name: "1", + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "int"), + comment: '缓存方式: 磁盘' + },{ + name: "2", + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "int"), + comment: '缓存方式: 内存' + }]; + break; + case '@explain': + App.options = [{ + name: "true", + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "boolean"), + comment: '性能分析: 开启' + },{ + name: "false", + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "boolean"), + comment: '性能分析: 关闭' + }]; + break; + default: + if (key.endsWith('()')) { + if (key.startsWith('@')) { + App.options = [{ + name: quote + 'fun(arg0,arg1)' + quote, + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "string"), + comment: '存储过程' + }]; + } else { + var functionList = docObj == null ? null : docObj['Function[]']; + if (functionList != null) { + for (var i = 0; i < functionList.length; i++) { + var item = functionList[i]; + var name = item == null ? null : item.name; + if (StringUtil.isEmpty(name, true)) { + continue; + } + + App.options = ({ + name: quote + name + '(' + StringUtil.trim(item.arguments) + ')' + quote, + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "string"), + comment: item.detail + }); + } + } + } + } + break; + } + + var columnList = App.getColumnListWithModelName(table); + if (columnList != null) { + var ks = ''; + var first = true; + for (var j = 0; j < columnList.length; j++) { + var column = App.getColumnObj(columnList, j) + var name = column == null ? null : column.column_name; + if (StringUtil.isEmpty(name, true)) { + continue; + } + + var k = name; + switch (key) { + case '@having': + var arr = ['max', 'min', 'sum', 'avg', 'length', 'len', 'json_length']; + var which = Math.floor(arr.length*Math.random()); + k = arr[which] + '(' + name + ')'; + break; + case '@order': + k = name + (Math.random() < 0.2 ? '' : (Math.random() < 0.5 ? '-' : '+')); + break; + case '@cast': + k = name + ':' + StringUtil.toUpperCase(column.column_type); + break; + // case '@column': + // case '@group': + // case '@json': + // case '@null': + default: + k = name; + break; + } + + App.options.push({ + name: quote + k + quote, + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, column.column_type), + comment: column.column_comment + }) + + ks += (first ? '' : ',') + k; + first = false; + } + + App.options.push({ + name: quote + ks + quote, + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, 'string'), + comment: '所有字段组合' + }) + } + } + } + else { + App.selectIndex = -1; + App.options = [ + { + name: "@column", + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "varchar"), + comment: "返回字段" + }, + {name: "@from@", type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "object"), comment: "数据来源"}, + { + name: "@group", + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "varchar"), + comment: "分组方式" + }, + { + name: "@having", + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "varchar"), + comment: "聚合函数" + }, + { + name: "@order", + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "varchar"), + comment: "排序方式" + }, + { + name: "@combine", + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "varchar"), + comment: "条件组合" + }, + { + name: "@raw", + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "varchar"), + comment: "原始SQL片段" + }, + { + name: "@json", + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "varchar"), + comment: "转为JSON" + }, + { + name: "@null", + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "varchar"), + comment: "NULL值字段" + }, + {name: "@cast", type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "varchar"), comment: "类型转换"}, + { + name: "@schema", + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "varchar"), + comment: "集合空间(数据库名/模式)" + }, + { + name: "@database", + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "varchar"), + comment: "数据库类型" + }, + { + name: "@datasource", + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "varchar"), + comment: "跨数据源" + }, + {name: "@role", type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "varchar"), comment: "来访角色"}, + { + name: "@cache", + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "varchar"), + comment: "缓存方式" + }, + { + name: "@explain", + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "varchar"), + comment: "性能分析" + }, + ]; + + if (isArrayKey) { + App.options = [ + {name: "count", type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "int"), comment: "每页数量"}, + {name: "page", type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "int"), comment: "分页页码"}, + {name: "query", type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "int"), comment: "查询内容"}, + { + name: "compat", + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "boolean"), + comment: "兼容统计" + }, + { + name: "join", + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "varchar"), + comment: "联表查询" + }, + ]; + } else if (isSubqueryKey) { + App.options = [ + { + name: "from", + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "varchar"), + comment: "主表名称" + }, + {name: "count", type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "int"), comment: "每页数量"}, + {name: "page", type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "int"), comment: "分页页码"}, + { + name: "range", + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "varchar"), + comment: "比较范围" + }, + { + name: "join", + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "varchar"), + comment: "联表查询" + }, + ]; + } else if (App.isTableKey(table)) { + var columnList = App.getColumnListWithModelName(table); + if (columnList != null) { + for (var j = 0; j < columnList.length; j++) { + var column = App.getColumnObj(columnList, j) + var name = column == null ? null : column.column_name; + if (StringUtil.isEmpty(name, true)) { + continue; + } + + App.options.push({ + name: name, + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, column.column_type), + comment: column.column_comment + }) + } + } + } else { + App.options.push([ + { + name: "format", + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "varchar"), + comment: "格式化" + }, + {name: "tag", type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "varchar"), comment: "请求标识"}, + { + name: "version", + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "varchar"), + comment: "请求版本" + }, + ]) + } + + if (App.isTableKey(table) != true) { + var tableList = docObj['[]'] + if (tableList != null) { + for (var j = 0; j < tableList.length; j++) { + var tableObj = App.getTableObj(j); + var name = tableObj == null ? null : App.getModelNameByTableName(tableObj.table_name); + if (StringUtil.isEmpty(name, true)) { + continue; + } + + App.options.push({ + name: name, + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, 'object'), + comment: tableObj.table_comment + }) + } + } + } + + } + + vOption.focus(); } }, watch: { @@ -8418,149 +8915,6 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea } - function showOptions(target, text, before, after) { - currentTarget = target; - selectionStart = target.selectionStart; - selectionEnd = target.selectionEnd; - App.options = [] - - var posX = 0, posY = 0; - - var event = window.event; - if (event.pageX || event.pageY) { - posX = event.pageX; - posY = event.pageY; - } - else if (event.clientX || event.clientY) { - posX = event.clientX + document.documentElement.scrollLeft + document.body.scrollLeft; - posY = event.clientY + document.documentElement.scrollTop + document.body.scrollTop; - } - else if (target.offsetHeight || target.offsetWidth) { - // posX = target.offsetHeight; - // posY = target.offsetWidth; - } - - vOption.style.left = posX + 'px'; - vOption.style.top = posY + 'px'; - - var table = null; - var isArrayKey = false; - var isSubqueryKey = false; - while (before != null && before.length > 0) { - var lastIndex = before.lastIndexOf('{'); - before = before.substring(0, lastIndex).trimRight(); - if (before.endsWith(':')) { - before = before.substring(0, before.length - 1).trimRight(); - var endsWithDoubleQuote = before.endsWith('"') - if (endsWithDoubleQuote || before.endsWith("'")) { - before = before.substring(0, before.length - 1); - lastIndex = before.lastIndexOf('\n'); - var lastLine = before.substring(lastIndex + 1, before.length); - var ind = lastLine.lastIndexOf(endsWithDoubleQuote ? '"' : "'"); - table = ind < 0 ? null : lastLine.substring(ind + 1, lastLine.length); - if (App.isTableKey(table)) { - break; - } - if (table != null && table.endsWith('[]')) { - isArrayKey = true; - break; - } - if (table != null && table.endsWith('@')) { - isSubqueryKey = true; - break; - } - - before = lastIndex <= 0 ? '' : before.substring(0, lastIndex); - } - } - } - - App.selectIndex = 0; - App.options = [ - {name:"@column", type: "string", comment:"返回字段"}, - {name:"@from@", type: "object", comment:"数据来源"}, - {name:"@group", type: "string", comment:"分组方式"}, - {name:"@having", type: "string", comment:"聚合函数"}, - {name:"@order", type: "string", comment:"排序方式"}, - {name:"@combine", type: "string", comment:"条件组合"}, - {name:"@raw", type: "string", comment:"原始SQL片段"}, - {name:"@json", type: "string", comment:"转为JSON"}, - {name:"@null", type: "string", comment:"NULL值字段"}, - {name:"@cast", type: "string", comment:"类型转换"}, - {name:"@schema", type: "string", comment:"集合空间(数据库名/模式)"}, - {name:"@database", type: "string", comment:"数据库类型"}, - {name:"@datasource", type: "string", comment:"跨数据源"}, - {name:"@role", type: "string", comment:"来访角色"}, - {name:"@cache", type: "string", comment:"缓存方式"}, - {name:"@explain", type: "string", comment:"性能分析"}, - ]; - - if (isArrayKey) { - App.options = [ - {name:"count", type: "integer", comment:"每页数量"}, - {name:"page", type: "integer", comment:"分页页码"}, - {name:"query", type: "integer", comment:"查询内容"}, - {name:"compat", type: "boolean", comment:"兼容统计"}, - {name:"join", type: "string", comment:"联表查询"}, - ]; - } - else if (isSubqueryKey) { - App.options = [ - {name:"from", type: "string", comment:"主表名称"}, - {name:"count", type: "integer", comment:"每页数量"}, - {name:"page", type: "integer", comment:"分页页码"}, - {name:"range", type: "string", comment:"比较范围"}, - {name:"join", type: "string", comment:"联表查询"}, - ]; - } - else if (App.isTableKey(table)) { - var columnList = App.getColumnListWithModelName(table); - if (columnList != null) { - for (var j = 0; j < columnList.length; j++) { - var column = App.getColumnObj(columnList, j) - var name = column == null ? null : column.column_name; - if (StringUtil.isEmpty(name, true)) { - continue; - } - - App.options.push({ - name: name, - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, column.column_type), - comment: column.column_comment - }) - } - } - } - else { - App.options.push([ - {name:"format", type: "string", comment:"格式化"}, - {name:"tag", type: "string", comment:"请求标识"}, - {name:"version", type: "string", comment:"请求版本"}, - ]) - } - - if (App.isTableKey(table) != true) { - var tableList = docObj['[]'] - if (tableList != null) { - for (var j = 0; j < tableList.length; j++) { - var tableObj = App.getTableObj(j); - var name = tableObj == null ? null : App.getModelNameByTableName(tableObj.table_name); - if (StringUtil.isEmpty(name, true)) { - continue; - } - - App.options.push({ - name: name, - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, 'object'), - comment: tableObj.table_comment - }) - } - } - } - - vOption.focus(); - } - // 快捷键 CTRL + I 格式化 JSON document.addEventListener('keydown', function(event) { // alert(event.key) 小写字母 i 而不是 KeyI @@ -8574,44 +8928,48 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea if (document.activeElement == vOption || App.options.length > 0) { App.options = []; target.focus(); + return; } } else if (keyCode === 40 || keyCode === 38) { // 方向键 上 和 下 - if (keyCode === 38) { - if (App.selectIndex > 0) { - App.selectIndex -- - App.selectInput(vInput, App.options[App.selectIndex], App.selectIndex) - } - } else if (App.selectIndex < App.options.length - 1) { - App.selectIndex ++ - App.selectInput(vInput, App.options[App.selectIndex], App.selectIndex) - } - - // var options = document.activeElement == vOption || App.options.length > 0 ? App.options : null; // vOption.options : null; - // if (options != null) { - // for (var i = 0; i < options.length; i++) { - // var opt = options[i] - // if (opt != null && (opt.selected || i == App.selectIndex)) { - // if (keyCode === 38) { - // if (i > 0) { - // opt.selected = false - // options[i - 1].selected = true - // App.selectInput(vInput, App.options[i - 1], i - 1) - // } - // } else { - // if (i < options.length - 1) { - // opt.selected = false - // options[i + 1].selected = true - // App.selectInput(vInput, App.options[i + 1], i + 1) - // } - // } - // - // break - // } - // } + if (document.activeElement == vOption || App.options.length > 0) { + if (keyCode === 38) { + if (App.selectIndex >= 0) { + App.selectIndex -- + App.selectInput(vInput, App.selectIndex < 0 ? null : App.options[App.selectIndex], App.selectIndex, false, isInputValue) + } + } else if (App.selectIndex < App.options.length) { + App.selectIndex ++ + App.selectInput(vInput, App.selectIndex >= App.options.length ? null : App.options[App.selectIndex], App.selectIndex, false, isInputValue) + } + + // var options = document.activeElement == vOption || App.options.length > 0 ? App.options : null; // vOption.options : null; + // if (options != null) { + // for (var i = 0; i < options.length; i++) { + // var opt = options[i] + // if (opt != null && (opt.selected || i == App.selectIndex)) { + // if (keyCode === 38) { + // if (i > 0) { + // opt.selected = false + // options[i - 1].selected = true + // App.selectInput(vInput, App.options[i - 1], i - 1) + // } + // } else { + // if (i < options.length - 1) { + // opt.selected = false + // options[i + 1].selected = true + // App.selectInput(vInput, App.options[i + 1], i + 1) + // } + // } + // + // break + // } + // } event.preventDefault(); - // } + return; + // } + } } else if (isEnter || isDel) { // enter || delete if (document.activeElement == vOption || App.options.length > 0) { // hasFocus is undefined vOption.hasFocus()) { @@ -8624,7 +8982,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea for (var i = 0; i < options.length; i++) { var opt = options[i] if (opt != null && (opt.selected || i == App.selectIndex)) { - App.selectInput(currentTarget, App.options[i], i, true); + App.selectInput(currentTarget, App.options[i], i, true, isInputValue); break; } } @@ -8712,7 +9070,11 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea event.preventDefault(); if (hasNewKey) { - showOptions(target, text, before, after); + App.showOptions(target, text, before, after); + if (target == vInput) { + inputted = target.value; + } + return; } } else if (isDel) { @@ -8904,8 +9266,10 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea target.selectionStart = selectionStart; target.selectionEnd = selectionEnd; } - }) + App.selectIndex = -1; + App.options = [] + }) } } From b30ad84dd8e239be842177ab929f12e58d9b4a46 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Tue, 8 Nov 2022 08:11:03 +0800 Subject: [PATCH 647/818] =?UTF-8?q?=E8=87=AA=E5=8A=A8=E8=A1=A5=E5=85=A8?= =?UTF-8?q?=E5=8F=82=E6=95=B0=EF=BC=9A=E5=AE=8C=E5=96=84=E8=BF=9C=E7=A8=8B?= =?UTF-8?q?=E5=87=BD=E6=95=B0=E3=80=81=E5=AD=98=E5=82=A8=E8=BF=87=E7=A8=8B?= =?UTF-8?q?=E3=80=81=E5=88=86=E9=A1=B5=E5=8F=82=E6=95=B0=E7=AD=89=E6=8F=90?= =?UTF-8?q?=E7=A4=BA=EF=BC=8C=E8=A7=A3=E5=86=B3=E5=AF=B9=20APIJSON=20?= =?UTF-8?q?=E8=BF=9C=E7=A8=8B=E5=87=BD=E6=95=B0=E7=94=9F=E6=88=90=E4=B8=8D?= =?UTF-8?q?=E4=BA=86=E5=80=BC=EF=BC=8C=E8=A7=A3=E5=86=B3=20count,=20page?= =?UTF-8?q?=20=E7=AD=89=E6=95=B0=E5=AD=97=E5=AF=BC=E8=87=B4=E7=94=9F?= =?UTF-8?q?=E6=88=90=E9=87=8D=E5=A4=8D=20JSON?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- js/main.js | 116 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 112 insertions(+), 4 deletions(-) diff --git a/js/main.js b/js/main.js index 7ef562e..b4f441b 100755 --- a/js/main.js +++ b/js/main.js @@ -8284,6 +8284,8 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea } } + App.selectIndex = -1; + if (isValue) { var lastIndex = before.lastIndexOf('\n'); var lastLine = before.substring(lastIndex + 1, before.length); @@ -8310,7 +8312,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea App.options = [{ name: "{}", - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "varchar"), + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "object"), comment: (isArrayKey ? '数组 < ' + table + ': ' : '') + StringUtil.trim((App.getTableByModelName(table) || {}).table_comment) }] } @@ -8335,7 +8337,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea var ks = ''; var first = true; for (var k in json) { - if (StringUtil.isNotEmpty(k, true)) { + if (StringUtil.isNotEmpty(k, true) && (isRaw || (k.startsWith('@') != true && key.indexOf('()') < 0))) { App.options.push({ name: quote + k + quote, type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "string"), @@ -8451,6 +8453,72 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea comment: '缓存方式: 内存' }]; break; + case 'count': + case 'page': + var isPage = key == 'page'; + for (var i = 0; i < 100; i++) { + App.options.push({ + name: new String(i), // 直接用数字导致重复生成 JSON + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "int"), + comment: isPage ? '分页页码' : '每页数量' + }); + } + break; + case 'tag': + case 'version': + var isVersion = key == 'version'; + var requestList = docObj == null ? null : docObj['Request[]']; + if (requestList != null) { + for (var i = 0; i < requestList.length; i++) { + var item = requestList[i]; + if (item == null) { + continue; + } + + App.options.push({ + name: isVersion ? item.version : item.tag, + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "int"), + comment: isVersion ? '请求版本' : '请求标识' + }); + } + } + break; + case 'query': + App.options = [{ + name: "0", + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "int"), + comment: '查询内容: 数据' + },{ + name: "1", + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "int"), + comment: '查询内容: 数量' + },{ + name: "2", + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "int"), + comment: '查询内容: 全部' + }]; + break; + case 'range': + App.options = [{ + name: quote + "ANY" + quote, + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "string"), + comment: '比较范围: 任意' + },{ + name: quote + "ALL" + quote, + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "string"), + comment: '比较范围: 全部' + }]; + case 'compat': + App.options = [{ + name: "true", + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "boolean"), + comment: '兼容统计: 开启' + },{ + name: "false", + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "boolean"), + comment: '兼容统计: 关闭' + }]; + break; case '@explain': App.options = [{ name: "true", @@ -8462,6 +8530,17 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea comment: '性能分析: 关闭' }]; break; + case '': + App.options = [{ + name: "true", + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "boolean"), + comment: '性能分析: 开启' + },{ + name: "false", + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "boolean"), + comment: '性能分析: 关闭' + }]; + break; default: if (key.endsWith('()')) { if (key.startsWith('@')) { @@ -8480,7 +8559,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea continue; } - App.options = ({ + App.options.push({ name: quote + name + '(' + StringUtil.trim(item.arguments) + ')' + quote, type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "string"), comment: item.detail @@ -8544,7 +8623,6 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea } } else { - App.selectIndex = -1; App.options = [ { name: "@column", @@ -8614,6 +8692,36 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "varchar"), comment: "性能分析" }, + { + name: "key-()", + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "varchar"), + comment: "远程函数: 优先执行" + }, + { + name: "key()", + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "varchar"), + comment: "远程函数" + }, + { + name: "key+()", + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "varchar"), + comment: "远程函数: 延后执行" + }, + { + name: "@key-()", + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "varchar"), + comment: "存储过程: 优先执行" + }, + { + name: "@key()", + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "varchar"), + comment: "存储过程" + }, + { + name: "@key+()", + type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "varchar"), + comment: "存储过程: 延后执行" + }, ]; if (isArrayKey) { From 6a19eadc732e6133a695b0afdfb877a8cd671d27 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Tue, 8 Nov 2022 08:39:57 +0800 Subject: [PATCH 648/818] =?UTF-8?q?=E8=87=AA=E5=8A=A8=E8=A1=A5=E5=85=A8?= =?UTF-8?q?=E5=8F=82=E6=95=B0=EF=BC=9A=E5=AE=8C=E5=96=84=E5=90=84=E7=A7=8D?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=E7=AC=A6=E7=9A=84=20key=20=E7=94=9F=E6=88=90?= =?UTF-8?q?=EF=BC=8C=E8=A7=A3=E5=86=B3=E8=AF=AD=E8=A8=80=E5=9B=BA=E5=AE=9A?= =?UTF-8?q?=E4=B8=BA=20JavaScript=20=E8=80=8C=E4=B8=8D=E6=98=AF=E8=AE=BE?= =?UTF-8?q?=E7=BD=AE=E7=9A=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- js/main.js | 197 +++++++++++++++++++++++++++-------------------------- 1 file changed, 101 insertions(+), 96 deletions(-) diff --git a/js/main.js b/js/main.js index b4f441b..aa60374 100755 --- a/js/main.js +++ b/js/main.js @@ -8312,7 +8312,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea App.options = [{ name: "{}", - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "object"), + type: CodeUtil.getType4Language(App.language, "object"), comment: (isArrayKey ? '数组 < ' + table + ': ' : '') + StringUtil.trim((App.getTableByModelName(table) || {}).table_comment) }] } @@ -8321,7 +8321,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea case '@from@': App.options = [{ name: "{}", - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "object"), + type: CodeUtil.getType4Language(App.language, "object"), comment: '数据来源' }]; break; @@ -8340,7 +8340,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea if (StringUtil.isNotEmpty(k, true) && (isRaw || (k.startsWith('@') != true && key.indexOf('()') < 0))) { App.options.push({ name: quote + k + quote, - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "string"), + type: CodeUtil.getType4Language(App.language, "string"), comment: isRaw ? '原始SQL片段' : '条件组合' }); @@ -8352,7 +8352,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea if (StringUtil.isNotEmpty(ks, true)) { App.options.push({ name: quote + ks + quote, - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "string"), + type: CodeUtil.getType4Language(App.language, "string"), comment: isRaw ? '原始SQL片段' : '条件组合' }); } @@ -8365,7 +8365,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea if (StringUtil.isNotEmpty(sch, true)) { App.options.push({ name: quote + sch + quote, - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "string"), + type: CodeUtil.getType4Language(App.language, "string"), comment: '集合空间(数据库名/模式)' }); } @@ -8375,81 +8375,81 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea case '@database': App.options = [{ name: isSingle ? "'MYSQL'" : '"MYSQL"', - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "string"), + type: CodeUtil.getType4Language(App.language, "string"), comment: 'MySQL' },{ name: isSingle ? "'POSTGRESQL'" : '"POSTGRESQL"', - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "string"), + type: CodeUtil.getType4Language(App.language, "string"), comment: 'PostgreSQL' },{ name: isSingle ? "'SQLSERVER'" : '"SQLSERVER"', - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "string"), + type: CodeUtil.getType4Language(App.language, "string"), comment: 'SQLServer' },{ name: isSingle ? "'ORACLE'" : '"ORACLE"', - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "string"), + type: CodeUtil.getType4Language(App.language, "string"), comment: 'Oracle' },{ name: isSingle ? "'DB2'" : '"DB2"', - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "string"), + type: CodeUtil.getType4Language(App.language, "string"), comment: 'DB2' },{ name: isSingle ? "'DAMENG'" : '"DAMENG"', - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "string"), + type: CodeUtil.getType4Language(App.language, "string"), comment: '达梦数据库' },{ name: isSingle ? "'CLICKHOUSE'" : '"CLICKHOUSE"', - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "string"), + type: CodeUtil.getType4Language(App.language, "string"), comment: 'ClickHouse' },{ name: isSingle ? "'SQLITE'" : '"SQLITE"', - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "string"), + type: CodeUtil.getType4Language(App.language, "string"), comment: 'SQLite' },{ name: isSingle ? "'TDENGINE'" : '"TDENGINE"', - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "string"), + type: CodeUtil.getType4Language(App.language, "string"), comment: 'TDengine' }]; break; case '@role': App.options = [{ name: isSingle ? "'UNKNOWN'" : '"UNKNOWN"', - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "string"), + type: CodeUtil.getType4Language(App.language, "string"), comment: '来访角色: 未登录' },{ name: isSingle ? "'LOGIN'" : '"LOGIN"', - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "string"), + type: CodeUtil.getType4Language(App.language, "string"), comment: '来访角色: 已登录' },{ name: isSingle ? "'CIRCLE'" : '"CIRCLE"', - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "string"), + type: CodeUtil.getType4Language(App.language, "string"), comment: '来访角色: 圈子成员' },{ name: isSingle ? "'CONTACT'" : '"CONTACT"', - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "string"), + type: CodeUtil.getType4Language(App.language, "string"), comment: '来访角色: 联系人' },{ name: isSingle ? "'OWNER'" : '"OWNER"', - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "string"), + type: CodeUtil.getType4Language(App.language, "string"), comment: '来访角色: 拥有者' },{ name: isSingle ? "'ADMIN'" : '"ADMIN"', - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "string"), + type: CodeUtil.getType4Language(App.language, "string"), comment: '来访角色: 管理员' }]; break; case '@cache': App.options = [{ name: "0", - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "int"), + type: CodeUtil.getType4Language(App.language, "int"), comment: '缓存方式: 全部' },{ name: "1", - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "int"), + type: CodeUtil.getType4Language(App.language, "int"), comment: '缓存方式: 磁盘' },{ name: "2", - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "int"), + type: CodeUtil.getType4Language(App.language, "int"), comment: '缓存方式: 内存' }]; break; @@ -8459,7 +8459,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea for (var i = 0; i < 100; i++) { App.options.push({ name: new String(i), // 直接用数字导致重复生成 JSON - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "int"), + type: CodeUtil.getType4Language(App.language, "int"), comment: isPage ? '分页页码' : '每页数量' }); } @@ -8477,7 +8477,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea App.options.push({ name: isVersion ? item.version : item.tag, - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "int"), + type: CodeUtil.getType4Language(App.language, "int"), comment: isVersion ? '请求版本' : '请求标识' }); } @@ -8486,58 +8486,59 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea case 'query': App.options = [{ name: "0", - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "int"), + type: CodeUtil.getType4Language(App.language, "int"), comment: '查询内容: 数据' },{ name: "1", - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "int"), + type: CodeUtil.getType4Language(App.language, "int"), comment: '查询内容: 数量' },{ name: "2", - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "int"), + type: CodeUtil.getType4Language(App.language, "int"), comment: '查询内容: 全部' }]; break; case 'range': App.options = [{ name: quote + "ANY" + quote, - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "string"), + type: CodeUtil.getType4Language(App.language, "string"), comment: '比较范围: 任意' },{ name: quote + "ALL" + quote, - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "string"), + type: CodeUtil.getType4Language(App.language, "string"), comment: '比较范围: 全部' }]; + break; case 'compat': App.options = [{ name: "true", - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "boolean"), + type: CodeUtil.getType4Language(App.language, "boolean"), comment: '兼容统计: 开启' },{ name: "false", - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "boolean"), + type: CodeUtil.getType4Language(App.language, "boolean"), comment: '兼容统计: 关闭' }]; break; case '@explain': App.options = [{ name: "true", - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "boolean"), + type: CodeUtil.getType4Language(App.language, "boolean"), comment: '性能分析: 开启' },{ name: "false", - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "boolean"), + type: CodeUtil.getType4Language(App.language, "boolean"), comment: '性能分析: 关闭' }]; break; case '': App.options = [{ name: "true", - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "boolean"), + type: CodeUtil.getType4Language(App.language, "boolean"), comment: '性能分析: 开启' },{ name: "false", - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "boolean"), + type: CodeUtil.getType4Language(App.language, "boolean"), comment: '性能分析: 关闭' }]; break; @@ -8546,7 +8547,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea if (key.startsWith('@')) { App.options = [{ name: quote + 'fun(arg0,arg1)' + quote, - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "string"), + type: CodeUtil.getType4Language(App.language, "string"), comment: '存储过程' }]; } else { @@ -8561,7 +8562,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea App.options.push({ name: quote + name + '(' + StringUtil.trim(item.arguments) + ')' + quote, - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "string"), + type: CodeUtil.getType4Language(App.language, "string"), comment: item.detail }); } @@ -8573,6 +8574,9 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea var columnList = App.getColumnListWithModelName(table); if (columnList != null) { + var isHaving = key == '@having'; + var arr = ['max', 'min', 'sum', 'avg', 'length', 'len', 'json_length']; + var ks = ''; var first = true; for (var j = 0; j < columnList.length; j++) { @@ -8585,9 +8589,8 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea var k = name; switch (key) { case '@having': - var arr = ['max', 'min', 'sum', 'avg', 'length', 'len', 'json_length']; var which = Math.floor(arr.length*Math.random()); - k = arr[which] + '(' + name + ')'; + k = arr[which] + '(' + name + ')' + (Math.random() < 0.2 ? '<82010' : (Math.random() < 0.5 ? '>3' : '%2=0')); break; case '@order': k = name + (Math.random() < 0.2 ? '' : (Math.random() < 0.5 ? '-' : '+')); @@ -8606,17 +8609,17 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea App.options.push({ name: quote + k + quote, - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, column.column_type), + type: CodeUtil.getType4Language(App.language, column.column_type), comment: column.column_comment }) - ks += (first ? '' : ',') + k; + ks += (first ? '' : (isHaving ? ';' : ',')) + k; first = false; } App.options.push({ name: quote + ks + quote, - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, 'string'), + type: CodeUtil.getType4Language(App.language, 'string'), comment: '所有字段组合' }) } @@ -8626,137 +8629,130 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea App.options = [ { name: "@column", - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "varchar"), + type: CodeUtil.getType4Language(App.language, "varchar"), comment: "返回字段" }, - {name: "@from@", type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "object"), comment: "数据来源"}, + {name: "@from@", type: CodeUtil.getType4Language(App.language, "object"), comment: "数据来源"}, { name: "@group", - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "varchar"), + type: CodeUtil.getType4Language(App.language, "varchar"), comment: "分组方式" }, { name: "@having", - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "varchar"), + type: CodeUtil.getType4Language(App.language, "varchar"), comment: "聚合函数" }, { name: "@order", - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "varchar"), + type: CodeUtil.getType4Language(App.language, "varchar"), comment: "排序方式" }, { name: "@combine", - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "varchar"), + type: CodeUtil.getType4Language(App.language, "varchar"), comment: "条件组合" }, { name: "@raw", - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "varchar"), + type: CodeUtil.getType4Language(App.language, "varchar"), comment: "原始SQL片段" }, { name: "@json", - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "varchar"), + type: CodeUtil.getType4Language(App.language, "varchar"), comment: "转为JSON" }, { name: "@null", - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "varchar"), + type: CodeUtil.getType4Language(App.language, "varchar"), comment: "NULL值字段" }, - {name: "@cast", type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "varchar"), comment: "类型转换"}, + {name: "@cast", type: CodeUtil.getType4Language(App.language, "varchar"), comment: "类型转换"}, { name: "@schema", - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "varchar"), + type: CodeUtil.getType4Language(App.language, "varchar"), comment: "集合空间(数据库名/模式)" }, { name: "@database", - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "varchar"), + type: CodeUtil.getType4Language(App.language, "varchar"), comment: "数据库类型" }, { name: "@datasource", - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "varchar"), + type: CodeUtil.getType4Language(App.language, "varchar"), comment: "跨数据源" }, - {name: "@role", type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "varchar"), comment: "来访角色"}, + {name: "@role", type: CodeUtil.getType4Language(App.language, "varchar"), comment: "来访角色"}, { name: "@cache", - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "varchar"), + type: CodeUtil.getType4Language(App.language, "varchar"), comment: "缓存方式" }, { name: "@explain", - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "varchar"), + type: CodeUtil.getType4Language(App.language, "varchar"), comment: "性能分析" }, { name: "key-()", - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "varchar"), + type: CodeUtil.getType4Language(App.language, "varchar"), comment: "远程函数: 优先执行" }, { name: "key()", - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "varchar"), + type: CodeUtil.getType4Language(App.language, "varchar"), comment: "远程函数" }, { name: "key+()", - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "varchar"), + type: CodeUtil.getType4Language(App.language, "varchar"), comment: "远程函数: 延后执行" }, { name: "@key-()", - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "varchar"), + type: CodeUtil.getType4Language(App.language, "varchar"), comment: "存储过程: 优先执行" }, { name: "@key()", - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "varchar"), + type: CodeUtil.getType4Language(App.language, "varchar"), comment: "存储过程" }, { name: "@key+()", - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "varchar"), + type: CodeUtil.getType4Language(App.language, "varchar"), comment: "存储过程: 延后执行" }, ]; if (isArrayKey) { App.options = [ - {name: "count", type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "int"), comment: "每页数量"}, - {name: "page", type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "int"), comment: "分页页码"}, - {name: "query", type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "int"), comment: "查询内容"}, - { - name: "compat", - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "boolean"), - comment: "兼容统计" - }, - { - name: "join", - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "varchar"), - comment: "联表查询" - }, + {name: "count", type: CodeUtil.getType4Language(App.language, "int"), comment: "每页数量"}, + {name: "page", type: CodeUtil.getType4Language(App.language, "int"), comment: "分页页码"}, + {name: "query", type: CodeUtil.getType4Language(App.language, "int"), comment: "查询内容"}, + {name: "compat", type: CodeUtil.getType4Language(App.language, "boolean"), comment: "兼容统计"}, + {name: "join", type: CodeUtil.getType4Language(App.language, "varchar"), comment: "联表查询"}, + {name: "[]", type: CodeUtil.getType4Language(App.language, "array"), comment: "数组对象"}, ]; } else if (isSubqueryKey) { App.options = [ { name: "from", - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "varchar"), + type: CodeUtil.getType4Language(App.language, "varchar"), comment: "主表名称" }, - {name: "count", type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "int"), comment: "每页数量"}, - {name: "page", type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "int"), comment: "分页页码"}, + {name: "count", type: CodeUtil.getType4Language(App.language, "int"), comment: "每页数量"}, + {name: "page", type: CodeUtil.getType4Language(App.language, "int"), comment: "分页页码"}, { name: "range", - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "varchar"), + type: CodeUtil.getType4Language(App.language, "varchar"), comment: "比较范围" }, { name: "join", - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "varchar"), + type: CodeUtil.getType4Language(App.language, "varchar"), comment: "联表查询" }, ]; @@ -8772,24 +8768,33 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea App.options.push({ name: name, - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, column.column_type), + type: CodeUtil.getType4Language(App.language, column.column_type), + comment: column.column_comment + }) + } + + var arr = ['{}', '$', '~', '<>', '>', '<', '<=', '>=', '!', '}{', '%', '&$', '|{}', '!~','+', '-']; + for (var j = 0; j < columnList.length; j++) { + var column = App.getColumnObj(columnList, j) + var name = column == null ? null : column.column_name; + if (StringUtil.isEmpty(name, true)) { + continue; + } + + var which = Math.floor(arr.length*Math.random()); + App.options.push({ + name: name + arr[which], + type: CodeUtil.getType4Language(App.language, column.column_type), comment: column.column_comment }) } } } else { App.options.push([ - { - name: "format", - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "varchar"), - comment: "格式化" - }, - {name: "tag", type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "varchar"), comment: "请求标识"}, - { - name: "version", - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, "varchar"), - comment: "请求版本" - }, + {name: "format", type: CodeUtil.getType4Language(App.language, "varchar"), comment: "格式化"}, + {name: "tag", type: CodeUtil.getType4Language(App.language, "varchar"), comment: "请求标识"}, + {name: "version", type: CodeUtil.getType4Language(App.language, "varchar"), comment: "请求版本"}, + {name: "[]", type: CodeUtil.getType4Language(App.language, "array"), comment: "数组对象"}, ]) } @@ -8805,7 +8810,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea App.options.push({ name: name, - type: CodeUtil.getType4Language(CodeUtil.LANGUAGE_JAVA_SCRIPT, 'object'), + type: CodeUtil.getType4Language(App.language, 'object'), comment: tableObj.table_comment }) } From a1ead38672c8c02ac0541c83feebf404d3c48b2a Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Thu, 10 Nov 2022 05:47:03 +0800 Subject: [PATCH 649/818] =?UTF-8?q?=E8=87=AA=E5=8A=A8=E8=A1=A5=E5=85=A8?= =?UTF-8?q?=E5=8F=82=E6=95=B0=EF=BC=9A=E5=AE=8C=E5=96=84=E8=BF=9C=E7=A8=8B?= =?UTF-8?q?=E5=87=BD=E6=95=B0=E7=9A=84=E7=B1=BB=E5=9E=8B=EF=BC=8C=E8=A7=A3?= =?UTF-8?q?=E5=86=B3=E5=80=BC=E5=90=8E=E5=A4=9A=E4=BA=86=E9=80=97=E5=8F=B7?= =?UTF-8?q?=EF=BC=8C=E8=A7=A3=E5=86=B3=20@cast=20=E5=80=99=E9=80=89?= =?UTF-8?q?=E9=A1=B9=E4=B8=AD=E7=B1=BB=E5=9E=8B=E5=A4=9A=E4=BA=86=E9=95=BF?= =?UTF-8?q?=E5=BA=A6=EF=BC=9B=E8=87=AA=E5=8A=A8=E7=94=9F=E6=88=90=E6=B3=A8?= =?UTF-8?q?=E9=87=8A=EF=BC=9A=E4=BC=98=E5=8C=96=E6=95=B0=E7=BB=84=E3=80=81?= =?UTF-8?q?=E8=BF=9C=E7=A8=8B=E5=87=BD=E6=95=B0=E7=9A=84=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apijson/CodeUtil.js | 11 ++++---- index.html | 2 +- js/main.js | 63 +++++++++++++++++++++++++-------------------- 3 files changed, 42 insertions(+), 34 deletions(-) diff --git a/apijson/CodeUtil.js b/apijson/CodeUtil.js index d1e60a2..da07c38 100644 --- a/apijson/CodeUtil.js +++ b/apijson/CodeUtil.js @@ -5880,7 +5880,7 @@ var CodeUtil = { }, DATABASE_KEYS: ['MYSQL', 'POSTGRESQL', 'SQLSERVER', 'ORACLE', 'DB2', 'DAMENG', 'CLICKHOUSE', 'SQLITE', 'TDENGINE'], - getComment4Function: function (funCallStr, method) { + getComment4Function: function (funCallStr, method, language) { if (typeof funCallStr != 'string') { return '远程函数 value 必须是 String 类型!'; } @@ -5928,7 +5928,7 @@ var CodeUtil = { throw new Error('远程函数参数数量 ' + argLen + ' 非法!必须是 ' + allowArgLen + ' 个!格式为 ' + fun + '(' + StringUtil.trim(allowArgStr) + ')') } - return funObj.rawDetail || funObj.detail + return CodeUtil.getType4Language(language, funObj.returntype) + ', ' + (funObj.rawDetail || funObj.detail) }, getFunctionFromList: function (name, method) { @@ -6086,7 +6086,7 @@ var CodeUtil = { var c = '' if (StringUtil.isNotEmpty(value)) { // isValueNotEmpty 居然不对 try { - c = CodeUtil.getComment4Function(value, method) + c = CodeUtil.getComment4Function(value, method, language) } catch (e) { return ' ! ' + e.message } @@ -6137,8 +6137,9 @@ var CodeUtil = { else if (value instanceof Object) { if ((isReq != true || isRestful != true) && StringUtil.isEmpty(key, true)) { if (names == null || names.length <= 0) { - return isReq != true || isWarning ? '' : ' ' + CodeUtil.getComment('根对象,可在内部加 Table:{}, []:{} 等' + - '或 format,tag,version,@role,@database,@schema,@datasource,@explain,@cache 等全局关键词键值对', false, ' '); + return isReq != true || isWarning ? '' : ' ' + CodeUtil.getComment('根对象,可在内部加 Table:{}' + + (method == null || method == 'GET' || method == 'GETS' ? ', []:{}' : (method == 'POST' || method == 'PUT' ? ', []:[{}]' : '')) + + ' 等或 format,tag,version,@role,@database,@schema,@datasource,@explain,@cache 等全局关键词键值对', false, ' '); } // 解决 APIJSON 批量 POST/PUT "Table[]": [{ key:value }] 中 {} 不显示注释 diff --git a/index.html b/index.html index 28b028e..d36a168 100755 --- a/index.html +++ b/index.html @@ -613,7 +613,7 @@ - + +
+ + + + + +
+ -
+
+
- 搜索 - - - - + + + + 每页 - +
diff --git a/js/main.js b/js/main.js index 22548e3..f65cce7 100755 --- a/js/main.js +++ b/js/main.js @@ -1172,7 +1172,11 @@ https://github.com/Tencent/APIJSON/issues deepDoneCount: 0, deepAllCount: 0, randomDoneCount: 0, - randomAllCount: 0 + randomAllCount: 0, + coverage: { + json: {}, + html: '' + } }, methods: { @@ -1338,12 +1342,12 @@ https://github.com/Tencent/APIJSON/issues } }, getUrl: function () { - var url = StringUtil.get(this.host) + new String(vUrl.value) - return url.replace(/ /g, '') + var url = StringUtil.get(this.host) + vUrl.value + return url.replaceAll(' ', '') }, //获取基地址 getBaseUrl: function (url_) { - var url = new String(url_ || vUrl.value).trim() + var url = StringUtil.trim(url_ || vUrl.value) var length = this.getBaseUrlLength(url) url = length <= 0 ? '' : url.substring(0, length) return url == '' ? URL_BASE : url @@ -3825,7 +3829,7 @@ https://github.com/Tencent/APIJSON/issues } App.exTxt.button = 'All:' + App.uploadTotal + '\nDone:' + App.uploadDoneCount + '\nFail:' + App.uploadFailCount if (App.uploadDoneCount + App.uploadFailCount >= App.uploadTotal) { - alert('导入完成,其中 ' + App.uploadRandomCount + ' 个接口已存在,改为生成和上传了参数注入配置') + alert('导入完成,其中 ' + App.uploadRandomCount + ' 个用例已存在,改为生成和上传了参数注入配置') App.isSyncing = false App.testCasePage = 0 App.isRandomShow = true @@ -4089,6 +4093,17 @@ https://github.com/Tencent/APIJSON/issues isCaseItemShow: function () { return this.caseShowType != 2 || (this.caseGroups.length <= 0 && this.casePaths.length > 0) }, + getCaseGroupShowName: function(index, item) { + if (StringUtil.isNotEmpty(item.groupName, true)) { + return item.groupName + } + if (StringUtil.isEmpty(item.groupUrl, true)) { + return '-' + } + + var prev = index <= 0 ? null : (this.casePaths[index-1] || {}).groupUrl + return item.groupUrl.substring(prev == null ? 1 : prev.length + 1) + }, selectCaseGroup: function (index, group) { this.isCaseGroupEditable = false @@ -4142,9 +4157,9 @@ https://github.com/Tencent/APIJSON/issues 'groupName$': search, 'groupUrl$': search, '@combine': search == null ? null : 'groupName$,groupUrl$', - '@column': "groupName,groupUrl;any_value(groupName):rawName;length(groupName):groupNameLen;count(*):count", + '@column': "groupName,groupUrl;any_value(groupName):rawName;length(groupName):groupNameLen;length(groupUrl):groupUrlLen;count(*):count", '@group': 'groupName,groupUrl', - '@order': 'groupNameLen+,groupName-,groupUrl+', + '@order': 'groupNameLen+,groupName-,groupUrlLen+,groupUrl+', } }, '@role': IS_NODE ? null : 'LOGIN', @@ -4233,7 +4248,7 @@ https://github.com/Tencent/APIJSON/issues return; } - this.isTestCaseShow = false + // this.isTestCaseShow = false var reportId = this.reportId var methods = this.methods @@ -4250,6 +4265,9 @@ https://github.com/Tencent/APIJSON/issues search = StringUtil.isEmpty(search, true) ? null : '%' + StringUtil.trim(search).replaceAll('_', '\\_').replaceAll('%', '\\%') + '%' var url = this.server + '/get' + + this.coverage = {} + this.view = 'markdown' var req = { format: false, '[]': { @@ -4305,6 +4323,7 @@ https://github.com/Tencent/APIJSON/issues } this.request(true, REQUEST_TYPE_POST, REQUEST_TYPE_JSON, url, req, {}, function (url, res, err) { + App.isTestCaseShow = false if (callback) { callback(url, res, err) return @@ -4776,6 +4795,48 @@ https://github.com/Tencent/APIJSON/issues this.setRememberLogin(user.remember) this.account = user.phone this.password = user.password + + var schemas = StringUtil.isEmpty(this.schema, true) ? null : StringUtil.split(this.schema) + + const req = { + type: 0, // 登录方式,非必须 0-密码 1-验证码 + // asDBAccount: ! isAdminOperation, // 直接 /execute 接口传 account, password + phone: this.account, + password: this.password, + version: 1, // 全局默认版本号,非必须 + remember: vRemember.checked, + format: false, + defaults: isAdmin ? { + key: IS_NODE ? this.key : undefined // 突破常规查询数量限制 + } : { + '@database': StringUtil.isEmpty(this.database, true) ? undefined : this.database, + '@schema': schemas == null || schemas.length != 1 ? undefined : this.schema + } + } + + this.isRandomShow = true + this.isRandomListShow = false + this.isHeaderShow = true + + this.method = REQUEST_TYPE_POST + this.type = REQUEST_TYPE_JSON + + if (IS_BROWSER) { + this.showUrl(isAdmin, '/login') + + vInput.value = JSON.stringify(req, null, ' ') + + this.testRandomCount = 1 + vRandom.value = `phone: App.account\npassword: App.password\nremember: vRemember.checked` + } + + this.scripts = newDefaultScript() + this.method = REQUEST_TYPE_POST + this.type = REQUEST_TYPE_JSON + this.showTestCase(false, this.isLocalShow) + if (IS_BROWSER) { + this.onChange(false) + } }, setRememberLogin: function (remember) { @@ -4793,7 +4854,6 @@ https://github.com/Tencent/APIJSON/issues /**登录 */ login: function (isAdminOperation, callback) { - this.isLoginShow = false this.isEditResponse = false var schemas = StringUtil.isEmpty(this.schema, true) ? null : StringUtil.split(this.schema) @@ -4814,6 +4874,8 @@ https://github.com/Tencent/APIJSON/issues } if (isAdminOperation) { + this.isLoginShow = false + this.request(isAdminOperation, REQUEST_TYPE_POST, REQUEST_TYPE_JSON, this.server + '/login', req, this.getHeader(vHeader.value), function (url, res, err) { if (callback) { callback(url, res, err) @@ -4838,32 +4900,45 @@ https://github.com/Tencent/APIJSON/issues } } - if (IS_BROWSER) { - this.showUrl(isAdminOperation, '/login') + const isLoginShow = this.isLoginShow + var curUser = this.getCurrentAccount() || {} + const loginMethod = curUser.loginMethod || REQUEST_TYPE_POST + const loginType = curUser.loginType || REQUEST_TYPE_JSON + const loginUrl = curUser.loginUrl || '/login' + const loginReq = curUser.loginReq || req + const loginHeader = curUser.loginHeader || {} + + function loginCallback(url, res, err, random) { + if (callback) { + callback(url, res, err) + return + } - vInput.value = JSON.stringify(req, null, ' ') + App.onLoginResponse(isAdminOperation, req, url, res, err, + isLoginShow ? App.method : loginMethod, + isLoginShow ? App.type : loginType, + isLoginShow ? App.getBranchUrl() : loginUrl, + isLoginShow ? App.getRequest(vInput.value) : loginReq, + isLoginShow ? App.getHeader(vHeader.value) : loginHeader + ) } - this.scripts = newDefaultScript() - this.method = REQUEST_TYPE_POST - this.type = REQUEST_TYPE_JSON - this.showTestCase(false, this.isLocalShow) - if (IS_BROWSER) { - this.onChange(false) + if (isLoginShow) { + this.isLoginShow = false + + this.testRandomWithText(true, loginCallback) + return } - this.send(isAdminOperation, function (url, res, err) { - if (App.isEnvCompareEnabled != true) { - if (callback) { - callback(url, res, err) - return - } - App.onLoginResponse(isAdminOperation, req, url, res, err) + this.scripts = newDefaultScript() + this.request(isAdminOperation, loginMethod, loginType, this.getBaseUrl() + loginUrl, loginReq, loginHeader, function (url, res, err) { + if (App.isEnvCompareEnabled != true) { + loginCallback(url, res, err, null, loginMethod, loginType, loginUrl, loginReq, loginHeader) return } - App.request(isAdminOperation, REQUEST_TYPE_POST, REQUEST_TYPE_JSON, App.getBaseUrl(App.otherEnv) + '/login' - , req, App.getHeader(vHeader.value), function (url_, res_, err_) { + App.request(isAdminOperation, loginMethod, loginType, App.getBaseUrl(App.otherEnv) + loginUrl + , loginReq, loginHeader, function(url_, res_, err_) { var data = res_.data var user = JSONResponse.isSuccess(data) ? data.user : null if (user != null) { @@ -4878,14 +4953,13 @@ https://github.com/Tencent/APIJSON/issues } App.onResponse(url_, res_, err_); - App.onLoginResponse(isAdminOperation, req, url, res, err) - }, App.scripts) - + App.onLoginResponse(isAdminOperation, req, url, res, err, loginMethod, loginType, loginUrl, loginReq, loginHeader) + }, App.scripts) }) } }, - onLoginResponse: function(isAdmin, req, url, res, err) { + onLoginResponse: function(isAdmin, req, url, res, err, loginMethod, loginType, loginUrl, loginReq, loginHeader) { res = res || {} if (isAdmin) { var rpObj = res.data || {} @@ -4936,6 +5010,11 @@ https://github.com/Tencent/APIJSON/issues phone: req.phone, password: req.password, remember: data.remember, + loginMethod: loginMethod, + loginType: loginType, + loginUrl: loginUrl, + loginReq: loginReq, + loginHeader: loginHeader, cookie: res.cookie || (res.headers || {}).cookie }) @@ -4946,8 +5025,9 @@ https://github.com/Tencent/APIJSON/issues App.currentAccountIndex = App.accounts.length - 1 - App.saveCache(App.getBaseUrl(), 'currentAccountIndex', App.currentAccountIndex) - App.saveCache(App.getBaseUrl(), 'accounts', App.accounts) + var key = App.getBaseUrl(loginUrl) + App.saveCache(key, 'currentAccountIndex', App.currentAccountIndex) + App.saveCache(key, 'accounts', App.accounts) App.listScript() } @@ -6701,14 +6781,28 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea return false; } doc = d; - vOutput.value = (this.isTestCaseShow ? '' : output) + ( + var url = StringUtil.trim((this.coverage || {}).url) + if (url != null && url.startsWith('/')) { + url = this.getBaseUrl() + url + this.view = 'html' + vHtml.innerHTML = '
' + return true + } + var html = null // (this.coverage || {}).html + if (StringUtil.isEmpty(html) != true) { + this.view = 'html' + vHtml.innerHTML = html + return true + } + vOutput.value = (StringUtil.isEmpty(url, true) ? (StringUtil.isEmpty(html, true) ? '' : StringUtil.trim(html) + '
') : '
') + + (this.isTestCaseShow ? '' : output) + ( '\n\n\n## 文档 \n\n 通用文档见 [APIJSON通用文档](https://github.com/Tencent/APIJSON/blob/master/Document.md#3.2) \n### 数据字典\n自动查数据库表和字段属性来生成 \n\n' + d + '

关于

' + '

APIAuto-机器学习 HTTP 接口工具' + '
机器学习零代码测试、生成代码与静态检查、生成文档与光标悬浮注释' + '
APIAuto(前端网页工具), APIJSON(后端接口服务) 等提供技术支持' + '
遵循 Apache-2.0 开源协议' - + '
Copyright © 2016-' + new Date().getFullYear() + ' Tommy Lemon' + + '
Copyright © 2017-' + new Date().getFullYear() + ' Tommy Lemon' + '
粤ICP备18005508号-1' + '



' ); @@ -7643,15 +7737,80 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea this.onChange(false) }, - // toDoubleJSON: function (json, defaultValue) { - // if (StringUtil.isEmpty(json)) { - // return defaultValue == null ? '{}' : JSON.stringify(defaultValue) - // } - // else if (json.indexOf("'") >= 0) { - // json = json.replace(/'/g, '"'); - // } - // return json; - // }, + getTotalAndCoverageString: function(typeName, count, total) { + count = count || 0 + total = total || 0 + if (count > total) { + count = total + } + return '共 ' + total + ' 个' + (typeName || '子项') + ',覆盖 ' + count + ' 个' + + (Number.isInteger(total) != true || total <= 0 ? '' : ',覆盖率 ' + (100*count/total).toFixed(2) + '%'); + }, + getRealClassTotal: function(data, packageName) { + if (data == null) { + return 0; + } + var packageList = data.packageList + var len = packageList == null ? 0 : packageList.length + if (StringUtil.isEmpty(packageName, true)) { + return Math.max(data.classTotal || 0, len); + } + if (len <= 0) { + return 0; + } + for (var i in packageList) { + var pkgObj = packageList[i] + if (pkgObj != null && pkgObj['package'] == packageName) { + return Math.max(pkgObj.classTotal || 0, (pkgObj.classList || []).length || 0); + } + } + return 0; + }, + getRealMethodTotal: function(data, packageName, className) { + if (data == null) { + return 0; + } + var packageList = data.packageList + var len = packageList == null ? 0 : packageList.length + if (StringUtil.isEmpty(packageName, true)) { + if (StringUtil.isEmpty(className, true)) { + return Math.max(data.classTotal || 0, len); + } + return 0; + } + if (len <= 0) { + return 0; + } + for (var i in packageList) { + var pkgObj = packageList[i] + if (pkgObj != null && pkgObj['package'] == packageName) { + var classList = pkgObj.classList + var len2 = classList == null ? 0 : classList.length + if (StringUtil.isEmpty(className, true)) { + return Math.max(data.methodTotal || 0, len2); + } + if (len2 <= 0) { + return 0; + } + for (var j in classList) { + var clsObj = classList[j] + if (clsObj != null && clsObj['class'] == className) { + return Math.max(clsObj.methodTotal || 0, (clsObj.methodList || []).length || 0); + } + } + } + } + return 0; + }, + toDoubleJSON: function (json, defaultValue) { + if (StringUtil.isEmpty(json)) { + return defaultValue == null ? '{}' : JSON.stringify(defaultValue) + } + else if (json.indexOf("'") >= 0) { + json = json.replace(/'/g, '"'); + } + return json; + }, switchQuote: function (before) { if (before == null) { @@ -8455,7 +8614,6 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea totalCount: count } - var methods = this.methods this.testRandomSingle(show, false, this.isRandomSubListShow, this.currentRandomItem, this.isShowMethod() ? this.method : null, this.type, this.getUrl() , this.getRequest(vInput.value, {}), this.getHeader(vHeader.value), false, false, callback @@ -8903,7 +9061,18 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea cs.totalCount = total } - this.test(false, accountIndex, isCross, callback) + this.coverage = {} + this.request(false, REQUEST_TYPE_POST, REQUEST_TYPE_JSON, this.getBaseUrl() + '/coverage/start', {}, {}, function (url, res, err) { + try { + App.onResponse(url, res, err) + if (DEBUG) { + App.log('test App.request >> res.data = ' + JSON.stringify(res.data, null, ' ')) + } + } catch (e) { + App.log('test App.request >> } catch (e) {\n' + e.message) + } + App.test(false, accountIndex, isCross, callback) + }) }, /**回归测试 * 原理: @@ -9040,77 +9209,53 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea const isEnvCompare = StringUtil.isNotEmpty(otherBaseUrl, true) // 对比自己也行,看看前后两次是否幂等 && otherBaseUrl != baseUrl for (var i = 0; i < allCount; i++) { - const item = list[i] - const document = item == null ? null : item.Document - if (document == null || document.name == null) { - if (isRandom) { - App.randomDoneCount ++ - } else { - App.doneCount ++ + try { + const item = list[i] + const document = item == null ? null : item.Document + if (document == null || document.name == null) { + if (isRandom) { + App.randomDoneCount ++ + } else { + App.doneCount ++ + } + continue } - continue - } - if (document.url == '/login' || document.url == '/logout') { //login会导致登录用户改变为默认的但UI上还显示原来的,单独测试OWNER权限时能通过很困惑 - this.log('startTest document.url == "/login" || document.url == "/logout" >> continue') - if (isRandom) { - App.randomDoneCount ++ - } else { - App.doneCount ++ + if (document.url == '/login' || document.url == '/logout') { //login会导致登录用户改变为默认的但UI上还显示原来的,单独测试OWNER权限时能通过很困惑 + this.log('startTest document.url == "/login" || document.url == "/logout" >> continue') + if (isRandom) { + App.randomDoneCount ++ + } else { + App.doneCount ++ + } + continue } - continue - } - - if (DEBUG) { - this.log('test document = ' + JSON.stringify(document, null, ' ')) - } - const index = i - - var hdr = null - try { - hdr = this.getHeader(document.header) - } catch (e) { - this.log('test for ' + i + ' >> try { header = this.getHeader(document.header) } catch (e) { \n' + e.message) - } - const header = hdr - - const caseScript = { - pre: item['Script:pre'], - post: item['Script:post'] - } + if (DEBUG) { + this.log('test document = ' + JSON.stringify(document, null, ' ')) + } - const method = document.method - const type = document.type - const req = this.getRequest(document.request, null, true) - const otherEnvUrl = isEnvCompare ? (otherBaseUrl + document.url) : null - const curEnvUrl = baseUrl + document.url + const index = i - this.request(false, method, type, isEnvCompare ? otherEnvUrl : curEnvUrl, req, header, function (url, res, err) { + var hdr = null try { - App.onResponse(url, res, err) - if (DEBUG) { - App.log('test App.request >> res.data = ' + JSON.stringify(res.data, null, ' ')) - } + hdr = this.getHeader(document.header) } catch (e) { - App.log('test App.request >> } catch (e) {\n' + e.message) + this.log('test for ' + i + ' >> try { header = this.getHeader(document.header) } catch (e) { \n' + e.message) } + const header = hdr - if (isEnvCompare != true) { - App.compareResponse(res, allCount, list, index, item, res.data, isRandom, accountIndex, false, err, null, isCross, callback) - return + const caseScript = { + pre: item['Script:pre'], + post: item['Script:post'] } - const otherErr = err - const rsp = App.removeDebugInfo(res.data) - const rspStr = JSON.stringify(rsp) - const tr = item.TestRecord || {} - if (isMLEnabled) { - tr.response = rspStr - } - tr[standardKey] = isMLEnabled ? JSON.stringify(JSONResponse.updateFullStandard({}, rsp, isMLEnabled)) : rspStr // res.data - item.TestRecord = tr + const method = document.method + const type = document.type + const req = this.getRequest(document.request, null, true) + const otherEnvUrl = isEnvCompare ? (otherBaseUrl + document.url) : null + const curEnvUrl = baseUrl + document.url - App.request(false, method, type, curEnvUrl, req, header, function (url, res, err) { + this.request(false, method, type, isEnvCompare ? otherEnvUrl : curEnvUrl, req, header, function (url, res, err) { try { App.onResponse(url, res, err) if (DEBUG) { @@ -9120,17 +9265,47 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea App.log('test App.request >> } catch (e) {\n' + e.message) } - App.compareResponse(res, allCount, list, index, item, res.data, isRandom, accountIndex, false, err || otherErr, null, isCross, callback) - }, caseScript) + if (isEnvCompare != true) { + App.compareResponse(res, allCount, list, index, item, res.data, isRandom, accountIndex, false, err, null, isCross, callback) + return + } + + const otherErr = err + const rsp = App.removeDebugInfo(res.data) + const rspStr = JSON.stringify(rsp) + const tr = item.TestRecord || {} + if (isMLEnabled) { + tr.response = rspStr + } + tr[standardKey] = isMLEnabled ? JSON.stringify(JSONResponse.updateFullStandard({}, rsp, isMLEnabled)) : rspStr // res.data + item.TestRecord = tr + + App.request(false, method, type, curEnvUrl, req, header, function (url, res, err) { + try { + App.onResponse(url, res, err) + if (DEBUG) { + App.log('test App.request >> res.data = ' + JSON.stringify(res.data, null, ' ')) + } + } catch (e) { + App.log('test App.request >> } catch (e) {\n' + e.message) + } + + App.compareResponse(res, allCount, list, index, item, res.data, isRandom, accountIndex, false, err || otherErr, null, isCross, callback) + }, caseScript) - }, caseScript) + }, caseScript) + } + catch(e) { + this.compareResponse(null, allCount, list, index, item, null, isRandom, accountIndex, false, e, null, isCross, callback) + } } }, compareResponse: function (res, allCount, list, index, item, response, isRandom, accountIndex, justRecoverTest, err, ignoreTrend, isCross, callback) { var it = item || {} //请求异步 - var d = (isRandom ? (this.currentRemoteItem || {}).Document : it.Document) || {} //请求异步 + var cri = this.currentRemoteItem || {} //请求异步 + var d = (isRandom ? cri.Document : it.Document) || {} //请求异步 var r = isRandom ? it.Random : null //请求异步 var tr = it.TestRecord || {} //请求异步 @@ -9364,6 +9539,31 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea if (typeof autoTestCallback == 'function') { autoTestCallback('已完成回归测试') } + + App.request(false, REQUEST_TYPE_POST, REQUEST_TYPE_JSON, App.getBaseUrl() + '/coverage/report', {}, {}, function (url, res, err) { + try { + App.onResponse(url, res, err) + if (DEBUG) { + App.log('test App.request >> res.data = ' + JSON.stringify(res.data, null, ' ')) + } + } catch (e) { + App.log('test App.request >> } catch (e) {\n' + e.message) + } + + App.coverage = res.data + if (IS_BROWSER) { + setTimeout(function () { + var url = StringUtil.trim((App.coverage || {}).url) + if (StringUtil.isEmpty(url, false)) { + url = App.getBaseUrl() + "/htmlcov/index.html" + } + if (url.startsWith('/')) { + url = App.getBaseUrl() + url + } + window.open(url) + }, 2000) + } + }) } } } @@ -9759,8 +9959,6 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea var random = item.Random = item.Random || {} var document; if (isRandom) { - this.isRandomShow = true - this.isRandomListShow = true if ((random.count || 0) > 1) { this.currentRandomIndex = index // this.currentRandomSubIndex = -1 @@ -9900,6 +10098,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea } const isNewRandom = isRandom && random.id <= 0 + const userId = this.User.id //TODO 先检查是否有重复名称的!让用户确认! // if (isML != true) { @@ -9907,6 +10106,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea const req = { Random: isNewRandom != true ? null : { toId: random.toId, + userId: userId, documentId: random.documentId, name: random.name, count: random.count, @@ -9916,12 +10116,14 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea id: undefined, reportId: this.reportId, host: this.getBaseUrl(), + userId: userId, testAccountId: this.getCurrentAccountId(), duration: item.duration, minDuration: minDuration, maxDuration: maxDuration, compare: JSON.stringify(testRecord.compare || {}), }) : { + userId: userId, documentId: isNewRandom ? null : (isRandom ? random.documentId : document.id), randomId: isRandom && ! isNewRandom ? random.id : null, reportId: this.reportId, @@ -11226,7 +11428,9 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea this.listScript() } - if (this.caseShowType != 1 && this.casePaths.length <= 0 && this.caseGroups.length <= 0) { + var isLoggedIn = this.User != null && this.User.id != null && this.User.id > 0 + + if (isLoggedIn && this.caseShowType != 1 && this.casePaths.length <= 0 && this.caseGroups.length <= 0) { this.selectCaseGroup(-1, null) } @@ -11234,7 +11438,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea if (rawReq == null || (StringUtil.isEmpty(rawReq.type, true) && StringUtil.isEmpty(rawReq.reportId, true))) { this.transfer() - if (this.User != null && this.User.id != null && this.User.id > 0) { + if (isLoggedIn) { setTimeout(function () { App.showTestCase(true, false) // 本地历史仍然要求登录 this.User == null || this.User.id == null) }, 1000) From 094936544d2e261875f1f5a131ec4fd1a6ebca95 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Wed, 17 Jan 2024 22:47:33 +0800 Subject: [PATCH 776/818] =?UTF-8?q?=E9=9B=B6=E4=BB=A3=E7=A0=81=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=EF=BC=9A=E8=A7=A3=E5=86=B3=E6=9C=89=E6=97=B6=E9=9A=8F?= =?UTF-8?q?=E6=9C=BA=E4=B8=8E=E9=A1=BA=E5=BA=8F=E6=B5=8B=E8=AF=95=E6=8A=A5?= =?UTF-8?q?=E9=94=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apijson/CodeUtil.js | 2 +- index.html | 6 +++--- js/main.js | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/apijson/CodeUtil.js b/apijson/CodeUtil.js index 7a96a34..8f91cd8 100644 --- a/apijson/CodeUtil.js +++ b/apijson/CodeUtil.js @@ -295,7 +295,7 @@ var CodeUtil = { getOperation: function (method, json) { var ind = method == null ? -1 : method.indexOf('?'); - var method = StringUtil.toLowerCase(ind < 0 ? method : method.substring(0, ind)); + method = StringUtil.toLowerCase(ind < 0 ? method : method.substring(0, ind)); if (method.startsWith('insert') || method.startsWith('post') || method.startsWith('add') || method.startsWith('pub') || method.startsWith('write')) { return 'INSERT' diff --git a/index.html b/index.html index af50040..e90124a 100755 --- a/index.html +++ b/index.html @@ -147,8 +147,8 @@
+ placeholder="请输入请求的接口地址,可粘贴浏览器/抓包工具/接口工具 的 Network/Header/Content 等请求信息,自动填充到界面,格式为 key: value" + style="z-index: 0; background: #0000; padding-left: 2px; padding-right: 1px; scrollbar-width: none; " >
@@ -187,7 +187,7 @@
  • - {{(isCaseGroupEditable ? '' : (StringUtil.isEmpty(item.groupName) ? '-' : item.groupName) + ' ') + item.groupUrl}}{{' (' + item.count + ') '}} + {{(isCaseGroupEditable ? '' : (StringUtil.isEmpty(item.groupName) ? '-' : item.groupName) + ' ') + item.groupUrl}}{{' (' + item.count + ') '}} diff --git a/js/main.js b/js/main.js index f65cce7..b8a3391 100755 --- a/js/main.js +++ b/js/main.js @@ -8300,7 +8300,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea }) } catch (e) { - this.compareResponse(res, allCount, list, index, item, data, true, this.currentAccountIndex, false, e, null, isCross, callback) + this.compareResponse(null, allCount, list, index, item, data, true, this.currentAccountIndex, false, e, null, isCross, callback) } } } From 3123fd9bfb800b149cf6f74c12ebcd560d61bf84 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Wed, 17 Jan 2024 23:06:17 +0800 Subject: [PATCH 777/818] =?UTF-8?q?=E7=94=A8=E4=BE=8B=E5=88=97=E8=A1=A8?= =?UTF-8?q?=EF=BC=9A=E8=A7=A3=E5=86=B3=E6=9C=AC=E5=9C=B0=E5=8E=86=E5=8F=B2?= =?UTF-8?q?=E9=A1=B5=E4=B9=9F=E6=98=BE=E7=A4=BA=E4=BA=86=E5=88=86=E9=A1=B5?= =?UTF-8?q?=E5=92=8C=E6=90=9C=E7=B4=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.html b/index.html index e90124a..e4f5f54 100755 --- a/index.html +++ b/index.html @@ -139,7 +139,7 @@
    -
    +
    @@ -241,7 +241,7 @@
  • -
    +
    From c33bdf11b1b0e80f8b53c595426b22b87aac8505 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Thu, 18 Jan 2024 21:01:12 +0800 Subject: [PATCH 778/818] =?UTF-8?q?=E8=87=AA=E5=8A=A8=E7=BB=BF=E8=89=B2?= =?UTF-8?q?=E6=B3=A8=E9=87=8A=EF=BC=9A=E8=A7=A3=E5=86=B3=E4=B8=8A=E4=BC=A0?= =?UTF-8?q?=E8=AF=B7=E6=B1=82=20JSON=20=E5=8F=B3=E4=BE=A7=20//=20=E6=B3=A8?= =?UTF-8?q?=E9=87=8A=E6=97=A0=E6=95=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apijson/CodeUtil.js | 4 ++-- js/main.js | 9 +++++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/apijson/CodeUtil.js b/apijson/CodeUtil.js index 8f91cd8..0f6d580 100644 --- a/apijson/CodeUtil.js +++ b/apijson/CodeUtil.js @@ -132,8 +132,8 @@ var CodeUtil = { var comment = ''; if (cIndex >= 0) { - if (isExtract && standardObj != null && (depth != 1 - || (isReq != true && [JSONResponse.KEY_CODE, JSONResponse.KEY_MSG, JSONResponse.KEY_THROW].indexOf(key) < 0))) { + if (isExtract && standardObj != null && (isReq || depth != 1 + || [JSONResponse.KEY_CODE, JSONResponse.KEY_MSG, JSONResponse.KEY_THROW].indexOf(key) < 0)) { comment = line.substring(cIndex + ccLen).trim(); // standardObj = CodeUtil.updateStandardPart(standardObj, names, key, value, comment) } diff --git a/js/main.js b/js/main.js index b8a3391..f6977d8 100755 --- a/js/main.js +++ b/js/main.js @@ -2517,13 +2517,18 @@ https://github.com/Tencent/APIJSON/issues catch(e) { log(e) } + var code_ = inputObj.code - inputObj.code = null // delete inputObj.code + if (isEditResponse) { + inputObj.code = null // delete inputObj.code + } commentObj = JSONResponse.updateStandard(commentStddObj, inputObj); CodeUtil.parseComment(after, docObj == null ? null : docObj['[]'], path, this.database, this.language, isEditResponse != true, commentObj, true); - inputObj.code = code_ + if (isEditResponse) { + inputObj.code = code_ + } } var rawRspStr = JSON.stringify(currentResponse || {}) From dc9a4f1a98ee04b174325f47d07c5d6431790899 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Fri, 19 Jan 2024 20:42:06 +0800 Subject: [PATCH 779/818] =?UTF-8?q?=E9=9A=8F=E6=9C=BA=E4=B8=8E=E9=A1=BA?= =?UTF-8?q?=E5=BA=8F=E6=B5=8B=E8=AF=95=EF=BC=9A=E8=A7=A3=E5=86=B3=20ORDER?= =?UTF-8?q?=5FIN+2,=20ORDER=5FINT-3=20=E8=B7=B3=E6=AD=A5=E8=AE=A1=E7=AE=97?= =?UTF-8?q?=E9=94=99=E8=AF=AF=EF=BC=9B=E8=B4=A6=E5=8F=B7=EF=BC=9A=E9=80=9A?= =?UTF-8?q?=E8=BF=87=E5=BC=B9=E7=AA=97=E7=99=BB=E5=BD=95=E5=90=8E=E6=81=A2?= =?UTF-8?q?=E5=A4=8D=E5=8E=9F=E6=9D=A5=E7=9A=84=E8=BE=93=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- js/main.js | 109 ++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 78 insertions(+), 31 deletions(-) diff --git a/js/main.js b/js/main.js index f6977d8..651cd99 100755 --- a/js/main.js +++ b/js/main.js @@ -593,16 +593,16 @@ https://github.com/Tencent/APIJSON/issues var HTTP_CONTENT_TYPES = [REQUEST_TYPE_PARAM, REQUEST_TYPE_FORM, REQUEST_TYPE_DATA, REQUEST_TYPE_JSON, REQUEST_TYPE_GRPC] var CONTENT_TYPE_MAP = { - // 'PARAM': 'plain/text', - 'FORM': 'x-www-form-urlencoded', - 'DATA': 'form-data', + // 'PARAM': 'text/plain', + 'FORM': 'application/x-www-form-urlencoded', + 'DATA': 'multipart/form-data', 'JSON': 'application/json', 'GRPC': 'application/json', } var CONTENT_VALUE_TYPE_MAP = { - 'plain/text': 'JSON', - 'x-www-form-urlencoded': 'FORM', - 'form-data': 'DATA', + 'text/plain': 'JSON', + 'application/x-www-form-urlencoded': 'FORM', + 'multipart/form-data': 'DATA', 'application/json': 'JSON' } @@ -837,7 +837,7 @@ https://github.com/Tencent/APIJSON/issues function orderIn(desc, index, ...args) { // alert('orderIn index = ' + index + '; args = ' + JSON.stringify(args)); index = index || 0; - return args == null || args.length <= index ? null : args[desc ? args.length - index : index]; + return args == null || args.length <= index ? null : args[desc ? args.length - 1 - index : index]; } function orderBad(defaultArgs, desc, index, ...args) { // alert('orderIn index = ' + index + '; args = ' + JSON.stringify(args)); @@ -893,11 +893,16 @@ https://github.com/Tencent/APIJSON/issues if (orderIndex == null || orderIndex < -1) { orderIndex = -1; } + if (argCount == null) { + argCount = 0; + } + if (step == null) { + step = 1; + } orderIndex ++ - orderIndex = argCount == null || argCount <= 0 ? orderIndex : orderIndex%argCount; - orderIndex = step == null ? orderIndex : step*orderIndex%argCount; - ORDER_MAP[randomId][line] = orderIndex >= 0 ? orderIndex : argCount + orderIndex; + ORDER_MAP[randomId][line] = orderIndex; + orderIndex = argCount <= 0 ? step*orderIndex : step*orderIndex%argCount; // alert('orderIndex = ' + orderIndex) // alert('ORDER_MAP = ' + JSON.stringify(ORDER_MAP, null, ' ')); @@ -3907,7 +3912,6 @@ https://github.com/Tencent/APIJSON/issues onClickAccount: function (index, item, callback) { - this.isTestCaseShow = false var accounts = this.accounts var num = accounts == null ? 0 : accounts.length if (index < 0 || index >= num) { @@ -4280,7 +4284,7 @@ https://github.com/Tencent/APIJSON/issues 'page': page || 0, 'join': '@/TestRecord,@/Script:pre,@/Script:post', 'Document': { - '@column': 'id,userId,version,date,name,operation,method,type,url,request,standard', // ;substr(url,' + (StringUtil.length(groupUrl) + 2) + '):substr', + // '@column': 'id,userId,version,date,name,operation,method,type,url,request,apijson,standard', // ;substr(url,' + (StringUtil.length(groupUrl) + 2) + '):substr', '@order': 'version-,date-', 'userId': this.User.id, 'name$': search, @@ -4819,16 +4823,26 @@ https://github.com/Tencent/APIJSON/issues } } + this.isHeaderShow = true this.isRandomShow = true this.isRandomListShow = false - this.isHeaderShow = true - this.method = REQUEST_TYPE_POST - this.type = REQUEST_TYPE_JSON + if (IS_BROWSER && ! isAdmin) { + this.prevMethod = this.method + this.prevType = this.type - if (IS_BROWSER) { - this.showUrl(isAdmin, '/login') + this.prevUrl = vUrl.value + this.prevUrlComment = vUrlComment.value + this.prevInput = vInput.value + this.prevComment = vComment.value + this.prevWarning = vWarning.value + this.prevRandom = vRandom.value + this.prevHeader = vHeader.value + this.prevScript = vScript.value + this.method = REQUEST_TYPE_POST + this.type = REQUEST_TYPE_JSON + this.showUrl(isAdmin, '/login') vInput.value = JSON.stringify(req, null, ' ') this.testRandomCount = 1 @@ -4880,7 +4894,6 @@ https://github.com/Tencent/APIJSON/issues if (isAdminOperation) { this.isLoginShow = false - this.request(isAdminOperation, REQUEST_TYPE_POST, REQUEST_TYPE_JSON, this.server + '/login', req, this.getHeader(vHeader.value), function (url, res, err) { if (callback) { callback(url, res, err) @@ -4891,11 +4904,32 @@ https://github.com/Tencent/APIJSON/issues }) } else { + function recover() { + App.isLoginShow = false + + if (App.prevUrl != null) { + App.method = App.prevMethod || REQUEST_TYPE_POST + App.type = App.prevType || REQUEST_TYPE_JSON + + vUrl.value = App.prevUrl || (URL_BASE + '/get') + vUrlComment.value = App.prevUrlComment || '' + vComment.value = App.prevComment || '' + vWarning.value = App.prevWarning || '' + vInput.value = App.prevInput || '{}' + vRandom.value = App.prevRandom || '' + vHeader.value = App.prevHeader || '' + vScript.value = App.prevScript || '' + + App.prevUrl = null + } + } + if (IS_BROWSER && callback == null) { var item for (var i in this.accounts) { item = this.accounts[i] if (item != null && req.phone == item.phone) { + recover() alert(req.phone + ' 已在测试账号中!') // this.currentAccountIndex = i item.remember = vRemember.checked @@ -4904,28 +4938,40 @@ https://github.com/Tencent/APIJSON/issues } } } + + this.scripts = newDefaultScript() const isLoginShow = this.isLoginShow var curUser = this.getCurrentAccount() || {} - const loginMethod = curUser.loginMethod || REQUEST_TYPE_POST - const loginType = curUser.loginType || REQUEST_TYPE_JSON - const loginUrl = curUser.loginUrl || '/login' - const loginReq = curUser.loginReq || req - const loginHeader = curUser.loginHeader || {} + const loginMethod = (isLoginShow ? this.method : curUser.loginMethod) || REQUEST_TYPE_POST + const loginType = (isLoginShow ? this.type : curUser.loginType) || REQUEST_TYPE_JSON + const loginUrl = (isLoginShow ? this.getBranchUrl() : curUser.loginUrl) || '/login' + const loginReq = (isLoginShow ? this.getRequest(vInput.value) : curUser.loginReq) || req + const loginHeader = (isLoginShow ? this.getHeader(vHeader.value) : curUser.loginHeader) || {} function loginCallback(url, res, err, random) { + recover() if (callback) { callback(url, res, err) - return + } else { + App.onLoginResponse(isAdminOperation, req, url, res, err, loginMethod, loginType, loginUrl, loginReq, loginHeader) } - App.onLoginResponse(isAdminOperation, req, url, res, err, - isLoginShow ? App.method : loginMethod, - isLoginShow ? App.type : loginType, - isLoginShow ? App.getBranchUrl() : loginUrl, - isLoginShow ? App.getRequest(vInput.value) : loginReq, - isLoginShow ? App.getHeader(vHeader.value) : loginHeader - ) + if (App.prevUrl != null) { + App.method = App.prevMethod || REQUEST_TYPE_POST + App.type = App.prevType || REQUEST_TYPE_JSON + + vUrl.value = App.prevUrl || (URL_BASE + '/get') + vUrlComment.value = App.prevUrlComment || '' + vComment.value = App.prevComment || '' + vWarning.value = App.prevWarning || '' + vInput.value = App.prevInput || '{}' + vRandom.value = App.prevRandom || '' + vHeader.value = App.prevHeader || '' + vScript.value = App.prevScript || '' + + App.prevUrl = null + } } if (isLoginShow) { @@ -4936,6 +4982,7 @@ https://github.com/Tencent/APIJSON/issues } this.scripts = newDefaultScript() + this.request(isAdminOperation, loginMethod, loginType, this.getBaseUrl() + loginUrl, loginReq, loginHeader, function (url, res, err) { if (App.isEnvCompareEnabled != true) { loginCallback(url, res, err, null, loginMethod, loginType, loginUrl, loginReq, loginHeader) From 322e6298867df9b09beb8075e19a205a1b19a0bc Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Tue, 30 Jan 2024 23:10:35 +0800 Subject: [PATCH 780/818] =?UTF-8?q?=E4=BC=98=E5=8C=96=20UI=20=E5=B8=83?= =?UTF-8?q?=E5=B1=80=E4=B8=8E=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.html | 4 ++-- js/main.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/index.html b/index.html index e4f5f54..a88740b 100755 --- a/index.html +++ b/index.html @@ -118,7 +118,7 @@ {{ isRandomShow ? '隐藏(固定)参数注入 Random Test' : '显示(编辑)参数注入 Random Test' }} {{ (isHeaderShow ? '隐藏(固定)' : '显示(编辑)') + (isEditResponse ? '响应头 Response Header' : '请求头 Request Header' ) }} {{ (isScriptShow ? '隐藏(固定)' : '显示(编辑)') + '执行脚本 JavaScript' }} - {{ (isStatisticsEnabled ? '隐藏' : '显示') + '测试统计报告 Test Report' }} + {{ (isStatisticsEnabled ? '隐藏' : '显示') + '测试统计报告 Test Report' }} 生成代码(封装,解析) : {{ language || '例如 Java' }} 数据库类型 Database: {{ database || '例如 MYSQL' }} 数据库名/模式 Schema: {{ schema || '例如 sys' }} @@ -246,7 +246,7 @@ - +
    diff --git a/js/main.js b/js/main.js index 651cd99..dfb2dc2 100755 --- a/js/main.js +++ b/js/main.js @@ -11391,7 +11391,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea this.isEncodeEnabled = this.getCache('', 'isEncodeEnabled', this.isEncodeEnabled) this.isEnvCompareEnabled = this.getCache('', 'isEnvCompareEnabled', this.isEnvCompareEnabled) //预览了就不能编辑了,点开看会懵 this.isPreviewEnabled = this.getCache('', 'isPreviewEnabled', this.isPreviewEnabled) - this.isStatisticsEnabled = this.getCache('', 'isStatisticsEnabled', this.isStatisticsEnabled) + this.isStatisticsEnabled = false // 解决每次都查不到有效 Response this.getCache('', 'isStatisticsEnabled', this.isStatisticsEnabled) this.isHeaderShow = this.getCache('', 'isHeaderShow', this.isHeaderShow) this.isRandomShow = this.getCache('', 'isRandomShow', this.isRandomShow) } catch (e) { From 26736e7aac52eeb2593bb7470d0135f6079d452b Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Tue, 30 Jan 2024 23:11:18 +0800 Subject: [PATCH 781/818] =?UTF-8?q?=E6=9C=BA=E5=99=A8=E5=AD=A6=E4=B9=A0?= =?UTF-8?q?=E9=9B=B6=E4=BB=A3=E7=A0=81=E6=B5=8B=E8=AF=95=EF=BC=9A=E6=A8=A1?= =?UTF-8?q?=E5=9E=8B=E5=8F=82=E6=95=B0=20notnull=20=E6=94=B9=E4=B8=BA=20no?= =?UTF-8?q?tNull,=20notempty=20=E6=94=B9=E4=B8=BA=20notEmpty?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apijson/JSONResponse.js | 46 ++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/apijson/JSONResponse.js b/apijson/JSONResponse.js index dc9d042..64e1910 100644 --- a/apijson/JSONResponse.js +++ b/apijson/JSONResponse.js @@ -815,11 +815,11 @@ var JSONResponse = { var guess = target.guess; log('compareWithStandard guess = target.guess = ' + guess + ' >>'); - var notnull = target.notnull; - log('compareWithStandard notnull = target.notnull = ' + notnull + ' >>'); + var notNull = target.notNull; + log('compareWithStandard notNull = target.notNull = ' + notNull + ' >>'); - var notempty = target.notempty; - log('compareWithStandard notempty = target.notempty = ' + notempty + ' >>'); + var notEmpty = target.notEmpty; + log('compareWithStandard notEmpty = target.notEmpty = ' + notEmpty + ' >>'); var type = target.type; log('compareWithStandard type = target.type = ' + type + ' >>'); @@ -832,8 +832,8 @@ var JSONResponse = { var firstVal = values == null || values.length <= 0 ? null : values[0]; if (firstVal == null && (type == 'object' || type == 'array')) { - if (notnull == true) { // values{} values&{} - throw new Error('Standard 在 ' + folder + ' 语法错误,Object 或 Array 在 notnull: true 时 values 必须为有值的数组 !'); + if (notNull == true) { // values{} values&{} + throw new Error('Standard 在 ' + folder + ' 语法错误,Object 或 Array 在 notNull: true 时 values 必须为有值的数组 !'); } log('compareWithStandard values == null; real ' + (real == null ? '=' : '!') + '= null >> return ' + (real == null ? 'COMPARE_EQUAL' : 'COMPARE_KEY_MORE')); @@ -846,17 +846,17 @@ var JSONResponse = { } if (real == null) { //少了key - log('compareWithStandard real == null >> return ' + (notnull == true ? 'COMPARE_KEY_LESS' : 'COMPARE_EQUAL')); + log('compareWithStandard real == null >> return ' + (notNull == true ? 'COMPARE_KEY_LESS' : 'COMPARE_EQUAL')); return { - code: notnull == true ? JSONResponse.COMPARE_KEY_LESS : JSONResponse.COMPARE_EQUAL, - msg: notnull == true ? '是缺少的' : '结果正确', - path: notnull == true ? folder : '', + code: notNull == true ? JSONResponse.COMPARE_KEY_LESS : JSONResponse.COMPARE_EQUAL, + msg: notNull == true ? '是缺少的' : '结果正确', + path: notNull == true ? folder : '', value: real }; } - if (notempty == true && typeof real != 'boolean' && typeof real != 'number' && StringUtil.isEmpty(real, true)) { // 空 - log('compareWithStandard notempty == true && StringUtil.isEmpty(real, true) >> return COMPARE_VALUE_EMPTY'); + if (notEmpty == true && typeof real != 'boolean' && typeof real != 'number' && StringUtil.isEmpty(real, true)) { // 空 + log('compareWithStandard notEmpty == true && StringUtil.isEmpty(real, true) >> return COMPARE_VALUE_EMPTY'); return { code: JSONResponse.COMPARE_VALUE_EMPTY, msg: '是空的', @@ -1282,16 +1282,16 @@ var JSONResponse = { log('\n\n\n\n\nupdateStandard <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n' + ' \ntarget = ' + JSON.stringify(target, null, ' ') + '\n\n\nreal = ' + JSON.stringify(real, null, ' ')); - var notnull = target.notnull; - log('updateStandard notnull = target.notnull = ' + notnull + ' >>'); - if (notnull == null) { - notnull = target.notnull = real != null; + var notNull = target.notNull; + log('updateStandard notNull = target.notNull = ' + notNull + ' >>'); + if (notNull == null) { + notNull = target.notNull = real != null; } - var notempty = target.notempty; - log('updateStandard notempty = target.notempty = ' + notempty + ' >>'); + var notEmpty = target.notEmpty; + log('updateStandard notEmpty = target.notEmpty = ' + notEmpty + ' >>'); if (real != null && typeof real != 'boolean' && typeof real != 'number') { - notempty = target.notempty = StringUtil.isNotEmpty(real, true); + notEmpty = target.notEmpty = StringUtil.isNotEmpty(real, true); } var type = target.type; @@ -1470,10 +1470,10 @@ var JSONResponse = { // 解决总是报错缺少字段 delete real[k2]; // 解决总是多出来 key: null real[k2] = null; if (firstVal[k2] == null) { - firstVal[k2] = { notnull: false }; + firstVal[k2] = { notNull: false }; } else { - firstVal[k2].notnull = false; + firstVal[k2].notNull = false; } } } @@ -1664,7 +1664,7 @@ var JSONResponse = { if (child == null) { child = {}; child.type = typeof k == 'number' ? 'array' : 'number'; // TODO 没看懂为啥是 array - child.notnull = false; + child.notNull = false; tgt.values[0] = child; } @@ -1686,7 +1686,7 @@ var JSONResponse = { } var startsWithQuestion = comment.startsWith('?') tgt.type = JSONResponse.getType(real); - tgt.notnull = real != null && startsWithQuestion != true + tgt.notNull = real != null && startsWithQuestion != true tgt.comment = startsWithQuestion ? comment.substring(1) : comment return target; From 2acdcf34255977209e18291be75a5b043da43461 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sun, 18 Feb 2024 12:05:32 +0800 Subject: [PATCH 782/818] =?UTF-8?q?=E5=9B=9E=E5=BD=92=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E6=97=B6=E8=87=AA=E5=8A=A8=E9=9A=90=E8=97=8F=E5=88=86=E7=BB=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- js/main.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/js/main.js b/js/main.js index dfb2dc2..49bd139 100755 --- a/js/main.js +++ b/js/main.js @@ -9062,7 +9062,8 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea onClickTest: function (callback) { this.isRandomTest = false this.isStatisticsEnabled = true - this.reportId = new Date().getTime(); + this.reportId = new Date().getTime() + this.caseShowType = 1 // 自动往右移动,避免断言结果遮挡太多接口名称、URL var split_obj = IS_BROWSER ? $('.splitx') : null From 11f38d1180146111238586f6d6c9d20ba2488993 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Wed, 21 Feb 2024 19:51:49 +0800 Subject: [PATCH 783/818] =?UTF-8?q?=E5=85=B6=E5=AE=83=E9=A1=B9=E7=9B=AE?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=20UIGO=20-=20=F0=9F=93=B1=20=E9=9B=B6?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E5=BF=AB=E5=87=86=E7=A8=B3=20UI=20=E6=99=BA?= =?UTF-8?q?=E8=83=BD=E5=BD=95=E5=88=B6=E5=9B=9E=E6=94=BE=E5=B9=B3=E5=8F=B0?= =?UTF-8?q?=20=F0=9F=9A=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 自动兼容任意宽高比分辨率屏幕,自动精准等待网络请求,录制回放快、准、稳! 创作不易,右上角点 ⭐Star 来支持/收藏下吧,谢谢 ^_^ https://github.com/TommyLemon/UIGO --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index b967696..3d7a897 100755 --- a/README.md +++ b/README.md @@ -260,7 +260,7 @@ https://github.com/TommyLemon/APIAuto/issues ### 技术交流 ##### 关于作者 [https://github.com/TommyLemon](https://github.com/TommyLemon)
    -image + 如果有什么问题或建议可以 [提 issue](https://github.com/TommyLemon/APIAuto/issues),交流技术,分享经验。
    如果你解决了某些 bug,或者新增了一些功能,欢迎 [提 PR 贡献代码](https://github.com/Tencent/APIJSON/blob/master/CONTRIBUTING.md),感激不尽。 @@ -275,6 +275,8 @@ https://github.com/TommyLemon/APIAuto/issues [SQLAuto](https://github.com/TommyLemon/SQLAuto) 智能零代码自动化测试 SQL 语句执行结果的数据库工具,任意增删改查、任意 SQL 模板变量、一键批量生成参数组合、快速构造大量测试数据 +[UIGO](https://github.com/TommyLemon/UIGO) 📱 零代码快准稳 UI 智能录制回放平台 🚀 自动兼容任意宽高比分辨率屏幕,自动精准等待网络请求,录制回放快、准、稳! + [apijson-doc](https://github.com/vincentCheng/apijson-doc) APIJSON 官方文档,提供排版清晰、搜索方便的文档内容展示,包括设计规范、图文教程等 [APIJSONdocs](https://github.com/ruoranw/APIJSONdocs) APIJSON 英文文档,提供排版清晰的文档内容展示,包括详细介绍、设计规范、使用方式等 From b8933161e3613d9c6fcb71b9b15919e9d0e6eeed Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Thu, 14 Mar 2024 22:05:09 +0800 Subject: [PATCH 784/818] =?UTF-8?q?=E6=96=B0=E5=A2=9E=20=E2=AD=90=EF=B8=8F?= =?UTF-8?q?=20Star=20=E8=B4=A6=E5=8F=B7=E5=85=B3=E8=81=94=E5=85=AC?= =?UTF-8?q?=E5=8F=B8=E6=88=AA=E5=B1=8F=EF=BC=8C=E5=8C=85=E6=8B=AC=E8=85=BE?= =?UTF-8?q?=E8=AE=AF=E3=80=81NVIDIA=E3=80=81=E9=98=BF=E9=87=8C=E3=80=81?= =?UTF-8?q?=E7=99=BE=E5=BA=A6=E3=80=81=E4=BA=AC=E4=B8=9C=20=E7=AD=89?= =?UTF-8?q?=E5=90=84=E5=A4=A7=E7=9F=A5=E5=90=8D=E5=85=AC=E5=8F=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://github.com/TommyLemon/APIAuto/blob/master/README.md#%E6%88%91%E8%A6%81%E8%B5%9E%E8%B5%8F --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 3d7a897..b9bd660 100755 --- a/README.md +++ b/README.md @@ -309,5 +309,8 @@ https://github.com/TommyLemon/APIAuto/commits/master ### 我要赞赏 +![image](https://github.com/TommyLemon/APIAuto/assets/5738175/723e1c9c-7cf7-431a-b29a-b878e99c7e39) 创作不易,右上角点 ⭐Star 支持下本项目吧,谢谢 ^_^
    https://github.com/TommyLemon/APIAuto + + From 9c95458db3b8b95145d5d126f59d073a47421d5a Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Thu, 14 Mar 2024 23:20:37 +0800 Subject: [PATCH 785/818] =?UTF-8?q?=E8=85=BE=E8=AE=AF=20=E5=AD=97=E8=8A=82?= =?UTF-8?q?=20=E9=98=BF=E9=87=8C=20=E7=BE=8E=E5=9B=A2=20=E5=92=8C=20NVIDIA?= =?UTF-8?q?,=20Amazon=20=E7=AD=89=E5=90=84=E5=A4=A7=E7=9F=A5=E5=90=8D?= =?UTF-8?q?=E5=A4=A7=E5=8E=82=E5=91=98=E5=B7=A5=E7=82=B9=E4=BA=86=20Star?= =?UTF-8?q?=EF=BC=8C=E6=84=9F=E8=B0=A2=E5=A4=A7=E5=AE=B6=E7=9A=84=E6=94=AF?= =?UTF-8?q?=E6=8C=81~?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://github.com/TommyLemon/APIAuto#%E6%88%91%E8%A6%81%E8%B5%9E%E8%B5%8F --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index b9bd660..530f2d6 100755 --- a/README.md +++ b/README.md @@ -309,8 +309,11 @@ https://github.com/TommyLemon/APIAuto/commits/master ### 我要赞赏 +腾讯、中国邮政、字节跳动、阿里巴巴、美团、网易、百度、京东、滴滴、平安、SHEIN、快手、携程、Bilibili、微众银行、VIVO、
    +58 集团、中兴 等 和国外 NVIDIA, Amazon, SAP, ThoughtWorks, Red Hat 等各大知名大厂员工点了 Star,感谢大家的支持~
    ![image](https://github.com/TommyLemon/APIAuto/assets/5738175/723e1c9c-7cf7-431a-b29a-b878e99c7e39) -创作不易,右上角点 ⭐Star 支持下本项目吧,谢谢 ^_^
    + +**创作不易、坚持更难,右上角点亮 ⭐Star 支持/收藏下本项目吧,谢谢 ^_^**
    https://github.com/TommyLemon/APIAuto From f2590a8501ad613836f3d1cbecfc1002d9173fba Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sat, 27 Apr 2024 19:03:49 +0800 Subject: [PATCH 786/818] =?UTF-8?q?=E5=9C=BA=E6=99=AF=E4=B8=B2=E8=81=94?= =?UTF-8?q?=E7=94=A8=E4=BE=8B=EF=BC=9A=E6=96=B0=E5=A2=9E=E6=94=AF=E6=8C=81?= =?UTF-8?q?=20=E6=9F=A5=E8=AF=A2=20=E5=92=8C=20=E6=96=B0=E5=A2=9E=20?= =?UTF-8?q?=E5=88=86=E7=BB=84=E3=80=81=E6=AD=A5=E9=AA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.html | 30 ++++- js/main.js | 387 +++++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 390 insertions(+), 27 deletions(-) diff --git a/index.html b/index.html index a88740b..d0592fd 100755 --- a/index.html +++ b/index.html @@ -157,7 +157,7 @@ - 测试用例:{{ isLocalShow ? '本地历史' : '远程在线' }} + 测试用例:{{ isLocalShow ? '本地历史' : (isChainShow ? '场景串联' : '远程在线') }} @@ -182,9 +182,9 @@
    -
    + + + +
    + +
    • diff --git a/js/main.js b/js/main.js index 49bd139..5ef7cb7 100755 --- a/js/main.js +++ b/js/main.js @@ -1000,7 +1000,9 @@ https://github.com/Tencent/APIJSON/issues history: {name: '请求0'}, remotes: [], locals: [], + chainPaths: [], casePaths: [], + chainGroups: [], caseGroups: [], testCases: [], randoms: [], @@ -1034,6 +1036,7 @@ https://github.com/Tencent/APIJSON/issues otherEnvCookieMap: {}, allSummary: {}, currentAccountIndex: 0, + currentChainGroupIndex: -1, currentDocIndex: -1, currentRandomIndex: -1, currentRandomSubIndex: -1, @@ -1068,7 +1071,9 @@ https://github.com/Tencent/APIJSON/issues isLoginShow: false, isConfigShow: false, isDeleteShow: false, + groupShowType: 0, caseShowType: 0, + chainShowType: 0, statisticsShowType: 0, currentHttpResponse: {}, currentDocItem: {}, @@ -1112,6 +1117,7 @@ https://github.com/Tencent/APIJSON/issues isEncodeEnabled: true, isEditResponse: false, isLocalShow: false, + isChainShow: false, uploadTotal: 0, uploadDoneCount: 0, uploadFailCount: 0, @@ -1154,6 +1160,12 @@ https://github.com/Tencent/APIJSON/issues page: 0, count: 50, search: '', + chainGroupPage: 0, + chainGroupPages: {}, + chainGroupCount: 0, + chainGroupCounts: {}, + chainGroupSearch: '', + chainGroupSearches: {}, caseGroupPage: 0, caseGroupPages: {}, caseGroupCount: 0, @@ -1587,6 +1599,11 @@ https://github.com/Tencent/APIJSON/issues isClickSelectInput = false; // vOption.focusout() + if (this.isChainShow) { + this.addCase2Chain(item.value) + return + } + if (isInputValue != true) { App.showOptions(target, text, before + name + (isSingle ? "'" : '"') + ': ', after.substring(3), true); } @@ -4091,15 +4108,153 @@ https://github.com/Tencent/APIJSON/issues } }, + onClickChainPath: function (index, path) { + var chainPaths = this.chainPaths + this.chainPaths = chainPaths.slice(0, index) + this.selectChainGroup(0, path) + }, + isChainGroupShow: function () { + return this.chainShowType != 1 && (this.chainGroups.length > 0 || this.chainPaths.length <= 0) + }, + isChainItemShow: function () { + return this.chainShowType != 2 || (this.chainGroups.length <= 0 && this.chainPaths.length > 0) + }, + selectChainGroup: function (index, group) { + this.currentChainGroupIndex = index + this.isCaseGroupEditable = false + + if (group == null) { + if (index == null) { + index = this.chainPaths.length - 1 + group = this.chainPaths[index] + } else { + this.chainPaths = [] + } + } else { + this.chainPaths.push(group) + } + + var groupId = group == null ? 0 : group.groupId + if (group != null && groupId == 0) { + this.chainGroups = [] + this.remotes = App.testCases = [] + this.showTestCase(true, false, null) + return + } + + var key = groupId + '' + var page = this.chainGroupPage = this.chainGroupPages[key] || 0 + var count = this.chainGroupCount = this.chainGroupCounts[key] || 0 + var search = this.chainGroupSearch = this.chainGroupSearches[key] || '' + + search = StringUtil.isEmpty(search, true) ? null : '%' + StringUtil.trim(search).replaceAll('_', '\\_').replaceAll('%', '\\%') + '%' + var req = { + format: false, + 'Chain[]': { + 'count': count || 0, + 'page': page || 0, + 'Chain': { + 'toGroupId': groupId, + 'groupName$': search, + '@column': "groupId;any_value(groupName):groupName;count(*):count", + '@group': 'groupId', + '@order': 'groupId-', + } + }, + '@role': IS_NODE ? null : 'LOGIN', + key: IS_NODE ? this.key : undefined // 突破常规查询数量限制 + } + + if (IS_BROWSER) { + this.onChange(false) + } + + this.request(true, REQUEST_TYPE_POST, REQUEST_TYPE_JSON, this.server + '/get', req, {}, function (url, res, err) { + App.onResponse(url, res, err) + var data = res.data + if (JSONResponse.isSuccess(data) == false) { + alert('获取场景用例分组失败!\n' + (err != null ? err.message : (data || '').msg)) + if (IS_BROWSER) { // 解决一旦错了,就只能清缓存 + App.chainGroupCount = 50 + App.chainGroupPage = 0 + App.chainGroupSearch = '' + App.chainGroupCounts = {} + App.chainGroupPages = {} + App.chainGroupSearches = {} + + App.saveCache(App.server, 'chainGroupCount', App.chainGroupCount) + App.saveCache(App.server, 'chainGroupPage', App.chainGroupPage) + App.saveCache(App.server, 'chainGroupSearch', App.chainGroupSearch) + App.saveCache(App.server, 'chainGroupCounts', App.chainGroupCounts) + App.saveCache(App.server, 'chainGroupPages', App.chainGroupPages) + App.saveCache(App.server, 'chainGroupSearches', App.chainGroupSearches) + } + return + } + + App.chainGroups = data['Chain[]'] || [] + App.remotes = App.testCases = [] + App.showTestCase(true, false, null) + }) + }, + + addCase2Chain: function (item) { + var id = item == null ? null : item.id + if (id == null || id <= 0) { + alert('请选择有效的用例!') + return + } + + var group = this.chainGroups[this.currentChainGroupIndex] + if (id == null || id <= 0) { + alert('请选择有效的场景串联用例分组!') + return + } + + var isAdd = true + this.request(true, REQUEST_TYPE_POST, REQUEST_TYPE_JSON, this.server + '/post', { + Chain: { + 'groupName': group.groupName, + 'groupId': group.groupId, + 'documentId': item.id + }, + tag: 'Chain' + }, {}, function (url, res, err) { + App.onResponse(url, res, err) + var isOk = JSONResponse.isSuccess(res.data) + + var msg = isOk ? '' : ('\nmsg: ' + StringUtil.get((res.data || {}).msg)) + if (err != null) { + msg += '\nerr: ' + err.msg + } + alert((isAdd ? '新增' : '修改') + (isOk ? '成功' : '失败') + (isAdd ? '! \n' :'!\ngroupId: ' + groupId) + '\ngroupName: ' + groupName + '\n' + msg) + + App.isCaseGroupEditable = ! isOk + }) + }, + onClickPath: function (index, path) { - var casePaths = this.casePaths; - this.casePaths = casePaths.slice(0, index) + if (this.isChainShow) { + this.onClickChainPath(index, path) + return + } + + var paths = this.casePaths + this.casePaths = paths.slice(0, index) this.selectCaseGroup(0, path) }, isCaseGroupShow: function () { + if (this.isChainShow) { + return this.isChainGroupShow() + } + return this.caseShowType != 1 && (this.caseGroups.length > 0 || this.casePaths.length <= 0) }, isCaseItemShow: function () { + if (this.isChainShow) { + return this.isChainItemShow() + } + return this.caseShowType != 2 || (this.caseGroups.length <= 0 && this.casePaths.length > 0) }, getCaseGroupShowName: function(index, item) { @@ -4114,6 +4269,11 @@ https://github.com/Tencent/APIJSON/issues return item.groupUrl.substring(prev == null ? 1 : prev.length + 1) }, selectCaseGroup: function (index, group) { + if (this.isChainShow) { + this.selectChainGroup(index, group) + return + } + this.isCaseGroupEditable = false if (group == null) { @@ -4214,6 +4374,14 @@ https://github.com/Tencent/APIJSON/issues return } + if (this.isChainShow) { + this.chainShowType = (this.chainShowType + 1)%3 + if (this.chainShowType != 1 && this.chainPaths.length <= 0 && this.chainGroups.length <= 0) { + this.selectChainGroup(-1, null) + } + return + } + this.caseShowType = (this.caseShowType + 1)%3 if (this.caseShowType != 1 && this.casePaths.length <= 0 && this.caseGroups.length <= 0) { this.selectCaseGroup(-1, null) @@ -4221,9 +4389,27 @@ https://github.com/Tencent/APIJSON/issues }, onClickPathRoot: function () { - if (this.casePaths.length <= 0) { - this.showTestCase(true, ! this.isLocalShow) - } else { + var isChainShow = this.isChainShow + var paths = isChainShow ? this.chainPaths : this.casePaths + if (paths.length <= 0) { + var type = this.groupShowType = (this.groupShowType + 1)%3 + this.isChainShow = type == 1 + this.isLocalShow = type == 2 + if (type == 1 && this.chainGroups.length <= 0) { + this.selectChainGroup(-1, null) + } + else if (type == 0 && this.caseGroups.length <= 0) { + this.selectCaseGroup(-1, null) + } + else { + this.testCases = this.remotes = [] + this.showTestCase(true, this.isLocalShow) + } + } + else if (isChainShow) { + this.selectChainGroup(-1, null) + } + else { this.selectCaseGroup(-1, null) } }, @@ -4263,17 +4449,22 @@ https://github.com/Tencent/APIJSON/issues var methods = this.methods var types = this.types - var index = this.casePaths.length - 1 - var group = this.casePaths[index] + var isChainShow = this.isChainShow + var paths = isChainShow ? this.chainPaths : this.casePaths + var index = paths.length - 1 + var group = paths[index] + var groupId = group == null ? 0 : (group.groupId || 0) var groupUrl = group == null ? '' : (group.groupUrl || '') + var groupKey = isChainShow ? groupId + '' : groupUrl - var page = this.testCasePage = this.testCasePages[groupUrl] || 0 - var count = this.testCaseCount = this.testCaseCounts[groupUrl] || 100 - var search = this.testCaseSearch = this.testCaseSearches[groupUrl] || '' + var page = this.testCasePage = this.testCasePages[groupKey] || 0 + var count = this.testCaseCount = this.testCaseCounts[groupKey] || 100 + var search = this.testCaseSearch = this.testCaseSearches[groupKey] || '' search = StringUtil.isEmpty(search, true) ? null : '%' + StringUtil.trim(search).replaceAll('_', '\\_').replaceAll('%', '\\%') + '%' var url = this.server + '/get' + var userId = this.User.id this.coverage = {} this.view = 'markdown' @@ -4282,11 +4473,18 @@ https://github.com/Tencent/APIJSON/issues '[]': { 'count': count || 100, //200 条测试直接卡死 0, 'page': page || 0, - 'join': '@/TestRecord,@/Script:pre,@/Script:post', + 'join': isChainShow ? '@/Document,@/Random' : '@/TestRecord,@/Script:pre,@/Script:post', + 'Chain': isChainShow ? { + // TODO 后续再支持嵌套子组合 'toGroupId': groupId, + 'groupId': groupId, + '@column': "id,groupId,documentId,randomId", + '@order': 'id+', + } : null, 'Document': { + 'id@': isChainShow ? '/Chain/documentId' : null, // '@column': 'id,userId,version,date,name,operation,method,type,url,request,apijson,standard', // ;substr(url,' + (StringUtil.length(groupUrl) + 2) + '):substr', '@order': 'version-,date-', - 'userId': this.User.id, + 'userId': userId, 'name$': search, 'operation$': search, 'url$': search, @@ -4299,9 +4497,17 @@ https://github.com/Tencent/APIJSON/issues '@null': 'sqlauto', //'sqlauto{}': '=null' // '@having': StringUtil.isEmpty(groupUrl) ? null : "substring_index(substr,'/',1)<0" }, + 'Random': isChainShow ? { + 'id@': '/Chain/randomId', + 'toId': isChainShow ? 0 : null, +// 'chainGroupId@': isChainShow ? '/Chain/groupId' : null, + 'documentId@': isChainShow ? null : '/Document/documentId', + 'userId': userId + }: null, 'TestRecord': { + 'chainGroupId@': isChainShow ? '/Chain/groupId' : null, 'documentId@': '/Document/id', - 'userId': this.User.id, + 'userId': userId, // 'testAccountId': this.getCurrentAccountId(), 'randomId': 0, 'reportId': reportId <= 0 ? null : reportId, @@ -4313,12 +4519,14 @@ https://github.com/Tencent/APIJSON/issues 'Script:pre': { 'ahead': 1, // 'testAccountId': 0, + 'chainGroupId@': isChainShow ? '/Chain/groupId' : null, 'documentId@': '/Document/id', '@order': 'date-' }, 'Script:post': { 'ahead': 0, // 'testAccountId': 0, + 'chainGroupId@': isChainShow ? '/Chain/groupId' : null, 'documentId@': '/Document/id', '@order': 'date-' } @@ -5042,6 +5250,9 @@ https://github.com/Tencent/APIJSON/issues App.onClickAccount(App.currentAccountIndex, item) //自动登录测试账号 if (user.id > 0) { + if (App.chainShowType != 1 && App.chainPaths.length <= 0 && App.chainGroups.length <= 0) { + App.selectChainGroup(-1, null) + } if (App.caseShowType != 1 && App.casePaths.length <= 0 && App.caseGroups.length <= 0) { App.selectCaseGroup(-1, null) } @@ -6488,6 +6699,115 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea return } + if (type == 'chainGroupAdd' || type == 'chainGroup') { + var isAdd = type == 'chainGroupAdd' + var groupName = item == null ? null : item.groupName + if (StringUtil.isEmpty(groupName)) { + alert('请输入名称!') + return + } + + var groupId = item == null ? null : item.groupId + if (groupId == null || groupId <= 0) { + if (! isAdd) { + alert('请选择有效的列表项!') + return + } + + groupId = new Date().getTime() + } + + //修改 Document + this.request(true, REQUEST_TYPE_POST, REQUEST_TYPE_JSON, this.server + (isAdd ? '/post' : '/put'), { + Chain: { + 'groupName': groupName, + 'groupId': isAdd ? groupId : null, + 'groupId{}': isAdd ? null : [groupId] + }, + tag: 'Chain-group' + }, {}, function (url, res, err) { + App.onResponse(url, res, err) + var isOk = JSONResponse.isSuccess(res.data) + + var msg = isOk ? '' : ('\nmsg: ' + StringUtil.get((res.data || {}).msg)) + if (err != null) { + msg += '\nerr: ' + err.msg + } + alert((isAdd ? '新增' : '修改') + (isOk ? '成功' : '失败') + (isAdd ? '! \n' :'!\ngroupId: ' + groupId) + '\ngroupName: ' + groupName + '\n' + msg) + + App.isCaseGroupEditable = ! isOk + }) + + return + } + + if (type == 'chainAdd') { + var groupName = item == null ? null : item.groupName + if (StringUtil.isEmpty(groupName)) { + alert('请输入名称!') + return + } + + var search = StringUtil.isEmpty(groupName, true) ? null : '%' + StringUtil.trim(groupName).replaceAll('_', '\\_').replaceAll('%', '\\%') + '%' + var methods = this.methods + var types = this.types + + //修改 Document + this.request(true, REQUEST_TYPE_POST, REQUEST_TYPE_JSON, this.server + '/get', { + format: false, + 'Document[]': { + 'count': 100, //200 条测试直接卡死 0, + 'page': 0, + 'Document': { + '@column': 'id,userId,version,date,name,operation,method,type,url,request,apijson', + '@order': 'version-,date-', + 'userId': this.User.id, + 'name$': search, + 'operation$': search, + 'url$': search, + // 'group{}': group == null || StringUtil.isNotEmpty(groupUrl) ? null : 'length(group)<=0', + // 'group{}': group == null ? null : (group.groupName == null ? "=null" : [group.groupName]), + '@combine': search == null ? null : 'name$,operation$,url$', + 'method{}': methods == null || methods.length <= 0 ? null : methods, + 'type{}': types == null || types.length <= 0 ? null : types, + '@null': 'sqlauto', //'sqlauto{}': '=null' + // '@having': StringUtil.isEmpty(groupUrl) ? null : "substring_index(substr,'/',1)<0" + } + } + }, {}, function (url, res, err) { + App.onResponse(url, res, err) + var isOk = JSONResponse.isSuccess(res.data) + + var msg = isOk ? '' : ('\nmsg: ' + StringUtil.get((res.data || {}).msg)) + if (err != null) { + msg += '\nerr: ' + err.msg + } + if (! isOk) { + alert(isOk ? '选择右侧接口来添加' : '查询失败!\ngroupName: ' + groupName + '\n' + msg) + } else { + var list = res.data['Document[]'] || [] + var options = [] + for (var i = 0; i < list.length; i ++) { + var item = list[i] || {} + options.push({ + name: '[' + item.method + '] [' + item.type + '] ' + item.name + ' ' + item.url, + // type: stringType, + value: item, + } + ) + } + + App.options = options + document.activeElement = vOption // vChainAdd.focusout() + vOption.focus() + // App.showOptions(target, text, before, after); + } + + }) + + return + } + if (type == 'caseGroup') { var groupUrl = item == null ? null : item.groupUrl var rawName = item == null ? null : item.rawName @@ -6643,15 +6963,34 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea }, onFilterChange: function(type) { type = type || '' - if (type == 'testCase' || type == 'caseGroup') { - var index = this.casePaths.length - 1 - var group = this.casePaths[index] + if (type == 'testCase' || type == 'caseGroup' || type == 'chainGroup') { + var isChainShow = this.isChainShow + var paths = isChainShow ? this.chainPaths : this.casePaths + var index = paths.length - 1 + var group = paths[index] + var groupId = group == null ? 0 : (group.groupId || 0) var groupUrl = group == null ? '' : (group.groupUrl || '') + var groupKey = isChainShow ? groupId + '' : groupUrl - if (type == 'caseGroup') { - this.caseGroupPages[groupUrl] = this.caseGroupPage - this.caseGroupCounts[groupUrl] = this.caseGroupCount - this.caseGroupSearches[groupUrl] = this.caseGroupSearch + if (type == 'chainGroup') { + this.chainGroupPages[groupKey] = this.chainGroupPage + this.chainGroupCounts[groupKey] = this.chainGroupCount + this.chainGroupSearches[groupKey] = this.chainGroupSearch + if (index < 0) { + this.saveCache(this.server, 'chainGroupPage', this.chainGroupPage) + this.saveCache(this.server, 'chainGroupCount', this.chainGroupCount) + // this.saveCache(this.server, 'chainGroupSearch', this.chainGroupSearch) + } + this.saveCache(this.server, 'chainGroupPages', this.chainGroupPages) + this.saveCache(this.server, 'chainGroupCounts', this.chainGroupCounts) + // this.saveCache(this.server, 'chainGroupSearches', this.chainGroupSearches) + + this.selectChainGroup() + } + else if (type == 'caseGroup') { + this.caseGroupPages[groupKey] = this.caseGroupPage + this.caseGroupCounts[groupKey] = this.caseGroupCount + this.caseGroupSearches[groupKey] = this.caseGroupSearch if (index < 0) { this.saveCache(this.server, 'caseGroupPage', this.caseGroupPage) this.saveCache(this.server, 'caseGroupCount', this.caseGroupCount) @@ -6664,9 +7003,9 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea this.selectCaseGroup() } else { - this.testCasePages[groupUrl] = this.testCasePage - this.testCaseCounts[groupUrl] = this.testCaseCount - this.testCaseSearches[groupUrl] = this.testCaseSearch + this.testCasePages[groupKey] = this.testCasePage + this.testCaseCounts[groupKey] = this.testCaseCount + this.testCaseSearches[groupKey] = this.testCaseSearch if (index < 0) { this.saveCache(this.server, 'testCasePage', this.testCasePage) @@ -11614,7 +11953,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea // alert(event.key) 小写字母 i 而不是 KeyI var target = event.target; - if (target == vSearch || target == vTestCaseSearch || target == vCaseGroupSearch) { + if (target == vSearch || target == vTestCaseSearch || target == vCaseGroupSearch || target == vChainGroupSearch || target == vChainGroupAdd || target == vChainAdd) { return } From 0aab24df03cc62129c598a4de756eb72d03fff4b Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sat, 27 Apr 2024 21:47:44 +0800 Subject: [PATCH 787/818] =?UTF-8?q?=E5=9C=BA=E6=99=AF=E4=B8=B2=E8=81=94?= =?UTF-8?q?=E7=94=A8=E4=BE=8B=EF=BC=9A=E4=BC=98=E5=8C=96=E4=BA=A4=E4=BA=92?= =?UTF-8?q?=EF=BC=8C=E8=A7=A3=E5=86=B3=E5=AD=90=E7=94=A8=E4=BE=8B=E4=B8=8D?= =?UTF-8?q?=E6=98=BE=E7=A4=BA=EF=BC=8C=E8=A7=A3=E5=86=B3=E6=90=9C=E7=B4=A2?= =?UTF-8?q?=E4=B8=8D=E5=87=BA=E6=9D=A5=E7=AD=89=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.html | 2 +- js/main.js | 72 ++++++++++++++++++++++++++++++++++-------------------- 2 files changed, 47 insertions(+), 27 deletions(-) diff --git a/index.html b/index.html index d0592fd..5779f69 100755 --- a/index.html +++ b/index.html @@ -221,7 +221,7 @@
    diff --git a/js/main.js b/js/main.js index 5ef7cb7..125c67d 100755 --- a/js/main.js +++ b/js/main.js @@ -4114,10 +4114,10 @@ https://github.com/Tencent/APIJSON/issues this.selectChainGroup(0, path) }, isChainGroupShow: function () { - return this.chainShowType != 1 && (this.chainGroups.length > 0 || this.chainPaths.length <= 0) + return true // this.chainShowType != 1 && (this.chainGroups.length > 0) // || this.chainPaths.length <= 0) }, isChainItemShow: function () { - return this.chainShowType != 2 || (this.chainGroups.length <= 0 && this.chainPaths.length > 0) + return true // this.chainShowType != 2 || (this.chainGroups.length <= 0 && this.chainPaths.length > 0) }, selectChainGroup: function (index, group) { this.currentChainGroupIndex = index @@ -4134,9 +4134,11 @@ https://github.com/Tencent/APIJSON/issues this.chainPaths.push(group) } +// this.casePaths = this.chainPaths + var groupId = group == null ? 0 : group.groupId - if (group != null && groupId == 0) { - this.chainGroups = [] + if (groupId != null && groupId > 0) { // group != null && groupId == 0) { +// this.chainGroups = [] this.remotes = App.testCases = [] this.showTestCase(true, false, null) return @@ -4156,9 +4158,11 @@ https://github.com/Tencent/APIJSON/issues 'Chain': { 'toGroupId': groupId, 'groupName$': search, +// '@raw': '@column', '@column': "groupId;any_value(groupName):groupName;count(*):count", '@group': 'groupId', '@order': 'groupId-', +// 'documentId>': 0 } }, '@role': IS_NODE ? null : 'LOGIN', @@ -4193,6 +4197,11 @@ https://github.com/Tencent/APIJSON/issues } App.chainGroups = data['Chain[]'] || [] + if (App.chainGroups.length > 0) { + App.currentChainGroupIndex = 0 + App.chainPaths.push(App.chainGroups[0]) + } + App.remotes = App.testCases = [] App.showTestCase(true, false, null) }) @@ -4206,16 +4215,23 @@ https://github.com/Tencent/APIJSON/issues } var group = this.chainGroups[this.currentChainGroupIndex] - if (id == null || id <= 0) { + if (group == null) { + var index = this.chainPaths.length - 1 + group = this.chainPaths[index] + } + var groupId = group == null ? 0 : group.groupId + if (groupId == null || groupId <= 0) { alert('请选择有效的场景串联用例分组!') return } + var groupName = group.groupName + var isAdd = true this.request(true, REQUEST_TYPE_POST, REQUEST_TYPE_JSON, this.server + '/post', { Chain: { - 'groupName': group.groupName, - 'groupId': group.groupId, + 'groupName': groupName, + 'groupId': groupId, 'documentId': item.id }, tag: 'Chain' @@ -4390,7 +4406,8 @@ https://github.com/Tencent/APIJSON/issues onClickPathRoot: function () { var isChainShow = this.isChainShow - var paths = isChainShow ? this.chainPaths : this.casePaths +// var paths = isChainShow ? this.chainPaths : this.casePaths + var paths = isChainShow ? [] : this.casePaths if (paths.length <= 0) { var type = this.groupShowType = (this.groupShowType + 1)%3 this.isChainShow = type == 1 @@ -4473,12 +4490,13 @@ https://github.com/Tencent/APIJSON/issues '[]': { 'count': count || 100, //200 条测试直接卡死 0, 'page': page || 0, - 'join': isChainShow ? '@/Document,@/Random' : '@/TestRecord,@/Script:pre,@/Script:post', + 'join': isChainShow ? '&/Document,@/Random' : '@/TestRecord,@/Script:pre,@/Script:post', 'Chain': isChainShow ? { // TODO 后续再支持嵌套子组合 'toGroupId': groupId, 'groupId': groupId, '@column': "id,groupId,documentId,randomId", '@order': 'id+', + 'documentId>': 0 } : null, 'Document': { 'id@': isChainShow ? '/Chain/documentId' : null, @@ -6784,25 +6802,27 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea } if (! isOk) { alert(isOk ? '选择右侧接口来添加' : '查询失败!\ngroupName: ' + groupName + '\n' + msg) - } else { - var list = res.data['Document[]'] || [] - var options = [] - for (var i = 0; i < list.length; i ++) { - var item = list[i] || {} - options.push({ - name: '[' + item.method + '] [' + item.type + '] ' + item.name + ' ' + item.url, - // type: stringType, - value: item, - } - ) - } + return + } - App.options = options - document.activeElement = vOption // vChainAdd.focusout() - vOption.focus() - // App.showOptions(target, text, before, after); + var list = res.data['Document[]'] || [] + var options = [] + for (var i = 0; i < list.length; i ++) { + var item = list[i] || {} + options.push({ + name: '[' + item.method + '][' + item.type + ']', // + item.name + ' ' + item.url, + type: item.name, + comment: item.url, + value: item + } + ) } + App.options = options + document.activeElement = vOption // vChainAdd.focusout() + vOption.focus() + // App.showOptions(target, text, before, after); + }) return @@ -6985,7 +7005,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea this.saveCache(this.server, 'chainGroupCounts', this.chainGroupCounts) // this.saveCache(this.server, 'chainGroupSearches', this.chainGroupSearches) - this.selectChainGroup() + this.selectChainGroup(-1, null) } else if (type == 'caseGroup') { this.caseGroupPages[groupKey] = this.caseGroupPage From 6018a7f6c41e84f0e1522e35bac2e9e032fef614 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sun, 28 Apr 2024 00:24:04 +0800 Subject: [PATCH 788/818] =?UTF-8?q?=E5=9C=BA=E6=99=AF=E4=B8=B2=E8=81=94?= =?UTF-8?q?=E7=94=A8=E4=BE=8B=EF=BC=9A=E6=96=B0=E5=A2=9E=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E6=89=B9=E9=87=8F=E6=B5=8B=E8=AF=95=EF=BC=8C=E6=AF=8F=E4=B8=AA?= =?UTF-8?q?=E5=88=86=E7=BB=84=E5=86=85=E7=94=A8=E4=BE=8B=E9=83=BD=E5=85=88?= =?UTF-8?q?=E5=90=8E=E4=B8=B2=E8=81=94=E8=B0=83=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.html | 4 +- js/main.js | 152 ++++++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 129 insertions(+), 27 deletions(-) diff --git a/index.html b/index.html index 5779f69..f1ec99d 100755 --- a/index.html +++ b/index.html @@ -220,8 +220,8 @@ diff --git a/js/main.js b/js/main.js index 125c67d..3bfd986 100755 --- a/js/main.js +++ b/js/main.js @@ -4139,11 +4139,14 @@ https://github.com/Tencent/APIJSON/issues var groupId = group == null ? 0 : group.groupId if (groupId != null && groupId > 0) { // group != null && groupId == 0) { // this.chainGroups = [] - this.remotes = App.testCases = [] - this.showTestCase(true, false, null) + this.remotes = this.testCases = (this.chainGroups[index] || {})['[]'] || [] +// this.showTestCase(true, false, null) return } + var isMLEnabled = this.isMLEnabled + var userId = this.User.id + var key = groupId + '' var page = this.chainGroupPage = this.chainGroupPages[key] || 0 var count = this.chainGroupCount = this.chainGroupCounts[key] || 0 @@ -4152,7 +4155,7 @@ https://github.com/Tencent/APIJSON/issues search = StringUtil.isEmpty(search, true) ? null : '%' + StringUtil.trim(search).replaceAll('_', '\\_').replaceAll('%', '\\%') + '%' var req = { format: false, - 'Chain[]': { + '[]': { 'count': count || 0, 'page': page || 0, 'Chain': { @@ -4163,7 +4166,68 @@ https://github.com/Tencent/APIJSON/issues '@group': 'groupId', '@order': 'groupId-', // 'documentId>': 0 - } + }, + '[]': { + 'count': 0, //200 条测试直接卡死 0, + 'page': 0, + 'join': '&/Document,@/Random', + 'Chain': { + // TODO 后续再支持嵌套子组合 'toGroupId': groupId, + 'groupId@': '[]/Chain/groupId', + '@column': "id,groupId,documentId,randomId", + '@order': 'id+', + 'documentId>': 0 + }, + 'Document': { + 'id@': '/Chain/documentId', + // '@column': 'id,userId,version,date,name,operation,method,type,url,request,apijson,standard', // ;substr(url,' + (StringUtil.length(groupUrl) + 2) + '):substr', + '@order': 'version-,date-', + 'userId': userId, + 'name$': search, + 'operation$': search, + 'url$': search, + // 'group{}': group == null || StringUtil.isNotEmpty(groupUrl) ? null : 'length(group)<=0', + // 'group{}': group == null ? null : (group.groupName == null ? "=null" : [group.groupName]), + '@combine': search == null ? null : 'name$,operation$,url$', +// 'method{}': methods == null || methods.length <= 0 ? null : methods, +// 'type{}': types == null || types.length <= 0 ? null : types, + '@null': 'sqlauto', //'sqlauto{}': '=null' + // '@having': StringUtil.isEmpty(groupUrl) ? null : "substring_index(substr,'/',1)<0" + }, + 'Random': { + 'id@': '/Chain/randomId', + 'toId': 0, +// 'chainGroupId@': isChainShow ? '/Chain/groupId' : null, +// 'documentId@': '/Document/documentId', + 'userId': userId + }, + 'TestRecord': { + 'chainGroupId@': '/Chain/groupId', + 'documentId@': '/Document/id', + 'userId': userId, +// 'testAccountId': this.getCurrentAccountId(), + 'randomId': 0, +// 'reportId': reportId <= 0 ? null : reportId, +// 'invalid': reportId == null ? 0 : null, + '@order': 'date-', + '@column': 'id,userId,documentId,testAccountId,reportId,duration,minDuration,maxDuration,response' + (this.isStatisticsEnabled ? ',compare' : '')+ (isMLEnabled ? ',standard' : ''), + 'standard{}': isMLEnabled ? (this.database == 'SQLSERVER' ? 'len(standard)>2' : 'length(standard)>2') : null //用 MySQL 5.6 '@having': this.isMLEnabled ? 'json_length(standard)>0' : null + }, + 'Script:pre': { + 'ahead': 1, + // 'testAccountId': 0, + 'chainGroupId@': '/Chain/groupId', + 'documentId@': '/Document/id', + '@order': 'date-' + }, + 'Script:post': { + 'ahead': 0, + // 'testAccountId': 0, + 'chainGroupId@': '/Chain/groupId', + 'documentId@': '/Document/id', + '@order': 'date-' + } + }, }, '@role': IS_NODE ? null : 'LOGIN', key: IS_NODE ? this.key : undefined // 突破常规查询数量限制 @@ -4196,14 +4260,14 @@ https://github.com/Tencent/APIJSON/issues return } - App.chainGroups = data['Chain[]'] || [] + App.chainGroups = data['[]'] || [] if (App.chainGroups.length > 0) { App.currentChainGroupIndex = 0 - App.chainPaths.push(App.chainGroups[0]) + App.chainPaths.push((App.chainGroups[0] || {}).Chain) } - App.remotes = App.testCases = [] - App.showTestCase(true, false, null) + App.remotes = App.testCases = (App.chainGroups[0] || {})['[]'] || [] +// App.showTestCase(true, false, null) }) }, @@ -4412,6 +4476,8 @@ https://github.com/Tencent/APIJSON/issues var type = this.groupShowType = (this.groupShowType + 1)%3 this.isChainShow = type == 1 this.isLocalShow = type == 2 + + this.testCases = this.remotes = [] if (type == 1 && this.chainGroups.length <= 0) { this.selectChainGroup(-1, null) } @@ -4419,7 +4485,6 @@ https://github.com/Tencent/APIJSON/issues this.selectCaseGroup(-1, null) } else { - this.testCases = this.remotes = [] this.showTestCase(true, this.isLocalShow) } } @@ -4432,7 +4497,7 @@ https://github.com/Tencent/APIJSON/issues }, //显示远程的测试用例文档 - showTestCase: function (show, isLocal, callback) { + showTestCase: function (show, isLocal, callback, group) { this.isTestCaseShow = show this.isLocalShow = isLocal @@ -4469,7 +4534,7 @@ https://github.com/Tencent/APIJSON/issues var isChainShow = this.isChainShow var paths = isChainShow ? this.chainPaths : this.casePaths var index = paths.length - 1 - var group = paths[index] + group = group != null ? group : paths[index] var groupId = group == null ? 0 : (group.groupId || 0) var groupUrl = group == null ? '' : (group.groupUrl || '') var groupKey = isChainShow ? groupId + '' : groupUrl @@ -9454,8 +9519,8 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea var accounts = this.accounts var num = accounts == null ? 0 : accounts.length - var remotes = this.remotes - var total = remotes == null ? 0 : remotes.length + var cases = this.isChainShow ? this.chainGroups : this.remotes + var total = cases == null ? 0 : cases.length var als = this.getAllSummary() als = this.resetCount(als, false, false, num) @@ -9553,8 +9618,8 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea // return // } - const list = (isRandom ? this.randoms : this.remotes) || [] - const allCount = list.length + const list = (isRandom ? this.randoms : (this.isChainShow ? this.chainGroups : this.remotes)) || [] + var allCount = list.length App.doneCount = 0 App.deepAllCount = 0 App.randomDoneCount = 0 @@ -9583,6 +9648,15 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea return } + if (this.isChainShow) { + for (var i = 0; i < list.length; i++) { + var item = list[i] + var stepList = item['[]'] || [] + var stepCount = stepList == null ? 0 : stepList.length + allCount += (stepCount - 1) + } + } + if (isCross) { if (accountIndex < 0 && accounts[this.currentAccountIndex] != null) { //退出登录已登录的账号 accounts[this.currentAccountIndex].isLoggedIn = true @@ -9603,6 +9677,16 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea } }, + startTestChain: function (list, allCount, index, item, isRandom, accountIndex, isCross, callback) { + if (list == null || index == null || index >= list.length) { + return + } + + this.startTestSingle(list, allCount, index, item, isRandom, accountIndex, isCross, function(url, res, err) { + App.startTestChain(list, allCount, index + 1, list[index + 1], isRandom, accountIndex, isCross, callback) + }) + }, + toTestDocIndexes: [], startTest: function (list, allCount, isRandom, accountIndex, isCross, callback) { @@ -9613,16 +9697,33 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea this.autoTestCallback(this.testProcess) } - const isMLEnabled = this.isMLEnabled - const standardKey = isMLEnabled != true ? 'response' : 'standard' + var isChainShow = this.isChainShow + + for (var i = 0; i < list.length; i++) { + const item = list[i] + if (isChainShow) { +// this.showTestCase(true, false, function(url, res, err) { + var stepList = item['[]'] // res.data['[]'] + var stepCount = stepList == null ? 0 : stepList.length + this.startTestChain(stepList, stepCount, 0, stepCount <= 0 ? null : stepList[0], isRandom, accountIndex, isCross, callback) +// }, item) + continue + } + + this.startTestSingle(list, allCount, i, item, isRandom, accountIndex, isCross, callback) + } - const otherEnv = this.otherEnv; - const otherBaseUrl = this.isEnvCompareEnabled && StringUtil.isNotEmpty(otherEnv, true) ? this.getBaseUrl(otherEnv) : null - const isEnvCompare = StringUtil.isNotEmpty(otherBaseUrl, true) // 对比自己也行,看看前后两次是否幂等 && otherBaseUrl != baseUrl + }, - for (var i = 0; i < allCount; i++) { + startTestSingle: function (list, allCount, index, item, isRandom, accountIndex, isCross, callback) { try { - const item = list[i] + const isMLEnabled = this.isMLEnabled + const standardKey = isMLEnabled != true ? 'response' : 'standard' + + const otherEnv = this.otherEnv; + const otherBaseUrl = this.isEnvCompareEnabled && StringUtil.isNotEmpty(otherEnv, true) ? this.getBaseUrl(otherEnv) : null + const isEnvCompare = StringUtil.isNotEmpty(otherBaseUrl, true) // 对比自己也行,看看前后两次是否幂等 && otherBaseUrl != baseUrl + const document = item == null ? null : item.Document if (document == null || document.name == null) { if (isRandom) { @@ -9630,7 +9731,8 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea } else { App.doneCount ++ } - continue + + return } if (document.url == '/login' || document.url == '/logout') { //login会导致登录用户改变为默认的但UI上还显示原来的,单独测试OWNER权限时能通过很困惑 this.log('startTest document.url == "/login" || document.url == "/logout" >> continue') @@ -9639,7 +9741,8 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea } else { App.doneCount ++ } - continue + + return } if (DEBUG) { @@ -9710,7 +9813,6 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea catch(e) { this.compareResponse(null, allCount, list, index, item, null, isRandom, accountIndex, false, e, null, isCross, callback) } - } }, From 4927ba0cabbfc12962b827b929a35a8ae3c884d1 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Thu, 2 May 2024 17:50:20 +0800 Subject: [PATCH 789/818] =?UTF-8?q?=E5=9C=BA=E6=99=AF=E4=B8=B2=E8=81=94?= =?UTF-8?q?=E7=94=A8=E4=BE=8B=EF=BC=9A=E8=A7=A3=E5=86=B3=E4=B8=8D=E8=83=BD?= =?UTF-8?q?=E4=B8=B2=E8=81=94=E8=B0=83=E7=94=A8=EF=BC=8C=E4=BB=A5=E5=8F=8A?= =?UTF-8?q?=E4=B8=8D=E6=98=BE=E7=A4=BA=E6=96=AD=E8=A8=80=E7=BB=93=E6=9E=9C?= =?UTF-8?q?=E7=AD=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- js/main.js | 47 +++++++++++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/js/main.js b/js/main.js index 3bfd986..0681793 100755 --- a/js/main.js +++ b/js/main.js @@ -4114,10 +4114,10 @@ https://github.com/Tencent/APIJSON/issues this.selectChainGroup(0, path) }, isChainGroupShow: function () { - return true // this.chainShowType != 1 && (this.chainGroups.length > 0) // || this.chainPaths.length <= 0) + return this.chainShowType != 1 && (this.chainGroups.length > 0) // || this.chainPaths.length <= 0) }, isChainItemShow: function () { - return true // this.chainShowType != 2 || (this.chainGroups.length <= 0 && this.chainPaths.length > 0) + return this.chainShowType != 2 || (this.chainGroups.length <= 0 && this.chainPaths.length > 0) }, selectChainGroup: function (index, group) { this.currentChainGroupIndex = index @@ -4359,7 +4359,7 @@ https://github.com/Tencent/APIJSON/issues if (group == null) { if (index == null) { index = this.casePaths.length - 1 - group = this.casePaths[index] + group = (this.casePaths[index] || {}).Chain } else { this.casePaths = [] } @@ -9682,8 +9682,9 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea return } - this.startTestSingle(list, allCount, index, item, isRandom, accountIndex, isCross, function(url, res, err) { - App.startTestChain(list, allCount, index + 1, list[index + 1], isRandom, accountIndex, isCross, callback) + this.startTestSingle(list, allCount, index, item, isRandom, accountIndex, isCross, callback + , function(res, allCount, list, index, response, cmp, isRandom, accountIndex, justRecoverTest, isCross) { + App.startTestChain(list, allCount, index + 1, list[index + 1], isRandom, accountIndex, isCross, callback) }) }, @@ -9715,7 +9716,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea }, - startTestSingle: function (list, allCount, index, item, isRandom, accountIndex, isCross, callback) { + startTestSingle: function (list, allCount, index, item, isRandom, accountIndex, isCross, callback, singleCallback) { try { const isMLEnabled = this.isMLEnabled const standardKey = isMLEnabled != true ? 'response' : 'standard' @@ -9735,7 +9736,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea return } if (document.url == '/login' || document.url == '/logout') { //login会导致登录用户改变为默认的但UI上还显示原来的,单独测试OWNER权限时能通过很困惑 - this.log('startTest document.url == "/login" || document.url == "/logout" >> continue') + this.log('startTestSingle document.url == "/login" || document.url == "/logout" >> continue') if (isRandom) { App.randomDoneCount ++ } else { @@ -9746,16 +9747,14 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea } if (DEBUG) { - this.log('test document = ' + JSON.stringify(document, null, ' ')) + this.log('startTestSingle document = ' + JSON.stringify(document, null, ' ')) } - const index = i - var hdr = null try { hdr = this.getHeader(document.header) } catch (e) { - this.log('test for ' + i + ' >> try { header = this.getHeader(document.header) } catch (e) { \n' + e.message) + this.log('startTestSingle try { header = this.getHeader(document.header) } catch (e) { \n' + e.message) } const header = hdr @@ -9774,14 +9773,14 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea try { App.onResponse(url, res, err) if (DEBUG) { - App.log('test App.request >> res.data = ' + JSON.stringify(res.data, null, ' ')) + App.log('startTestSingle App.request >> res.data = ' + JSON.stringify(res.data, null, ' ')) } } catch (e) { - App.log('test App.request >> } catch (e) {\n' + e.message) + App.log('startTestSingle App.request >> } catch (e) {\n' + e.message) } if (isEnvCompare != true) { - App.compareResponse(res, allCount, list, index, item, res.data, isRandom, accountIndex, false, err, null, isCross, callback) + App.compareResponse(res, allCount, list, index, item, res.data, isRandom, accountIndex, false, err, null, isCross, callback, singleCallback) return } @@ -9799,24 +9798,24 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea try { App.onResponse(url, res, err) if (DEBUG) { - App.log('test App.request >> res.data = ' + JSON.stringify(res.data, null, ' ')) + App.log('startTestSingle App.request >> res.data = ' + JSON.stringify(res.data, null, ' ')) } } catch (e) { - App.log('test App.request >> } catch (e) {\n' + e.message) + App.log('startTestSingle App.request >> } catch (e) {\n' + e.message) } - App.compareResponse(res, allCount, list, index, item, res.data, isRandom, accountIndex, false, err || otherErr, null, isCross, callback) + App.compareResponse(res, allCount, list, index, item, res.data, isRandom, accountIndex, false, err || otherErr, null, isCross, callback, singleCallback) }, caseScript) }, caseScript) } catch(e) { - this.compareResponse(null, allCount, list, index, item, null, isRandom, accountIndex, false, e, null, isCross, callback) + this.compareResponse(null, allCount, list, index, item, null, isRandom, accountIndex, false, e, null, isCross, callback, singleCallback) } }, - compareResponse: function (res, allCount, list, index, item, response, isRandom, accountIndex, justRecoverTest, err, ignoreTrend, isCross, callback) { + compareResponse: function (res, allCount, list, index, item, response, isRandom, accountIndex, justRecoverTest, err, ignoreTrend, isCross, callback, singleCallback) { var it = item || {} //请求异步 var cri = this.currentRemoteItem || {} //请求异步 var d = (isRandom ? cri.Document : it.Document) || {} //请求异步 @@ -9871,10 +9870,10 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea tr.compare.duration = it.durationHint } - this.onTestResponse(res, allCount, list, index, it, d, r, tr, response, tr.compare || {}, isRandom, accountIndex, justRecoverTest, isCross, callback); + this.onTestResponse(res, allCount, list, index, it, d, r, tr, response, tr.compare || {}, isRandom, accountIndex, justRecoverTest, isCross, callback, singleCallback); }, - onTestResponse: function(res, allCount, list, index, it, d, r, tr, response, cmp, isRandom, accountIndex, justRecoverTest, isCross, callback) { + onTestResponse: function(res, allCount, list, index, it, d, r, tr, response, cmp, isRandom, accountIndex, justRecoverTest, isCross, callback, singleCallback) { tr = tr || {} cmp = cmp || {} tr.compare = cmp @@ -9995,6 +9994,10 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea } // this.showTestCase(true) + if (singleCallback != null && singleCallback(res, allCount, list, index, response, cmp, isRandom, accountIndex, justRecoverTest, isCross)) { + return + } + if (doneCount >= allCount) { // 导致不继续测试 App.doneCount == allCount) { if (callback != null && callback(isRandom, allCount)) { return @@ -10004,7 +10007,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea const deepAllCount = this.toTestDocIndexes == null ? 0 : this.toTestDocIndexes.length App.deepAllCount = deepAllCount - if (isRandom != true && deepAllCount > 0) { // 自动给非 红色 报错的接口跑参数注入 + if (isRandom != true && deepAllCount > 0 && ! this.isChainShow) { // 自动给非 红色 报错的接口跑参数注入 App.deepDoneCount = 0; this.startRandomTest4Doc(list, this.toTestDocIndexes, 0, deepAllCount, accountIndex, isCross) } else if (isCross && doneCount == allCount && accountIndex <= this.accounts.length) { From e5560513a0e1e0a9c2bfd95f3f74f6c88f629d0e Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Thu, 2 May 2024 21:07:51 +0800 Subject: [PATCH 790/818] =?UTF-8?q?=E5=9C=BA=E6=99=AF=E4=B8=B2=E8=81=94?= =?UTF-8?q?=E7=94=A8=E4=BE=8B=EF=BC=9A=E6=96=B0=E5=A2=9E=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E6=89=A7=E8=A1=8C=E5=8F=82=E6=95=B0=E6=B3=A8=E5=85=A5=EF=BC=9B?= =?UTF-8?q?=E5=8F=82=E6=95=B0=E6=B3=A8=E5=85=A5=EF=BC=9A=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E6=94=AF=E6=8C=81=20id:=20PRE=5FDATA('[]/0/User/id')=20?= =?UTF-8?q?=E6=8F=90=E5=8F=96=E4=B8=8A=E4=B8=AA=E6=8E=A5=E5=8F=A3=E8=BF=94?= =?UTF-8?q?=E5=9B=9E=E7=9A=84=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apijson/JSONResponse.js | 48 +++++++ js/main.js | 294 +++++++++++++++++++++++++++++----------- 2 files changed, 261 insertions(+), 81 deletions(-) diff --git a/apijson/JSONResponse.js b/apijson/JSONResponse.js index 64e1910..7560963 100644 --- a/apijson/JSONResponse.js +++ b/apijson/JSONResponse.js @@ -1559,6 +1559,54 @@ var JSONResponse = { return target; }, + /**根据 APIJSON 引用赋值路径精准地获取值 + */ + getValByPath: function(target, pathKeys) { + if (target == null) { + return null; + } + + var tgt = target; + var depth = pathKeys == null ? 0 : pathKeys.length + if (depth <= 0) { + return target; + } + + for (var i = 0; i < depth; i ++) { + if (tgt == null) { + return null; + } + + var k = pathKeys[i]; + if (k == null) { + return null; + } + + if (tgt instanceof Object) { + if (k == '') { + if (tgt instanceof Array) { + k = 0; + } else { + ks = Object.keys(tgt); + k = ks == null ? null : ks[0]; + if (k == null) { + return null; + } + } + } + + tgt = tgt[k]; + + continue; + } + + return null; + } + + return tgt; + }, + + /**根据路径精准地更新测试标准中的键值对 */ getStandardByPath: function(target, pathKeys) { diff --git a/js/main.js b/js/main.js index 0681793..93f0e99 100755 --- a/js/main.js +++ b/js/main.js @@ -610,6 +610,26 @@ https://github.com/Tencent/APIJSON/issues , 'content-type', 'date', 'keep-alive', 'proxy-connection', 'set-cookie', 'vary', 'accept', 'cache-control', 'dnt' , 'host', 'origin', 'pragma', 'referer', 'user-agent'] + var PRE = 'PRE' // PRE() + var CUR = 'CUR' // CUR() + var NEXT = 'NEXT' // NEXT() + + var PRE_REQ = 'PRE_REQ' // PRE_REQ('[]/page') + var PRE_ARG = 'PRE_ARG' // PRE_ARG('[]/page') + var PRE_RES = 'PRE_RES' // PRE_RES('[]/0/User/id') + var PRE_DATA = 'PRE_DATA' // PRE_DATA('[]/0/User/id') + var PRE_EXT = 'PRE_EXT' // PRE_EXT('key') + var CUR_REQ = 'CUR_REQ' // CUR_REQ('User/id') + var CUR_ARG = 'CUR_ARG' // CUR_REQ('User/id') + var CUR_PUT = 'CUR_PUT' // CUR_PUT('key', val) + + function get4Path(obj, path) { + if (StringUtil.isEmpty(path, false)) { + return obj + } + return JSONResponse.getValByPath(obj, StringUtil.split(path, '/'), true) + } + var RANDOM_DB = 'RANDOM_DB' var RANDOM_IN = 'RANDOM_IN' var RANDOM_INT = 'RANDOM_INT' @@ -2171,7 +2191,9 @@ https://github.com/Tencent/APIJSON/issues var scripts = item.scripts if (isRemote) { - var orginItem = item + var originItem = item + item.random = (originItem.Random || {}).config + doc = item.Document || {} docId = doc.id || 0 @@ -2207,7 +2229,7 @@ https://github.com/Tencent/APIJSON/issues } // var scripts = item.scripts || {} - var scripts = orginItem.scripts || {} + var scripts = originItem.scripts || {} // var ss = scripts.case // if (ss == null) { // scripts.case = ss = {} @@ -2222,15 +2244,15 @@ https://github.com/Tencent/APIJSON/issues var pre = rpObj['Script:pre'] if (pre != null && pre.script != null) { - bs.pre = orginItem['Script:pre'] = rpObj['Script:pre'] + bs.pre = originItem['Script:pre'] = rpObj['Script:pre'] } var post = rpObj['Script:post'] if (post != null && post.script != null) { - bs.post = orginItem['Script:post'] = rpObj['Script:post'] + bs.post = originItem['Script:post'] = rpObj['Script:post'] } - orginItem.scripts = scripts + originItem.scripts = scripts App.changeScriptType(App.scriptType) App.scripts.case[docId] = scripts @@ -2446,9 +2468,12 @@ https://github.com/Tencent/APIJSON/issues const isExportRandom = this.isExportRandom const isExportScript = this.isExportScript + const cri = this.currentRemoteItem || {} + const chain = cri.Chain || {} const currentAccountId = this.getCurrentAccountId() - const doc = (this.currentRemoteItem || {}).Document || {} - const tr = (this.currentRemoteItem || {}).TestRecord || {} + const doc = cri.Document || {} + const tr = cri.TestRecord || {} + const cgId = chain.groupId const did = isExportRandom && btnIndex == 1 ? null : doc.id if (isExportScript) { @@ -2671,12 +2696,14 @@ https://github.com/Tencent/APIJSON/issues format: false, 'Random': { toId: 0, + chainGroupId: cgId, documentId: did, count: App.requestCount, name: App.exTxt.name, config: config }, 'TestRecord': { + 'chainGroupId': cgId, 'response': rawRspStr, 'standard': isML ? JSON.stringify(stddObj) : null }, @@ -2686,6 +2713,7 @@ https://github.com/Tencent/APIJSON/issues 'Document': isEditResponse ? null : { 'id': did == null ? undefined : did, // 'testAccountId': currentAccountId, +// 'chainGroupId': cgId, 'operation': CodeUtil.getOperation(path, reqObj), 'name': extName, 'method': method, @@ -2698,6 +2726,7 @@ https://github.com/Tencent/APIJSON/issues 'detail': App.getExtraComment() || ((App.currentRemoteItem || {}).Document || {}).detail, }, 'TestRecord': isEditResponse != true && did != null ? null : { +// 'chainGroupId': cgId, 'documentId': isEditResponse ? did : undefined, 'randomId': 0, 'host': baseUrl, @@ -4170,7 +4199,7 @@ https://github.com/Tencent/APIJSON/issues '[]': { 'count': 0, //200 条测试直接卡死 0, 'page': 0, - 'join': '&/Document,@/Random', + 'join': '&/Document', 'Chain': { // TODO 后续再支持嵌套子组合 'toGroupId': groupId, 'groupId@': '[]/Chain/groupId', @@ -4195,10 +4224,10 @@ https://github.com/Tencent/APIJSON/issues // '@having': StringUtil.isEmpty(groupUrl) ? null : "substring_index(substr,'/',1)<0" }, 'Random': { - 'id@': '/Chain/randomId', +// 'id@': '/Chain/randomId', 'toId': 0, -// 'chainGroupId@': isChainShow ? '/Chain/groupId' : null, -// 'documentId@': '/Document/documentId', + 'chainGroupId@': '/Chain/groupId', + 'documentId@': '/Document/id', 'userId': userId }, 'TestRecord': { @@ -9121,11 +9150,11 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea * @param show * @param callback */ - parseRandom: function (json, config, randomId, generateJSON, generateConfig, generateName, callback, preScript) { + parseRandom: function (json, config, randomId, generateJSON, generateConfig, generateName, callback, preScript, ctx) { var lines = config == null ? null : config.trim().split('\n') if (lines == null || lines.length <= 0) { // return null; - callback(null, null, null); + callback('', '', json); return } json = json || {}; @@ -9419,42 +9448,68 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea ) + ', ' + value.substring(start + 1); } else { //随机函数 - fun = funWithOrder; //还原,其它函数不支持 升降序和跨步! - - if (fun == RANDOM_DB) { - request4Db(JSONResponse.getTableName(pathKeys[pathKeys.length - 2]), which, p_k, pathKeys, key, lastKeyInPath, true); //'random()'); - continue; - } - - if (fun == RANDOM_IN) { - toEval = 'randomIn' + value.substring(start); - } - else if (fun == RANDOM_INT) { - toEval = 'randomInt' + value.substring(start); + if (fun == PRE_REQ) { + toEval = 'get4Path(((ctx || {}).pre || {}).req, ' + value.substring(start + 1); } - else if (fun == RANDOM_NUM) { - toEval = 'randomNum' + value.substring(start); + else if (fun == PRE_ARG) { + toEval = 'get4Path(((ctx || {}).pre || {}).arg, ' + value.substring(start + 1); } - else if (fun == RANDOM_STR) { - toEval = 'randomStr' + value.substring(start); + else if (fun == PRE_RES) { + toEval = 'get4Path(((ctx || {}).pre || {}).res, ' + value.substring(start + 1); } - else if (fun == RANDOM_BAD) { - toEval = 'randomBad' + value.substring(start); + else if (fun == PRE_DATA) { + toEval = 'get4Path(((ctx || {}).pre || {}).data, ' + value.substring(start + 1); } - else if (fun == RANDOM_BAD_BOOL) { - toEval = 'randomBadBool' + value.substring(start); + else if (fun == PRE_EXT) { + toEval = 'get4Path(((ctx || {}).pre || {}).ext, ' + value.substring(start + 1); } - else if (fun == RANDOM_BAD_NUM) { - toEval = 'randomBadNum' + value.substring(start); + else if (fun == CUR_REQ) { + toEval = 'get4Path(((ctx || {}).cur || {}).req, ' + value.substring(start + 1); } - else if (fun == RANDOM_BAD_STR) { - toEval = 'randomBadStr' + value.substring(start); + else if (fun == CUR_ARG) { + toEval = 'get4Path(((ctx || {}).cur || {}).arg, ' + value.substring(start + 1); } - else if (fun == RANDOM_BAD_ARR) { - toEval = 'randomBadArr' + value.substring(start); + else if (fun == CUR_PUT) { + toEval = 'put4Path(((ctx || {}).cur || {}).ctx, ' + value.substring(start + 1); } - else if (fun == RANDOM_BAD_OBJ) { - toEval = 'randomBadObj' + value.substring(start); + else { + fun = funWithOrder; //还原,其它函数不支持 升降序和跨步! + + if (fun == RANDOM_DB) { + request4Db(JSONResponse.getTableName(pathKeys[pathKeys.length - 2]), which, p_k, pathKeys, key, lastKeyInPath, true); //'random()'); + continue; + } + + if (fun == RANDOM_IN) { + toEval = 'randomIn' + value.substring(start); + } + else if (fun == RANDOM_INT) { + toEval = 'randomInt' + value.substring(start); + } + else if (fun == RANDOM_NUM) { + toEval = 'randomNum' + value.substring(start); + } + else if (fun == RANDOM_STR) { + toEval = 'randomStr' + value.substring(start); + } + else if (fun == RANDOM_BAD) { + toEval = 'randomBad' + value.substring(start); + } + else if (fun == RANDOM_BAD_BOOL) { + toEval = 'randomBadBool' + value.substring(start); + } + else if (fun == RANDOM_BAD_NUM) { + toEval = 'randomBadNum' + value.substring(start); + } + else if (fun == RANDOM_BAD_STR) { + toEval = 'randomBadStr' + value.substring(start); + } + else if (fun == RANDOM_BAD_ARR) { + toEval = 'randomBadArr' + value.substring(start); + } + else if (fun == RANDOM_BAD_OBJ) { + toEval = 'randomBadObj' + value.substring(start); + } } } @@ -9677,15 +9732,49 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea } }, - startTestChain: function (list, allCount, index, item, isRandom, accountIndex, isCross, callback) { + startTestChain: function (list, allCount, index, item, prev, ctx, isRandom, accountIndex, isCross, callback) { if (list == null || index == null || index >= list.length) { return } - this.startTestSingle(list, allCount, index, item, isRandom, accountIndex, isCross, callback - , function(res, allCount, list, index, response, cmp, isRandom, accountIndex, justRecoverTest, isCross) { - App.startTestChain(list, allCount, index + 1, list[index + 1], isRandom, accountIndex, isCross, callback) - }) + var cur = item = item || {} + cur.index = index +// item.pre = pre // list[index - 1] + + var doc = item.Document || {} + var method = cur.method = doc.method + var type = cur.type = doc.type + var url = cur.url = doc.url + var json = cur.arg = this.getRequest(doc.request, {}) + var req = cur.req = { + method: method, + url: url, + header: doc.header, + data: json + } + var header = cur.header = doc.header +// +// this.parseRandom(json, rawConfig, random.id, true, false, function (randomName, constConfig, constJson) { + this.startTestSingle(list, allCount, index, item, isRandom, accountIndex, isCross, callback + , function(res, allCount, list, index, response, cmp, isRandom, accountIndex, justRecoverTest, isCross) { + + res = res || {} + var config = res.config || {} + cur.arg = App.getRequest(config.data || config.params, {}) + cur.req = { + method: method, + url: config.url, + header: config.header, + arg: cur.arg + } + cur.status = res.status + cur.statusText = res.statusText + cur.res = res + cur.data = res.data + App.startTestChain(list, allCount, index + 1, list[index + 1], item, ctx, isRandom, accountIndex, isCross, callback) + }) + return true +// }) }, toTestDocIndexes: [], @@ -9706,7 +9795,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea // this.showTestCase(true, false, function(url, res, err) { var stepList = item['[]'] // res.data['[]'] var stepCount = stepList == null ? 0 : stepList.length - this.startTestChain(stepList, stepCount, 0, stepCount <= 0 ? null : stepList[0], isRandom, accountIndex, isCross, callback) + this.startTestChain(stepList, stepCount, 0, stepCount <= 0 ? null : stepList[0], null, { Chain: item }, isRandom, accountIndex, isCross, callback) // }, item) continue } @@ -9768,46 +9857,57 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea const req = this.getRequest(document.request, null, true) const otherEnvUrl = isEnvCompare ? (otherBaseUrl + document.url) : null const curEnvUrl = baseUrl + document.url + const cur = item + const pre = list[index - 1] || {} // item.pre = item.pre || list[index - 1] || {} + const ctx = item.ctx = item.ctx || {} - this.request(false, method, type, isEnvCompare ? otherEnvUrl : curEnvUrl, req, header, function (url, res, err) { - try { - App.onResponse(url, res, err) - if (DEBUG) { - App.log('startTestSingle App.request >> res.data = ' + JSON.stringify(res.data, null, ' ')) - } - } catch (e) { - App.log('startTestSingle App.request >> } catch (e) {\n' + e.message) - } - - if (isEnvCompare != true) { - App.compareResponse(res, allCount, list, index, item, res.data, isRandom, accountIndex, false, err, null, isCross, callback, singleCallback) - return - } + var random = item.Random || {} + this.parseRandom(req, random.config, random.id, true, false, false, function(randomName, constConfig, constJson) { + App.request(false, method, type, isEnvCompare ? otherEnvUrl : curEnvUrl, constJson, header, function (url, res, err) { + try { + App.onResponse(url, res, err) + if (DEBUG) { + App.log('startTestSingle App.request >> res.data = ' + JSON.stringify(res.data, null, ' ')) + } + } catch (e) { + App.log('startTestSingle App.request >> } catch (e) {\n' + e.message) + } - const otherErr = err - const rsp = App.removeDebugInfo(res.data) - const rspStr = JSON.stringify(rsp) - const tr = item.TestRecord || {} - if (isMLEnabled) { - tr.response = rspStr - } - tr[standardKey] = isMLEnabled ? JSON.stringify(JSONResponse.updateFullStandard({}, rsp, isMLEnabled)) : rspStr // res.data - item.TestRecord = tr + if (isEnvCompare != true) { + App.compareResponse(res, allCount, list, index, item, res.data, isRandom, accountIndex, false, err, null, isCross, callback, singleCallback) + return + } - App.request(false, method, type, curEnvUrl, req, header, function (url, res, err) { - try { - App.onResponse(url, res, err) - if (DEBUG) { - App.log('startTestSingle App.request >> res.data = ' + JSON.stringify(res.data, null, ' ')) + const otherErr = err + const rsp = App.removeDebugInfo(res.data) + const rspStr = JSON.stringify(rsp) + const tr = item.TestRecord || {} + if (isMLEnabled) { + tr.response = rspStr } - } catch (e) { - App.log('startTestSingle App.request >> } catch (e) {\n' + e.message) - } + tr[standardKey] = isMLEnabled ? JSON.stringify(JSONResponse.updateFullStandard({}, rsp, isMLEnabled)) : rspStr // res.data + item.TestRecord = tr - App.compareResponse(res, allCount, list, index, item, res.data, isRandom, accountIndex, false, err || otherErr, null, isCross, callback, singleCallback) - }, caseScript) + App.request(false, method, type, curEnvUrl, constJson, header, function (url, res, err) { + try { + App.onResponse(url, res, err) + if (DEBUG) { + App.log('startTestSingle App.request >> res.data = ' + JSON.stringify(res.data, null, ' ')) + } + } catch (e) { + App.log('startTestSingle App.request >> } catch (e) {\n' + e.message) + } - }, caseScript) + App.compareResponse(res, allCount, list, index, item, res.data, isRandom, accountIndex, false, err || otherErr, null, isCross, callback, singleCallback) + }, caseScript) + + }, caseScript) + }, caseScript.pre, { + index: index, + cur: cur, + pre: pre, + ctx: ctx + }) } catch(e) { this.compareResponse(null, allCount, list, index, item, null, isRandom, accountIndex, false, e, null, isCross, callback, singleCallback) @@ -10616,6 +10716,9 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea const isNewRandom = isRandom && random.id <= 0 const userId = this.User.id + const cri = this.currentRemoteItem || {} + const chain = cri.Chain || {} + const cgId = chain.groupId //TODO 先检查是否有重复名称的!让用户确认! // if (isML != true) { @@ -10624,6 +10727,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea Random: isNewRandom != true ? null : { toId: random.toId, userId: userId, + chainGroupId: cgId, documentId: random.documentId, name: random.name, count: random.count, @@ -10635,12 +10739,14 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea host: this.getBaseUrl(), userId: userId, testAccountId: this.getCurrentAccountId(), + chainGroupId: cgId, duration: item.duration, minDuration: minDuration, maxDuration: maxDuration, compare: JSON.stringify(testRecord.compare || {}), }) : { userId: userId, + chainGroupId: cgId, documentId: isNewRandom ? null : (isRandom ? random.documentId : document.id), randomId: isRandom && ! isNewRandom ? random.id : null, reportId: this.reportId, @@ -11209,6 +11315,32 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea name: "Math.round(100*Math.random())", type: stringType, comment: '自定义代码' } ] + + if (App.isChainShow) { + App.options = [ + { + name: "PRE_RES('[]/0/User/id')", + type: stringType, + comment: "从上个请求的返回结果中取值 function(path:String)" + }, { + name: "PRE_REQ('[]/page')", + type: stringType, + comment: "从上个请求的参数中取值 function(path:String)" + }, { + name: "PRE_EXT('isMale')", + type: stringType, + comment: "从上个请求的扩展对象中取值 function(path:String)" + }, { + name: "CUR_REQ('[]/count')", + type: stringType, + comment: "从当前请求的参数中取值 function(path:String)" + }, { + name: "CUR_PUT('isMale', true)", + type: stringType, + comment: "在当前请求的扩展对象中存放键值对 function(path:String, val:Any)" + } + ].concat(App.options || []) + } } else { App.options.push({ From df4e8fbc44ee6463c873133fa8f3ae57a97a99e0 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Fri, 3 May 2024 01:51:35 +0800 Subject: [PATCH 791/818] =?UTF-8?q?=E5=9C=BA=E6=99=AF=E4=B8=B2=E8=81=94?= =?UTF-8?q?=E7=94=A8=E4=BE=8B=EF=BC=9APRE=5FDATA=20=E7=AD=89=E6=8F=90?= =?UTF-8?q?=E5=8F=96=E5=80=BC=E5=87=BD=E6=95=B0=E6=94=AF=E6=8C=81=E7=9C=81?= =?UTF-8?q?=E7=95=A5=E8=B7=AF=E5=BE=84=EF=BC=8C=E5=85=B6=E4=B8=AD=E6=95=B0?= =?UTF-8?q?=E7=BB=84=E4=B8=8B=E6=A0=87=E6=94=AF=E6=8C=81=20-1=20=E8=BF=99?= =?UTF-8?q?=E7=A7=8D=E8=B4=9F=E6=95=B0=E6=9D=A5=E5=80=92=E5=BA=8F=E6=9F=A5?= =?UTF-8?q?=E6=89=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apijson/JSONResponse.js | 31 +++++++++++++++++++++++++------ js/main.js | 31 ++++++++++++++++--------------- 2 files changed, 41 insertions(+), 21 deletions(-) diff --git a/apijson/JSONResponse.js b/apijson/JSONResponse.js index 7560963..2493b0a 100644 --- a/apijson/JSONResponse.js +++ b/apijson/JSONResponse.js @@ -1581,6 +1581,7 @@ var JSONResponse = { if (k == null) { return null; } + k = decodeURI(k) if (tgt instanceof Object) { if (k == '') { @@ -1594,11 +1595,26 @@ var JSONResponse = { } } } + else { + k = decodeURI(k) + if (tgt instanceof Array) { + try { + var n = Number.parseInt(k); + if (Number.isSafeInteger(n)) { + k = n > 0 ? n : n + tgt.length; + } + } catch (e) { + } + } + } tgt = tgt[k]; continue; } + else { + throw new Error('getValByPath 语法错误,' + k + ': value 中 value 类型应该是 Object 或 Array !'); + } return null; } @@ -1638,12 +1654,15 @@ var JSONResponse = { k = 0; } else { - try { - var n = Number.parseInt(k); - if (Number.isSafeInteger(n)) { - k = 0; - } - } catch (e) { + k = decodeURI(k) + if (tgt instanceof Array) { + try { + var n = Number.parseInt(k); + if (Number.isSafeInteger(n)) { + k = n > 0 ? n : n + tgt.length; + } + } catch (e) { + } } } diff --git a/js/main.js b/js/main.js index 93f0e99..977512a 100755 --- a/js/main.js +++ b/js/main.js @@ -623,11 +623,12 @@ https://github.com/Tencent/APIJSON/issues var CUR_ARG = 'CUR_ARG' // CUR_REQ('User/id') var CUR_PUT = 'CUR_PUT' // CUR_PUT('key', val) - function get4Path(obj, path) { - if (StringUtil.isEmpty(path, false)) { - return obj + function get4Path(obj, path, nullable) { + var val = JSONResponse.getValByPath(obj, StringUtil.split(path, '/'), true) + if (val == null && nullable != true) { + throw new Error('找不到 ' + path + ' 对应在 obj 中的非 null 值!') } - return JSONResponse.getValByPath(obj, StringUtil.split(path, '/'), true) + return val } var RANDOM_DB = 'RANDOM_DB' @@ -4307,7 +4308,7 @@ https://github.com/Tencent/APIJSON/issues return } - var group = this.chainGroups[this.currentChainGroupIndex] + var group = (this.chainGroups[this.currentChainGroupIndex] || {}).Chain if (group == null) { var index = this.chainPaths.length - 1 group = this.chainPaths[index] @@ -4388,7 +4389,7 @@ https://github.com/Tencent/APIJSON/issues if (group == null) { if (index == null) { index = this.casePaths.length - 1 - group = (this.casePaths[index] || {}).Chain + group = this.casePaths[index] } else { this.casePaths = [] } @@ -9194,7 +9195,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea const index = line.indexOf(': '); //APIJSON Table:alias 前面不会有空格 //致后面就接 { 'a': 1} 报错 Unexpected token ':' lastIndexOf(': '); // indexOf(': '); 可能会有 Comment:to const p_k = line.substring(0, index); const bi = -1; //没必要支持,用 before: undefined, after: .. 同样支持替换,反而这样导致不兼容包含空格的 key p_k.indexOf(' '); - const path = bi < 0 ? p_k : p_k.substring(0, bi); // User/id + const path = decodeURI(bi < 0 ? p_k : p_k.substring(0, bi)); // User/id const pathKeys = path.split('/') if (pathKeys == null || pathKeys.length <= 0) { @@ -9449,28 +9450,28 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea } else { //随机函数 if (fun == PRE_REQ) { - toEval = 'get4Path(((ctx || {}).pre || {}).req, ' + value.substring(start + 1); + toEval = 'get4Path(((ctx || {}).pre || {}).req, ' + (value == ')' ? JSON.stringify(path) : '') + value.substring(start + 1); } else if (fun == PRE_ARG) { - toEval = 'get4Path(((ctx || {}).pre || {}).arg, ' + value.substring(start + 1); + toEval = 'get4Path(((ctx || {}).pre || {}).arg, ' + (value == ')' ? JSON.stringify(path) : '') + value.substring(start + 1); } else if (fun == PRE_RES) { - toEval = 'get4Path(((ctx || {}).pre || {}).res, ' + value.substring(start + 1); + toEval = 'get4Path(((ctx || {}).pre || {}).res, ' + (value == ')' ? JSON.stringify(path) : '') + value.substring(start + 1); } else if (fun == PRE_DATA) { - toEval = 'get4Path(((ctx || {}).pre || {}).data, ' + value.substring(start + 1); + toEval = 'get4Path(((ctx || {}).pre || {}).data, ' + (value == ')' ? JSON.stringify(path) : '') + value.substring(start + 1); } else if (fun == PRE_EXT) { - toEval = 'get4Path(((ctx || {}).pre || {}).ext, ' + value.substring(start + 1); + toEval = 'get4Path(((ctx || {}).pre || {}).ext, ' + (value == ')' ? JSON.stringify(path) : '') + value.substring(start + 1); } else if (fun == CUR_REQ) { - toEval = 'get4Path(((ctx || {}).cur || {}).req, ' + value.substring(start + 1); + toEval = 'get4Path(((ctx || {}).cur || {}).req, ' + (value == ')' ? JSON.stringify(path) : '') + value.substring(start + 1); } else if (fun == CUR_ARG) { - toEval = 'get4Path(((ctx || {}).cur || {}).arg, ' + value.substring(start + 1); + toEval = 'get4Path(((ctx || {}).cur || {}).arg, ' + (value == ')' ? JSON.stringify(path) : '') + value.substring(start + 1); } else if (fun == CUR_PUT) { - toEval = 'put4Path(((ctx || {}).cur || {}).ctx, ' + value.substring(start + 1); + toEval = 'put4Path(((ctx || {}).cur || {}).ctx, ' + (value == ')' ? JSON.stringify(path) : '') + value.substring(start + 1); } else { fun = funWithOrder; //还原,其它函数不支持 升降序和跨步! From 6105e364aff0487fa9f0f7d341c4b48c896bf34e Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Fri, 3 May 2024 01:58:15 +0800 Subject: [PATCH 792/818] =?UTF-8?q?=E9=9B=B6=E4=BB=A3=E7=A0=81=E5=9B=9E?= =?UTF-8?q?=E5=BD=92=E6=B5=8B=E8=AF=95=EF=BC=9A=E8=A7=A3=E5=86=B3=E5=9C=BA?= =?UTF-8?q?=E6=99=AF=E4=B8=B2=E8=81=94=E7=94=A8=E4=BE=8B=E5=92=8C=E5=8D=95?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E7=94=A8=E4=BE=8B=E7=9A=84=E5=8F=82=E6=95=B0?= =?UTF-8?q?=E6=B3=A8=E5=85=A5=E9=85=8D=E7=BD=AE=E7=9B=B8=E4=BA=92=E5=B9=B2?= =?UTF-8?q?=E6=89=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- js/main.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/js/main.js b/js/main.js index 977512a..c9005b6 100755 --- a/js/main.js +++ b/js/main.js @@ -4856,12 +4856,17 @@ https://github.com/Tencent/APIJSON/issues ? null : '%' + StringUtil.trim(this.randomSearch) + '%') var url = this.server + '/get' + const cri = this.currentRemoteItem || {} + const chain = cri.Chain || {} + const cgId = chain.groupId || 0 + var req = { '[]': { 'count': (isSub ? this.randomSubCount : this.randomCount) || 100, 'page': (isSub ? this.randomSubPage : this.randomPage) || 0, 'Random': { 'toId': isSub ? item.id : 0, + 'chainGroupId': cgId, 'documentId': isSub ? null : item.id, '@order': "date-", 'name$': search @@ -4877,6 +4882,7 @@ https://github.com/Tencent/APIJSON/issues 'page': this.randomSubPage || 0, 'Random': { 'toId@': '[]/Random/id', + 'chainGroupId': cgId, 'documentId': item.id, '@order': "date-", 'name$': subSearch @@ -10719,7 +10725,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea const userId = this.User.id const cri = this.currentRemoteItem || {} const chain = cri.Chain || {} - const cgId = chain.groupId + const cgId = chain.groupId || 0 //TODO 先检查是否有重复名称的!让用户确认! // if (isML != true) { From ff5177e37eb34f87da5e80aa03c52ab9404e7bf9 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Fri, 3 May 2024 16:24:53 +0800 Subject: [PATCH 793/818] =?UTF-8?q?=E9=9B=B6=E4=BB=A3=E7=A0=81=E5=9B=9E?= =?UTF-8?q?=E5=BD=92=E6=B5=8B=E8=AF=95=EF=BC=9A=E8=A7=A3=E5=86=B3=E5=9C=BA?= =?UTF-8?q?=E6=99=AF=E4=B8=B2=E8=81=94=E7=94=A8=E4=BE=8B=E5=92=8C=E5=8D=95?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E7=94=A8=E4=BE=8B=E7=9A=84=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E8=AE=B0=E5=BD=95=E7=9B=B8=E4=BA=92=E5=B9=B2=E6=89=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apijson/JSONResponse.js | 5 +++-- js/main.js | 21 +++++++++++++++++---- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/apijson/JSONResponse.js b/apijson/JSONResponse.js index 2493b0a..c8519dc 100644 --- a/apijson/JSONResponse.js +++ b/apijson/JSONResponse.js @@ -1561,7 +1561,7 @@ var JSONResponse = { /**根据 APIJSON 引用赋值路径精准地获取值 */ - getValByPath: function(target, pathKeys) { + getValByPath: function(target, pathKeys, isTry) { if (target == null) { return null; } @@ -1612,7 +1612,8 @@ var JSONResponse = { continue; } - else { + + if (isTry != true) { throw new Error('getValByPath 语法错误,' + k + ': value 中 value 类型应该是 Object 或 Array !'); } diff --git a/js/main.js b/js/main.js index c9005b6..bbbabc0 100755 --- a/js/main.js +++ b/js/main.js @@ -624,7 +624,7 @@ https://github.com/Tencent/APIJSON/issues var CUR_PUT = 'CUR_PUT' // CUR_PUT('key', val) function get4Path(obj, path, nullable) { - var val = JSONResponse.getValByPath(obj, StringUtil.split(path, '/'), true) + var val = JSONResponse.getValByPath(obj, StringUtil.split(path, '/')) if (val == null && nullable != true) { throw new Error('找不到 ' + path + ' 对应在 obj 中的非 null 值!') } @@ -2209,16 +2209,22 @@ https://github.com/Tencent/APIJSON/issues var postId = post.id if (docId > 0 && (preId == null || postId == null)) { // var accountId = this.getCurrentAccountId(); + const cri = this.currentRemoteItem || {} + const chain = cri.Chain || {} + const cgId = chain.groupId || 0 + this.request(true, REQUEST_TYPE_POST, REQUEST_TYPE_JSON, '/get', { 'Script:pre': preId != null ? undefined : { 'ahead': 1, // 'testAccountId': 0, + 'chainGroupId': cgId, 'documentId': docId, '@order': 'date-' }, 'Script:post': postId != null ? undefined : { 'ahead': 0, // 'testAccountId': 0, + 'chainGroupId': cgId, 'documentId': docId, '@order': 'date-' } @@ -2474,7 +2480,7 @@ https://github.com/Tencent/APIJSON/issues const currentAccountId = this.getCurrentAccountId() const doc = cri.Document || {} const tr = cri.TestRecord || {} - const cgId = chain.groupId + const cgId = chain.groupId || 0 const did = isExportRandom && btnIndex == 1 ? null : doc.id if (isExportScript) { @@ -2489,6 +2495,7 @@ https://github.com/Tencent/APIJSON/issues 'id': sid == null ? undefined : sid, 'simple': 1, 'ahead': this.isPreScript ? 1 : 0, + 'chainGroupId': cgId, 'documentId': did == null || scriptType != 'case' ? 0 : did, 'testAccountId': scriptType != 'account' ? 0 : currentAccountId, 'name': extName, @@ -4612,13 +4619,14 @@ https://github.com/Tencent/APIJSON/issues }, 'Random': isChainShow ? { 'id@': '/Chain/randomId', - 'toId': isChainShow ? 0 : null, + 'toId': 0, // isChainShow ? 0 : null, // 'chainGroupId@': isChainShow ? '/Chain/groupId' : null, - 'documentId@': isChainShow ? null : '/Document/documentId', +// 'documentId@': isChainShow ? null : '/Document/documentId', 'userId': userId }: null, 'TestRecord': { 'chainGroupId@': isChainShow ? '/Chain/groupId' : null, + 'chainGroupId': isChainShow ? null : 0, 'documentId@': '/Document/id', 'userId': userId, // 'testAccountId': this.getCurrentAccountId(), @@ -4633,6 +4641,7 @@ https://github.com/Tencent/APIJSON/issues 'ahead': 1, // 'testAccountId': 0, 'chainGroupId@': isChainShow ? '/Chain/groupId' : null, + 'chainGroupId': isChainShow ? null : 0, 'documentId@': '/Document/id', '@order': 'date-' }, @@ -4640,6 +4649,7 @@ https://github.com/Tencent/APIJSON/issues 'ahead': 0, // 'testAccountId': 0, 'chainGroupId@': isChainShow ? '/Chain/groupId' : null, + 'chainGroupId': isChainShow ? null : 0, 'documentId@': '/Document/id', '@order': 'date-' } @@ -7138,6 +7148,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea this.resetTestCount(this.currentAccountIndex) + this.isStatisticsEnabled = false this.remotes = null this.showTestCase(true, false) } @@ -9910,6 +9921,8 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea }, caseScript) }, caseScript.pre, { + list: list, + allCount: allCount, index: index, cur: cur, pre: pre, From e81c400034930af314845b310ff4c01c67077d7e Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Fri, 3 May 2024 17:59:59 +0800 Subject: [PATCH 794/818] =?UTF-8?q?=E8=B4=A6=E5=8F=B7=EF=BC=9A=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E6=94=AF=E6=8C=81=E5=88=A0=E9=99=A4=20URL=20=E8=BE=93?= =?UTF-8?q?=E5=85=A5=E6=A1=86=E7=9A=84=20Base=20URL=20=E5=90=8E=E6=98=BE?= =?UTF-8?q?=E7=A4=BA=E5=85=A8=E9=83=A8=20Base=20URL=20=E7=9A=84=E5=85=A8?= =?UTF-8?q?=E9=83=A8=E8=B4=A6=E5=8F=B7=EF=BC=8C=E5=8F=AF=E4=B8=80=E6=AC=A1?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E4=B8=8D=E5=90=8C=E6=9C=8D=E5=8A=A1=E5=99=A8?= =?UTF-8?q?=E7=9A=84=E7=9B=B8=E5=90=8C=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.html | 2 +- js/main.js | 89 ++++++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 71 insertions(+), 20 deletions(-) diff --git a/index.html b/index.html index f1ec99d..a83ce0e 100755 --- a/index.html +++ b/index.html @@ -653,7 +653,7 @@
    - +
    diff --git a/js/main.js b/js/main.js index bbbabc0..b60b14d 100755 --- a/js/main.js +++ b/js/main.js @@ -793,7 +793,7 @@ https://github.com/Tencent/APIJSON/issues // end = end || Number.MAX_SAFE_INTEGER if (min == null) { - min = Number.MIN_SAFE_INTEGER + min = 0 // Number.MIN_SAFE_INTEGER } if (max == null) { max = Number.MAX_SAFE_INTEGER @@ -844,7 +844,7 @@ https://github.com/Tencent/APIJSON/issues function orderInt(desc, index, min, max) { if (min == null) { - min = Number.MIN_SAFE_INTEGER + min = 0 // Number.MIN_SAFE_INTEGER } if (max == null) { max = Number.MAX_SAFE_INTEGER @@ -1054,6 +1054,7 @@ https://github.com/Tencent/APIJSON/issues 'password': '123456' } ], + otherEnvTokenMap: {}, otherEnvCookieMap: {}, allSummary: {}, currentAccountIndex: 0, @@ -1377,6 +1378,30 @@ https://github.com/Tencent/APIJSON/issues // var index = baseUrl.indexOf(':') //http://localhost:8080 // this.server = (index < 0 ? baseUrl : baseUrl.substring(0, baseUrl)) + ':9090' + var baseUrls = this.getCache('', 'baseUrls', []) + if (baseUrls.indexOf(bu) <= 0) { + baseUrls.push(bu) + this.saveCache('', 'baseUrls', baseUrls) + } + + var accounts = [] + if (StringUtil.isNotEmpty(bu, true)) { + accounts = this.getCache(bu, 'accounts', []) + } + else { + for (var i = 0; i < baseUrls.length; i ++) { + var bu2 = baseUrls[i] + var ats = this.getCache(bu2, 'accounts', []) +// accounts.push({ +// baseUrl: bu2, +// id: 0, +// phone: 0, +// name: '' +// }) + accounts = accounts.concat(ats) + } + } + this.accounts = accounts } }, getUrl: function () { @@ -1385,10 +1410,17 @@ https://github.com/Tencent/APIJSON/issues }, //获取基地址 getBaseUrl: function (url_) { - var url = StringUtil.trim(url_ || vUrl.value) + var url = StringUtil.trim(url_ != undefined ? url_ : vUrl.value) var length = this.getBaseUrlLength(url) + if (length <= 0 && url_ == null) { + var account = this.getCurrentAccount() + if (account != null) { + return account.baseUrl || '' + } + } + url = length <= 0 ? '' : url.substring(0, length) - return url == '' ? URL_BASE : url + return url // == '' ? URL_BASE : url }, //获取基地址长度,以://后的第一个/分割baseUrl和method getBaseUrlLength: function (url_) { @@ -3964,7 +3996,6 @@ https://github.com/Tencent/APIJSON/issues - onClickAccount: function (index, item, callback) { var accounts = this.accounts var num = accounts == null ? 0 : accounts.length @@ -3976,8 +4007,9 @@ https://github.com/Tencent/APIJSON/issues App.onResponse(url, res, err) item.isLoggedIn = false - App.saveCache(App.getBaseUrl(), 'currentAccountIndex', App.currentAccountIndex) - App.saveCache(App.getBaseUrl(), 'accounts', App.accounts) + baseUrl = item.baseUrl || App.getBaseUrl() + App.saveCache(baseUrl, 'currentAccountIndex', App.currentAccountIndex) + App.saveCache(baseUrl, 'accounts', App.accounts) App.changeScriptType(App.scriptType) if (callback != null) { @@ -4038,16 +4070,19 @@ https://github.com/Tencent/APIJSON/issues } else { var headers = res.headers || {} + baseUrl = item.baseUrl || App.getBaseUrl() + item.baseUrl = baseUrl item.id = user.id item.name = user.name item.remember = data.remember item.isLoggedIn = true + item.token = headers.token || headers.Token || data.token || data.Token || user.token || user.Token item.cookie = res.cookie || headers.cookie || headers.Cookie || headers['set-cookie'] || headers['Set-Cookie'] App.accounts[App.currentAccountIndex] = item - App.saveCache(App.getBaseUrl(), 'currentAccountIndex', App.currentAccountIndex) - App.saveCache(App.getBaseUrl(), 'accounts', App.accounts) + App.saveCache(baseUrl, 'currentAccountIndex', App.currentAccountIndex) + App.saveCache(baseUrl, 'accounts', App.accounts) App.changeScriptType(App.scriptType) if (callback != null) { @@ -5261,11 +5296,13 @@ https://github.com/Tencent/APIJSON/issues } } + const baseUrl = this.getBaseUrl() + if (IS_BROWSER && callback == null) { var item for (var i in this.accounts) { item = this.accounts[i] - if (item != null && req.phone == item.phone) { + if (item != null && baseUrl == item.baseUrl && req.phone == item.phone) { recover() alert(req.phone + ' 已在测试账号中!') // this.currentAccountIndex = i @@ -5320,7 +5357,7 @@ https://github.com/Tencent/APIJSON/issues this.scripts = newDefaultScript() - this.request(isAdminOperation, loginMethod, loginType, this.getBaseUrl() + loginUrl, loginReq, loginHeader, function (url, res, err) { + this.request(isAdminOperation, loginMethod, loginType, baseUrl + loginUrl, loginReq, loginHeader, function (url, res, err) { if (App.isEnvCompareEnabled != true) { loginCallback(url, res, err, null, loginMethod, loginType, loginUrl, loginReq, loginHeader) return @@ -5332,7 +5369,9 @@ https://github.com/Tencent/APIJSON/issues var user = JSONResponse.isSuccess(data) ? data.user : null if (user != null) { var headers = res.headers || {} - App.otherEnvCookieMap[req.phone] = res.cookie || headers.cookie || headers.Cookie || headers['set-cookie'] || headers['Set-Cookie'] + App.otherEnvTokenMap[req.phone + '@' + baseUrl] = headers.token || headers.Token || data.token || data.Token || user.token || user.Token + App.otherEnvCookieMap[req.phone + '@' + baseUrl] = res.cookie || headers.cookie || headers.Cookie || headers['set-cookie'] || headers['Set-Cookie'] + App.saveCache(App.otherEnv, 'otherEnvTokenMap', App.otherEnvTokenMap) App.saveCache(App.otherEnv, 'otherEnvCookieMap', App.otherEnvCookieMap) } @@ -5397,6 +5436,7 @@ https://github.com/Tencent/APIJSON/issues var user = data.user || {} App.accounts.push({ isLoggedIn: true, + baseUrl: App.getBaseUrl(), id: user.id, name: user.name, phone: req.phone, @@ -6064,7 +6104,8 @@ https://github.com/Tencent/APIJSON/issues } if (StringUtil.isEmpty(this.host, true)) { - if (StringUtil.get(vUrl.value).startsWith('http://') != true && StringUtil.get(vUrl.value).startsWith('https://') != true) { + var url = StringUtil.get(vUrl.value) + if (url.startsWith('/') != true && url.startsWith('http://') != true && url.startsWith('https://') != true) { alert('URL 缺少 http:// 或 https:// 前缀,可能不完整或不合法,\n可能使用同域的 Host,很可能访问出错!') } } @@ -6242,9 +6283,9 @@ https://github.com/Tencent/APIJSON/issues } else { // alert('request App.accounts[App.currentAccountIndex].isLoggedIn = false ') - - if (App.accounts[App.currentAccountIndex] != null) { - App.accounts[App.currentAccountIndex].isLoggedIn = false + var account = App.accounts[App.currentAccountIndex] + if (account != null) { + account.isLoggedIn = false } } } @@ -6444,7 +6485,7 @@ https://github.com/Tencent/APIJSON/issues } // Node 环境内通过 headers 设置 Cookie 无效 - header.Cookie = isEnvCompare ? this.otherEnvCookieMap[curUser.phone] : curUser.cookie + header.Cookie = isEnvCompare ? this.otherEnvCookieMap[curUser.phone + '@' + baseUrl] : curUser.cookie } } @@ -12028,13 +12069,23 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea '\n} catch (e) {\n' + e.message) } try { //这里是初始化,不能出错 - var otherEnvCookieMap = this.getCache(App.otherEnv, 'otherEnvCookieMap') + var otherEnvTokenMap = this.getCache(this.otherEnv, 'otherEnvTokenMap') + if (otherEnvTokenMap != null) { + this.otherEnvTokenMap = otherEnvTokenMap + } + } catch (e) { + console.log('created try { ' + + '\nvar otherEnvTokenMap = this.getCache(this.otherEnv, otherEnvTokenMap)' + + '\n} catch (e) {\n' + e.message) + } + try { //这里是初始化,不能出错 + var otherEnvCookieMap = this.getCache(this.otherEnv, 'otherEnvCookieMap') if (otherEnvCookieMap != null) { this.otherEnvCookieMap = otherEnvCookieMap } } catch (e) { console.log('created try { ' + - '\nvar accounts = this.getCache(URL_BASE, accounts)' + + '\nvar otherEnvCookieMap = this.getCache(this.otherEnv, otherEnvCookieMap)' + '\n} catch (e) {\n' + e.message) } From e2ee85ec3abe4d77ffe2c4485c9ee54a76b0815c Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Fri, 3 May 2024 23:28:40 +0800 Subject: [PATCH 795/818] =?UTF-8?q?=E8=B4=A6=E5=8F=B7=EF=BC=9A=E8=A7=A3?= =?UTF-8?q?=E5=86=B3=E5=9C=A8=20URL=20=E8=BE=93=E5=85=A5=E6=A1=86=E5=88=A0?= =?UTF-8?q?=E9=99=A4=20Base=20URL=20=E5=90=8E=E8=87=AA=E5=8A=A8=E4=BF=9D?= =?UTF-8?q?=E5=AD=98=E5=A4=A7=E9=87=8F=E9=87=8D=E5=A4=8D=E8=B4=A6=E5=8F=B7?= =?UTF-8?q?=E5=AF=BC=E8=87=B4=E5=8D=A1=E6=AD=BB=EF=BC=9B=E8=A7=A3=E5=86=B3?= =?UTF-8?q?=E6=9C=89=E6=97=B6=E7=82=B9=E8=B4=A6=E5=8F=B7=20tab=20=E4=BC=9A?= =?UTF-8?q?=E7=99=BB=E5=BD=95=E9=94=99=E8=AF=AF=E7=9A=84=E8=B4=A6=E5=8F=B7?= =?UTF-8?q?=EF=BC=9B=E8=A7=A3=E5=86=B3=E7=82=B9=E8=B4=A6=E5=8F=B7=20tab=20?= =?UTF-8?q?=E9=80=80=E5=87=BA=E7=99=BB=E5=BD=95=E5=8F=88=E6=98=BE=E7=A4=BA?= =?UTF-8?q?=E5=B7=B2=E9=9A=90=E8=97=8F=E7=9A=84=20Base=20URL?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- js/main.js | 120 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 72 insertions(+), 48 deletions(-) diff --git a/js/main.js b/js/main.js index b60b14d..481377d 100755 --- a/js/main.js +++ b/js/main.js @@ -1343,7 +1343,7 @@ https://github.com/Tencent/APIJSON/issues showUrl: function (isAdminOperation, branchUrl) { if (StringUtil.isEmpty(this.host, true)) { //显示(可编辑)URL Host if (isAdminOperation != true) { - baseUrl = this.getBaseUrl() + baseUrl = this.getBaseUrl(vUrl.value) } vUrl.value = (isAdminOperation ? this.server : baseUrl) + branchUrl } @@ -1378,17 +1378,12 @@ https://github.com/Tencent/APIJSON/issues // var index = baseUrl.indexOf(':') //http://localhost:8080 // this.server = (index < 0 ? baseUrl : baseUrl.substring(0, baseUrl)) + ':9090' - var baseUrls = this.getCache('', 'baseUrls', []) - if (baseUrls.indexOf(bu) <= 0) { - baseUrls.push(bu) - this.saveCache('', 'baseUrls', baseUrls) - } - var accounts = [] if (StringUtil.isNotEmpty(bu, true)) { accounts = this.getCache(bu, 'accounts', []) } else { + var baseUrls = this.getCache('', 'baseUrls', []) for (var i = 0; i < baseUrls.length; i ++) { var bu2 = baseUrls[i] var ats = this.getCache(bu2, 'accounts', []) @@ -1401,7 +1396,10 @@ https://github.com/Tencent/APIJSON/issues accounts = accounts.concat(ats) } } - this.accounts = accounts + + if (accounts.length >= 1) { + this.accounts = accounts + } } }, getUrl: function () { @@ -4007,9 +4005,11 @@ https://github.com/Tencent/APIJSON/issues App.onResponse(url, res, err) item.isLoggedIn = false - baseUrl = item.baseUrl || App.getBaseUrl() - App.saveCache(baseUrl, 'currentAccountIndex', App.currentAccountIndex) - App.saveCache(baseUrl, 'accounts', App.accounts) + baseUrl = App.getBaseUrl(vUrl.value) + if (StringUtil.isNotEmpty(baseUrl, true)) { + App.saveCache(baseUrl, 'currentAccountIndex', App.currentAccountIndex) + App.saveCache(baseUrl, 'accounts', App.accounts) + } App.changeScriptType(App.scriptType) if (callback != null) { @@ -4044,8 +4044,11 @@ https://github.com/Tencent/APIJSON/issues App.onResponse(url, res, err) item.isLoggedIn = false - App.saveCache(App.getBaseUrl(), 'currentAccountIndex', App.currentAccountIndex) - App.saveCache(App.getBaseUrl(), 'accounts', App.accounts) + baseUrl = App.getBaseUrl(vUrl.value) + if (StringUtil.isNotEmpty(baseUrl, true)) { + App.saveCache(baseUrl, 'currentAccountIndex', App.currentAccountIndex) + App.saveCache(baseUrl, 'accounts', App.accounts) + } App.changeScriptType(App.scriptType) if (callback != null) { @@ -4070,9 +4073,9 @@ https://github.com/Tencent/APIJSON/issues } else { var headers = res.headers || {} - baseUrl = item.baseUrl || App.getBaseUrl() + baseUrl = App.getBaseUrl(vUrl.value) - item.baseUrl = baseUrl + item.baseUrl = item.baseUrl || baseUrl item.id = user.id item.name = user.name item.remember = data.remember @@ -4081,8 +4084,12 @@ https://github.com/Tencent/APIJSON/issues item.cookie = res.cookie || headers.cookie || headers.Cookie || headers['set-cookie'] || headers['Set-Cookie'] App.accounts[App.currentAccountIndex] = item - App.saveCache(baseUrl, 'currentAccountIndex', App.currentAccountIndex) - App.saveCache(baseUrl, 'accounts', App.accounts) + + if (StringUtil.isNotEmpty(baseUrl, true)) { + App.saveCache(baseUrl, 'currentAccountIndex', App.currentAccountIndex) + App.saveCache(baseUrl, 'accounts', App.accounts) + } + App.changeScriptType(App.scriptType) if (callback != null) { @@ -4131,8 +4138,11 @@ https://github.com/Tencent/APIJSON/issues this.currentAccountIndex = this.accounts.length - 1 } - this.saveCache(this.getBaseUrl(), 'currentAccountIndex', this.currentAccountIndex) - this.saveCache(this.getBaseUrl(), 'accounts', this.accounts) + baseUrl = this.getBaseUrl(vUrl.value) + if (StringUtil.isNotEmpty(baseUrl, true)) { + this.saveCache(baseUrl, 'currentAccountIndex', this.currentAccountIndex) + this.saveCache(baseUrl, 'accounts', this.accounts) + } }, addAccountTab: function () { this.showLogin(true, false) @@ -5321,6 +5331,7 @@ https://github.com/Tencent/APIJSON/issues const loginType = (isLoginShow ? this.type : curUser.loginType) || REQUEST_TYPE_JSON const loginUrl = (isLoginShow ? this.getBranchUrl() : curUser.loginUrl) || '/login' const loginReq = (isLoginShow ? this.getRequest(vInput.value) : curUser.loginReq) || req + const loginRandom = (isLoginShow ? vRandom.value : curUser.loginRandom) || '' const loginHeader = (isLoginShow ? this.getHeader(vHeader.value) : curUser.loginHeader) || {} function loginCallback(url, res, err, random) { @@ -5328,7 +5339,7 @@ https://github.com/Tencent/APIJSON/issues if (callback) { callback(url, res, err) } else { - App.onLoginResponse(isAdminOperation, req, url, res, err, loginMethod, loginType, loginUrl, loginReq, loginHeader) + App.onLoginResponse(isAdminOperation, req, url, res, err, loginMethod, loginType, loginUrl, loginReq, loginRandom, loginHeader) } if (App.prevUrl != null) { @@ -5357,37 +5368,39 @@ https://github.com/Tencent/APIJSON/issues this.scripts = newDefaultScript() - this.request(isAdminOperation, loginMethod, loginType, baseUrl + loginUrl, loginReq, loginHeader, function (url, res, err) { - if (App.isEnvCompareEnabled != true) { - loginCallback(url, res, err, null, loginMethod, loginType, loginUrl, loginReq, loginHeader) - return - } + this.parseRandom(loginReq, loginRandom, 0, true, false, false, function(randomName, constConfig, constJson) { + App.request(isAdminOperation, loginMethod, loginType, baseUrl + loginUrl, constJson, loginHeader, function (url, res, err) { + if (App.isEnvCompareEnabled != true) { + loginCallback(url, res, err, null, loginMethod, loginType, loginUrl, constJson, loginHeader) + return + } - App.request(isAdminOperation, loginMethod, loginType, App.getBaseUrl(App.otherEnv) + loginUrl - , loginReq, loginHeader, function(url_, res_, err_) { - var data = res_.data - var user = JSONResponse.isSuccess(data) ? data.user : null - if (user != null) { - var headers = res.headers || {} - App.otherEnvTokenMap[req.phone + '@' + baseUrl] = headers.token || headers.Token || data.token || data.Token || user.token || user.Token - App.otherEnvCookieMap[req.phone + '@' + baseUrl] = res.cookie || headers.cookie || headers.Cookie || headers['set-cookie'] || headers['Set-Cookie'] - App.saveCache(App.otherEnv, 'otherEnvTokenMap', App.otherEnvTokenMap) - App.saveCache(App.otherEnv, 'otherEnvCookieMap', App.otherEnvCookieMap) - } + App.request(isAdminOperation, loginMethod, loginType, App.getBaseUrl(App.otherEnv) + loginUrl + , loginReq, loginHeader, function(url_, res_, err_) { + var data = res_.data + var user = JSONResponse.isSuccess(data) ? data.user : null + if (user != null) { + var headers = res.headers || {} + App.otherEnvTokenMap[req.phone + '@' + baseUrl] = headers.token || headers.Token || data.token || data.Token || user.token || user.Token + App.otherEnvCookieMap[req.phone + '@' + baseUrl] = res.cookie || headers.cookie || headers.Cookie || headers['set-cookie'] || headers['Set-Cookie'] + App.saveCache(App.otherEnv, 'otherEnvTokenMap', App.otherEnvTokenMap) + App.saveCache(App.otherEnv, 'otherEnvCookieMap', App.otherEnvCookieMap) + } - if (callback) { - callback(url, res, err) - return - } + if (callback) { + callback(url, res, err) + return + } - App.onResponse(url_, res_, err_); - App.onLoginResponse(isAdminOperation, req, url, res, err, loginMethod, loginType, loginUrl, loginReq, loginHeader) - }, App.scripts) + App.onResponse(url_, res_, err_); + App.onLoginResponse(isAdminOperation, req, url, res, err, loginMethod, loginType, loginUrl, constJson, loginRandom, loginHeader) + }, App.scripts) + }) }) } }, - onLoginResponse: function(isAdmin, req, url, res, err, loginMethod, loginType, loginUrl, loginReq, loginHeader) { + onLoginResponse: function(isAdmin, req, url, res, err, loginMethod, loginType, loginUrl, loginReq, loginRandom, loginHeader) { res = res || {} if (isAdmin) { var rpObj = res.data || {} @@ -5446,6 +5459,7 @@ https://github.com/Tencent/APIJSON/issues loginType: loginType, loginUrl: loginUrl, loginReq: loginReq, + loginRandom: loginRandom, loginHeader: loginHeader, cookie: res.cookie || (res.headers || {}).cookie }) @@ -5457,9 +5471,12 @@ https://github.com/Tencent/APIJSON/issues App.currentAccountIndex = App.accounts.length - 1 - var key = App.getBaseUrl(loginUrl) - App.saveCache(key, 'currentAccountIndex', App.currentAccountIndex) - App.saveCache(key, 'accounts', App.accounts) + baseUrl = App.getBaseUrl(vUrl.value) + if (StringUtil.isNotEmpty(baseUrl, true)) { +// var key = App.getBaseUrl(loginUrl) + App.saveCache(baseUrl, 'currentAccountIndex', App.currentAccountIndex) + App.saveCache(baseUrl, 'accounts', App.accounts) + } App.listScript() } @@ -6151,9 +6168,16 @@ https://github.com/Tencent/APIJSON/issues this.setBaseUrl() this.request(isAdminOperation, method, this.type, url, req, isAdminOperation ? {} : header, callback, caseScript, accountScript_, globalScript_, ignorePreScript) + var baseUrls = this.getCache('', 'baseUrls', []) + var bu = this.getBaseUrl(url) + if (baseUrls.indexOf(bu) < 0) { + baseUrls.push(bu) + this.saveCache('', 'baseUrls', baseUrls) + } + this.locals = this.locals || [] if (this.locals.length >= 1000) { //最多1000条,太多会很卡 - this.locals.splice(999, this.locals.length - 999) + this.locals.splice(900, this.locals.length - 900) } var path = this.getMethod() this.locals.unshift({ From 56b064f8133df8b04d2ad75dea20f4d091b9d4ee Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sat, 4 May 2024 00:37:25 +0800 Subject: [PATCH 796/818] =?UTF-8?q?=E9=9B=B6=E4=BB=A3=E7=A0=81=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=EF=BC=9A=E8=A7=A3=E5=86=B3=E4=B8=8D=E8=83=BD=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=E5=A4=9A=E4=B8=AA=E8=B4=A6=E5=8F=B7=E5=AF=B9=E5=BA=94?= =?UTF-8?q?=E7=9A=84=E5=A4=9A=E4=B8=AA=20Base=20URL=EF=BC=9B=E8=B4=A6?= =?UTF-8?q?=E5=8F=B7=EF=BC=9A=E8=A7=A3=E5=86=B3=E6=9C=89=E6=97=B6=E4=BF=9D?= =?UTF-8?q?=E5=AD=98=E8=B4=A6=E5=8F=B7=E5=AF=B9=E5=BA=94=20Base=20URL=20?= =?UTF-8?q?=E9=94=99=E4=B9=B1=EF=BC=8C=E8=A7=A3=E5=86=B3=E5=88=87=E6=8D=A2?= =?UTF-8?q?=20tab=20=E6=9C=89=E6=97=B6=E6=9C=AA=E9=80=89=E6=8B=A9=E7=9A=84?= =?UTF-8?q?=E4=BB=8D=E7=84=B6=E9=AB=98=E4=BA=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.html | 2 +- js/main.js | 92 +++++++++++++++++++++++++++++++++--------------------- 2 files changed, 58 insertions(+), 36 deletions(-) diff --git a/index.html b/index.html index a83ce0e..647ed05 100755 --- a/index.html +++ b/index.html @@ -653,7 +653,7 @@
    - +
    diff --git a/js/main.js b/js/main.js index 481377d..e07055c 100755 --- a/js/main.js +++ b/js/main.js @@ -1343,7 +1343,7 @@ https://github.com/Tencent/APIJSON/issues showUrl: function (isAdminOperation, branchUrl) { if (StringUtil.isEmpty(this.host, true)) { //显示(可编辑)URL Host if (isAdminOperation != true) { - baseUrl = this.getBaseUrl(vUrl.value) + baseUrl = this.getBaseUrl(vUrl.value, true) } vUrl.value = (isAdminOperation ? this.server : baseUrl) + branchUrl } @@ -1365,9 +1365,9 @@ https://github.com/Tencent/APIJSON/issues return } // 重新拉取文档 - var bu = this.getBaseUrl() + var bu = this.getBaseUrl(vUrl.value, true) if (baseUrl != bu) { - baseUrl = bu; + baseUrl = bu doc = null //这个是本地的数据库字典及非开放请求文档 this.saveCache('', 'URL_BASE', baseUrl) @@ -1381,6 +1381,12 @@ https://github.com/Tencent/APIJSON/issues var accounts = [] if (StringUtil.isNotEmpty(bu, true)) { accounts = this.getCache(bu, 'accounts', []) +// for (var i = 0; i < accounts.length; i ++) { +// var ats = accounts[i] +// if (ats == null || (StringUtil.isNotEmpty(ats.baseUrl, true) && ats.baseUrl != bu)) { +// +// } +// } } else { var baseUrls = this.getCache('', 'baseUrls', []) @@ -1407,10 +1413,10 @@ https://github.com/Tencent/APIJSON/issues return url.replaceAll(' ', '') }, //获取基地址 - getBaseUrl: function (url_) { + getBaseUrl: function (url_, fixed) { var url = StringUtil.trim(url_ != undefined ? url_ : vUrl.value) var length = this.getBaseUrlLength(url) - if (length <= 0 && url_ == null) { + if (length <= 0 && url_ == undefined) { var account = this.getCurrentAccount() if (account != null) { return account.baseUrl || '' @@ -1418,7 +1424,7 @@ https://github.com/Tencent/APIJSON/issues } url = length <= 0 ? '' : url.substring(0, length) - return url // == '' ? URL_BASE : url + return url == '' ? (fixed != true ? URL_BASE : '') : url }, //获取基地址长度,以://后的第一个/分割baseUrl和method getBaseUrlLength: function (url_) { @@ -3993,6 +3999,44 @@ https://github.com/Tencent/APIJSON/issues }, + saveAccounts: function() { + baseUrl = this.getBaseUrl() + this.saveCache(baseUrl, 'currentAccountIndex', this.currentAccountIndex) + + var accounts = this.accounts || [] + var accountMap = {} + for (var i = 0; i < accounts.length; i ++) { + var account = accounts[i] + if (account == null || account.phone == null) { + continue + } + + var bu = account.baseUrl || baseUrl + var list = accountMap[bu] || [] + + var find = false + for (var j = 0; j < list.length; j ++) { + var act = list[j] + if (act == null) { + continue + } + + if (act.baseUrl == bu && act.phone == account.phone) { + find = true + break + } + } + + if (find != true) { + list.push(account) + accountMap[bu] = list + } + } + + for (var k in accountMap) { + this.saveCache(k, 'accounts', accountMap[k]) + } + }, onClickAccount: function (index, item, callback) { var accounts = this.accounts @@ -4005,11 +4049,8 @@ https://github.com/Tencent/APIJSON/issues App.onResponse(url, res, err) item.isLoggedIn = false - baseUrl = App.getBaseUrl(vUrl.value) - if (StringUtil.isNotEmpty(baseUrl, true)) { - App.saveCache(baseUrl, 'currentAccountIndex', App.currentAccountIndex) - App.saveCache(baseUrl, 'accounts', App.accounts) - } + App.saveAccounts() + App.changeScriptType(App.scriptType) if (callback != null) { @@ -4044,11 +4085,7 @@ https://github.com/Tencent/APIJSON/issues App.onResponse(url, res, err) item.isLoggedIn = false - baseUrl = App.getBaseUrl(vUrl.value) - if (StringUtil.isNotEmpty(baseUrl, true)) { - App.saveCache(baseUrl, 'currentAccountIndex', App.currentAccountIndex) - App.saveCache(baseUrl, 'accounts', App.accounts) - } + App.saveAccounts() App.changeScriptType(App.scriptType) if (callback != null) { @@ -4084,11 +4121,7 @@ https://github.com/Tencent/APIJSON/issues item.cookie = res.cookie || headers.cookie || headers.Cookie || headers['set-cookie'] || headers['Set-Cookie'] App.accounts[App.currentAccountIndex] = item - - if (StringUtil.isNotEmpty(baseUrl, true)) { - App.saveCache(baseUrl, 'currentAccountIndex', App.currentAccountIndex) - App.saveCache(baseUrl, 'accounts', App.accounts) - } + App.saveAccounts() App.changeScriptType(App.scriptType) @@ -4138,11 +4171,7 @@ https://github.com/Tencent/APIJSON/issues this.currentAccountIndex = this.accounts.length - 1 } - baseUrl = this.getBaseUrl(vUrl.value) - if (StringUtil.isNotEmpty(baseUrl, true)) { - this.saveCache(baseUrl, 'currentAccountIndex', this.currentAccountIndex) - this.saveCache(baseUrl, 'accounts', this.accounts) - } + this.saveAccounts() }, addAccountTab: function () { this.showLogin(true, false) @@ -5470,14 +5499,7 @@ https://github.com/Tencent/APIJSON/issues } App.currentAccountIndex = App.accounts.length - 1 - - baseUrl = App.getBaseUrl(vUrl.value) - if (StringUtil.isNotEmpty(baseUrl, true)) { -// var key = App.getBaseUrl(loginUrl) - App.saveCache(baseUrl, 'currentAccountIndex', App.currentAccountIndex) - App.saveCache(baseUrl, 'accounts', App.accounts) - } - + App.saveAccounts() App.listScript() } } @@ -9871,6 +9893,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea } var isChainShow = this.isChainShow + baseUrl = StringUtil.trim(this.getBaseUrl()) for (var i = 0; i < list.length; i++) { const item = list[i] @@ -9885,7 +9908,6 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea this.startTestSingle(list, allCount, i, item, isRandom, accountIndex, isCross, callback) } - }, startTestSingle: function (list, allCount, index, item, isRandom, accountIndex, isCross, callback, singleCallback) { From 6d0edc19338222870035eafea745ad39df55cb51 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sat, 4 May 2024 01:38:34 +0800 Subject: [PATCH 797/818] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=94=AF=E6=8C=81=20?= =?UTF-8?q?=E9=A1=B9=E7=9B=AE=20=E7=BB=B4=E5=BA=A6=EF=BC=8C=E5=85=B3?= =?UTF-8?q?=E8=81=94=20Base=20URL=E3=80=81=E8=B4=A6=E5=8F=B7=E3=80=81?= =?UTF-8?q?=E7=94=A8=E4=BE=8B=20=E7=AD=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- css/main.css | 35 ++++++++++++++++++++++++++++++++++- index.html | 17 ++++++++++++++--- js/main.js | 21 ++++++++++++++++++--- 3 files changed, 66 insertions(+), 7 deletions(-) diff --git a/css/main.css b/css/main.css index 352ee79..16693cf 100755 --- a/css/main.css +++ b/css/main.css @@ -555,7 +555,6 @@ table.diff thead th.texttitle { background-color: #FFF; } - .historys li { display: block; padding: 10px; @@ -582,6 +581,40 @@ table.diff thead th.texttitle { } +.projects { + margin: 0; + padding: 0; + width: 200px; + + background-color: #FFF; +} + +.projects li { + display: block; + padding: 10px; + border-bottom: #DDD 1px solid; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; + padding-right: 20px; + position: relative +} + +.projects li a { + display: inline-block; + width: 100%; +} + +.projects svg { + position: absolute; + display: inline-block; + cursor: pointer; + right: 5px; + width: 15px; + height: 15px; +} + + .pop-save { padding: 10px; width: 250px; diff --git a/index.html b/index.html index 647ed05..20477d0 100755 --- a/index.html +++ b/index.html @@ -69,8 +69,19 @@ + APIAuto: + + {{ project }} + + 2s @@ -128,7 +139,7 @@ 托管服务器地址 URL: {{ server || '点击设置' }} 导入第三方文档(平台名 URL):
    {{ thirdParty || '点击设置' }}
    - + diff --git a/js/main.js b/js/main.js index e07055c..05ef467 100755 --- a/js/main.js +++ b/js/main.js @@ -1177,6 +1177,12 @@ https://github.com/Tencent/APIJSON/issues thirdParty: 'SWAGGER /v2/api-docs', //apijson.cn // thirdParty: 'RAP /repository/joined /repository/get', // thirdParty: 'YAPI /api/interface/list_menu /api/interface/get', + project: 'APIJSON.cn', + projects: [ + {name: 'localhost', url: 'http://localhost:8080/'}, + {name: 'APIJSON.cn', url: 'http://apijson.cn:8080/'}, + {name: 'APIJSON.cn:9090', url: 'http://apijson.cn:9090/'} + ], language: CodeUtil.LANGUAGE_KOTLIN, header: {}, page: 0, @@ -2166,8 +2172,14 @@ https://github.com/Tencent/APIJSON/issues }, // 删除已保存的 - remove: function (item, index, isRemote, isRandom) { + remove: function (item, index, isRemote, isRandom, isProject) { if (isRemote == null || isRemote == false) { //null != false + if (isProject) { + this.projects.splice(index, 1) + this.saveCache('', 'projects', this.projects) + return + } + localforage.removeItem(item.key, function () { App.historys.splice(index, 1) }) @@ -4182,15 +4194,18 @@ https://github.com/Tencent/APIJSON/issues var allCount = testCases == null ? 0 : testCases.length App.allCount = allCount if (allCount > 0) { + var accountIndex = (this.accounts[this.currentAccountIndex] || {}).isLoggedIn ? this.currentAccountIndex : -1 this.currentAccountIndex = accountIndex //解决 onTestResponse 用 -1 存进去, handleTest 用 currentAccountIndex 取出来为空 +// var account = this.accounts[accountIndex] +// baseUrl = this.getBaseUrl() var reportId = this.reportId if (reportId == null || Number.isNaN(reportId)) { reportId = null } - var tests = this.tests[String(accountIndex)] + var tests = this.tests[String(accountIndex)] // FIXME account.phone + '@' + (account.baseUrl || baseUrl)] if ((reportId != null && reportId >= 0) || (tests != null && JSONObject.isEmpty(tests) != true)) { for (var i = 0; i < allCount; i++) { var item = testCases[i] @@ -6192,7 +6207,7 @@ https://github.com/Tencent/APIJSON/issues var baseUrls = this.getCache('', 'baseUrls', []) var bu = this.getBaseUrl(url) - if (baseUrls.indexOf(bu) < 0) { + if (StringUtil.isNotEmpty(bu, true) && baseUrls.indexOf(bu) < 0) { baseUrls.push(bu) this.saveCache('', 'baseUrls', baseUrls) } From 05928867792da19a2c3009d5453e22ff90516d24 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sat, 4 May 2024 02:08:53 +0800 Subject: [PATCH 798/818] =?UTF-8?q?=E9=A1=B9=E7=9B=AE=EF=BC=9A=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E6=94=AF=E6=8C=81=E8=AF=BB=E5=86=99=E5=AD=98=E5=82=A8?= =?UTF-8?q?=E5=92=8C=E7=BC=96=E8=BE=91=E5=90=8D=E7=A7=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.html | 10 +++++----- js/main.js | 37 ++++++++++++++++++++++++++++++++++--- 2 files changed, 39 insertions(+), 8 deletions(-) diff --git a/index.html b/index.html index 20477d0..4cee5c7 100755 --- a/index.html +++ b/index.html @@ -71,12 +71,12 @@ - {{ project }} -
      -
    • - {{project.url + (StringUtil.isEmpty(project.name, true) ? '' : ' // ' + project.name)}} + {{ project.name }} +
        +
      • + {{item.url + (StringUtil.isEmpty(item.name, true) ? '' : ' //')}} - +
      • diff --git a/js/main.js b/js/main.js index 05ef467..b7de465 100755 --- a/js/main.js +++ b/js/main.js @@ -1177,9 +1177,9 @@ https://github.com/Tencent/APIJSON/issues thirdParty: 'SWAGGER /v2/api-docs', //apijson.cn // thirdParty: 'RAP /repository/joined /repository/get', // thirdParty: 'YAPI /api/interface/list_menu /api/interface/get', - project: 'APIJSON.cn', + project: {name: 'APIJSON.cn', url: 'http://apijson.cn:8080/'}, projects: [ - {name: 'localhost', url: 'http://localhost:8080/'}, + {name: 'Localhost', url: 'http://localhost:8080/'}, {name: 'APIJSON.cn', url: 'http://apijson.cn:8080/'}, {name: 'APIJSON.cn:9090', url: 'http://apijson.cn:9090/'} ], @@ -6210,6 +6210,27 @@ https://github.com/Tencent/APIJSON/issues if (StringUtil.isNotEmpty(bu, true) && baseUrls.indexOf(bu) < 0) { baseUrls.push(bu) this.saveCache('', 'baseUrls', baseUrls) + var projects = this.projects || [] + var project = this.project || {} + var find = false + for (var j = 0; j < projects.length; j ++) { + var pjt = projects[j] + if (pjt == null || StringUtil.isEmpty(pjt.url, true)) { + continue + } + + if (pjt.url == project.url) { + find = true + break + } + } + + if (find != true) { + projects.push({name: bu, url: bu}) + this.projects = projects + this.saveCache('', 'projects', projects) + } + } this.locals = this.locals || [] @@ -12118,9 +12139,19 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea '\nvar url = this.getCache(, url) ...' + '\n} catch (e) {\n' + e.message) } + try { //这里是初始化,不能出错 + var projects = this.getCache('', 'projects') + if (projects != null && projects.length >= 1) { + this.projects = projects + } + } catch (e) { + console.log('created try { ' + + '\nvar accounts = this.getCache(URL_BASE, accounts)' + + '\n} catch (e) {\n' + e.message) + } try { //这里是初始化,不能出错 var accounts = this.getCache(URL_BASE, 'accounts') - if (accounts != null) { + if (accounts != null && accounts.length >= 1) { this.accounts = accounts this.currentAccountIndex = this.getCache(URL_BASE, 'currentAccountIndex') } From b8ccdf1895e81c6907586cfe00cd03c485a8a1e5 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sat, 4 May 2024 18:54:33 +0800 Subject: [PATCH 799/818] =?UTF-8?q?=E9=A1=B9=E7=9B=AE=EF=BC=9A=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E6=94=AF=E6=8C=81=E5=90=8C=E6=95=B0=E6=8D=AE=E5=BA=93?= =?UTF-8?q?=E6=9F=A5=20Base=20URL=20=E5=8F=8A=E9=A1=B9=E7=9B=AE=E5=88=97?= =?UTF-8?q?=E8=A1=A8=E3=80=81=E7=94=A8=E5=AE=83=E4=BB=AC=E7=AD=9B=E9=80=89?= =?UTF-8?q?=E7=94=A8=E4=BE=8B=E3=80=81=E7=BC=96=E8=BE=91=E5=90=8E=E5=90=8C?= =?UTF-8?q?=E6=AD=A5=E7=94=A8=E4=BE=8B=E5=88=B0=E6=95=B0=E6=8D=AE=E5=BA=93?= =?UTF-8?q?=E7=AD=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.html | 25 +++--- js/main.js | 260 ++++++++++++++++++++++++++++++++++++++++------------- 2 files changed, 214 insertions(+), 71 deletions(-) diff --git a/index.html b/index.html index 4cee5c7..74f1d6a 100755 --- a/index.html +++ b/index.html @@ -71,21 +71,26 @@ - {{ project.name }} -
          -
        • - {{item.url + (StringUtil.isEmpty(item.name, true) ? '' : ' //')}} - - - - -
        • + {{ StringUtil.isEmpty(projectHost.project, true) ? projectHost.host : projectHost.project }} + 2s - +
          diff --git a/js/main.js b/js/main.js index b7de465..8d9c7bd 100755 --- a/js/main.js +++ b/js/main.js @@ -1173,15 +1173,14 @@ https://github.com/Tencent/APIJSON/issues otherEnv: 'http://localhost:8080/', // 其它环境服务地址,用来对比当前的 server: 'http://apijson.cn:9090/', // 'http://localhost:8080/', // Chrome 90+ 跨域问题非常难搞,开发模式启动都不行了 // server: 'http://47.74.39.68:9090/', // apijson.org - // project: 'http://apijson.cn:8080/', // apijson.cn + projectHost: {host: 'http://apijson.cn:8080/', project: 'APIJSON.cn'}, // apijson.cn thirdParty: 'SWAGGER /v2/api-docs', //apijson.cn // thirdParty: 'RAP /repository/joined /repository/get', // thirdParty: 'YAPI /api/interface/list_menu /api/interface/get', - project: {name: 'APIJSON.cn', url: 'http://apijson.cn:8080/'}, - projects: [ - {name: 'Localhost', url: 'http://localhost:8080/'}, - {name: 'APIJSON.cn', url: 'http://apijson.cn:8080/'}, - {name: 'APIJSON.cn:9090', url: 'http://apijson.cn:9090/'} + projectHosts: [ + {host: 'http://localhost:8080/', project: 'Localhost'}, + {host: 'http://apijson.cn:8080/', project: 'APIJSON.cn'}, + {host: 'http://apijson.cn:9090/', project: 'APIJSON.cn:9090'} ], language: CodeUtil.LANGUAGE_KOTLIN, header: {}, @@ -2175,8 +2174,8 @@ https://github.com/Tencent/APIJSON/issues remove: function (item, index, isRemote, isRandom, isProject) { if (isRemote == null || isRemote == false) { //null != false if (isProject) { - this.projects.splice(index, 1) - this.saveCache('', 'projects', this.projects) + this.projectHosts.splice(index, 1) + this.saveCache('', 'projectHosts', this.projectHosts) return } @@ -2369,6 +2368,106 @@ https://github.com/Tencent/APIJSON/issues // }) }, + onClickHost: function(index, item) { + this.projectHost = item = item || {} + this.isTestCaseShow = false + + this.host = '' + var bu = this.getBranchUrl() + + vUrl.value = item.host + bu + this.showUrl(false, bu) + }, + + listProjectHost: function() { + var req = { + 'TestRecord[]': { + 'count': 0, + 'TestRecord': { + '@column': 'DISTINCT host,project', + '@from@': { + 'join': '&/Document', + 'TestRecord': { + '@column': 'host,documentId', + '@group': 'host,documentId', + 'host{}': 'length(host)>2' + }, + 'Document': { + 'id@': '/TestRecord/documentId', + '@column': "ifnull(project,''):project", + '@group': 'project', +// 'project{}': 'length(project)>0' + } + } + } + } + } + + this.request(true, REQUEST_TYPE_POST, REQUEST_TYPE_JSON, this.server + '/get', req, {}, function (url, res, err) { + var rpObj = res.data + if (JSONResponse.isSuccess(rpObj) != true) { + App.log(err != null ? err : (rpObj == null ? '' : rpObj.msg)) + return + } + + var projectHosts = App.getCache('', 'projectHosts', []) + var list = rpObj['TestRecord[]'] || [] +// var phs = [] +// for (var i = 0; i < list.length; i ++) { +// var item = list[i] || {} +// var host = (item.TestRecord || {}).host +// if (StringUtil.isEmpty(host, true)) { +// continue +// } +// +// phs.push({ 'host': host, 'project': (item.Document || {}).project }) +// } + + App.projectHosts = projectHosts.concat(list) + }) + }, + + syncProjectHost: function(index, item) { + var rawProject = item == null ? null : item.rawProject + var project = item == null ? null : item.project + + var list = this.testCases + var count = list == null ? 0 : list.length + if (count <= 0) { + alert('没有可操作的用例!请先查询用例,保证有至少一个显示!') + return + } + + var ids = [] + for (var i = 0; i < count; i ++) { + var item = list[i] + var doc = item == null ? null : item.Document + var id = doc == null ? null : doc.id + if (id == null || id <= 0) { + continue + } + + ids.push(id) + } + + var req = { + 'Document': { + 'id{}': ids, + 'project{}': [null, '', rawProject], + 'project': project || '' + }, + 'tag': 'Document-project[]' + } + + this.adminRequest('/put', req, {}, function (url, res, err) { + App.onResponse(url, res, err) + var rpObj = res.data + if (JSONResponse.isSuccess(rpObj)) { + App.listProjectHost() + } + }) + }, + // 获取所有保存的json listHistory: function () { localforage.iterate(function (value, key, iterationNumber) { @@ -2520,6 +2619,8 @@ https://github.com/Tencent/APIJSON/issues return } + const project = (this.projectHost || {}).project + const isExportRandom = this.isExportRandom const isExportScript = this.isExportScript @@ -2759,6 +2860,7 @@ https://github.com/Tencent/APIJSON/issues config: config }, 'TestRecord': { + 'host': StringUtil.isEmpty(baseUrl, true) ? null : baseUrl, 'chainGroupId': cgId, 'response': rawRspStr, 'standard': isML ? JSON.stringify(stddObj) : null @@ -2768,6 +2870,7 @@ https://github.com/Tencent/APIJSON/issues format: false, 'Document': isEditResponse ? null : { 'id': did == null ? undefined : did, + 'project': StringUtil.isEmpty(project, true) ? null : project, // 'testAccountId': currentAccountId, // 'chainGroupId': cgId, 'operation': CodeUtil.getOperation(path, reqObj), @@ -2885,38 +2988,40 @@ https://github.com/Tencent/APIJSON/issues } }, newAndUploadRandomConfig: function(baseUrl, req, documentId, config, count, callback, isReleaseRESTful) { - if (documentId == null) { - return - } - const isGenerate = StringUtil.isEmpty(config, true); - var configs = isGenerate ? [] : [config] - if (isGenerate) { - var config = StringUtil.trim(this.newRandomConfig(null, '', req, false)) - if (StringUtil.isEmpty(config, true)) { - return; - } - configs.push(config) - config2 = StringUtil.trim(this.newRandomConfig(null, '', req, true)) - if (StringUtil.isNotEmpty(config2, true)) { - configs.push(config2) - } - } - for (var i = 0; i < configs.length; i ++) { - const config = configs[i] - this.request(true, REQUEST_TYPE_POST, REQUEST_TYPE_JSON, (isReleaseRESTful ? baseUrl : this.server) + '/post', { - format: false, - Random: { - documentId: documentId, - count: count, - name: '默认配置' + (isGenerate ? '(上传测试用例时自动生成)' : ''), - config: config - }, - TestRecord: { - host: baseUrl, - response: '' - }, - tag: 'Random' - }, {}, callback) + if (documentId == null) { + return + } + const isGenerate = StringUtil.isEmpty(config, true); + var configs = isGenerate ? [] : [config] + if (isGenerate) { + var config = StringUtil.trim(this.newRandomConfig(null, '', req, false)) + if (StringUtil.isEmpty(config, true)) { + return; + } + + configs.push(config) + config2 = StringUtil.trim(this.newRandomConfig(null, '', req, true)) + if (StringUtil.isNotEmpty(config2, true)) { + configs.push(config2) + } + } + + for (var i = 0; i < configs.length; i ++) { + const config = configs[i] + this.request(true, REQUEST_TYPE_POST, REQUEST_TYPE_JSON, (isReleaseRESTful ? baseUrl : this.server) + '/post', { + format: false, + Random: { + documentId: documentId, + count: count, + name: '默认配置' + (isGenerate ? '(上传测试用例时自动生成)' : ''), + config: config + }, + TestRecord: { + host: baseUrl, + response: '' + }, + tag: 'Random' + }, {}, callback) } }, @@ -3917,7 +4022,7 @@ https://github.com/Tencent/APIJSON/issues } : undefined, 'TestRecord': { 'randomId': 0, - 'host': baseUrl, + 'host': StringUtil.isEmpty(baseUrl, true) ? null : baseUrl, 'testAccountId': currentAccountId, 'response': rspObj == null ? '' : JSON.stringify(rspObj, null, ' '), 'standard': standard == null ? '' : JSON.stringify(standard, null, ' '), @@ -4272,6 +4377,8 @@ https://github.com/Tencent/APIJSON/issues var isMLEnabled = this.isMLEnabled var userId = this.User.id + var project = this.projectHost.project + baseUrl = this.getBaseUrl(vUrl.value, true) var key = groupId + '' var page = this.chainGroupPage = this.chainGroupPages[key] || 0 @@ -4309,6 +4416,7 @@ https://github.com/Tencent/APIJSON/issues // '@column': 'id,userId,version,date,name,operation,method,type,url,request,apijson,standard', // ;substr(url,' + (StringUtil.length(groupUrl) + 2) + '):substr', '@order': 'version-,date-', 'userId': userId, + 'project': StringUtil.isEmpty(project, true) ? null : project, 'name$': search, 'operation$': search, 'url$': search, @@ -4331,6 +4439,7 @@ https://github.com/Tencent/APIJSON/issues 'chainGroupId@': '/Chain/groupId', 'documentId@': '/Document/id', 'userId': userId, + 'host': StringUtil.isEmpty(baseUrl, true) ? null : baseUrl, // 'testAccountId': this.getCurrentAccountId(), 'randomId': 0, // 'reportId': reportId <= 0 ? null : reportId, @@ -4501,6 +4610,8 @@ https://github.com/Tencent/APIJSON/issues return } + var project = (this.projectHost || {}).project + var page = this.caseGroupPage = this.caseGroupPages[groupUrl] || 0 var count = this.caseGroupCount = this.caseGroupCounts[groupUrl] || 0 var search = this.caseGroupSearch = this.caseGroupSearches[groupUrl] || '' @@ -4517,6 +4628,7 @@ https://github.com/Tencent/APIJSON/issues '@raw': '@column', '@column': "substr(url,1,length(url)-length(substring_index(url,'/',-1))-1):groupUrl;group:groupName", // (CASE WHEN length(`group`) > 0 THEN `group` ELSE '-' END):name", 'userId': this.User.id, + 'project': StringUtil.isEmpty(project, true) ? null : project, 'group$': search, 'url$': search, // 'url&$': StringUtil.isEmpty(groupUrl) ? null : [groupUrl.replaceAll('_', '\\_').replaceAll('%', '\\%') + '/%'], @@ -4651,6 +4763,8 @@ https://github.com/Tencent/APIJSON/issues return; } + var project = (this.projectHost || {}).project + // this.isTestCaseShow = false var reportId = this.reportId @@ -4694,6 +4808,7 @@ https://github.com/Tencent/APIJSON/issues // '@column': 'id,userId,version,date,name,operation,method,type,url,request,apijson,standard', // ;substr(url,' + (StringUtil.length(groupUrl) + 2) + '):substr', '@order': 'version-,date-', 'userId': userId, + 'project': StringUtil.isEmpty(project, true) ? null : project, 'name$': search, 'operation$': search, 'url$': search, @@ -4718,6 +4833,7 @@ https://github.com/Tencent/APIJSON/issues 'chainGroupId': isChainShow ? null : 0, 'documentId@': '/Document/id', 'userId': userId, + 'host': StringUtil.isEmpty(baseUrl, true) ? null : baseUrl, // 'testAccountId': this.getCurrentAccountId(), 'randomId': 0, 'reportId': reportId <= 0 ? null : reportId, @@ -4955,6 +5071,7 @@ https://github.com/Tencent/APIJSON/issues ? null : '%' + StringUtil.trim(this.randomSearch) + '%') var url = this.server + '/get' + baseUrl = this.getBaseUrl(vUrl.value, true) const cri = this.currentRemoteItem || {} const chain = cri.Chain || {} const cgId = chain.groupId || 0 @@ -4973,7 +5090,7 @@ https://github.com/Tencent/APIJSON/issues 'TestRecord': { 'randomId@': '/Random/id', // 'testAccountId': this.getCurrentAccountId(), - 'host': this.getBaseUrl(), + 'host': StringUtil.isEmpty(baseUrl, true) ? null : baseUrl, '@order': 'date-' }, '[]': isSub ? null : { @@ -4989,7 +5106,7 @@ https://github.com/Tencent/APIJSON/issues 'TestRecord': { 'randomId@': '/Random/id', // 'testAccountId': this.getCurrentAccountId(), - 'host': this.getBaseUrl(), + 'host': StringUtil.isEmpty(baseUrl, true) ? null : baseUrl, '@order': 'date-' } } @@ -6210,25 +6327,25 @@ https://github.com/Tencent/APIJSON/issues if (StringUtil.isNotEmpty(bu, true) && baseUrls.indexOf(bu) < 0) { baseUrls.push(bu) this.saveCache('', 'baseUrls', baseUrls) - var projects = this.projects || [] - var project = this.project || {} + var projectHosts = this.projectHosts || [] + var projectHost = this.projectHost || {} var find = false for (var j = 0; j < projects.length; j ++) { - var pjt = projects[j] - if (pjt == null || StringUtil.isEmpty(pjt.url, true)) { + var pjt = projectHosts[j] + if (pjt == null || StringUtil.isEmpty(pjt.host, true)) { continue } - if (pjt.url == project.url) { + if (pjt.url == projectHost.host) { find = true break } } if (find != true) { - projects.push({name: bu, url: bu}) - this.projects = projects - this.saveCache('', 'projects', projects) + projectHosts.push({host: bu, project: projectHost.project}) + this.projectHosts = projectHosts + this.saveCache('', 'projectHosts', projects) } } @@ -6241,6 +6358,7 @@ https://github.com/Tencent/APIJSON/issues this.locals.unshift({ 'Document': { 'userId': this.User.id, + 'project': (this.projectHost || {}).project, 'name': this.formatDateTime() + ' ' + (this.urlComment || StringUtil.trim(req.tag)), 'operation': CodeUtil.getOperation(path, req), 'method': method, @@ -6254,6 +6372,10 @@ https://github.com/Tencent/APIJSON/issues this.saveCache('', 'locals', this.locals) }, + adminRequest: function (url, req, header, callback) { + this.request(true, REQUEST_TYPE_POST, REQUEST_TYPE_JSON, url, req, header, callback) + }, + //请求 request: function (isAdminOperation, method, type, url, req, header, callback, caseScript_, accountScript_, globalScript_, ignorePreScript) { this.loadingCount ++ @@ -6919,13 +7041,23 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea */ doOnKeyUp: function (event, type, isFilter, item) { var keyCode = event.keyCode ? event.keyCode : (event.which ? event.which : event.charCode); + var isEnter = keyCode == 13 if (type == 'option') { - if (keyCode == 13) { + if (isEnter) { this.selectInput(item); } return } + if (type == 'project') { + if (isEnter || item.host == (this.projectHost || {}).host) { + this.projectHost = {project: item.project} + } + return + } + + var project = (this.projectHost || {}).project + if (isFilter && type == 'caseGroup') { this.isCaseGroupEditable = true } @@ -6937,7 +7069,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea this.currentRemoteItem = null } - if (keyCode == 13) { // enter + if (isEnter) { // enter if (isFilter) { this.onFilterChange(type) return @@ -7014,6 +7146,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea '@column': 'id,userId,version,date,name,operation,method,type,url,request,apijson', '@order': 'version-,date-', 'userId': this.User.id, + 'project': StringUtil.isEmpty(project, true) ? null : project, 'name$': search, 'operation$': search, 'url$': search, @@ -7073,6 +7206,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea //修改 Document this.request(true, REQUEST_TYPE_POST, REQUEST_TYPE_JSON, this.server + '/put', { Document: { + 'project': StringUtil.isEmpty(project, true) ? null : project, 'group': item.groupName, '@raw': '@key', '@key':"url:substr(url,1,length(url)-length(substring_index(url,'/',-1))-1)", @@ -10858,6 +10992,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea } const isNewRandom = isRandom && random.id <= 0 + const baseUrl = this.getBaseUrl() const userId = this.User.id const cri = this.currentRemoteItem || {} const chain = cri.Chain || {} @@ -10879,7 +11014,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea TestRecord: isDuration ? Object.assign(testRecord, { id: undefined, reportId: this.reportId, - host: this.getBaseUrl(), + host: baseUrl, userId: userId, testAccountId: this.getCurrentAccountId(), chainGroupId: cgId, @@ -10893,7 +11028,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea documentId: isNewRandom ? null : (isRandom ? random.documentId : document.id), randomId: isRandom && ! isNewRandom ? random.id : null, reportId: this.reportId, - host: this.getBaseUrl(), + host: baseUrl, testAccountId: this.getCurrentAccountId(), compare: JSON.stringify(testRecord.compare || {}), response: rawRspStr, @@ -12140,13 +12275,13 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea '\n} catch (e) {\n' + e.message) } try { //这里是初始化,不能出错 - var projects = this.getCache('', 'projects') - if (projects != null && projects.length >= 1) { - this.projects = projects + var projectHosts = this.getCache('', 'projectHosts') + if (projectHosts != null && projectHosts.length >= 1) { + this.projectHosts = projectHosts } } catch (e) { console.log('created try { ' + - '\nvar accounts = this.getCache(URL_BASE, accounts)' + + '\nvar projectHosts = this.getCache("", projectHosts)' + '\n} catch (e) {\n' + e.message) } try { //这里是初始化,不能出错 @@ -12241,9 +12376,12 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea } var isLoggedIn = this.User != null && this.User.id != null && this.User.id > 0 + if (isLoggedIn) { + this.listProjectHost() - if (isLoggedIn && this.caseShowType != 1 && this.casePaths.length <= 0 && this.caseGroups.length <= 0) { - this.selectCaseGroup(-1, null) + if (this.caseShowType != 1 && this.casePaths.length <= 0 && this.caseGroups.length <= 0) { + this.selectCaseGroup(-1, null) + } } var rawReq = getRequestFromURL() From dfcb484c2055d5308d2c4697b634a189f70c07c5 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sat, 4 May 2024 20:21:23 +0800 Subject: [PATCH 800/818] =?UTF-8?q?=E5=9C=BA=E6=99=AF=E4=B8=B2=E8=81=94?= =?UTF-8?q?=EF=BC=9A=E6=96=B0=E5=A2=9E=E6=94=AF=E6=8C=81=E5=88=A0=E9=99=A4?= =?UTF-8?q?=E5=88=86=E7=BB=84=E5=92=8C=E6=AD=A5=E9=AA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.html | 5 ++++- js/main.js | 66 ++++++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 53 insertions(+), 18 deletions(-) diff --git a/index.html b/index.html index 74f1d6a..bcb547f 100755 --- a/index.html +++ b/index.html @@ -237,7 +237,10 @@
        diff --git a/js/main.js b/js/main.js index 8d9c7bd..f321c24 100755 --- a/js/main.js +++ b/js/main.js @@ -2063,10 +2063,11 @@ https://github.com/Tencent/APIJSON/issues }, // 显示删除弹窗 - showDelete: function (show, item, index, isRandom) { + showDelete: function (show, item, index, isRandom, isChainGroup) { this.isDeleteShow = show this.isDeleteRandom = isRandom - this.exTxt.name = '请输入' + (isRandom ? '随机配置' : '接口') + '名来确认' + this.isDeleteChainGroup = isChainGroup + this.exTxt.name = '请输入' + (isRandom ? '随机配置' : (isChainGroup ? '分组' : '接口')) + '名来确认' if (isRandom) { this.currentRandomItem = Object.assign(item, { index: index @@ -2082,15 +2083,16 @@ https://github.com/Tencent/APIJSON/issues // 删除接口文档 deleteDoc: function () { var isDeleteRandom = this.isDeleteRandom + var isDeleteChainGroup = this.isDeleteChainGroup var item = (isDeleteRandom ? this.currentRandomItem : this.currentDocItem) || {} - var doc = (isDeleteRandom ? item.Random : item.Document) || {} + var doc = (isDeleteRandom ? item.Random : (isDeleteChainGroup ? item.Chain : item.Document)) || {} - var type = isDeleteRandom ? '随机配置' : '接口' - if (doc.id == null) { + var type = isDeleteRandom ? '随机配置' : (isDeleteChainGroup ? '分组' : '接口') + if ((isDeleteChainGroup && doc.groupId == null) || (isDeleteChainGroup != true && doc.id == null)) { alert('未选择' + type + '或' + type + '不存在!') return } - if (doc.name != this.exTxt.name) { + if ((isDeleteChainGroup && doc.groupName != this.exTxt.name) || (isDeleteChainGroup != true && doc.name != this.exTxt.name)) { alert('输入的' + type + '名和要删除的' + type + '名不匹配!') return } @@ -2099,6 +2101,7 @@ https://github.com/Tencent/APIJSON/issues this.isTestCaseShow = false this.isRandomListShow = false + var isChainShow = this.isChainShow var url = this.server + '/delete' var req = isDeleteRandom ? { @@ -2107,14 +2110,21 @@ https://github.com/Tencent/APIJSON/issues 'id': doc.id }, 'tag': 'Random' + } : (isDeleteChainGroup || isChainShow ? { + format: false, + 'Chain': { + 'id': isDeleteChainGroup ? null : doc.id, + 'groupId': isDeleteChainGroup ? doc.groupId : null + }, + 'tag': isDeleteChainGroup ? 'Chain-group' : 'Chain' } : { format: false, 'Document': { 'id': doc.id }, 'tag': 'Document' - } - this.request(true, REQUEST_TYPE_POST, REQUEST_TYPE_JSON, url, req, {}, function (url, res, err) { + }) + this.adminRequest(url, req, {}, function (url, res, err) { App.onResponse(url, res, err) var rpObj = res.data || {} @@ -2129,7 +2139,12 @@ https://github.com/Tencent/APIJSON/issues } // App.showRandomList(true, App.currentRemoteItem) } - } else { + } + else if (isDeleteChainGroup) { + App.chainGroups.splice(item.index, 1) + App.selectChainGroup(App.currentChainGroupIndex, null) + } + else { if (rpObj.Document != null && JSONResponse.isSuccess(rpObj.Document)) { App.remotes.splice(item.index, 1) App.showTestCase(true, App.isLocalShow) @@ -2171,7 +2186,7 @@ https://github.com/Tencent/APIJSON/issues }, // 删除已保存的 - remove: function (item, index, isRemote, isRandom, isProject) { + remove: function (item, index, isRemote, isRandom, isProject, isChainGroup) { if (isRemote == null || isRemote == false) { //null != false if (isProject) { this.projectHosts.splice(index, 1) @@ -2194,7 +2209,7 @@ https://github.com/Tencent/APIJSON/issues return } - this.showDelete(true, item, index, isRandom) + this.showDelete(true, item, index, isRandom, isChainGroup) } }, @@ -4495,13 +4510,19 @@ https://github.com/Tencent/APIJSON/issues return } - App.chainGroups = data['[]'] || [] - if (App.chainGroups.length > 0) { - App.currentChainGroupIndex = 0 - App.chainPaths.push((App.chainGroups[0] || {}).Chain) + var chainGroups = App.chainGroups = data['[]'] || [] + var count = chainGroups.length + var index = App.currentChainGroupIndex + if (index == null || index < 0 || index >= count) { + App.currentChainGroupIndex = index = 0 + } + + var item = chainGroups[index] || {} + if (item.Chain != null) { + App.chainPaths.push(item.Chain) } - App.remotes = App.testCases = (App.chainGroups[0] || {})['[]'] || [] + App.remotes = App.testCases = item['[]'] || [] // App.showTestCase(true, false, null) }) }, @@ -4545,6 +4566,11 @@ https://github.com/Tencent/APIJSON/issues alert((isAdd ? '新增' : '修改') + (isOk ? '成功' : '失败') + (isAdd ? '! \n' :'!\ngroupId: ' + groupId) + '\ngroupName: ' + groupName + '\n' + msg) App.isCaseGroupEditable = ! isOk + if (isOk) { +// App.remotes = App.testCases = [] +// App.showTestCase(true, false, null) + App.selectChainGroup(App.currentChainGroupIndex, null) + } }) }, @@ -4891,6 +4917,12 @@ https://github.com/Tencent/APIJSON/issues this.isLocalShow = false this.testCases = App.remotes = rpObj['[]'] this.getCurrentRandomSummary().summaryType = 'total' // App.onClickSummary('total', true) + if (this.isChainShow && this.currentChainGroupIndex >= 0) { + var chain = this.chainGroups[this.currentChainGroupIndex] + if (chain != null) { + chain['[]'] = this.testCases + } + } if (IS_BROWSER) { vOutput.value = show ? '' : (output || '') @@ -7373,7 +7405,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea this.saveCache(this.server, 'chainGroupCounts', this.chainGroupCounts) // this.saveCache(this.server, 'chainGroupSearches', this.chainGroupSearches) - this.selectChainGroup(-1, null) + this.selectChainGroup(this.currentChainGroupIndex, null) } else if (type == 'caseGroup') { this.caseGroupPages[groupKey] = this.caseGroupPage From e6502c850d7b144cc4f8050ebf2b1c5bb9424f09 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Wed, 8 May 2024 00:11:41 +0800 Subject: [PATCH 801/818] =?UTF-8?q?=E5=9C=BA=E6=99=AF=E4=B8=B2=E8=81=94?= =?UTF-8?q?=EF=BC=9A=E9=9A=90=E8=97=8F=E5=88=86=E7=BB=84=E6=97=B6=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E5=8F=AA=E6=B5=8B=E5=BD=93=E5=89=8D=E5=88=97=E8=A1=A8?= =?UTF-8?q?=E7=9A=84=EF=BC=8C=E8=A7=A3=E5=86=B3=20bug=EF=BC=8C=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E5=8F=82=E6=95=B0=E4=BC=A0=E9=80=92=E5=92=8C=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E8=A1=A5=E5=85=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apijson/CodeUtil.js | 4 +- apijson/JSONResponse.js | 28 +++++--- index.html | 2 +- js/main.js | 156 ++++++++++++++++++++++++++-------------- 4 files changed, 126 insertions(+), 64 deletions(-) diff --git a/apijson/CodeUtil.js b/apijson/CodeUtil.js index 0f6d580..e3ae612 100644 --- a/apijson/CodeUtil.js +++ b/apijson/CodeUtil.js @@ -7007,7 +7007,7 @@ res_data = rep.json() var verifyType = isSubquery != true && value != null; if (onlyTableAndColumn) { - key = new String(columnName); + key = StringUtil.get(columnName); } else { //功能符 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @@ -7172,7 +7172,7 @@ res_data = rep.json() } else { fun = ''; - key = new String(columnName); + key = StringUtil.get(columnName); } diff --git a/apijson/JSONResponse.js b/apijson/JSONResponse.js index c8519dc..174f45f 100644 --- a/apijson/JSONResponse.js +++ b/apijson/JSONResponse.js @@ -1162,18 +1162,30 @@ var JSONResponse = { getType: function(o) { //typeof [] = 'object' if (o == null) { - return 'object'; + return 'object'; // FIXME return null } + if (o instanceof Array) { return 'array'; } - var t = typeof o; - if (t == 'number' && Number.isInteger(o)) { + if (JSONResponse.isBoolean(o)) { + return 'boolean'; + } + + if (JSONResponse.isInteger(o)) { return 'integer'; } - return t; + if (JSONResponse.isNumber(o)) { + return 'number'; + } + + if (JSONResponse.isString(o)) { + return 'string'; + } + + return typeof o; }, isObject: function(o) { @@ -1184,16 +1196,16 @@ var JSONResponse = { return o instanceof Array; }, isString: function(o) { - return typeof o == 'string'; + return typeof o == 'string' || o instanceof String; }, isNumber: function(o) { - return typeof o == 'number'; + return typeof o == 'number' || o instanceof Number; }, isInteger: function(o) { - return JSONResponse.getType(o) == 'integer'; + return Number.isInteger(o); }, isBoolean: function(o) { - return typeof o == 'boolean'; + return typeof o == 'boolean' || o instanceof Boolean; }, diff --git a/index.html b/index.html index bcb547f..20fde11 100755 --- a/index.html +++ b/index.html @@ -1038,7 +1038,7 @@ var vVerify = document.getElementById("vVerify"); var vRemember = document.getElementById("vRemember"); - vUrl.value = new String(URL_BASE + '/get'); //main.js里访问不到,可能是script引用顺序问题 + vUrl.value = StringUtil.get(URL_BASE + '/get'); //main.js里访问不到,可能是script引用顺序问题 var vRequestMarkdown = document.getElementById('vRequestMarkdown'); var vMarkdown = document.getElementById('vMarkdown'); diff --git a/js/main.js b/js/main.js index f321c24..db0171a 100755 --- a/js/main.js +++ b/js/main.js @@ -618,19 +618,28 @@ https://github.com/Tencent/APIJSON/issues var PRE_ARG = 'PRE_ARG' // PRE_ARG('[]/page') var PRE_RES = 'PRE_RES' // PRE_RES('[]/0/User/id') var PRE_DATA = 'PRE_DATA' // PRE_DATA('[]/0/User/id') - var PRE_EXT = 'PRE_EXT' // PRE_EXT('key') + var CTX_EXT = 'CTX_EXT' // CTX_EXT('key') var CUR_REQ = 'CUR_REQ' // CUR_REQ('User/id') var CUR_ARG = 'CUR_ARG' // CUR_REQ('User/id') - var CUR_PUT = 'CUR_PUT' // CUR_PUT('key', val) + var CUR_RES = 'CUR_RES' // CUR_RES('[]/0/User/id') + var CUR_DATA = 'CUR_DATA' // CUR_DATA('[]/0/User/id') + var CTX_PUT = 'CTX_PUT' // CTX_PUT('key', val) - function get4Path(obj, path, nullable) { + function get4Path(obj, path, defaultVal, msg) { var val = JSONResponse.getValByPath(obj, StringUtil.split(path, '/')) - if (val == null && nullable != true) { - throw new Error('找不到 ' + path + ' 对应在 obj 中的非 null 值!') + if (val == null && defaultVal == undefined) { + throw new Error('找不到 ' + path + ' 对应在 obj 中的非 null 值!' + StringUtil.get(msg)) } return val } + function put4Path(obj, key, val, msg) { + if (obj == null) { + throw new Error('obj = null !不能 put ' + key + ' !' + StringUtil.get(msg)) + } + obj[key] = val + } + var RANDOM_DB = 'RANDOM_DB' var RANDOM_IN = 'RANDOM_IN' var RANDOM_INT = 'RANDOM_INT' @@ -1451,7 +1460,7 @@ https://github.com/Tencent/APIJSON/issues }, //获取操作方法 getMethod: function (url, noQuery) { - var url = new String(url == null ? vUrl.value : url).trim() + var url = StringUtil.get(url == null ? vUrl.value : url).trim() var index = this.getBaseUrlLength(url) url = index <= 0 ? url : url.substring(index) index = noQuery ? url.indexOf("?") : -1 @@ -1461,7 +1470,7 @@ https://github.com/Tencent/APIJSON/issues return url.startsWith('/') ? url.substring(1) : url }, getBranchUrl: function (url) { - var url = new String(url == null ? vUrl.value : url).trim() + var url = StringUtil.get(url == null ? vUrl.value : url).trim() var index = this.getBaseUrlLength(url) url = index <= 0 ? url : url.substring(index) return url.startsWith('/') ? url : '/' + url @@ -1478,6 +1487,9 @@ https://github.com/Tencent/APIJSON/issues }, getRequest: function (json, defaultValue, isRaw) { // JSON5 兜底,减少修改范围 , isSingle) { + if (JSONResponse.isString(json) != true) { + return json == null ? defaultValue : json + } var s = isRaw != true && isSingle ? this.switchQuote(json) : json; // this.toDoubleJSON(json, defaultValue); if (StringUtil.isEmpty(s, true)) { return defaultValue @@ -1661,7 +1673,7 @@ https://github.com/Tencent/APIJSON/issues isClickSelectInput = false; // vOption.focusout() - if (this.isChainShow) { + if (this.isChainShow && this.isTestCaseShow) { this.addCase2Chain(item.value) return } @@ -1942,7 +1954,7 @@ https://github.com/Tencent/APIJSON/issues break case 3: this.host = this.getBaseUrl() - this.showUrl(false, new String(vUrl.value).substring(this.host.length)) //没必要导致必须重新获取 Response,this.onChange(false) + this.showUrl(false, StringUtil.get(vUrl.value).substring(this.host.length)) //没必要导致必须重新获取 Response,this.onChange(false) break case 4: this.isHeaderShow = show @@ -2010,7 +2022,7 @@ https://github.com/Tencent/APIJSON/issues } else if (index == 3) { var host = StringUtil.get(this.host) - var branch = new String(vUrl.value) + var branch = StringUtil.get(vUrl.value) this.host = '' vUrl.value = host + branch //保证 showUrl 里拿到的 baseUrl = this.host (http://apijson.cn:8080/put /balance) this.setBaseUrl() //保证自动化测试等拿到的 baseUrl 是最新的 @@ -2273,20 +2285,20 @@ https://github.com/Tencent/APIJSON/issues // var accountId = this.getCurrentAccountId(); const cri = this.currentRemoteItem || {} const chain = cri.Chain || {} - const cgId = chain.groupId || 0 + const cId = chain.id || 0 this.request(true, REQUEST_TYPE_POST, REQUEST_TYPE_JSON, '/get', { 'Script:pre': preId != null ? undefined : { 'ahead': 1, // 'testAccountId': 0, - 'chainGroupId': cgId, + 'chainId': cId, 'documentId': docId, '@order': 'date-' }, 'Script:post': postId != null ? undefined : { 'ahead': 0, // 'testAccountId': 0, - 'chainGroupId': cgId, + 'chainId': cId, 'documentId': docId, '@order': 'date-' } @@ -2344,7 +2356,7 @@ https://github.com/Tencent/APIJSON/issues } // localforage.getItem(item.key || '', function (err, value) { - var branch = new String(item.url || '/get') + var branch = StringUtil.get(item.url || '/get') if (branch.startsWith('/') == false) { branch = '/' + branch } @@ -2645,6 +2657,7 @@ https://github.com/Tencent/APIJSON/issues const doc = cri.Document || {} const tr = cri.TestRecord || {} const cgId = chain.groupId || 0 + const cId = chain.id || 0 const did = isExportRandom && btnIndex == 1 ? null : doc.id if (isExportScript) { @@ -2660,6 +2673,7 @@ https://github.com/Tencent/APIJSON/issues 'simple': 1, 'ahead': this.isPreScript ? 1 : 0, 'chainGroupId': cgId, + 'chainId': cId, 'documentId': did == null || scriptType != 'case' ? 0 : did, 'testAccountId': scriptType != 'account' ? 0 : currentAccountId, 'name': extName, @@ -2869,6 +2883,7 @@ https://github.com/Tencent/APIJSON/issues 'Random': { toId: 0, chainGroupId: cgId, + chainId: cId, documentId: did, count: App.requestCount, name: App.exTxt.name, @@ -2877,6 +2892,7 @@ https://github.com/Tencent/APIJSON/issues 'TestRecord': { 'host': StringUtil.isEmpty(baseUrl, true) ? null : baseUrl, 'chainGroupId': cgId, + 'chainId': cId, 'response': rawRspStr, 'standard': isML ? JSON.stringify(stddObj) : null }, @@ -4446,12 +4462,12 @@ https://github.com/Tencent/APIJSON/issues 'Random': { // 'id@': '/Chain/randomId', 'toId': 0, - 'chainGroupId@': '/Chain/groupId', + 'chainId@': '/Chain/id', 'documentId@': '/Document/id', 'userId': userId }, 'TestRecord': { - 'chainGroupId@': '/Chain/groupId', + 'chainId@': '/Chain/id', 'documentId@': '/Document/id', 'userId': userId, 'host': StringUtil.isEmpty(baseUrl, true) ? null : baseUrl, @@ -4466,14 +4482,14 @@ https://github.com/Tencent/APIJSON/issues 'Script:pre': { 'ahead': 1, // 'testAccountId': 0, - 'chainGroupId@': '/Chain/groupId', + 'chainId@': '/Chain/id', 'documentId@': '/Document/id', '@order': 'date-' }, 'Script:post': { 'ahead': 0, // 'testAccountId': 0, - 'chainGroupId@': '/Chain/groupId', + 'chainId@': '/Chain/id', 'documentId@': '/Document/id', '@order': 'date-' } @@ -4521,8 +4537,8 @@ https://github.com/Tencent/APIJSON/issues if (item.Chain != null) { App.chainPaths.push(item.Chain) } - App.remotes = App.testCases = item['[]'] || [] + App.isTestCaseShow = true // App.showTestCase(true, false, null) }) }, @@ -4850,13 +4866,13 @@ https://github.com/Tencent/APIJSON/issues 'Random': isChainShow ? { 'id@': '/Chain/randomId', 'toId': 0, // isChainShow ? 0 : null, -// 'chainGroupId@': isChainShow ? '/Chain/groupId' : null, +// 'chainId@': isChainShow ? '/Chain/id' : null, // 'documentId@': isChainShow ? null : '/Document/documentId', 'userId': userId }: null, 'TestRecord': { - 'chainGroupId@': isChainShow ? '/Chain/groupId' : null, - 'chainGroupId': isChainShow ? null : 0, + 'chainId@': isChainShow ? '/Chain/id' : null, + 'chainId': isChainShow ? null : 0, 'documentId@': '/Document/id', 'userId': userId, 'host': StringUtil.isEmpty(baseUrl, true) ? null : baseUrl, @@ -4871,16 +4887,16 @@ https://github.com/Tencent/APIJSON/issues 'Script:pre': { 'ahead': 1, // 'testAccountId': 0, - 'chainGroupId@': isChainShow ? '/Chain/groupId' : null, - 'chainGroupId': isChainShow ? null : 0, + 'chainId@': isChainShow ? '/Chain/id' : null, + 'chainId': isChainShow ? null : 0, 'documentId@': '/Document/id', '@order': 'date-' }, 'Script:post': { 'ahead': 0, // 'testAccountId': 0, - 'chainGroupId@': isChainShow ? '/Chain/groupId' : null, - 'chainGroupId': isChainShow ? null : 0, + 'chainId@': isChainShow ? '/Chain/id' : null, + 'chainId': isChainShow ? null : 0, 'documentId@': '/Document/id', '@order': 'date-' } @@ -5106,7 +5122,7 @@ https://github.com/Tencent/APIJSON/issues baseUrl = this.getBaseUrl(vUrl.value, true) const cri = this.currentRemoteItem || {} const chain = cri.Chain || {} - const cgId = chain.groupId || 0 + const cId = chain.id || 0 var req = { '[]': { @@ -5114,7 +5130,7 @@ https://github.com/Tencent/APIJSON/issues 'page': (isSub ? this.randomSubPage : this.randomPage) || 0, 'Random': { 'toId': isSub ? item.id : 0, - 'chainGroupId': cgId, + 'chainId': cId, 'documentId': isSub ? null : item.id, '@order': "date-", 'name$': search @@ -5130,7 +5146,7 @@ https://github.com/Tencent/APIJSON/issues 'page': this.randomSubPage || 0, 'Random': { 'toId@': '[]/Random/id', - 'chainGroupId': cgId, + 'chainId': cId, 'documentId': item.id, '@order': "date-", 'name$': subSearch @@ -6036,7 +6052,7 @@ https://github.com/Tencent/APIJSON/issues return; } - inputted = new String(vInput.value); + inputted = StringUtil.get(vInput.value); vComment.value = ''; vWarning.value = ''; // vUrlComment.value = ''; @@ -6281,7 +6297,7 @@ https://github.com/Tencent/APIJSON/issues removeComment: function (json) { var reg = /("([^\\\"]*(\\.)?)*")|('([^\\\']*(\\.)?)*')|(\/{2,}.*?(\r|\n))|(\/\*(\n|.)*?\*\/)/g // 正则表达式 try { - return new String(json).replace(reg, function(word) { // 去除注释后的文本 + return StringUtil.get(json).replace(reg, function(word) { // 去除注释后的文本 return /^\/{2,}/.test(word) || /^\/\*/.test(word) ? "" : word; }) } catch (e) { @@ -8659,7 +8675,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea } if (typeof s != 'string') { - return new String(s) + return StringUtil.get(s) } //无效 @@ -9756,28 +9772,34 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea } else { //随机函数 if (fun == PRE_REQ) { - toEval = 'get4Path(((ctx || {}).pre || {}).req, ' + (value == ')' ? JSON.stringify(path) : '') + value.substring(start + 1); + toEval = 'get4Path(((ctx || {}).pre || {}).req, ' + (value == 'PRE_REQ()' ? JSON.stringify(path) : '') + value.substring(start + 1); } else if (fun == PRE_ARG) { - toEval = 'get4Path(((ctx || {}).pre || {}).arg, ' + (value == ')' ? JSON.stringify(path) : '') + value.substring(start + 1); + toEval = 'get4Path(((ctx || {}).pre || {}).arg, ' + (value == 'PRE_ARG()' ? JSON.stringify(path) : '') + value.substring(start + 1); } else if (fun == PRE_RES) { - toEval = 'get4Path(((ctx || {}).pre || {}).res, ' + (value == ')' ? JSON.stringify(path) : '') + value.substring(start + 1); + toEval = 'get4Path(((ctx || {}).pre || {}).res, ' + (value == 'PRE_RES()' ? JSON.stringify(path) : '') + value.substring(start + 1); } else if (fun == PRE_DATA) { - toEval = 'get4Path(((ctx || {}).pre || {}).data, ' + (value == ')' ? JSON.stringify(path) : '') + value.substring(start + 1); + toEval = 'get4Path(((ctx || {}).pre || {}).data, ' + (value == 'PRE_DATA()' ? JSON.stringify(path) : '') + value.substring(start + 1); + } + else if (fun == CTX_GET) { + toEval = 'get4Path(((ctx || {}).pre || {}).ctx, ' + (value == 'CTX_GET()' ? JSON.stringify(path) : '') + value.substring(start + 1); } - else if (fun == PRE_EXT) { - toEval = 'get4Path(((ctx || {}).pre || {}).ext, ' + (value == ')' ? JSON.stringify(path) : '') + value.substring(start + 1); + else if (fun == CTX_PUT) { + toEval = 'put4Path(((ctx || {}).cur || {}).ctx, ' + (value == 'CTX_PUT()' ? JSON.stringify(path) : '') + value.substring(start + 1); } else if (fun == CUR_REQ) { - toEval = 'get4Path(((ctx || {}).cur || {}).req, ' + (value == ')' ? JSON.stringify(path) : '') + value.substring(start + 1); + toEval = 'get4Path(((ctx || {}).cur || {}).req, ' + (value == 'CUR_REQ()' ? JSON.stringify(path) : '') + value.substring(start + 1); } else if (fun == CUR_ARG) { - toEval = 'get4Path(((ctx || {}).cur || {}).arg, ' + (value == ')' ? JSON.stringify(path) : '') + value.substring(start + 1); + toEval = 'get4Path(((ctx || {}).cur || {}).arg, ' + (value == 'CUR_ARG()' ? JSON.stringify(path) : '') + value.substring(start + 1); + } + else if (fun == CUR_RES) { + toEval = 'get4Path(((ctx || {}).cur || {}).res, ' + (value == 'CUR_RES()' ? JSON.stringify(path) : '') + value.substring(start + 1); } - else if (fun == CUR_PUT) { - toEval = 'put4Path(((ctx || {}).cur || {}).ctx, ' + (value == ')' ? JSON.stringify(path) : '') + value.substring(start + 1); + else if (fun == CUR_DATA) { + toEval = 'get4Path(((ctx || {}).cur || {}).data, ' + (value == 'CUR_DATA()' ? JSON.stringify(path) : '') + value.substring(start + 1); } else { fun = funWithOrder; //还原,其它函数不支持 升降序和跨步! @@ -9980,7 +10002,11 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea // return // } - const list = (isRandom ? this.randoms : (this.isChainShow ? this.chainGroups : this.remotes)) || [] + const list = (isRandom ? this.randoms : (this.isChainShow ? ( + this.isChainGroupShow() ? this.chainGroups : [this.chainGroups[0]] + ) : this.remotes) + ) || [] + var allCount = list.length App.doneCount = 0 App.deepAllCount = 0 @@ -11029,6 +11055,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea const cri = this.currentRemoteItem || {} const chain = cri.Chain || {} const cgId = chain.groupId || 0 + const cId = chain.id || 0 //TODO 先检查是否有重复名称的!让用户确认! // if (isML != true) { @@ -11038,6 +11065,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea toId: random.toId, userId: userId, chainGroupId: cgId, + chainId: cId, documentId: random.documentId, name: random.name, count: random.count, @@ -11050,6 +11078,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea userId: userId, testAccountId: this.getCurrentAccountId(), chainGroupId: cgId, + chainId: cId, duration: item.duration, minDuration: minDuration, maxDuration: maxDuration, @@ -11057,6 +11086,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea }) : { userId: userId, chainGroupId: cgId, + chainId: cId, documentId: isNewRandom ? null : (isRandom ? random.documentId : document.id), randomId: isRandom && ! isNewRandom ? random.id : null, reportId: this.reportId, @@ -11629,25 +11659,45 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea if (App.isChainShow) { App.options = [ { - name: "PRE_RES('[]/0/User/id')", + name: "PRE_DATA('[]/0/User/id')", + type: stringType, + comment: "从上个请求的返回结果中取值 function(path:String?, defaultVal:Any?, msg:String?)" + }, { + name: "PRE_ARG('[]/page')", type: stringType, - comment: "从上个请求的返回结果中取值 function(path:String)" + comment: "从上个请求的参数中取值 function(path:String?, defaultVal:Any?, msg:String?)" }, { - name: "PRE_REQ('[]/page')", + name: "CTX_GET('userId')", type: stringType, - comment: "从上个请求的参数中取值 function(path:String)" + comment: "在上下文存放键值对 function(key:String?, defaultVal:Any?, msg:String?)" }, { - name: "PRE_EXT('isMale')", + name: "CTX_PUT('userId', 'User/id', 'CUR_DATA')", type: stringType, - comment: "从上个请求的扩展对象中取值 function(path:String)" + comment: "在上下文存放键值对 function(key:String, val:Any, from:String?, msg:String?)" + }, { + name: "PRE_RES('[]/page')", + type: stringType, + comment: "从上个请求的 Response 对象中取值 function(path:String, defaultVal:Any?, msg:String?)" + }, { + name: "PRE_REQ('isMale')", + type: stringType, + comment: "从上个请求 Request 对象中取值 function(path:String, defaultVal:Any?, msg:String?)" + }, { + name: "CUR_ARG('[]/count')", + type: stringType, + comment: "从当前请求的参数中取值 function(path:String, defaultVal:Any?, msg:String?)" }, { name: "CUR_REQ('[]/count')", type: stringType, - comment: "从当前请求的参数中取值 function(path:String)" + comment: "从当前请求的 Request 对象中取值 function(path:String, defaultVal:Any?, msg:String?)" + }, { + name: "CUR_DATA('[]/count')", + type: stringType, + comment: "从当前请求的返回结果中取值 function(path:String?, defaultVal:Any?, msg:String?)" }, { - name: "CUR_PUT('isMale', true)", + name: "CUR_RES('[]/count')", type: stringType, - comment: "在当前请求的扩展对象中存放键值对 function(path:String, val:Any)" + comment: "从当前请求的 Response 对象中取值 function(path:String, defaultVal:Any?, msg:String?)" } ].concat(App.options || []) } @@ -11882,7 +11932,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea var isPage = key == 'page'; for (var i = 0; i < 100; i++) { App.options.push({ - name: new String(i), // 直接用数字导致重复生成 JSON + name: StringUtil.get(i), // 直接用数字导致重复生成 JSON type: intType, comment: isPage ? '分页页码' : '每页数量' }); From d67a85bc77349f944ecc798c35aebbbdda84bc2c Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sun, 12 May 2024 12:41:01 +0800 Subject: [PATCH 802/818] =?UTF-8?q?=E5=9C=BA=E6=99=AF=E4=B8=B2=E8=81=94?= =?UTF-8?q?=EF=BC=9A=E8=A7=A3=E5=86=B3=E4=B8=8A=E4=B8=8B=E6=96=87=E4=BC=A0?= =?UTF-8?q?=E5=8F=82=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- js/main.js | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/js/main.js b/js/main.js index db0171a..1d0aa83 100755 --- a/js/main.js +++ b/js/main.js @@ -618,7 +618,7 @@ https://github.com/Tencent/APIJSON/issues var PRE_ARG = 'PRE_ARG' // PRE_ARG('[]/page') var PRE_RES = 'PRE_RES' // PRE_RES('[]/0/User/id') var PRE_DATA = 'PRE_DATA' // PRE_DATA('[]/0/User/id') - var CTX_EXT = 'CTX_EXT' // CTX_EXT('key') + var CTX_GET = 'CTX_GET' // CTX_GET('key') var CUR_REQ = 'CUR_REQ' // CUR_REQ('User/id') var CUR_ARG = 'CUR_ARG' // CUR_REQ('User/id') var CUR_RES = 'CUR_RES' // CUR_RES('[]/0/User/id') @@ -9784,10 +9784,14 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea toEval = 'get4Path(((ctx || {}).pre || {}).data, ' + (value == 'PRE_DATA()' ? JSON.stringify(path) : '') + value.substring(start + 1); } else if (fun == CTX_GET) { - toEval = 'get4Path(((ctx || {}).pre || {}).ctx, ' + (value == 'CTX_GET()' ? JSON.stringify(path) : '') + value.substring(start + 1); + toEval = 'get4Path((ctx || {}).ctx, ' + (value == 'CTX_GET()' ? JSON.stringify(path) : '') + value.substring(start + 1); } else if (fun == CTX_PUT) { - toEval = 'put4Path(((ctx || {}).cur || {}).ctx, ' + (value == 'CTX_PUT()' ? JSON.stringify(path) : '') + value.substring(start + 1); + var as = StringUtil.split(value.substring(start + 1, end), ', ') + if (as.length >= 2) { + as[1] = 'get4Path((ctx || {}).ctx, ' + StringUtil.trim(as[1]) + ')' + } + toEval = 'put4Path((ctx || {}).ctx, ' + (value == 'CTX_PUT()' ? JSON.stringify(path) : '') + as.join(', ') + value.substring(end); } else if (fun == CUR_REQ) { toEval = 'get4Path(((ctx || {}).cur || {}).req, ' + (value == 'CUR_REQ()' ? JSON.stringify(path) : '') + value.substring(start + 1); @@ -10105,7 +10109,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea cur.res = res cur.data = res.data App.startTestChain(list, allCount, index + 1, list[index + 1], item, ctx, isRandom, accountIndex, isCross, callback) - }) + }, ctx) return true // }) }, @@ -10138,7 +10142,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea } }, - startTestSingle: function (list, allCount, index, item, isRandom, accountIndex, isCross, callback, singleCallback) { + startTestSingle: function (list, allCount, index, item, isRandom, accountIndex, isCross, callback, singleCallback, ctx) { try { const isMLEnabled = this.isMLEnabled const standardKey = isMLEnabled != true ? 'response' : 'standard' @@ -10192,7 +10196,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea const curEnvUrl = baseUrl + document.url const cur = item const pre = list[index - 1] || {} // item.pre = item.pre || list[index - 1] || {} - const ctx = item.ctx = item.ctx || {} +// const ctx = item.ctx = item.ctx || {} var random = item.Random || {} this.parseRandom(req, random.config, random.id, true, false, false, function(randomName, constConfig, constJson) { From 819180ce67f17b9df14ecbc8caddd19fe3d8aead Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Mon, 20 May 2024 23:51:57 +0800 Subject: [PATCH 803/818] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=94=AF=E6=8C=81=20?= =?UTF-8?q?App.wait=20=E5=BB=B6=E8=BF=9F=E8=AF=B7=E6=B1=82=E5=92=8C=20App.?= =?UTF-8?q?timeout=20=E8=AF=B7=E6=B1=82=E8=B6=85=E6=97=B6=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=EF=BC=9B=E8=A7=A3=E5=86=B3=20bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apijson/JSONResponse.js | 2 +- js/main.js | 15 +++++++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/apijson/JSONResponse.js b/apijson/JSONResponse.js index 174f45f..0af3738 100644 --- a/apijson/JSONResponse.js +++ b/apijson/JSONResponse.js @@ -1613,7 +1613,7 @@ var JSONResponse = { try { var n = Number.parseInt(k); if (Number.isSafeInteger(n)) { - k = n > 0 ? n : n + tgt.length; + k = n >= 0 ? n : n + tgt.length; } } catch (e) { } diff --git a/js/main.js b/js/main.js index 1d0aa83..51c2edc 100755 --- a/js/main.js +++ b/js/main.js @@ -1081,6 +1081,8 @@ https://github.com/Tencent/APIJSON/issues scriptType: 'case', scriptBelongId: 0, scripts: newDefaultScript(), + wait: 0, // 每个请求前的等待延迟 + timeout: null, // 每个请求的超时时间 loadingCount: 0, isPreScript: true, isRandomTest: false, @@ -6378,7 +6380,7 @@ https://github.com/Tencent/APIJSON/issues var projectHosts = this.projectHosts || [] var projectHost = this.projectHost || {} var find = false - for (var j = 0; j < projects.length; j ++) { + for (var j = 0; j < projectHosts.length; j ++) { var pjt = projectHosts[j] if (pjt == null || StringUtil.isEmpty(pjt.host, true)) { continue @@ -6393,7 +6395,7 @@ https://github.com/Tencent/APIJSON/issues if (find != true) { projectHosts.push({host: bu, project: projectHost.project}) this.projectHosts = projectHosts - this.saveCache('', 'projectHosts', projects) + this.saveCache('', 'projectHosts', projectHosts) } } @@ -6425,7 +6427,7 @@ https://github.com/Tencent/APIJSON/issues }, //请求 - request: function (isAdminOperation, method, type, url, req, header, callback, caseScript_, accountScript_, globalScript_, ignorePreScript) { + request: function (isAdminOperation, method, type, url, req, header, callback, caseScript_, accountScript_, globalScript_, ignorePreScript, timeout_, wait_) { this.loadingCount ++ const isEnvCompare = this.isEnvCompareEnabled @@ -6434,6 +6436,8 @@ https://github.com/Tencent/APIJSON/issues const globalScript = (isAdminOperation ? null : (globalScript_ != null ? globalScript_ : (scripts.global || {})[0])) || {} const accountScript = (isAdminOperation ? null : (accountScript_ != null ? accountScript_ : (scripts.account || {})[this.getCurrentAccountId() || 0])) || {} const caseScript = (isAdminOperation ? null : caseScript_) || {} + const timeout = timeout_ != null ? timeout_ : this.timeout + const wait = wait_ != null ? wait_ : (this.wait || 0) var evalPostScript = function () {} @@ -6486,6 +6490,7 @@ https://github.com/Tencent/APIJSON/issues headers: header, //Accept-Encoding(HTTP Header 大小写不敏感,SpringBoot 接收后自动转小写)可能导致 Response 乱码 withCredentials: true, //Cookie 必须要 type == REQUEST_TYPE_JSON // crossDomain: true + timeout: timeout }) .then(function (res) { App.currentHttpResponse = res @@ -6775,7 +6780,9 @@ https://github.com/Tencent/APIJSON/issues return } - sendRequest(isAdminOperation, method, type, url, req, header, callback) + setTimeout(function () { + sendRequest(isAdminOperation, method, type, url, req, header, callback) + }, wait < 0 ? 0 : wait) }, From 82b5a5e041da03908b756da275fc7e9c07cffd07 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Tue, 21 May 2024 00:18:34 +0800 Subject: [PATCH 804/818] =?UTF-8?q?=E6=96=B0=E5=A2=9E=20App.retry=20?= =?UTF-8?q?=E8=AE=BE=E7=BD=AE=E9=87=8D=E8=AF=95=E6=AC=A1=E6=95=B0=EF=BC=8C?= =?UTF-8?q?=E5=8F=AF=E5=9C=A8=20HTTP=20Status=20Code=20=3D=3D=20200=20?= =?UTF-8?q?=E7=9A=84=E8=AF=B7=E6=B1=82=E8=BF=94=E5=9B=9E=E5=90=8E=E9=80=9A?= =?UTF-8?q?=E8=BF=87=E8=84=9A=E6=9C=AC=E6=8A=9B=E5=BC=82=E5=B8=B8=E6=9D=A5?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E4=B8=9A=E5=8A=A1=E8=87=AA=E5=AE=9A=E4=B9=89?= =?UTF-8?q?=E5=BC=82=E5=B8=B8=E9=87=8D=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- js/main.js | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/js/main.js b/js/main.js index 51c2edc..2457404 100755 --- a/js/main.js +++ b/js/main.js @@ -1081,6 +1081,7 @@ https://github.com/Tencent/APIJSON/issues scriptType: 'case', scriptBelongId: 0, scripts: newDefaultScript(), + retry: 0, // 每个请求前的等待延迟 wait: 0, // 每个请求前的等待延迟 timeout: null, // 每个请求的超时时间 loadingCount: 0, @@ -6427,7 +6428,7 @@ https://github.com/Tencent/APIJSON/issues }, //请求 - request: function (isAdminOperation, method, type, url, req, header, callback, caseScript_, accountScript_, globalScript_, ignorePreScript, timeout_, wait_) { + request: function (isAdminOperation, method, type, url, req, header, callback, caseScript_, accountScript_, globalScript_, ignorePreScript, timeout_, wait_, retry_) { this.loadingCount ++ const isEnvCompare = this.isEnvCompareEnabled @@ -6438,6 +6439,24 @@ https://github.com/Tencent/APIJSON/issues const caseScript = (isAdminOperation ? null : caseScript_) || {} const timeout = timeout_ != null ? timeout_ : this.timeout const wait = wait_ != null ? wait_ : (this.wait || 0) + var retry = retry_ != null ? retry_ : (this.retry || 0) + var retryReq = function () { + if (retry == null || retry <= 0) { + return false + } + + retry -- + try { + sendRequest(isAdminOperation, method, type, url, req, header, callback) + } catch (e) { + App.log('request retryReq retry = ' + retry + ' >> try {\n' + + ' sendRequest(isAdminOperation, method, type, url, req, header, callback)\n' + + ' } catch (e) = ' + e.message) + return retryReq() + } + + return true + } var evalPostScript = function () {} @@ -6558,6 +6577,10 @@ https://github.com/Tencent/APIJSON/issues App.onResponse(url, res, null) }) .catch(function (err) { + if (retryReq()) { + return; + } + var errObj = err instanceof Array == false && err instanceof Object ? err : {} var res = {status: errObj.status || (errObj.response || {}).status, request: {url: url, headers: header, data: req}, data: (errObj.response || {}).data} App.currentHttpResponse = res From 7f6c5d5bb2b1bee429d4fcadfe30fa95a338ccef Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Tue, 21 May 2024 00:33:27 +0800 Subject: [PATCH 805/818] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E6=9C=89=E6=97=B6?= =?UTF-8?q?=E9=87=8D=E8=AF=95=E8=BF=87=E7=A8=8B=E6=8A=A5=E9=94=99=E6=B2=A1?= =?UTF-8?q?=E6=9C=89=20callback?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- js/main.js | 222 +++++++++++++++++++++++++++-------------------------- 1 file changed, 114 insertions(+), 108 deletions(-) diff --git a/js/main.js b/js/main.js index 2457404..784f07e 100755 --- a/js/main.js +++ b/js/main.js @@ -6440,19 +6440,126 @@ https://github.com/Tencent/APIJSON/issues const timeout = timeout_ != null ? timeout_ : this.timeout const wait = wait_ != null ? wait_ : (this.wait || 0) var retry = retry_ != null ? retry_ : (this.retry || 0) - var retryReq = function () { - if (retry == null || retry <= 0) { + + const onHttpResponse = function (res) { + App.currentHttpResponse = res + clearTimeout(errHandler) + var postEvalResult = evalPostScript(url, res, null) + if (postEvalResult == BREAK_ALL) { + return + } + + App.loadingCount -- + res = res || {} + + if (isDelegate) { + var hs = res.headers || {} + var delegateId = hs['Apijson-Delegate-Id'] || hs['apijson-delegate-id'] + + if (delegateId != null) { + if (isEnvCompare) { + if (delegateId != App.otherEnvDelegateId) { + App.otherEnvDelegateId = delegateId + App.saveCache(App.server, 'otherEnvDelegateId', delegateId) + } + } else { + if (delegateId != App.delegateId) { + App.delegateId = delegateId + App.saveCache(App.server, 'delegateId', delegateId) + } + } + } + } + + //any one of then callback throw error will cause it calls then(null) + // if ((res.config || {}).method == 'options') { + // return + // } + if (DEBUG) { + log('send >> success:\n' + JSON.stringify(res.data, null, ' ')) + } + + //未登录,清空缓存 + if (res.data != null && res.data.code == 407) { + // alert('request res.data != null && res.data.code == 407 >> isAdminOperation = ' + isAdminOperation) + if (isAdminOperation) { + // alert('request App.User = {} App.server = ' + App.server) + + App.clearUser() + } + else { + // alert('request App.accounts[App.currentAccountIndex].isLoggedIn = false ') + var account = App.accounts[App.currentAccountIndex] + if (account != null) { + account.isLoggedIn = false + } + } + } + + if (postEvalResult == BREAK_LAST) { + return + } + + if (callback != null) { + callback(url, res, null) + return + } + App.onResponse(url, res, null) + } + + const onHttpCatch = function (err) { + if (retry != null && retry > 0 && retryReq(err)) { + return; + } + + var errObj = err instanceof Array == false && err instanceof Object ? err : {} + var res = {status: errObj.status || (errObj.response || {}).status, request: {url: url, headers: header, data: req}, data: (errObj.response || {}).data} + App.currentHttpResponse = res + + var postEvalResult = evalPostScript(url, res, err) + if (postEvalResult == BREAK_ALL) { + return + } + + App.loadingCount -- + + log('send >> error:\n' + err) + if (isAdminOperation) { + App.delegateId = null + } + + if (postEvalResult == BREAK_LAST) { + return + } + + if (callback != null) { + callback(url, res, err) + return + } + + if (typeof App.autoTestCallback == 'function') { + App.autoTestCallback('Error when testing: ' + err + '.\nurl: ' + url + ' \nrequest: \n' + JSON.stringify(req, null, ' '), err) + } + + App.onResponse(url, {request: {url: url, headers: header, data: req}}, err) + } + + var retryReq = function (err) { + if (retry == null || retry < 0) { + onHttpCatch(err) return false } retry -- try { - sendRequest(isAdminOperation, method, type, url, req, header, callback) + setTimeout(function () { + sendRequest(isAdminOperation, method, type, url, req, header, callback) + }, wait < 0 ? 0 : wait) } catch (e) { App.log('request retryReq retry = ' + retry + ' >> try {\n' + ' sendRequest(isAdminOperation, method, type, url, req, header, callback)\n' + ' } catch (e) = ' + e.message) - return retryReq() + return retryReq(err) } return true @@ -6511,107 +6618,8 @@ https://github.com/Tencent/APIJSON/issues // crossDomain: true timeout: timeout }) - .then(function (res) { - App.currentHttpResponse = res - clearTimeout(errHandler) - var postEvalResult = evalPostScript(url, res, null) - if (postEvalResult == BREAK_ALL) { - return - } - - App.loadingCount -- - res = res || {} - - if (isDelegate) { - var hs = res.headers || {} - var delegateId = hs['Apijson-Delegate-Id'] || hs['apijson-delegate-id'] - - if (delegateId != null) { - if (isEnvCompare) { - if (delegateId != App.otherEnvDelegateId) { - App.otherEnvDelegateId = delegateId - App.saveCache(App.server, 'otherEnvDelegateId', delegateId) - } - } else { - if (delegateId != App.delegateId) { - App.delegateId = delegateId - App.saveCache(App.server, 'delegateId', delegateId) - } - } - } - } - - //any one of then callback throw error will cause it calls then(null) - // if ((res.config || {}).method == 'options') { - // return - // } - if (DEBUG) { - log('send >> success:\n' + JSON.stringify(res.data, null, ' ')) - } - - //未登录,清空缓存 - if (res.data != null && res.data.code == 407) { - // alert('request res.data != null && res.data.code == 407 >> isAdminOperation = ' + isAdminOperation) - if (isAdminOperation) { - // alert('request App.User = {} App.server = ' + App.server) - - App.clearUser() - } - else { - // alert('request App.accounts[App.currentAccountIndex].isLoggedIn = false ') - var account = App.accounts[App.currentAccountIndex] - if (account != null) { - account.isLoggedIn = false - } - } - } - - if (postEvalResult == BREAK_LAST) { - return - } - - if (callback != null) { - callback(url, res, null) - return - } - App.onResponse(url, res, null) - }) - .catch(function (err) { - if (retryReq()) { - return; - } - - var errObj = err instanceof Array == false && err instanceof Object ? err : {} - var res = {status: errObj.status || (errObj.response || {}).status, request: {url: url, headers: header, data: req}, data: (errObj.response || {}).data} - App.currentHttpResponse = res - - var postEvalResult = evalPostScript(url, res, err) - if (postEvalResult == BREAK_ALL) { - return - } - - App.loadingCount -- - - log('send >> error:\n' + err) - if (isAdminOperation) { - App.delegateId = null - } - - if (postEvalResult == BREAK_LAST) { - return - } - - if (callback != null) { - callback(url, res, err) - return - } - - if (typeof App.autoTestCallback == 'function') { - App.autoTestCallback('Error when testing: ' + err + '.\nurl: ' + url + ' \nrequest: \n' + JSON.stringify(req, null, ' '), err) - } - - App.onResponse(url, {request: {url: url, headers: header, data: req}}, err) - }) + .then(onHttpResponse) + .catch(onHttpCatch) } var evalScript = isAdminOperation || caseScript_ == null ? function () {} : function (isPre, code, res, err) { @@ -6803,9 +6811,7 @@ https://github.com/Tencent/APIJSON/issues return } - setTimeout(function () { - sendRequest(isAdminOperation, method, type, url, req, header, callback) - }, wait < 0 ? 0 : wait) + retryReq() }, From 9090c485200860368f2be7e850015b765201c2bb Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Mon, 10 Jun 2024 22:21:05 +0800 Subject: [PATCH 806/818] =?UTF-8?q?=E8=87=AA=E5=8A=A8=E7=94=9F=E6=88=90?= =?UTF-8?q?=E6=B3=A8=E9=87=8A=EF=BC=9A=E6=96=B0=E5=A2=9E=E5=B7=A6=E4=BE=A7?= =?UTF-8?q?=20JSON=20=E9=94=AE=E5=80=BC=E5=AF=B9=20User:{}=20=E5=90=8E?= =?UTF-8?q?=E9=9D=A2=20//=20apijson=5Fuser=3F,=20=E8=A1=A8=E7=A4=BA?= =?UTF-8?q?=E5=AE=9E=E9=99=85=E6=95=B0=E6=8D=AE=E5=BA=93=E8=A1=A8=E5=90=8D?= =?UTF-8?q?=E4=B8=94=E5=8F=AF=E7=A9=BA=EF=BC=8Cgender:=200=20=E5=90=8E?= =?UTF-8?q?=E9=9D=A2=20//=20sex!,=20=E8=A1=A8=E7=A4=BA=E5=AE=9E=E9=99=85?= =?UTF-8?q?=E5=AD=97=E6=AE=B5=E5=90=8D=E4=B8=94=E9=9D=9E=E7=A9=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apijson/CodeUtil.js | 162 +++++++++++++++++++++++----------------- apijson/JSONResponse.js | 24 +++++- js/main.js | 9 ++- 3 files changed, 119 insertions(+), 76 deletions(-) diff --git a/apijson/CodeUtil.js b/apijson/CodeUtil.js index e3ae612..078d2e6 100644 --- a/apijson/CodeUtil.js +++ b/apijson/CodeUtil.js @@ -2554,8 +2554,8 @@ res_data = rep.json() } } - var notnull = target.notnull; - log('parsePythonResponseByStandard notnull = target.notnull = ' + notnull + ' >>'); + var notNull = target.notNull; + log('parsePythonResponseByStandard notNull = target.notNull = ' + notNull + ' >>'); var funName = 'is_' + (isRoot ? '' : name + '_') + varName; var genFunDef = isSmart && funNames.indexOf(funName) < 0; @@ -2572,9 +2572,9 @@ res_data = rep.json() + '\n if not is_' + type + '(' + varName + ', strict):' + '\n return false\n' } - s += prefix + funName + '(' + varName + ', ' + notnull + ')'; + s += prefix + funName + '(' + varName + ', ' + notNull + ')'; } else { - if (notnull) { + if (notNull) { s += prefix + 'not_none(' + varName + ')'; } s += prefix + 'is_' + type + '(' + varName + ')'; @@ -2682,7 +2682,7 @@ res_data = rep.json() if (typeof format == 'string' && FORMAT_PRIORITIES[format] != null) { var verifier = FORMAT_VERIFIERS[format]; if (typeof verifier == 'function') { - fas = prefix2 + verifier.name + '(' + varName + ', ' + notnull + ')'; + fas = prefix2 + verifier.name + '(' + varName + ', ' + notNull + ')'; } } else if (format instanceof Array == false && format instanceof Object) { @@ -5254,8 +5254,8 @@ res_data = rep.json() return StringUtil.firstCase(StringUtil.noBlank(columnName), false); }, /**获取model方法名 - * @param prefix @NotNull 前缀,一般是get,set等 - * @param field @NotNull + * @param prefix @notNull 前缀,一般是get,set等 + * @param field @notNull * @return {*} */ getMethodName: function(prefix, field) { @@ -6320,11 +6320,11 @@ res_data = rep.json() } var typeOfValue = CodeUtil.getType4Request(value); - var valuesIsNotString = typeOfValue != 'string'; - var valuesIsNotInteger = typeOfValue != 'integer'; - // var valuesIsNotNumber = valuesIsNotInteger && typeOfValue != 'number'; - var valuesIsNotBoolean = typeOfValue != 'boolean'; - var isValueNotEmpty = valuesIsNotString ? (typeOfValue != 'array' ? value != null : value.length > 0) : StringUtil.isNotEmpty(value, true); + var isValueNotString = typeOfValue != 'string'; + var isValueNotInteger = typeOfValue != 'integer'; + // var isValueNotNumber = isValueNotInteger && typeOfValue != 'number'; + var isValueNotBoolean = typeOfValue != 'boolean'; + var isValueNotEmpty = isValueNotString ? (typeOfValue != 'array' ? value != null : value.length > 0) : StringUtil.isNotEmpty(value, true); var extraComment = ''; if (isAPIJSONRouter) { @@ -6412,7 +6412,7 @@ res_data = rep.json() return ' ! 远程函数只能用于 GET,HEAD 请求!!'; } - if (value != null && valuesIsNotString) { + if (value != null && isValueNotString) { return ' ! 远程函数 value 必须是 String 类型!'; } @@ -6566,9 +6566,9 @@ res_data = rep.json() if (isRestful != true && (isInSubquery || JSONObject.isArrayKey(name))) { switch (key) { case 'count': - return value != null && valuesIsNotInteger ? ' ! value必须是Integer类型!' : (isWarning ? '' : CodeUtil.getComment('每页数量' + (isValueNotEmpty ? '' : ',例如 5 10 20 等'), false, ' ')) + extraComment; + return value != null && isValueNotInteger ? ' ! value必须是Integer类型!' : (isWarning ? '' : CodeUtil.getComment('每页数量' + (isValueNotEmpty ? '' : ',例如 5 10 20 等'), false, ' ')) + extraComment; case 'page': - if (value != null && valuesIsNotInteger) { + if (value != null && isValueNotInteger) { return ' ! value必须是Integer类型!'; } return value != null && value < 0 ? ' ! 必须 >= 0 !' : (isWarning ? '' : CodeUtil.getComment('分页页码' + (isValueNotEmpty ? '' : ': 例如 0 1 2 ...'), false, ' ')) + extraComment; @@ -6576,7 +6576,7 @@ res_data = rep.json() var query = CodeUtil.QUERY_TYPES[value]; return StringUtil.isEmpty(query) ? ' ! value必须是[' + CodeUtil.QUERY_TYPE_KEYS.join() + ']中的一种!' : (isWarning ? '' : CodeUtil.getComment('查询内容:0-对象 1-总数和分页详情 2-数据、总数和分页详情', false, ' ')) + extraComment; case 'join': - if (valuesIsNotString) { + if (isValueNotString) { return ' ! value必须是String类型!'; } @@ -6628,12 +6628,12 @@ res_data = rep.json() if (isInSubquery) { switch (key) { case 'range': - if (valuesIsNotString) { + if (isValueNotString) { return ' ! value必须是String类型!'; } return CodeUtil.SUBQUERY_RANGES.indexOf(value) < 0 ? ' ! value必须是[' + CodeUtil.SUBQUERY_RANGES.join() + ']中的一种!' : (isWarning ? '' : CodeUtil.getComment('比较范围:ANY-任意 ALL-全部', false, ' ')) + extraComment; case 'from': - return valuesIsNotString ? ' ! value必须是String类型!' : (isWarning ? '' : CodeUtil.getComment('数据来源' + (isValueNotEmpty ? ',同一层级必须有 "' + value + '":{...}' : ',例如 "User",同一层级必须有 "User":{...}'), false, ' ')) + extraComment; + return isValueNotString ? ' ! value必须是String类型!' : (isWarning ? '' : CodeUtil.getComment('数据来源' + (isValueNotEmpty ? ',同一层级必须有 "' + value + '":{...}' : ',例如 "User",同一层级必须有 "User":{...}'), false, ' ')) + extraComment; } } break; @@ -6648,47 +6648,47 @@ res_data = rep.json() if (isRestful != true && JSONObject.isTableKey(objName)) { switch (key) { case '@column': - return valuesIsNotString ? ' ! value必须是String类型!' : (isWarning ? '' : CodeUtil.getComment( + return isValueNotString ? ' ! value必须是String类型!' : (isWarning ? '' : CodeUtil.getComment( '返回字段' + (isValueNotEmpty ? ',可传 字段(:别名)、SQL 函数(:别名,用分号 ; 隔开)、表达式,以及部分 SQL 关键词' : ':例如 "name" "toId:parentId" "id,userId;json_length(praiseUserIdList):praiseCount" 等'), false, ' ')) + extraComment; case '@from@': //value 类型为 Object 时 到不了这里,已在上方处理 - return valuesIsNotString && typeOfValue != 'object' ? ' ! value必须是String或Object类型!' : (isWarning ? '' : CodeUtil.getComment( + return isValueNotString && typeOfValue != 'object' ? ' ! value必须是String或Object类型!' : (isWarning ? '' : CodeUtil.getComment( '数据来源:引用赋值 子查询 "' + value + '@":{...} ', false, ' ')) + extraComment; case '@group': - return valuesIsNotString ? ' ! value必须是String类型!' : (isWarning ? '' : CodeUtil.getComment( + return isValueNotString ? ' ! value必须是String类型!' : (isWarning ? '' : CodeUtil.getComment( '分组方式' + (isValueNotEmpty ? '' : ',例如 "userId" "momentId,toId" 等'), false, ' ')) + extraComment; case '@having': - return valuesIsNotString ? ' ! value必须是String类型!' : (isWarning ? '' : CodeUtil.getComment( + return isValueNotString ? ' ! value必须是String类型!' : (isWarning ? '' : CodeUtil.getComment( '聚合函数' + (isValueNotEmpty ? ',可传 SQL 函数(用分号 ; 隔开)、表达式,以及部分 SQL 关键词' : ',例如 "max(id)>100" "length(phone)>0;sum(balance)<=10000" 等'), false, ' ')) + extraComment; case '@order': - return valuesIsNotString ? ' ! value必须是String类型!' : (isWarning ? '' : CodeUtil.getComment( + return isValueNotString ? ' ! value必须是String类型!' : (isWarning ? '' : CodeUtil.getComment( '排序方式:+升序,-降序' + (isValueNotEmpty ? '' : ',例如 "date-" "name+,id-" 等'), false, ' ')) + extraComment; case '@combine': //TODO 解析 value 并直接给出条件组合结果 - return valuesIsNotString ? ' ! value必须是String类型!' : (isWarning ? '' : CodeUtil.getComment( + return isValueNotString ? ' ! value必须是String类型!' : (isWarning ? '' : CodeUtil.getComment( '条件组合' + (isValueNotEmpty ? ',| 可省略。合并同类,外层按照 & | ! 顺序,内层按传参顺序组合成 (key0 & key1 & key6 & 其它key) & (key2 | key3 | key7) & !(key4 | key5)' : ',例如 "name$,tag$" "!userId<,!toId" 等'), false, ' ')) + extraComment; case '@raw': - return valuesIsNotString ? ' ! value必须是String类型!' : (isWarning ? '' : CodeUtil.getComment( + return isValueNotString ? ' ! value必须是String类型!' : (isWarning ? '' : CodeUtil.getComment( '原始SQL片段' + (isValueNotEmpty ? ',由后端 RAW_MAP 代码配置指定 "key0,key1.." 中每个 key 对应 key:"SQL片段" 中的 SQL片段' : ',例如 "@column" "id{},@having" 等'), false, ' ')) + extraComment; case '@json': - return valuesIsNotString ? ' ! value必须是String类型!' : (isWarning ? '' : CodeUtil.getComment( + return isValueNotString ? ' ! value必须是String类型!' : (isWarning ? '' : CodeUtil.getComment( '转为JSON' + (isValueNotEmpty ? '' : ',例如 "request" "gets,heads" 等'), false, ' ')) + extraComment; case '@null': - return valuesIsNotString ? ' ! value必须是String类型!' : (isWarning ? '' : CodeUtil.getComment( + return isValueNotString ? ' ! value必须是String类型!' : (isWarning ? '' : CodeUtil.getComment( 'NULL值字段' + (isValueNotEmpty ? '' : ',例如 "tag" "content,praiseUserIdList" 等'), false, ' ')) + extraComment; case '@cast': - return valuesIsNotString ? ' ! value必须是String类型!' : (isWarning ? '' : CodeUtil.getComment( + return isValueNotString ? ' ! value必须是String类型!' : (isWarning ? '' : CodeUtil.getComment( '类型转换' + (isValueNotEmpty ? '' : ',例如 "date:DATETIME" "date>:DATETIME,id{}:JSON" 等'), false, ' ')) + extraComment; case '@schema': - return valuesIsNotString ? ' ! value必须是String类型!' : (isWarning ? '' : CodeUtil.getComment( + return isValueNotString ? ' ! value必须是String类型!' : (isWarning ? '' : CodeUtil.getComment( '集合空间(数据库名/模式)' + (isValueNotEmpty ? '' : ',例如 "sys" "apijson" "postgres" "dbo" 等'), false, ' ')) + extraComment; case '@database': return CodeUtil.DATABASE_KEYS.indexOf(value) < 0 ? ' ! value必须是[' + CodeUtil.DATABASE_KEYS.join() + ']中的一种!' : (isWarning ? '' : CodeUtil.getComment( '数据库类型:例如 "MYSQL" "POSTGRESQL" "SQLSERVER" "ORACLE" "DB2" "CLICKHOUSE" 等', false, ' ')) + extraComment; case '@datasource': - return valuesIsNotString ? ' ! value必须是String类型!' : (isWarning ? '' : CodeUtil.getComment( + return isValueNotString ? ' ! value必须是String类型!' : (isWarning ? '' : CodeUtil.getComment( '跨数据源' + (isValueNotEmpty ? '' : ',例如 "DRUID" "HIKARICP" 等'), false, ' ')) + extraComment; case '@role': var role = CodeUtil.ROLES[value]; @@ -6699,12 +6699,12 @@ res_data = rep.json() return StringUtil.isEmpty(cache) ? ' ! value必须是[' + CodeUtil.CACHE_TYPE_KEYS.join() + ']中的一种!' : (isWarning ? '' : CodeUtil.getComment( '缓存方式:0-全部 1-磁盘 2-内存', false, ' ')) + extraComment; case '@explain': - return valuesIsNotBoolean ? ' ! value必须是Boolean类型!' : (isWarning ? '' : CodeUtil.getComment( + return isValueNotBoolean ? ' ! value必须是Boolean类型!' : (isWarning ? '' : CodeUtil.getComment( '性能分析:true-开启 false-关闭,返回执行的 SQL 及查询计划', false, ' ')) + extraComment; } if (key.startsWith('@')) { if (key.endsWith('()')) { - return valuesIsNotString ? ' ! value必须是String类型!' : (isWarning ? '' : CodeUtil.getComment( + return isValueNotString ? ' ! value必须是String类型!' : (isWarning ? '' : CodeUtil.getComment( '存储过程' + (isValueNotEmpty ? ',触发调用数据库存储过程' : ':例如 "getCommentByUserId(id,@limit,@offset)"'), false, ' ')) + extraComment; } return StringUtil.isEmpty(extraComment, true) ? '' : CodeUtil.getComment(extraComment.substring(3), false, ' '); @@ -6721,21 +6721,21 @@ res_data = rep.json() if (isRestful != true && StringUtil.isEmpty(name)) { switch (key) { case 'tag': - return valuesIsNotString ? ' ! value必须是String类型!' : (isWarning ? '' : CodeUtil.getComment( + return isValueNotString ? ' ! value必须是String类型!' : (isWarning ? '' : CodeUtil.getComment( '请求标识' + (method == 'GET' || method == 'HEAD' ? ',GET,HEAD 请求不会自动解析,仅为后续迭代可能的手动优化而预留' : (isValueNotEmpty ? ',用来区分不同请求并校验,由后端 Request 表中指定' : ',例如 "User" "Comment[]" "Privacy-CIRCLE" 等')), false, ' ')); case 'version': - return valuesIsNotInteger ? ' ! value必须是Integer类型!' : (isWarning ? '' : CodeUtil.getComment( + return isValueNotInteger ? ' ! value必须是Integer类型!' : (isWarning ? '' : CodeUtil.getComment( '版本号' + (method == 'GET' || method == 'HEAD' ? ',GET,HEAD 请求不会自动解析,仅为后续迭代可能的手动优化而预留' : (isValueNotEmpty ? ',用来使用特定版本的校验规则,由后端 Request 表中指定' : ',例如 1 2 3 等')), false, ' ')); case 'format': - return valuesIsNotBoolean ? ' ! value必须是Boolean类型!' : (isWarning ? '' : CodeUtil.getComment( + return isValueNotBoolean ? ' ! value必须是Boolean类型!' : (isWarning ? '' : CodeUtil.getComment( '格式化: true-是 false-否,将 TableName 转为 tableName, TableName[] 转为 tableNameList, Table:alias 转为 alias 等小驼峰格式', false, ' ')); case '@schema': - return valuesIsNotString ? ' ! value必须是String类型!' : (isWarning ? '' : CodeUtil.getComment( + return isValueNotString ? ' ! value必须是String类型!' : (isWarning ? '' : CodeUtil.getComment( '集合空间(数据库名/模式)' + (isValueNotEmpty ? '' : ',例如 "sys" "apijson" "postgres" "dbo" 等'), false, ' ')); case '@datasource': - return valuesIsNotString ? ' ! value必须是String类型!' : (isWarning ? '' : CodeUtil.getComment( + return isValueNotString ? ' ! value必须是String类型!' : (isWarning ? '' : CodeUtil.getComment( '跨数据源' + (isValueNotEmpty ? '' : ',例如 "DRUID" "HIKARICP" 等'), false, ' ')); case '@database': return CodeUtil.DATABASE_KEYS.indexOf(value) < 0 ? ' ! value必须是[' + CodeUtil.DATABASE_KEYS.join() + ']中的一种!' : (isWarning ? '' : CodeUtil.getComment( @@ -6749,7 +6749,7 @@ res_data = rep.json() return StringUtil.isEmpty(cache) ? ' ! value必须是[' + CodeUtil.CACHE_TYPE_KEYS.join() + ']中的一种!' : (isWarning ? '' : CodeUtil.getComment( '缓存方式:0-全部 1-磁盘 2-内存', false, ' ')); case '@explain': - return valuesIsNotBoolean ? ' ! value必须是Boolean类型!' : (isWarning ? '' : CodeUtil.getComment( + return isValueNotBoolean ? ' ! value必须是Boolean类型!' : (isWarning ? '' : CodeUtil.getComment( '性能分析:true-开启 false-关闭,返回执行的 SQL 及查询计划', false, ' ')); } } @@ -6767,16 +6767,25 @@ res_data = rep.json() * @param onlyTableAndColumn * @return {*} */ - getCommentFromDoc: function (tableList, tableName, columnName, method, database, language, onlyTableAndColumn, isReq, pathKeys, isRestful, value, ignoreError, standardObj, isSubquery, isWarning) { + getCommentFromDoc: function (tableList, tableName, columnName, method, database, language, onlyTableAndColumn + , isReq, pathKeys, isRestful, value, ignoreError, standardObj, isSubquery, isWarning) { log('getCommentFromDoc tableName = ' + tableName + '; columnName = ' + columnName + '; method = ' + method + '; database = ' + database + '; language = ' + language + '; onlyTableAndColumn = ' + onlyTableAndColumn + '; tableList = \n' + JSON.stringify(tableList)); + var typeOfValue = CodeUtil.getType4Request(value); + var isValueNotArray = typeOfValue != 'array'; + var isValueNotObject = typeOfValue != 'object'; + if (standardObj != null) { - var targetObj = JSONResponse.getStandardByPath(standardObj, pathKeys); + var parentObj = pathKeys == null || pathKeys.length <= 0 ? null : JSONResponse.getStandardByPath(standardObj, pathKeys.slice(0, pathKeys.length - 1)); + var targetValues = parentObj == null ? null : parentObj.values; + var targetObj = targetValues == null ? null : (targetValues[0] || {})[pathKeys[pathKeys.length - 1]]; // JSONResponse.getStandardByPath(standardObj, pathKeys); + var t = targetObj == null ? null : targetObj.type; var targetComment = targetObj == null ? null : targetObj.comment; - var c = targetObj == null ? null : CodeUtil.getType4Language(language, t, true) + (targetObj.notnull ? ', ' : '? ') + StringUtil.trim(targetComment); + var c = StringUtil.isEmpty(targetComment, true) ? null : CodeUtil.getType4Language(language, t, true) + + (targetObj.notEmpty ? '! ' : (targetObj.notNull ? ', ' : '? ')) + StringUtil.trim(targetComment); if (CodeUtil.isTypeMatch(t, CodeUtil.getType4Request(value)) != true) { c = ' ! value必须是' + CodeUtil.getType4Language(language, t) + '类型!' + (isWarning ? ' ' : CodeUtil.getComment(c, false, ' ')); if (ignoreError != true) { @@ -6788,23 +6797,35 @@ res_data = rep.json() } } - if (StringUtil.isEmpty(targetComment, true) == false) { // 如果这里没注释就从数据库/第三方平台取 + if (StringUtil.isNotEmpty(targetComment, true)) { // 如果这里没注释就从数据库/第三方平台取 return c; } + + var parentName = parentObj == null || StringUtil.isEmpty(parentObj.name, true) ? null : parentObj.name; + var name = targetObj == null || StringUtil.isEmpty(targetObj.name, true) ? null : targetObj.name; + if (StringUtil.isNotEmpty(parentName, true) || StringUtil.isNotEmpty(name, true)) { + var pn = parentName || tableName; + var n = name || columnName; + var isValObj = isValueNotObject != true; // && StringUtil.isName(pn) + + c = CodeUtil.getCommentFromDoc(tableList, isValObj ? n : pn, isValObj ? null : n + , method, database, language, onlyTableAndColumn, isReq, pathKeys, value, ignoreError, null, isSubquery, isWarning); + if (StringUtil.isNotEmpty(c, true)) { + return (isValObj && StringUtil.isNotEmpty(name, true) ? StringUtil.trim(name) : CodeUtil.getType4Language(language, t, true)) + + (targetObj.notEmpty ? '! ' : (targetObj.notNull ? ', ' : '? ')) + StringUtil.trim(c); + } + } } - var typeOfValue = CodeUtil.getType4Request(value); - var valuesIsNotString = typeOfValue != 'string'; - var valuesIsNotInteger = typeOfValue != 'integer'; - var valuesIsNotNumber = valuesIsNotInteger && typeOfValue != 'number'; - var valuesIsNotArray = typeOfValue != 'array'; - var valuesIsNotObject = typeOfValue != 'object'; - var valuesIsNotStringOrObject = valuesIsNotString && valuesIsNotObject; - var valuesIsNotStringOrArray = valuesIsNotString && valuesIsNotArray; - var valuesIsNotStringOrNumber = valuesIsNotString && valuesIsNotNumber; - var valuesIsNotStringOrNumberOrObject = valuesIsNotStringOrNumber && valuesIsNotObject; - var valuesIsNotStringOrArrayOrObject = valuesIsNotString && valuesIsNotArray && valuesIsNotObject; - var isValueNotEmpty = valuesIsNotString ? (typeOfValue != 'array' ? value != null : value.length > 0) : StringUtil.isEmpty(value, true) != true; + var isValueNotString = typeOfValue != 'string'; + var isValueNotInteger = typeOfValue != 'integer'; + var isValueNotNumber = isValueNotInteger && typeOfValue != 'number'; + var isValueNotStringOrObject = isValueNotString && isValueNotObject; + var isValueNotStringOrArray = isValueNotString && isValueNotArray; + var isValueNotStringOrNumber = isValueNotString && isValueNotNumber; + var isValueNotStringOrNumberOrObject = isValueNotStringOrNumber && isValueNotObject; + var isValueNotStringOrArrayOrObject = isValueNotString && isValueNotArray && isValueNotObject; + var isValueNotEmpty = isValueNotString ? (typeOfValue != 'array' ? value != null : value.length > 0) : StringUtil.isEmpty(value, true) != true; if (isRestful == true && StringUtil.isEmpty(columnName, true) == false && StringUtil.isEmpty(CodeUtil.thirdParty, true) == false) { // } && CodeUtil.thirdParty == 'YAPI') { var apiMap = CodeUtil.thirdPartyApiMap; @@ -6935,7 +6956,7 @@ res_data = rep.json() // return ' ! 远程函数只能用于 GET,HEAD 请求!!'; // } // - // if (value != null && valuesIsNotString) { + // if (value != null && isValueNotString) { // return ' ! value必须是String类型!'; // } // if (value != null) { @@ -6971,6 +6992,10 @@ res_data = rep.json() return isWarning ? ' ' : '...'; } + if (StringUtil.isEmpty(tableName, true)) { + return ' '; + } + var isTSQL = ['ORACLE', 'DAMENG'].indexOf(database) >= 0; var item; @@ -6983,7 +7008,8 @@ res_data = rep.json() //Table table = item == null ? null : (isTSQL ? item.AllTable : (database != 'SQLSERVER' ? item.Table : item.SysTable)); - if (table == null || tableName != CodeUtil.getModelName(table.table_name)) { + var table_name = table == null ? null : table.table_name; + if (table_name == null || table_name.replaceAll('_', '').toLowerCase().endsWith(tableName.replaceAll('_', '').toLowerCase()) != true) { // tableName != CodeUtil.getModelName(table.table_name)) { continue; } log('getDoc [] for i=' + i + ': table = \n' + format(JSON.stringify(table))); @@ -7017,7 +7043,7 @@ res_data = rep.json() return ' ! 远程函数只能用于 GET,HEAD 请求!!'; } - if (value != null && valuesIsNotString) { + if (value != null && isValueNotString) { return ' ! value必须是String类型!'; } if (value != null) { @@ -7060,7 +7086,7 @@ res_data = rep.json() at = '引用赋值' + (isValueNotEmpty ? (value.startsWith('/') ? ',从对象父级开始的相对(缺省)路径' : ',从最外层开始的绝对(完整)路径') : ',例如 "User/id" "[]/Moment/id" 等'); columnName = columnName.substring(0, columnName.length - 1); - if (value != null && valuesIsNotStringOrObject) { + if (value != null && isValueNotStringOrObject) { return ' ! value必须是String或Object类型!'; } @@ -7068,7 +7094,7 @@ res_data = rep.json() } if (columnName.endsWith("$")) {//搜索,查询时处理 - if (verifyType && hasAt != true && valuesIsNotStringOrArray) { + if (verifyType && hasAt != true && isValueNotStringOrArray) { return ' ! value必须是String或Array类型!'; } @@ -7076,7 +7102,7 @@ res_data = rep.json() key = columnName.substring(0, columnName.length - 1); } else if (columnName.endsWith("~")) {//匹配正则表达式,查询时处理 - if (verifyType && hasAt != true && valuesIsNotStringOrArray) { + if (verifyType && hasAt != true && isValueNotStringOrArray) { return ' ! value必须是String或Array类型!'; } @@ -7088,7 +7114,7 @@ res_data = rep.json() } } else if (columnName.endsWith("%")) {//连续范围 BETWEEN AND,查询时处理 - if (verifyType && hasAt != true && valuesIsNotStringOrArray) { + if (verifyType && hasAt != true && isValueNotStringOrArray) { return ' ! value必须是String或Array类型!'; } @@ -7096,11 +7122,11 @@ res_data = rep.json() key = columnName.substring(0, columnName.length - 1); } else if (columnName.endsWith("{}")) {//被包含,或者说key对应值处于value的范围内。查询时处理 - if (verifyType && hasAt != true && valuesIsNotStringOrArray) { + if (verifyType && hasAt != true && isValueNotStringOrArray) { return ' ! value必须是String或Array类型!'; } - fun = (valuesIsNotString ? '匹配选项' : '匹配条件') + (isValueNotEmpty ? '' : ',例如 ' + (valuesIsNotString ? '[1, 2, 3] ["%c%", "S%", "%end"] 等' : '">100" "%2=0;<=100000" 等')); + fun = (isValueNotString ? '匹配选项' : '匹配条件') + (isValueNotEmpty ? '' : ',例如 ' + (isValueNotString ? '[1, 2, 3] ["%c%", "S%", "%end"] 等' : '">100" "%2=0;<=100000" 等')); key = columnName.substring(0, columnName.length - 2); verifyType = false; @@ -7115,7 +7141,7 @@ res_data = rep.json() if (verifyType && hasAt != true && isSubquery != true) { return ' ! key}{ 后面必须接 @,写成 key}{@:{} 格式!'; } - if (verifyType && valuesIsNotObject) { + if (verifyType && isValueNotObject) { return ' ! value必须是Object类型!'; } @@ -7139,7 +7165,7 @@ res_data = rep.json() key = columnName.substring(0, columnName.length - 1); } else if (columnName.endsWith(">=")) {//大于或等于 - if (verifyType && hasAt != true && valuesIsNotStringOrNumber) { + if (verifyType && hasAt != true && isValueNotStringOrNumber) { return ' ! value必须是String或Number类型!'; } @@ -7147,7 +7173,7 @@ res_data = rep.json() key = columnName.substring(0, columnName.length - 2); } else if (columnName.endsWith("<=")) {//小于或等于 - if (verifyType && hasAt != true && valuesIsNotStringOrNumber) { + if (verifyType && hasAt != true && isValueNotStringOrNumber) { return ' ! value必须是String或Number类型!'; } @@ -7155,7 +7181,7 @@ res_data = rep.json() key = columnName.substring(0, columnName.length - 2); } else if (columnName.endsWith(">")) {//大于 - if (verifyType && hasAt != true && valuesIsNotStringOrNumber) { + if (verifyType && hasAt != true && isValueNotStringOrNumber) { return ' ! value必须是String或Number类型!'; } @@ -7163,7 +7189,7 @@ res_data = rep.json() key = columnName.substring(0, columnName.length - 1); } else if (columnName.endsWith("<")) {//小于 - if (verifyType && hasAt != true && valuesIsNotStringOrNumber) { + if (verifyType && hasAt != true && isValueNotStringOrNumber) { return ' ! value必须是String或Number类型!'; } diff --git a/apijson/JSONResponse.js b/apijson/JSONResponse.js index 0af3738..b686d75 100644 --- a/apijson/JSONResponse.js +++ b/apijson/JSONResponse.js @@ -1764,10 +1764,26 @@ var JSONResponse = { if (tgt == null) { tgt = {}; } - var startsWithQuestion = comment.startsWith('?') - tgt.type = JSONResponse.getType(real); - tgt.notNull = real != null && startsWithQuestion != true - tgt.comment = startsWithQuestion ? comment.substring(1) : comment + var ind = comment.indexOf(', ') + if (ind < 0) { + ind = comment.indexOf(',') + } + + var prefix = ind <= 0 ? '' : comment.substring(0, ind).trim() + comment = ind < 0 ? comment : comment.substring(ind + 1) + var nullable = prefix.endsWith('?') + var notEmpty = prefix.endsWith('!') + var name = nullable || notEmpty ? prefix.substring(0, prefix.length - 1) : prefix + if (StringUtil.isName(name)) { + tgt.name = name + } else { + nullable = notEmpty = null + } + + tgt.type = JSONResponse.getType(real) + tgt.notNull = notEmpty == true || nullable == false || (nullable == null && real != null) + tgt.notEmpty = notEmpty == true || (notEmpty == null && StringUtil.isNotEmpty(real)) + tgt.comment = comment return target; }, diff --git a/js/main.js b/js/main.js index 784f07e..724b5da 100755 --- a/js/main.js +++ b/js/main.js @@ -4467,7 +4467,8 @@ https://github.com/Tencent/APIJSON/issues 'toId': 0, 'chainId@': '/Chain/id', 'documentId@': '/Document/id', - 'userId': userId + 'userId': userId, + '@order': 'date-' }, 'TestRecord': { 'chainId@': '/Chain/id', @@ -9825,7 +9826,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea else if (fun == CTX_PUT) { var as = StringUtil.split(value.substring(start + 1, end), ', ') if (as.length >= 2) { - as[1] = 'get4Path((ctx || {}).ctx, ' + StringUtil.trim(as[1]) + ')' + as[1] = 'get4Path(((ctx || {}).pre || {}).data, ' + StringUtil.trim(as[1]) + ')' } toEval = 'put4Path((ctx || {}).ctx, ' + (value == 'CTX_PUT()' ? JSON.stringify(path) : '') + as.join(', ') + value.substring(end); } @@ -10043,7 +10044,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea // } const list = (isRandom ? this.randoms : (this.isChainShow ? ( - this.isChainGroupShow() ? this.chainGroups : [this.chainGroups[0]] + this.isChainGroupShow() ? this.chainGroups : [this.chainGroups[this.currentChainGroupIndex]] ) : this.remotes) ) || [] @@ -10339,7 +10340,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea if (isRandom) { stdd = stdd || ((this.currentRemoteItem || {}).TestRecord || {})[standardKey] } - + var standard = typeof stdd != 'string' ? stdd : (StringUtil.isEmpty(stdd, true) ? null : JSON.parse(stdd)) tr.compare = JSONResponse.compareResponse(res, standard, this.removeDebugInfo(response) || {}, '', isML, null, null, ignoreTrend) || {} tr.compare.duration = it.durationHint From d782ee46ff38c904129bcd8e5ce10cf9ecf8b4c2 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sat, 15 Jun 2024 22:42:39 +0800 Subject: [PATCH 807/818] =?UTF-8?q?=E5=9C=BA=E6=99=AF=E4=B8=B2=E8=81=94?= =?UTF-8?q?=EF=BC=9A=E8=A7=A3=E5=86=B3=E5=88=86=E7=BB=84=E5=92=8C=E7=94=A8?= =?UTF-8?q?=E4=BE=8B=E6=95=B0=E9=87=8F=E6=98=BE=E7=A4=BA=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.html | 48 ++++++++++++++++++++++++------------------------ js/main.js | 30 ++++++++++++++++++++++++++++-- 2 files changed, 52 insertions(+), 26 deletions(-) diff --git a/index.html b/index.html index 20fde11..2ea05c2 100755 --- a/index.html +++ b/index.html @@ -173,11 +173,11 @@ - 测试用例:{{ isLocalShow ? '本地历史' : (isChainShow ? '场景串联' : '远程在线') }} -
    -
    - - - +
    + -
    - - - - - -
    + + +
    + + + + +
    +
    diff --git a/js/main.js b/js/main.js index 724b5da..735620c 100755 --- a/js/main.js +++ b/js/main.js @@ -4396,10 +4396,10 @@ https://github.com/Tencent/APIJSON/issues this.chainPaths = [] } } else { - this.chainPaths.push(group) + this.chainPaths = [group] // .push(group) } -// this.casePaths = this.chainPaths + this.casePaths = this.chainPaths var groupId = group == null ? 0 : group.groupId if (groupId != null && groupId > 0) { // group != null && groupId == 0) { @@ -4780,6 +4780,32 @@ https://github.com/Tencent/APIJSON/issues } }, + getCaseCountStr: function() { + var isChainShow = this.isChainShow + var isCaseGroupShow = this.isCaseGroupShow() + var isLocalShow = this.isLocalShow + var caseShowType = this.caseShowType + var caseGroups = (isChainShow ? this.chainGroups : this.caseGroups) || [] + var testCases = this.testCases || [] + + if (isLocalShow) { + return '(' + testCases.length + ')' + } + + return '(' + (isCaseGroupShow ? caseGroups.length : '') + + (caseShowType == 0 && isCaseGroupShow ? '|' : '') + + (caseShowType == 2 && (isCaseGroupShow) ? '' : testCases.length) + ')'; + + // 以下代码不知道为啥结果显示不对 + // var isCaseGroupShow = this.isCaseGroupShow() + // var isCaseItemShow = this.isCaseItemShow() + // var caseGroups = (this.isChainShow ? this.chainGroups : this.caseGroups) || [] + // + // return '(' + (isCaseGroupShow ? caseGroups.length : '') + // + (isCaseGroupShow && isCaseItemShow ? '|' : '') + // + (isCaseItemShow ? '' : testCases.length) + ')'; + }, + //显示远程的测试用例文档 showTestCase: function (show, isLocal, callback, group) { this.isTestCaseShow = show From cf7cc26b2c374c81ca70c6d6c8fbae2d3b94d308 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sun, 16 Jun 2024 00:32:23 +0800 Subject: [PATCH 808/818] =?UTF-8?q?=E5=9C=BA=E6=99=AF=E4=B8=B2=E8=81=94?= =?UTF-8?q?=EF=BC=9A=E6=96=B0=E5=A2=9E=E6=94=AF=E6=8C=81=E6=AF=8F=E7=BB=84?= =?UTF-8?q?=E6=8C=87=E5=AE=9A=E9=80=89=E4=B8=AD=E6=AD=A5=E9=AA=A4=E5=89=8D?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=96=B0=E6=AD=A5=E9=AA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- js/main.js | 120 +++++++++++++++++++++++++++++------------------------ 1 file changed, 65 insertions(+), 55 deletions(-) diff --git a/js/main.js b/js/main.js index 735620c..efaa68c 100755 --- a/js/main.js +++ b/js/main.js @@ -1670,9 +1670,13 @@ https://github.com/Tencent/APIJSON/issues this.options = []; target.focus(); - selectionStart = target.selectionStart = selectionEnd + (isClickSelectInput ? (name.length - (isValue ? 4 : 0)) : 0) - + (isValue ? (after.startsWith(',') ? 1 : 0) : (target == vInput || target == vScript ? 3 : 2)); - selectionEnd = target.selectionEnd = selectionStart + (isValue ? 0 : 4) + try { + selectionStart = target.selectionStart = selectionEnd + (isClickSelectInput ? (name.length - (isValue ? 4 : 0)) : 0) + + (isValue ? (after.startsWith(',') ? 1 : 0) : (target == vInput || target == vScript ? 3 : 2)); + selectionEnd = target.selectionEnd = selectionStart + (isValue ? 0 : 4) + } catch (e) { + console.log(e) + } isClickSelectInput = false; // vOption.focusout() @@ -4125,7 +4129,7 @@ https://github.com/Tencent/APIJSON/issues if (date == null) { date = new Date() } - return this.fillZero(date.getHours()) + ':' + this.fillZero(date.getMinutes()) + return this.fillZero(date.getHours()) + ':' + this.fillZero(date.getMinutes()) + ':' + this.fillZero(date.getSeconds()) }, formatDateTime: function (date) { if (date == null) { @@ -4386,6 +4390,7 @@ https://github.com/Tencent/APIJSON/issues }, selectChainGroup: function (index, group) { this.currentChainGroupIndex = index + this.currentDocIndex = -1 this.isCaseGroupEditable = false if (group == null) { @@ -4441,8 +4446,8 @@ https://github.com/Tencent/APIJSON/issues 'Chain': { // TODO 后续再支持嵌套子组合 'toGroupId': groupId, 'groupId@': '[]/Chain/groupId', - '@column': "id,groupId,documentId,randomId", - '@order': 'id+', + '@column': "id,groupId,documentId,randomId,rank", + '@order': 'rank+,id+', 'documentId>': 0 }, 'Document': { @@ -4548,50 +4553,55 @@ https://github.com/Tencent/APIJSON/issues }, addCase2Chain: function (item) { - var id = item == null ? null : item.id - if (id == null || id <= 0) { - alert('请选择有效的用例!') - return - } + var id = item == null ? null : item.id + if (id == null || id <= 0) { + alert('请选择有效的用例!') + return + } - var group = (this.chainGroups[this.currentChainGroupIndex] || {}).Chain - if (group == null) { - var index = this.chainPaths.length - 1 - group = this.chainPaths[index] - } - var groupId = group == null ? 0 : group.groupId - if (groupId == null || groupId <= 0) { - alert('请选择有效的场景串联用例分组!') - return - } + var group = (this.chainGroups[this.currentChainGroupIndex] || {}).Chain + if (group == null) { + var index = this.chainPaths.length - 1 + group = this.chainPaths[index] + } - var groupName = group.groupName + var groupId = group == null ? 0 : group.groupId + if (groupId == null || groupId <= 0) { + alert('请选择有效的场景串联用例分组!') + return + } - var isAdd = true - this.request(true, REQUEST_TYPE_POST, REQUEST_TYPE_JSON, this.server + '/post', { - Chain: { - 'groupName': groupName, - 'groupId': groupId, - 'documentId': item.id - }, - tag: 'Chain' - }, {}, function (url, res, err) { - App.onResponse(url, res, err) - var isOk = JSONResponse.isSuccess(res.data) + var nextIndex = this.currentDocIndex + var nextChain = nextIndex == null || nextIndex < 0 ? null : (this.testCases[nextIndex] || {}).Chain + var nextRank = nextChain == null ? null : nextChain.rank - var msg = isOk ? '' : ('\nmsg: ' + StringUtil.get((res.data || {}).msg)) - if (err != null) { - msg += '\nerr: ' + err.msg - } - alert((isAdd ? '新增' : '修改') + (isOk ? '成功' : '失败') + (isAdd ? '! \n' :'!\ngroupId: ' + groupId) + '\ngroupName: ' + groupName + '\n' + msg) + var groupName = group.groupName + var isAdd = true + this.request(true, REQUEST_TYPE_POST, REQUEST_TYPE_JSON, this.server + '/post', { + Chain: { + 'rank': this.formatDateTime(StringUtil.isEmpty(nextRank, true) ? null : new Date(new Date(nextRank).getTime() - 10)), + 'groupName': groupName, + 'groupId': groupId, + 'documentId': item.id + }, + tag: 'Chain' + }, {}, function (url, res, err) { + App.onResponse(url, res, err) + var isOk = JSONResponse.isSuccess(res.data) - App.isCaseGroupEditable = ! isOk - if (isOk) { -// App.remotes = App.testCases = [] -// App.showTestCase(true, false, null) - App.selectChainGroup(App.currentChainGroupIndex, null) - } - }) + var msg = isOk ? '' : ('\nmsg: ' + StringUtil.get((res.data || {}).msg)) + if (err != null) { + msg += '\nerr: ' + err.msg + } + alert((isAdd ? '新增' : '修改') + (isOk ? '成功' : '失败') + (isAdd ? '! \n' :'!\ngroupId: ' + groupId) + '\ngroupName: ' + groupName + '\n' + msg) + + App.isCaseGroupEditable = ! isOk + if (isOk) { +// App.remotes = App.testCases = [] +// App.showTestCase(true, false, null) + App.selectChainGroup(App.currentChainGroupIndex, null) + } + }) }, onClickPath: function (index, path) { @@ -4859,7 +4869,7 @@ https://github.com/Tencent/APIJSON/issues var url = this.server + '/get' var userId = this.User.id - + this.coverage = {} this.view = 'markdown' var req = { @@ -4871,8 +4881,8 @@ https://github.com/Tencent/APIJSON/issues 'Chain': isChainShow ? { // TODO 后续再支持嵌套子组合 'toGroupId': groupId, 'groupId': groupId, - '@column': "id,groupId,documentId,randomId", - '@order': 'id+', + '@column': "id,groupId,documentId,randomId,documentName,randomName,rank", // ;unix_timestamp(rank):rank", + '@order': 'rank+,id+', 'documentId>': 0 } : null, 'Document': { @@ -4893,7 +4903,7 @@ https://github.com/Tencent/APIJSON/issues '@null': 'sqlauto', //'sqlauto{}': '=null' // '@having': StringUtil.isEmpty(groupUrl) ? null : "substring_index(substr,'/',1)<0" }, - 'Random': isChainShow ? { + 'Random': isChainShow ? { 'id@': '/Chain/randomId', 'toId': 0, // isChainShow ? 0 : null, // 'chainId@': isChainShow ? '/Chain/id' : null, @@ -5561,7 +5571,7 @@ https://github.com/Tencent/APIJSON/issues } } } - + this.scripts = newDefaultScript() const isLoginShow = this.isLoginShow @@ -5670,7 +5680,7 @@ https://github.com/Tencent/APIJSON/issues App.onClickAccount(App.currentAccountIndex, item) //自动登录测试账号 if (user.id > 0) { - if (App.chainShowType != 1 && App.chainPaths.length <= 0 && App.chainGroups.length <= 0) { + if (App.isChainShow && App.chainShowType != 1 && App.chainPaths.length <= 0 && App.chainGroups.length <= 0) { App.selectChainGroup(-1, null) } if (App.caseShowType != 1 && App.casePaths.length <= 0 && App.caseGroups.length <= 0) { @@ -9242,7 +9252,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea const which = i; var rawConfig = testSubList && i < existCount ? ((subs[i] || {}).Random || {}).config : random.config - + var cb = function (url, res, err) { if (callback != null) { callback(url, res, err, random) @@ -9251,7 +9261,7 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea App.onResponse(url, res, err) } }; - + try { this.parseRandom( JSON.parse(JSON.stringify(json)), rawConfig, random.id @@ -10248,8 +10258,8 @@ Content-Type: ` + contentType) + (StringUtil.isEmpty(headerStr, true) ? '' : hea const header = hdr const caseScript = { - pre: item['Script:pre'], - post: item['Script:post'] + pre: (item['Script:pre'] || {}).script, + post: (item['Script:post'] || {}).script } const method = document.method From cbf8cc5b8f93530d8a3d02f42c81034ff3eb4e6a Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sun, 8 Sep 2024 23:10:30 +0800 Subject: [PATCH 809/818] =?UTF-8?q?=E7=9B=B8=E5=85=B3=E6=8E=A8=E8=8D=90?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=20APIAuto:=20=E6=9C=80=E5=85=88=E8=BF=9B?= =?UTF-8?q?=E7=9A=84HTTP=E6=8E=A5=E5=8F=A3=E5=B7=A5=E5=85=B7=EF=BC=8C?= =?UTF-8?q?=E6=84=9F=E8=B0=A2=E5=8D=9A=E4=B8=BB=E7=9A=84=E8=B4=A1=E7=8C=AE?= =?UTF-8?q?~?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 点赞、收藏 支持下博主吧 ^_^ https://blog.csdn.net/Nifc666/article/details/141966487 --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 530f2d6..6dd704b 100755 --- a/README.md +++ b/README.md @@ -116,6 +116,8 @@ Bilibili:https://search.bilibili.com/all?keyword=APIAuto ### 相关推荐 [别再生成测试代码了!](https://mp.weixin.qq.com/s/G1GVNhhFbSX5GoyRU6GURg) +[APIAuto: 最先进的HTTP接口工具](https://blog.csdn.net/Nifc666/article/details/141966487) + ### 百度、搜狗、抖音公网接口调用演示
    因为这些接口不支持 CORS 跨域,所以需要开启托管服务代理。
    From 19336d4d151e6aaa3e8df5ecb6094ab9e472ad67 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sun, 8 Sep 2024 23:13:01 +0800 Subject: [PATCH 810/818] =?UTF-8?q?=E7=9B=B8=E5=85=B3=E6=8E=A8=E8=8D=90?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=20APIAuto:=20=E6=9C=80=E5=85=88=E8=BF=9B?= =?UTF-8?q?=E7=9A=84HTTP=E6=8E=A5=E5=8F=A3=E5=B7=A5=E5=85=B7=EF=BC=8C?= =?UTF-8?q?=E6=84=9F=E8=B0=A2=E5=8D=9A=E4=B8=BB=E7=9A=84=E8=B4=A1=E7=8C=AE?= =?UTF-8?q?~?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 点赞、收藏 支持下博主吧 ^_^ https://blog.csdn.net/Nifc666/article/details/141966487 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6dd704b..f0c7221 100755 --- a/README.md +++ b/README.md @@ -115,7 +115,7 @@ Bilibili:https://search.bilibili.com/all?keyword=APIAuto ### 相关推荐 -[别再生成测试代码了!](https://mp.weixin.qq.com/s/G1GVNhhFbSX5GoyRU6GURg) +[别再生成测试代码了!](https://mp.weixin.qq.com/s/G1GVNhhFbSX5GoyRU6GURg)
    [APIAuto: 最先进的HTTP接口工具](https://blog.csdn.net/Nifc666/article/details/141966487) From 64178a65f4ae74cabc8de6bc9e7dd36ab7d4d52c Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Thu, 19 Sep 2024 00:40:15 +0800 Subject: [PATCH 811/818] =?UTF-8?q?=E6=96=B0=E5=A2=9E=20=20Roadmap=20?= =?UTF-8?q?=E8=B7=AF=E7=BA=BF=E5=9B=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://github.com/TommyLemon/APIAuto/edit/master/README.md#Roadmap%20%E8%B7%AF%E7%BA%BF%E5%9B%BE --- README.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/README.md b/README.md index f0c7221..8f32dda 100755 --- a/README.md +++ b/README.md @@ -254,6 +254,24 @@ https://github.com/TommyLemon/APIAuto/issues
    +### Roadmap 路线图 +1.Translate document to English/Italian/Franch/Spanish...
    + +2.新增功能
    +1) 断言结果 新增按钮 变-\{原因},点击后右侧展示 JSON diff view;
    +2) 右下角列表展示具体每个断言有问题的字段,点击后 JSON view 只显示该字段对应值
    +其他待补充...
    +
    +3.完善自动断言,支持更多格式的匹配
    +
    +4.解决 bug
    +
    +5.提升性能
    +
    +6.其他待补充...
    + +
    + ### 感谢开源 * jsonon * editor.md From 8f6c2d982f045f86e4409eb814a81a412ec79b56 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sun, 27 Oct 2024 19:43:19 +0800 Subject: [PATCH 812/818] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E5=9C=A8=E5=8F=B3=E4=BE=A7=20Response=20JSON=20key=20=E5=90=8E?= =?UTF-8?q?=E5=8A=A0=20=E6=96=AD=E8=A8=80=E7=BB=93=E6=9E=9C=E5=8F=8A?= =?UTF-8?q?=E7=BA=A0=E9=94=99=E6=8C=89=E9=92=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apijson/JSONResponse.js | 127 +++++++++++++++ index.html | 52 +++--- js/main.js | 340 ++++++++++++++++++++++++++++++++-------- 3 files changed, 428 insertions(+), 91 deletions(-) diff --git a/apijson/JSONResponse.js b/apijson/JSONResponse.js index b686d75..96a9ea4 100644 --- a/apijson/JSONResponse.js +++ b/apijson/JSONResponse.js @@ -476,6 +476,54 @@ var JSONResponse = { COMPARE_CODE_CHANGE: 11, COMPARE_THROW_CHANGE: 12, + getCompareShowObj: function(cmp, status, response) { + var it = cmp; + var p = cmp.path + it.compareType = cmp.code; + it.compareMessage = (StringUtil.isEmpty(p, true) ? '' : p + ' ') + (cmp.msg || '查看结果') + switch (it.code) { + case JSONResponse.COMPARE_ERROR: + it.compareColor = 'red' + it.hintMessage = (status != null && status != 200 ? status + ' ' : '') + '请求出错!' + break; + case JSONResponse.COMPARE_NO_STANDARD: + it.compareColor = 'green' + it.hintMessage = '确认正确后点击[对的,纠正]' + break; + case JSONResponse.COMPARE_KEY_MORE: + case JSONResponse.COMPARE_VALUE_MORE: + case JSONResponse.COMPARE_EQUAL_EXCEPTION: + it.compareColor = 'green' + it.hintMessage = '新增字段/新增值 等' + break; + case JSONResponse.COMPARE_LENGTH_CHANGE: + case JSONResponse.COMPARE_VALUE_CHANGE: + it.compareColor = 'blue' + it.hintMessage = '值改变 等' + break; + case JSONResponse.COMPARE_VALUE_EMPTY: + case JSONResponse.COMPARE_KEY_LESS: + it.compareColor = 'orange' + it.hintMessage = '缺少字段/整数变小数 等' + break; + case JSONResponse.COMPARE_FORMAT_CHANGE: + case JSONResponse.COMPARE_NUMBER_TYPE_CHANGE: + case JSONResponse.COMPARE_TYPE_CHANGE: + case JSONResponse.COMPARE_CODE_CHANGE: + case JSONResponse.COMPARE_THROW_CHANGE: + var code = response == null ? null : response[JSONResponse.KEY_CODE] + it.compareColor = 'red' + it.hintMessage = (code != null && code != JSONResponse.CODE_SUCCESS + ? code + ' ' : (status != null && status != 200 ? status + ' ' : '')) + '状态码/异常/值类型 改变等' + break; + default: + it.compareColor = 'white' + it.hintMessage = '结果正确' + break; + } + return it; + }, + /**测试compare: 对比 新的请求与上次请求的结果 0-相同,无颜色; 1-对象新增字段或数组新增值,绿色; @@ -1635,6 +1683,85 @@ var JSONResponse = { return tgt; }, + /**根据 APIJSON 引用赋值路径精准地修改值 + */ + setValByPath: function(target, pathKeys, val, isTry) { + var depth = pathKeys == null ? 0 : pathKeys.length + if (depth <= 0) { + return target; + } + + var tgt = target; + var parent = target; + for (var i = 0; i < depth - 1; i ++) { + var k = pathKeys[i]; + if (k == null) { + return null; + } + k = decodeURI(k); + + if (tgt instanceof Object) { + if (k == '') { + if (tgt instanceof Array) { + k = 0; + } else { + ks = Object.keys(tgt); + k = ks == null ? null : ks[0]; + if (k == null) { + return null; + } + } + } + else { + if (tgt instanceof Array) { + try { + var n = Number.parseInt(k); + if (Number.isSafeInteger(n)) { + k = n >= 0 ? n : n + tgt.length; + } + } catch (e) { + } + } + } + + parent = tgt; + tgt = tgt[k]; + continue; + } + + if (tgt == null) { + try { + var n = Number.parseInt(k); + if (Number.isSafeInteger(n)) { + k = n >= 0 ? n : n + tgt.length; + } + } catch (e) { + } + + tgt = Number.isInteger(k) ? [] : {}; + if (i == 0 && parent == null) { + parent = target = tgt; + } else { + parent[k] = tgt; + } + + parent = tgt; + tgt = tgt[k]; + + continue; + } + + if (isTry != true) { + throw new Error('setValByPath 语法错误,' + k + ': value 中 value 类型应该是 Object 或 Array !'); + } + + return null; + } + + tgt[pathKeys[pathKeys.length - 1]] = val; + + return target; + }, /**根据路径精准地更新测试标准中的键值对 */ diff --git a/index.html b/index.html index 2ea05c2..ec7e64c 100755 --- a/index.html +++ b/index.html @@ -274,7 +274,7 @@ - +
    @@ -452,11 +452,11 @@
    - + - +
    @@ -482,19 +482,19 @@ {{ (item.Random || {}).name }} - -
    + +
    - + - +
    @@ -910,15 +910,15 @@ @@ -926,35 +926,39 @@ diff --git a/js/main.js b/js/main.js index 62119d2..3b24b41 100755 --- a/js/main.js +++ b/js/main.js @@ -197,12 +197,12 @@ if (val[0] instanceof Object && (val[0] instanceof Array == false)) { // && JSONObject.isArrayKey(key, null, isRestful)) { // alert('onRenderJSONItem key = ' + key + '; val = ' + JSON.stringify(val)) - var ckey = key.substring(0, key.lastIndexOf('[]')); + var ckey = key == null ? null : key.substring(0, key.lastIndexOf('[]')); - var aliaIndex = ckey.indexOf(':'); + var aliaIndex = ckey == null ? -1 : ckey.indexOf(':'); var objName = aliaIndex < 0 ? ckey : ckey.substring(0, aliaIndex); - var firstIndex = objName.indexOf('-'); + var firstIndex = objName == null ? -1 : objName.indexOf('-'); var firstKey = firstIndex < 0 ? objName : objName.substring(0, firstIndex); for (var i = 0; i < val.length; i++) { @@ -239,7 +239,7 @@ var pathKeys = StringUtil.split(pathUri, '/'); var target = App.isMLEnabled ? JSONResponse.getStandardByPath(standardObj, pathKeys) : JSONResponse.getValByPath(standardObj, pathKeys); var real = JSONResponse.getValByPath(responseObj, pathKeys); - var cmp = App.isMLEnabled ? JSONResponse.compareWithStandard(target, real, path) : JSONResponse.compareWithBefore(target, real, path); + var cmp = App.isMLEnabled ? JSONResponse.compareWithStandard(target, real, pathUri) : JSONResponse.compareWithBefore(target, real, pathUri); cmp.path = pathUri; var cmpShowObj = JSONResponse.getCompareShowObj(cmp); thiz[k] = [cmpShowObj.compareType, cmpShowObj.compareColor, cmpShowObj.compareMessage]; @@ -270,7 +270,7 @@ } } else if (val instanceof Object) { - var aliaIndex = key.indexOf(':'); + var aliaIndex = key == null ? -1 : key.indexOf(':'); var objName = aliaIndex < 0 ? key : key.substring(0, aliaIndex); // var newVal = JSON.parse(JSON.stringify(val)) @@ -299,7 +299,7 @@ var target = App.isMLEnabled ? JSONResponse.getStandardByPath(standardObj, pathKeys) : JSONResponse.getValByPath(standardObj, pathKeys); var real = JSONResponse.getValByPath(responseObj, pathKeys); // c = JSONResponse.compareWithBefore(target, real, path); - var cmp = App.isMLEnabled ? JSONResponse.compareWithStandard(target, real, path) : JSONResponse.compareWithBefore(target, real, path); + var cmp = App.isMLEnabled ? JSONResponse.compareWithStandard(target, real, pathUri) : JSONResponse.compareWithBefore(target, real, pathUri); cmp.path = pathUri; var cmpShowObj = JSONResponse.getCompareShowObj(cmp); thiz[k] = [cmpShowObj.compareType, cmpShowObj.compareColor, cmpShowObj.compareMessage]; @@ -1519,16 +1519,118 @@ https://github.com/Tencent/APIJSON/issues } catch (ex) { log(ex) } + + var path = null; + var key = null; + var thiz = { + _$_path_$_: null, + _$_table_$_: null + }; + if (isSingle || ret instanceof Array || (ret instanceof Object == false)) { - this.jsonhtml = ret + var val = ret; + if (isSingle != true && val instanceof Array && val[0] instanceof Object && (val[0] instanceof Array == false)) { + // alert('onRenderJSONItem key = ' + key + '; val = ' + JSON.stringify(val)) + var ckey = key == null ? null : key.substring(0, key.lastIndexOf('[]')); + + var aliaIndex = ckey == null ? -1 : ckey.indexOf(':'); + var objName = aliaIndex < 0 ? ckey : ckey.substring(0, aliaIndex); + + var firstIndex = objName == null ? -1 : objName.indexOf('-'); + var firstKey = firstIndex < 0 ? objName : objName.substring(0, firstIndex); + + for (var i = 0; i < val.length; i++) { + var vi = val[i] + + if (vi instanceof Object && vi instanceof Array == false && JSONObject.isTableKey(firstKey, val, isRestful)) { + // var newVal = JSON.parse(JSON.stringify(val[i])) + if (vi == null) { + continue + } + + var curPath = '' + i; + var curTable = firstKey; + var thiz = { + _$_path_$_: curPath, + _$_table_$_: curTable + }; + + var newVal = {}; + for (var k in vi) { + newVal[k] = vi[k]; //提升性能 + if (this.isFullAssert) { + try { + var tr = this.currentRemoteItem.TestRecord || {}; + var d = this.currentRemoteItem.Document || {}; + var standard = this.isMLEnabled ? tr.standard : tr.response; + var standardObj = StringUtil.isEmpty(standard, true) ? null : JSON.parse(standard); + var tests = this.tests[String(this.currentAccountIndex)] || {}; + var responseObj = (tests[d.id] || {})[0] + + var pathUri = (StringUtil.isEmpty(curPath, false) ? '' : curPath + '/') + k; + var pathKeys = StringUtil.split(pathUri, '/'); + var target = this.isMLEnabled ? JSONResponse.getStandardByPath(standardObj, pathKeys) : JSONResponse.getValByPath(standardObj, pathKeys); + var real = JSONResponse.getValByPath(responseObj, pathKeys); + var cmp = this.isMLEnabled ? JSONResponse.compareWithStandard(target, real, pathUri) : JSONResponse.compareWithBefore(target, real, pathUri); + cmp.path = pathUri; + var cmpShowObj = JSONResponse.getCompareShowObj(cmp); + thiz[k] = [cmpShowObj.compareType, cmpShowObj.compareColor, cmpShowObj.compareMessage]; + var countKey = '_$_' + cmpShowObj.compareColor + 'Count_$_'; + thiz[countKey] = thiz[countKey] == null ? 1 : thiz[countKey] + 1; + } catch (e) { + thiz[k] = [JSONResponse.COMPARE_ERROR, 'red', e.message]; + var countKey = '_$_redCount_$_'; + thiz[countKey] = thiz[countKey] == null ? 1 : thiz[countKey] + 1; + } + } + + delete vi[k] + } + + vi._$_this_$_ = JSON.stringify(thiz) + for (var k in newVal) { + vi[k] = newVal[k] + } + } + + } + } + + this.jsonhtml = val; } else { - this.jsonhtml = Object.assign({ - _$_this_$_: JSON.stringify({ - _$_path_$_: null, - _$_table_$_: null - }) - }, ret) + for (var k in ret) { + if (this.isFullAssert) { + try { + var tr = this.currentRemoteItem.TestRecord || {}; + var d = this.currentRemoteItem.Document || {}; + var standard = this.isMLEnabled ? tr.standard : tr.response; + var standardObj = StringUtil.isEmpty(standard, true) ? null : JSON.parse(standard); + var tests = this.tests[String(this.currentAccountIndex)] || {}; + var responseObj = (tests[d.id] || {})[0] + + var pathUri = k; + var pathKeys = StringUtil.split(pathUri, '/'); + var target = this.isMLEnabled ? JSONResponse.getStandardByPath(standardObj, pathKeys) : JSONResponse.getValByPath(standardObj, pathKeys); + var real = JSONResponse.getValByPath(responseObj, pathKeys); + // c = JSONResponse.compareWithBefore(target, real, path); + var cmp = this.isMLEnabled ? JSONResponse.compareWithStandard(target, real, pathUri) : JSONResponse.compareWithBefore(target, real, pathUri); + cmp.path = pathUri; + var cmpShowObj = JSONResponse.getCompareShowObj(cmp); + thiz[k] = [cmpShowObj.compareType, cmpShowObj.compareColor, cmpShowObj.compareMessage]; + var countKey = '_$_' + cmpShowObj.compareColor + 'Count_$_'; + thiz[countKey] = thiz[countKey] == null ? 1 : thiz[countKey] + 1; + } catch (e) { + thiz[k] = [JSONResponse.COMPARE_ERROR, 'red', e.message]; + var countKey = '_$_redCount_$_'; + thiz[countKey] = thiz[countKey] == null ? 1 : thiz[countKey] + 1; + } + } + } + + this.jsonhtml = Object.assign({ + _$_this_$_: JSON.stringify(thiz) + }, ret) } } @@ -1844,7 +1946,7 @@ https://github.com/Tencent/APIJSON/issues var name = item == null ? '' : StringUtil.get(item.name); target.value = text = before + name + after if (target == vScript) { // 不这样会自动回滚 - App.scripts[App.scriptType][App.scriptBelongId][App.isPreScript ? 'pre' : 'post'].script = text + this.scripts[this.scriptType][this.scriptBelongId][this.isPreScript ? 'pre' : 'post'].script = text } else if (target == vInput) { inputted = target.value; @@ -1870,7 +1972,7 @@ https://github.com/Tencent/APIJSON/issues } if (isInputValue != true) { - App.showOptions(target, text, before + name + (isSingle ? "'" : '"') + ': ', after.substring(3), true); + this.showOptions(target, text, before + name + (isSingle ? "'" : '"') + ': ', after.substring(3), true); } } else { target.selectionStart = selectionStart; diff --git a/js/server.js b/js/server.js index 5bbcad8..06e9bc7 100644 --- a/js/server.js +++ b/js/server.js @@ -79,11 +79,13 @@ app.use(async ctx => { ctx.set('Access-Control-Allow-Headers', "*"); ctx.set('Access-Control-Allow-Credentials', 'true'); ctx.set('Access-Control-Allow-Methods', 'GET,HEAD,POST,PUT,DELETE,OPTIONS,TRACE'); +// ctx.set('Access-Control-Expose-Headers', "*"); if (ctx.method == null || ctx.method.toUpperCase() == 'OPTIONS') { ctx.status = 200; return; } + if (ctx.path == '/test/start' || (isLoading != true && ctx.path == '/test')) { if (isLoading && ctx.path == '/test/start') { ctx.status = 200; From 3496f9c62403053724e48118cfaa088ca161407f Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sun, 5 Jan 2025 23:04:05 +0800 Subject: [PATCH 816/818] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=A4=9A=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E5=9C=BA=E6=99=AF=E4=B8=B2=E8=81=94=E5=8F=8A=E6=9C=BA?= =?UTF-8?q?=E5=99=A8=E5=AD=A6=E4=B9=A0=E9=9B=B6=E4=BB=A3=E7=A0=81=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E7=9A=84=E6=88=AA=E5=B1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://github.com/TommyLemon/APIAuto/releases/tag/4.0.0 --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 8f32dda..ad186b5 100755 --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@ 腾讯内部用户包括 IEG 互动娱乐事业群、TEG 技术工程事业群、CSIG 云与智慧事业群 的多个部门及团队,
    外部用户包含 华为、工商银行某地分行、500 强上市公司传音、跨境电商巨头 SHEIN、行业领头羊社保科技 等。 +![image](https://github.com/user-attachments/assets/24460af3-0001-46e7-aa2a-df28b711a8cf) ![](https://user-images.githubusercontent.com/5738175/145665502-94231804-5ea8-4784-b30d-d5558aad0f8d.jpeg)

    From acbd7290341aaa43168c60e554af531eaf642de2 Mon Sep 17 00:00:00 2001 From: TommyLemon <1184482681@qq.com> Date: Sat, 3 May 2025 12:42:59 +0800 Subject: [PATCH 817/818] =?UTF-8?q?=E6=96=B0=E5=A2=9E=20AI=20=E9=97=AE?= =?UTF-8?q?=E7=AD=94=EF=BC=8C=E5=AE=8C=E5=96=84=E8=87=AA=E5=8A=A8=E5=88=86?= =?UTF-8?q?=E7=BB=84=EF=BC=8C=E5=AE=8C=E5=96=84=E6=95=B0=E6=8D=AE=E5=BA=93?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B=EF=BC=8C=E8=A7=A3=E5=86=B3=20bug=20=E7=AD=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- apijson/CodeUtil.js | 23 +- apijson/JSONRequest.js | 6 +- apijson/JSONResponse.js | 61 +++-- apijson/StringUtil.js | 4 +- index.html | 35 +-- js/main.js | 518 +++++++++++++++++++++++++++------------- js/server.js | 2 +- 8 files changed, 425 insertions(+), 226 deletions(-) diff --git a/README.md b/README.md index ad186b5..1523203 100755 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ --- 敏捷开发最强大易用的 HTTP 接口工具,机器学习零代码测试、生成代码与静态检查、生成文档与光标悬浮注释。
    -集 文档、测试、Mock、调试、管理 于一体的一站式体验,还有一键 格式化、注释/取消注释 等高效易用的快捷键。
    +集合 文档、测试、Mock、调试、管理 的一站式体验,还有 **AI 问答** 和一键 格式化、注释/取消注释 等高效快捷键。
    在常用功能上远超 Postman, Swagger, YApi 等各种 开源、商业 的 API 文档/测试 工具,并能一键导入用例和文档。
    支持 GET, POST, PUT, PATCH, DELETE, HEAD 等各种 HTTP Method 及 Content-Type, URL /{Path}/{Variable}。
    不仅适用于 RESTful、类 RESTful、GRPC 的 API,还是腾讯 [APIJSON](https://github.com/Tencent/APIJSON) 官方建议的文档与测试工具。
    diff --git a/apijson/CodeUtil.js b/apijson/CodeUtil.js index 4a5a4ed..3190bab 100644 --- a/apijson/CodeUtil.js +++ b/apijson/CodeUtil.js @@ -54,7 +54,7 @@ var CodeUtil = { DATABASE_KINGBASE: 'KINGBASE', DATABASE_TIDB: 'TIDB', DATABASE_TDENGINE: 'TDENGINE', - DATABASE_NEBULA: 'NEBULA', + DATABASE_SURREALDB: 'SURREALDB', DATABASE_PRESTO: 'PRESTO', DATABASE_TRINO: 'TRINO', DATABASE_INFLUXDB: 'INFLUXDB', @@ -64,6 +64,13 @@ var CodeUtil = { DATABASE_KAFKA: 'KAFKA', DATABASE_MARIADB: 'MARIADB', DATABASE_HIVE: 'HIVE', + DATABASE_SNOWFLAKE: 'SNOWFLAKE', + DATABASE_DATABRICKS: 'DATABRICKS', + DATABASE_MILVUS: 'MILVUS', + DATABASE_IOTDB: 'IOTDB', + DATABASE_DUCKDB: 'DUCKDB', + DATABASE_CASSANDRA: 'CASSANDRA', + DATABASE_MONGODB: 'MONGODB', type: 'JSON', database: 'MYSQL', @@ -259,7 +266,7 @@ var CodeUtil = { } else { try { - value = JSON.parse(value) + value = parseJSON(value) } catch (e) { console.log(e) @@ -1839,7 +1846,7 @@ var CodeUtil = { return CodeUtil.parseCode(name, resObj, { onParseParentStart: function () { - return depth > 0 || StringUtil.isEmpty(name_, true) == false ? '' : CodeUtil.getBlank(depth) + varKey + ' ' + name + ' = JSON.parse(resultJson) \n'; + return depth > 0 || StringUtil.isEmpty(name_, true) == false ? '' : CodeUtil.getBlank(depth) + varKey + ' ' + name + ' = parseJSON(resultJson) \n'; }, onParseParentEnd: function () { @@ -2688,7 +2695,7 @@ res_data = rep.json() else if (format instanceof Array == false && format instanceof Object) { s += prefix2 + varName + '_json = json.loads(' + varName + ')' try { - var realObj = JSON.parse(real); + var realObj = parseJSON(real); var cs = CodeUtil.parsePythonResponseByStandard(varName + '_json', key, format, realObj, depth, isSmart, true, funDefs, funNames); if (StringUtil.isNotEmpty(cs, true)) { s += '\n' + padding + cs.trim(); @@ -2752,7 +2759,7 @@ res_data = rep.json() return CodeUtil.parseCode(name, resObj, { onParseParentStart: function () { - return depth > 0 || StringUtil.isEmpty(name_, true) == false ? '' : CodeUtil.getBlank(depth) + varKey + ' ' + name + ': object = JSON.parse(resultJson); \n'; + return depth > 0 || StringUtil.isEmpty(name_, true) == false ? '' : CodeUtil.getBlank(depth) + varKey + ' ' + name + ': object = parseJSON(resultJson); \n'; }, onParseParentEnd: function () { @@ -6222,7 +6229,7 @@ res_data = rep.json() OWNER: '拥有者', ADMIN: '管理员' }, - DATABASE_KEYS: ['MYSQL', 'POSTGRESQL', 'SQLSERVER', 'ORACLE', 'DB2', 'DAMENG', 'KINGBASE', 'MARIADB', 'SQLITE', 'INFLUXDB', 'TDENGINE', 'PRESTO', 'TRINO', 'HIVE', 'TIDB', 'CLICKHOUSE', 'ELASTICSEARCH', 'REDIS'], // , 'KAFKA'], + DATABASE_KEYS: ['MYSQL', 'POSTGRESQL', 'SQLSERVER', 'ORACLE', 'DB2', 'DAMENG', 'KINGBASE', 'MARIADB', 'SQLITE', 'INFLUXDB', 'TDENGINE', 'PRESTO', 'TRINO', 'HIVE', 'TIDB', 'CLICKHOUSE', 'ELASTICSEARCH', 'REDIS', 'IOTDB', 'SURREALDB', 'DUCKDB', 'CASSANDRA', 'MONGODB', 'SNOWFLAKE', 'DATABRICKS', 'MILVUS'], // , 'KAFKA'], getComment4Function: function (funCallStr, method, language) { if (typeof funCallStr != 'string') { @@ -6776,7 +6783,7 @@ res_data = rep.json() var typeOfValue = CodeUtil.getType4Request(value); var isValueNotArray = typeOfValue != 'array'; var isValueNotObject = typeOfValue != 'object'; - + if (standardObj != null) { var parentObj = pathKeys == null || pathKeys.length <= 0 ? null : JSONResponse.getStandardByPath(standardObj, pathKeys.slice(0, pathKeys.length - 1)); var targetValues = parentObj == null ? null : parentObj.values; @@ -7287,7 +7294,7 @@ res_data = rep.json() }, getType4Request: function (value) { - // return t != 'string' ? t : typeof JSON.parse(value); + // return t != 'string' ? t : typeof parseJSON(value); if (value instanceof Array) { return 'array' } diff --git a/apijson/JSONRequest.js b/apijson/JSONRequest.js index af43966..7f6c8ef 100644 --- a/apijson/JSONRequest.js +++ b/apijson/JSONRequest.js @@ -215,7 +215,7 @@ function format(json) { } try { - return JSON.stringify(JSON.parse(json), null, "\t"); + return JSON.stringify(parseJSON(json), null, "\t"); } catch(e) { log(TAG_REQUEST_UTIL, 'format try { ... } catch (err) { \n ' + e); return json; @@ -234,9 +234,9 @@ function format(json) { // var jsonObj; // if (typeof json == 'string'){ // try { - // jsonObj = JSON.parse(json); + // jsonObj = parseJSON(json); // } catch (err) { - // console.log('format try { jsonObj = JSON.parse(json); } catch (err) { \n ' + err); + // console.log('format try { jsonObj = parseJSON(json); } catch (err) { \n ' + err); // return json; // } // } diff --git a/apijson/JSONResponse.js b/apijson/JSONResponse.js index 912225f..065396f 100644 --- a/apijson/JSONResponse.js +++ b/apijson/JSONResponse.js @@ -531,8 +531,9 @@ var JSONResponse = { 3-对象缺少字段/整数变小数,黄色; 4-code/值类型 改变,红色; */ - compareResponse: function(res, target, real, folder, isMachineLearning, codeName, exceptKeys, ignoreTrend) { - var tStatus = (target || {}).status || 200; + compareResponse: function(res, target, real, folder, isMachineLearning, codeName, exceptKeys, ignoreTrend, noBizCode) { + target = target || {} + var tStatus = target.status || 200; var rStatus = (res || {}).status; if (rStatus != null && rStatus != tStatus) { return { @@ -542,8 +543,8 @@ var JSONResponse = { } } codeName = StringUtil.isEmpty(codeName, true) ? JSONResponse.KEY_CODE : codeName; - var tCode = (target || {})[codeName]; - var rCode = (real || {})[codeName]; + var tCode = (isMachineLearning != true && noBizCode) ? 0 : (target || {})[codeName]; + var rCode = noBizCode ? tCode : (real || {})[codeName]; //解决了弹窗提示机器学习更新标准异常,但导致所有项测试结果都变成状态码 code 改变 // if (real == null) { @@ -587,7 +588,7 @@ var JSONResponse = { } var tThrw = target.throw; - var rThrw = real.throw; + var rThrw = noBizCode ? tThrw : real.throw; var exceptions = target.exceptions || []; if (rCode != tCode || rThrw != tThrw) { @@ -620,11 +621,12 @@ var JSONResponse = { }; } - delete target[codeName]; - delete real[codeName]; - - delete target.throw; - delete real.throw; + if (noBizCode != true) { + delete target[codeName]; + delete real[codeName]; + delete target.throw; + delete real.throw; + } //可能提示语变化,也要提示 // delete target.msg; @@ -636,11 +638,14 @@ var JSONResponse = { ? JSONResponse.compareWithStandard(target, real, folder, exceptKeys, ignoreTrend) : JSONResponse.compareWithBefore(target, real, folder, exceptKeys); } finally { - target[codeName] = tCode; - real[codeName] = rCode; - - target.throw = tThrw; - real.throw = rThrw; + if (isMachineLearning || noBizCode != true) { + target[codeName] = tCode; + } + if (noBizCode != true) { + real[codeName] = rCode; + target.throw = tThrw; + real.throw = rThrw; + } } if (exceptions.length > 0 && (target.repeat || 0) <= 0 && (result || {}).code < JSONResponse.COMPARE_VALUE_CHANGE) { @@ -824,7 +829,7 @@ var JSONResponse = { } if (right instanceof Object) { - var m = JSON.parse(JSON.stringify(left)); + var m = parseJSON(JSON.stringify(left)); for (var k in right) { m[k] = JSONResponse.deepMerge(m[k], right[k]); } @@ -921,8 +926,8 @@ var JSONResponse = { }; var realType = JSONResponse.getType(real); - if (type != realType && (type != 'number' || realType != 'integer')) { //类型改变 - log('compareWithStandard type != getType(real) >> return COMPARE_TYPE_CHANGE'); + if (type != realType && type != 'undefined' && (type != 'number' || realType != 'integer')) { //类型改变 + log('compareWithStandard type != realType && type != undefined && (type != number || realType != integer) >> return COMPARE_TYPE_CHANGE'); max = { code: JSONResponse.COMPARE_TYPE_CHANGE, @@ -982,7 +987,7 @@ var JSONResponse = { } log('compareWithStandard for tk = ' + tk + ' >> '); - each = JSONResponse.compareWithStandard(firstVal[tk], real[tk], JSONResponse.getAbstractPath(folder, tk), exceptKeys); + each = JSONResponse.compareWithStandard(firstVal[tk], real[tk], JSONResponse.getAbstractPath(folder, tk), exceptKeys); if (max.code < each.code) { max = each; } @@ -1031,7 +1036,7 @@ var JSONResponse = { } else if (format instanceof Array == false && format instanceof Object) { try { - var realObj = JSON.parse(real); + var realObj = parseJSON(real); var result = JSONResponse.compareWithStandard(format, realObj, folder, exceptKeys, ignoreTrend); if (guess == true) { result.code -= 1; @@ -1257,7 +1262,7 @@ var JSONResponse = { }, - updateFullStandard: function (standard, currentResponse, isML) { + updateFullStandard: function (standard, currentResponse, isML, noBizCode) { if (currentResponse == null) { return standard; } @@ -1271,7 +1276,7 @@ var JSONResponse = { var msg = currentResponse.msg; var hasCode = standard.code != null; - var isCodeChange = standard.code != code; + var isCodeChange = noBizCode != true && standard.code != code; var exceptions = standard.exceptions || []; delete currentResponse.code; //code必须一致 @@ -1295,8 +1300,14 @@ var JSONResponse = { var stddObj = isML ? (isCodeChange && hasCode ? standard : JSONResponse.updateStandard(standard, currentResponse)) : {}; - currentResponse.code = code; - currentResponse.throw = thrw; +// if (noBizCode != true) { + currentResponse.code = code; + currentResponse.throw = thrw; +// } + + if (hasCode || isML) { + stddObj.code = code || 0; + } if (isCodeChange) { if (hasCode != true) { // 走正常分支 @@ -1590,7 +1601,7 @@ var JSONResponse = { } catch (e) { log(e) try { - var realObj = JSON.parse(real); + var realObj = parseJSON(real); var format2 = JSONResponse.updateStandard(target.format, realObj, exceptKeys, ignoreTrend, key); if (format2 != null) { target.format = format2; diff --git a/apijson/StringUtil.js b/apijson/StringUtil.js index 7d13d60..dfe8f0d 100644 --- a/apijson/StringUtil.js +++ b/apijson/StringUtil.js @@ -24,7 +24,7 @@ var StringUtil = { * @return */ get: function(s) { - return s == null ? '' : s; + return s == null ? '' : (JSONResponse.isString(s) ? s : JSON.stringify(s)); }, /**获取去掉前后空格后的string,为null则返回'' @@ -32,7 +32,7 @@ var StringUtil = { * @return */ trim: function(s) { - return s == null ? '' : s.trim(); + return StringUtil.get(s).trim(); }, /**获取去掉所有空格后的string,为null则返回'' diff --git a/index.html b/index.html index 17d4e56..caf4e3a 100755 --- a/index.html +++ b/index.html @@ -203,7 +203,7 @@
  • - +
    • - {{ isCaseGroupEditable ? '' : item.Chain.groupName }}{{' (' + (item.Chain.count - 1) + ') '}} + {{ isCaseGroupEditable ? '' : item.Chain.groupName }}{{' (' + (item.Chain.count - 1) + ') '}} @@ -256,7 +256,7 @@
      - +
      • @@ -743,14 +743,18 @@
        -
        - - - - - 每页 - - +
        + + + + + + 每页 + + + + +