(function () {
const DEBUG = false // true
const IS_NODE = typeof window == 'undefined'
const IS_BROWSER = typeof window == 'object'
if (IS_NODE) { // 解决在 Node 环境下缺少相关变量/常量/函数导致报错
try {
eval(`
var alert = function(msg) {console.log('alert: ' + msg)};
// var console = {log: function(msg) {}};
var vUrl = {value: 'http://localhost:8080/get'};
var vUrlComment = {value: ''};
var vTransfer = {value: '', disabled: false};
var vType = {value: 'JSON'};
var vSend = {value: '', disabled: false};
var vInput = {value: ''};
var vWarning = {value: ''};
var vComment = {value: ''};
var vHeader = {value: ''};
var vRandom = {value: ''};
var vScript = {value: ''};
var vOutput = {value: ''};
var vAccount = {value: ''};
var vPassword = {value: ''};
var vVerify = {value: ''};
var vRemember = {checked: true}
var vRequestMarkdown = {value: ''};
var vMarkdown = {value: ''};
var vPage = {value: '0'};
var vCount = {value: '100'};
var vSearch = {value: ''};
var vTestCasePage = {value: '0'};
var vTestCaseCount = {value: '100'};
var vTestCaseSearch = {value: ''};
var vRandomPage = {value: '0'};
var vRandomCount = {value: '100'};
var vRandomSearch = {value: ''};
var vRandomSubPage = {value: '0'};
var vRandomSubCount = {value: '100'};
var vRandomSubSearch = {value: ''};
var Vue = require('./vue.min'); // 某些版本不兼容 require('vue');
var StringUtil = require('../apijson/StringUtil');
var CodeUtil = require('../apijson/CodeUtil');
var JSONObject = require('../apijson/JSONObject');
var JSONResponse = require('../apijson/JSONResponse');
var JSONRequest0 = require('../apijson/JSONRequest');
var JSONRequest = JSONRequest0.JSONRequest; // require('../apijson/JSONRequest');
var toFormData = JSONRequest0.toFormData;
var parseJSON = JSONRequest0.parseJSON;
var encode = JSONRequest0.encode;
var localforage = require('./localforage.min');
var clipboard = require('./clipboard.min');
var jsonlint = require('./jsonlint');
var JSON5 = require('json5');
// var window = {};
// var $ = require('./jquery').jQuery;
// var $ = {
// isEmptyObject: function (obj) {
// return obj == null || Object.keys(obj).length <= 0;
// }
// };
// var LocalStorage = require('node-localstorage').LocalStorage;
// var localStorage = new LocalStorage('./scratch');
var localStorage = {
getItem: function (key) {},
setItem: function (key, value) {}
}
// var difflib = require('./difflib');
// var diffview = require('./diffview');
// var editor = require('./editor');
// var FileSaver = require('./FileSaver');
// var helper = require('./helper');
// var jquery = require('./jquery');
// var jsonlint = require('./jsonlint');
// var parse = require('./parse');
// var uuid = require('./uuid');
var axios = require('axios');
var editormd = null;
import { PageAgent } from 'page-agent'
import { PageAgentCoreConfig } from "@page-agent/core";
`)
} catch (e) {
console.log(e)
}
}
function log(msg) {
if (DEBUG) {
console.log(msg)
}
}
Vue.component('vue-item', {
props: ['jsondata', 'theme', 'thiz'],
template: '#item-template'
})
Vue.component('vue-outer', {
props: ['jsondata', 'isend', 'thiz', 'path', 'theme'],
template: '#outer-template'
})
Vue.component('vue-expand', {
props: [],
template: '#expand-template'
})
Vue.component('vue-val', {
props: ['field', 'val', 'isend', 'thiz', '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) {
// 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 cPath = (StringUtil.isEmpty(path, false) ? '' : path + '/') + key;
var vi = val[i]
if (JSONResponse.isObject(vi) && JSONObject.isTableKey(firstKey || '', vi, isRestful)) {
// var newVal = parseJSON(JSON.stringify(val[i]))
if (vi == null) {
continue
}
var curPath = cPath + '/' + i;
var curTable = firstKey;
var thiz = {
_$_path_$_: curPath,
_$_table_$_: curTable
};
var newVal = {};
for (var k in vi) {
newVal[k] = vi[k]; //提升性能
if (App.isFullAssert) {
try {
var cri = App.currentRemoteItem || {};
var tr = cri.TestRecord || {};
var d = cri.Document || {};
var standard = App.isMLEnabled ? tr.standard : tr.response;
var standardObj = StringUtil.isEmpty(standard, true) ? null : parseJSON(standard);
var curAccount = App.getCurrentAccount() || {}
var accountIdStr = String(curAccount.isLoggedIn ? curAccount.id || '' : '')
var tests = App.tests[accountIdStr] || {};
var responseObj = (tests[d.id] || {})[0]
var pathUri = (StringUtil.isEmpty(curPath, false) ? '' : curPath + '/') + k;
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, 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]
}
}
else {
this.onRenderJSONItem(vi, '' + i, cPath);
}
// this.$children[i]._$_this_$_ = key
// alert('this.$children[i]._$_this_$_ = ' + this.$children[i]._$_this_$_)
}
}
else if (val instanceof Object) {
var aliaIndex = key == null ? -1 : key.indexOf(':');
var objName = aliaIndex < 0 ? key : key.substring(0, aliaIndex);
// var newVal = parseJSON(JSON.stringify(val))
var curPath = (StringUtil.isEmpty(path, false) ? '' : path + '/') + key;
var curTable = JSONObject.isTableKey(objName, val, isRestful) ? objName : null;
var thiz = {
_$_path_$_: curPath,
_$_table_$_: curTable
};
var newVal = {};
for (var k in val) {
newVal[k] = val[k]; //提升性能
if (App.isFullAssert) {
try {
var cri = App.currentRemoteItem || {};
var tr = cri.TestRecord || {};
var d = cri.Document || {};
var standard = App.isMLEnabled ? tr.standard : tr.response;
var standardObj = StringUtil.isEmpty(standard, true) ? null : parseJSON(standard);
var curAccount = App.getCurrentAccount() || {}
var accountIdStr = String(curAccount.isLoggedIn ? curAccount.id || '' : '')
var tests = App.tests[accountIdStr] || {};
var responseObj = (tests[d.id] || {})[0]
var pathUri = (StringUtil.isEmpty(curPath, false) ? '' : curPath + '/') + k;
var pathKeys = StringUtil.split(pathUri, '/');
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, 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 val[k];
}
val._$_this_$_ = JSON.stringify(thiz)
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) {
if (DEBUG) {
alert('onRenderJSONItem try { ... } catch (e) {\n' + e.message)
} else {
console.log(e)
}
}
return true
}
/**显示 Response JSON 的注释
* @author TommyLemon
* @param val
* @param key
* @param $event
*/
Vue.prototype.setResponseHint = function (val, key, $event, isAssert, color, isDynamic) {
console.log('setResponseHint')
var responseKey = this.$refs.responseKey
if (responseKey == null) {
return
}
if (! isDynamic) {
CodeUtil.tableList = (docObj || {})['[]'] || CodeUtil.tableList;
}
responseKey.setAttribute('data-hint', isSingle ? '' : this.getResponseHint(val, key, $event, isAssert, color, isDynamic));
}
/**获取 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, isAssert, color, isDynamic) {
// alert('setResponseHint key = ' + key + '; val = ' + JSON.stringify(val))
var vue = this;
var s = ''
try {
var standardObj = null;
try {
var currentItem = App.isTestCaseShow ? App.remotes[App.currentDocIndex] : App.currentRemoteItem;
standardObj = parseJSON(((currentItem || {}).TestRecord || {}).standard);
} catch (e3) {
log(e3)
}
var path = null
var schema = App.schema
var table = null
var column = null
var isWarning = null
var isAPIJSONRouter = null;
var search = App.search;
var method = App.isTestCaseShow ? ((App.currentRemoteItem || {}).Document || {}).url : App.getMethod();
var isRestful = ! JSONObject.isAPIJSONPath(method);
var tableList = CodeUtil.tableList || (docObj || {})['[]']
var loaded = false;
var possibleColumns = [];
var possibleTables = [];
function loadColumnIfNeed(c, isWarning, column, table, schema, pathKeys) {
if (isRestful && StringUtil.isEmpty(c, true) && ! (loaded || isDynamic || isWarning)) { // || val instanceof Object)) {
loaded = true;
if (possibleColumns == null || possibleColumns.length <= 0) {
possibleColumns = [column, key]
}
if (possibleTables == null || possibleTables.length <= 0) {
possibleTables = CodeUtil.extractTableNames(pathKeys == null || pathKeys.length <= 1 ? null : pathKeys.slice(0, -1)) || [table];
}
App.lastTarget = $event.target
setTimeout(function () {
if ($event.target != App.lastTarget) {
vue.setResponseHint(val, key, $event, isAssert, color, true)
return
}
App.loadColumnDoc(possibleColumns, possibleTables, schema, App.database, function (d, url, res, err) {
var data = res == null ? null : res.data;
var list = data == null ? null : data['[]']
if ((list != null && list.length > 0) || $event.target != App.lastTarget || possibleTables == null || possibleTables.length <= 0) {
vue.setResponseHint(val, key, $event, isAssert, color, true)
return
}
App.loadColumnDoc(possibleColumns, null, schema, App.database, function (d, url, res, err) {
vue.setResponseHint(val, key, $event, isAssert, color, true)
})
})
}, 1000)
return '...'
}
return c
}
var parent = ($event.target || {}).parentElement || {}
parent = parent.parentElement || parent || {}
var valString = parent.textContent || ''
// alert('valString = ' + valString)
var i = valString.indexOf('"_$_this_$_":')
if (i >= 0) {
valString = valString.substring(i + '"_$_this_$_":'.length)
i = valString.indexOf('}"')
var i2 = valString.indexOf('"{')
if (i >= 0 && i2 >= 0 && i2 < i) {
valString = valString.substring(i2 + 1, i + 1)
// alert('valString = ' + valString)
var _$_this_$_ = parseJSON(valString)
path = _$_this_$_ == null ? null : _$_this_$_._$_path_$_
table = _$_this_$_ == null ? null : _$_this_$_._$_table_$_
}
if (val instanceof Object && (val instanceof Array == false)) {
var aliaIndex = key == null ? -1 : key.indexOf(':');
var objName = aliaIndex < 0 ? key : key.substring(0, aliaIndex);
if (JSONObject.isTableKey(objName, val, isRestful)) {
table = objName
schema = val['@schema'] || schema
} else if (JSONObject.isTableKey(table, val, isRestful)) {
column = key
schema = val['@schema'] || schema
}
// alert('path = ' + path + '; table = ' + table + '; column = ' + column)
}
else 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 tblObj = val[0]
schema = (tblObj instanceof Object && ! Array.isArray(tblObj) ? tblObj['@schema'] : null) || schema
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 pathKeys = StringUtil.splitPath(pathUri)
var c = CodeUtil.getCommentFromDoc(tableList, schema, isDynamic ? null : table, column, method
, App.database, App.language, true, false, pathKeys, isRestful, val, true, standardObj, isWarning
, isAPIJSONRouter, search, null, isDynamic ? true : null, function (callbackColumns, callbackTables) {
possibleColumns = callbackColumns;
possibleTables = callbackTables;
}, isDynamic
); // this.getResponseHint({}, table, $event
c = loadColumnIfNeed(c, isWarning, column, table, schema, pathKeys)
s0 = column + (StringUtil.isEmpty(c, true) ? '' : ': ' + c)
}
var pathUri = (StringUtil.isEmpty(path) ? '' : path + '/') + (StringUtil.isEmpty(column) ? key : column);
var pathKeys = StringUtil.splitPath(pathUri)
var c;
if (isAssert) {
try {
var tr = App.currentRemoteItem.TestRecord || {};
var d = App.currentRemoteItem.Document || {};
var standard = App.isMLEnabled ? tr.standard : tr.response;
var standardObj = StringUtil.isEmpty(standard, true) ? null : parseJSON(standard);
var curAccount = App.getCurrentAccount() || {}
var accountIdStr = String(curAccount.isLoggedIn ? curAccount.id || '' : '')
var tests = App.tests[accountIdStr] || {};
var responseObj = (tests[d.id] || {})[0]
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);
// cmp.path = pathUri;
return JSONResponse.getCompareShowObj(cmp);
} catch (e) {
s += '\n' + e.message
}
} else {
c = CodeUtil.getCommentFromDoc(tableList, schema, isDynamic ? null : table, isRestful ? key : null, method
, App.database, App.language, true, false, pathKeys, isRestful, val, true, standardObj, isWarning, isAPIJSONRouter, search
, null, isDynamic ? true : null, function (callbackColumns, callbackTables) {
possibleColumns = callbackColumns;
possibleTables = callbackTables;
}, isDynamic
);
c = loadColumnIfNeed(c, isWarning, column, table, schema, pathKeys)
}
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 pathKeys = StringUtil.splitPath(pathUri);
var c;
if (isAssert) {
try {
var tr = App.currentRemoteItem.TestRecord || {};
var d = App.currentRemoteItem.Document || {};
var standard = App.isMLEnabled ? tr.standard : tr.response;
var standardObj = StringUtil.isEmpty(standard, true) ? null : parseJSON(standard);
var curAccount = App.getCurrentAccount() || {}
var accountIdStr = String(curAccount.isLoggedIn ? curAccount.id || '' : '')
var tests = App.tests[accountIdStr] || {};
var responseObj = (tests[d.id] || {})[0]
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);
// cmp.path = pathUri;
return JSONResponse.getCompareShowObj(cmp);
} catch (e) {
s += '\n' + e.message
}
} else {
c = CodeUtil.getCommentFromDoc(tableList, schema, isDynamic ? null : table, isRestful ? key : column, method
, App.database, App.language, true, false, pathKeys, isRestful, val, true, standardObj, isWarning, isAPIJSONRouter, search
, null, isDynamic ? true : null, function (callbackColumns, callbackTables) {
possibleColumns = callbackColumns;
possibleTables = callbackTables;
}, isDynamic
);
c = loadColumnIfNeed(c, isWarning, column, table, schema, pathKeys)
}
s += pathUri + (StringUtil.isEmpty(c, true) ? '' : ': ' + c)
}
catch (e) {
s += '\n' + e.message
}
return s;
},
/**显示 Response JSON 的注释
* @author TommyLemon
* @param val
* @param key
* @param $event
*/
Vue.prototype.setResponseCounts = function (val, key, $event, isAssert) {
console.log('setResponseCounts')
this.$refs.responseGreenAssert.setAttribute('data-content', isSingle ? '' : this.getResponseGreenCount(val, key, $event));
this.$refs.responseBlueAssert.setAttribute('data-content', isSingle ? '' : this.getResponseBlueCount(val, key, $event));
this.$refs.responseOrangeAssert.setAttribute('data-content', isSingle ? '' : this.getResponseOrangeCount(val, key, $event));
this.$refs.responseRedAssert.setAttribute('data-content', isSingle ? '' : this.getResponseRedCount(val, key, $event));
},
/**获取 Response 断言失败 的数量
* @author TommyLemon
* @param val
* @param key
* @param $event
*/
Vue.prototype.setResponseAllCount = function (val, key, $event) {
return this.setResponseHint(val, key, $event, true, 'all')
},
/**获取 Response 断言失败 的数量
* @author TommyLemon
* @param val
* @param key
* @param $event
*/
Vue.prototype.getResponseAllCount = function (val, key, $event) {
return this.getResponseGreenCount(val, key, $event) + this.getResponseBlueCount(val, key, $event) + this.getResponseOrangeCount(val, key, $event) + this.getResponseRedCount(val, key, $event);
},
Vue.prototype.setResponseColorCount = function (val, key, $event) {
console.log('setResponseColorCount')
var assert = isSingle ? null : this.getResponseHint(val, key, $event, true, 'all')
var responseAssert = $event.target; // this.$refs.responseAssert
// responseAssert.innerText = (StringUtil.trim(assert.count) || '1');
// $(responseAssert).attr('data-hint', assert == null ? '' : StringUtil.trim(assert.hintMessage));
// responseAssert.setAttribute('data-content', assert == null ? '' : (StringUtil.trim(assert.count) || '1'));
responseAssert.setAttribute('data-hint', assert == null ? '' : StringUtil.trim(assert.compareMessage));
// $(responseAssert).attr('background', assert == null ? '' : assert.compareColor);
// $(responseAssert).attr('visibility', assert == null || assert.code == 0 ? 'hidden' : 'show');
},
Vue.prototype.setResponseCount = function (val, key, $event, color) {
console.log('setResponseCount')
// var count = isSingle ? 0 : this.getResponseCount(val, key, $event, color)
var assert = isSingle ? null : this.getResponseHint(val, key, $event, true, 'all')
var responseAssert = $event.target; // this.$refs['response' + StringUtil.firstCase(color, true) + 'Assert']
// responseAssert.innerText = (StringUtil.trim(assert.count) || '1');
$(responseAssert).attr('data-hint', assert == null ? '' : StringUtil.trim(assert.compareMessage));
// responseAssert.setAttribute('data-content', assert == null ? '' : (StringUtil.trim(assert.count) || '1'));
// responseAssert.setAttribute('data-hint', assert == null ? '' : StringUtil.trim(assert.hintMessage));
// $(responseAssert).attr('background', assert == null ? '' : assert.compareColor);
// $(responseAssert).attr('visibility', assert == null || assert.code == 0 ? 'hidden' : 'show');
},
Vue.prototype.getResponseCount = function (val, key, $event, color) {
return this.getResponseHint(val, key, $event, true, color)
},
Vue.prototype.setResponseGreenCount = function (val, key, $event, isAssert) {
this.setResponseCount(val, key, $event, 'green')
},
Vue.prototype.getResponseGreenCount = function (val, key, $event) {
return this.getResponseHint(val, key, $event, true, 'green')
},
Vue.prototype.setResponseBlueCount = function (val, key, $event, isAssert) {
this.setResponseCount(val, key, $event, 'blue')
},
Vue.prototype.getResponseBlueCount = function (val, key, $event) {
return this.getResponseHint(val, key, $event, true, 'blue')
},
Vue.prototype.setResponseOrangeCount = function (val, key, $event, isAssert) {
this.setResponseCount(val, key, $event, 'orange')
},
Vue.prototype.getResponseOrangeCount = function (val, key, $event) {
return this.getResponseHint(val, key, $event, true, 'orange')
},
Vue.prototype.setResponseRedCount = function (val, key, $event, isAssert) {
this.setResponseCount(val, key, $event, 'red')
},
Vue.prototype.getResponseRedCount = function (val, key, $event) {
return this.getResponseHint(val, key, $event, true, 'red')
}
}
})
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 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
var ERR_MSG = `出现了一些问题,可以按照以下步骤解决:
1.检查网络连接是否畅通,可用浏览器打开右侧地址: https://www.baidu.com/s?wd=%22APIJSON%22
2.检查 URL 是否为一个可用的 域名/IPV4 地址,可用浏览器打开试试:正常返回结果 或 非 GET 请求返回 Whitelabel Error Page,一般都没问题
3.开启或关闭 右上方 设置>托管服务器代理,然后再试:如果开启后才通应该是 CORS 跨域问题;关闭后才通应该是用外网服务代理来访问内网导致,可退出登录后修改退关服务器地址为内网的 APIJSON 代理服务地址
4.Disable 关闭 VPN 等 电脑/手机/平板 上的网络代理软件 App 客户端,或者切换代理服务器地址,然后再试
5.按 Fn+F12 或 右键网页>Inspect 检查 查看 Network 接口调用信息和 Console 控制台日志
6.查看请求目标服务器上的日志,优先找异常报错内容
7.改用 Postman 等其它 HTTP API 接口工具测试同一个接口
8.再试一次
# 问题与解答大全(可截屏后 New issue 上报问题等待解答):
https://github.com/TommyLemon/APIAuto/issues
如果是请求 APIJSON 后端服务,则使用以下链接:
https://github.com/Tencent/APIJSON/issues
There may be something wrong, you can follow by the steps:
1. Check whether the network connection is available, you can open the address with a browser: https://www.google.com/search?q=%22APIJSON%22
2. Check whether the URL is an available domain name/IPV4 address, try opening it with a browser: if return the result normally or return a Whitelabel Error Page for a non-GET request, generally the URL is available
3. Turn it on or off at the top right, Settings>Server Proxy, and try again: If it is enabled, it should be a CORS cross-domain problem; and if it is turned off, it should be caused by using an external network service proxy to access the internet, You can log out and modify the logout server address to the APIJSON proxy service address of the internet
4. Disable the network proxy software App client on the computer/phone/tablet such as VPN, or switch the proxy server address, and then try again
5. Press Fn+F12 or right-click the webpage>Inspect to view the Network interface call information and Console console log
6. Check the log on the request target server, and give priority to find the abnormal error content
7. Use other HTTP API tools such as Postman to test the same interface
8. Try again
# Questions and answers (you can report the problem after taking a screenshot and wait for the answer):
https://github.com/TommyLemon/APIAuto/issues
If you are requesting an APIJSON backend service, use the following link:
https://github.com/Tencent/APIJSON/issues
`;
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 = parseJSON(v)
}
catch (e) {
console.log(e)
}
}
theRequest[part.substring(0, ind)] = v;
}
return theRequest;
}
function markdownToHTML(md, isRequest) {
if (typeof editormd == 'undefined' || 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 application/x-www-form-urlencoded
var REQUEST_TYPE_DATA = 'DATA' // POST multipart/form-data
var REQUEST_TYPE_JSON = 'JSON' // POST application/json
var REQUEST_TYPE_GRPC = 'GRPC' // POST application/json
var REQUEST_TYPE_PLAIN = 'TEXT' // text/plain
var REQUEST_TYPE_TXML = 'TXML' // text/xml
var REQUEST_TYPE_AXML = 'AXML' // application/xml
var REQUEST_TYPE_HTML = 'HTML' // text/html
var REQUEST_TYPE_XHTML = 'XHTML' // application/xhtml+xml
var HTTP_METHOD_GET = 'GET' // GET ?a=1&b=c&key=value
var HTTP_METHOD_POST = 'POST' // POST application/json
var HTTP_METHOD_PUT = 'PUT' // PUT
var HTTP_METHOD_PATCH = 'PATCH' // PATCH
var HTTP_METHOD_DELETE = 'DELETE' // DELETE
var HTTP_METHOD_HEAD = 'HEAD' // HEAD
var HTTP_METHOD_OPTIONS = 'OPTIONS' // OPTIONS
var HTTP_METHOD_TRACE = 'TRACE' // TRACE
var HTTP_METHODS = [HTTP_METHOD_GET, HTTP_METHOD_POST, HTTP_METHOD_PUT, HTTP_METHOD_PATCH, HTTP_METHOD_DELETE, HTTP_METHOD_HEAD, HTTP_METHOD_OPTIONS, HTTP_METHOD_TRACE]
var HTTP_POST_TYPES = [HTTP_METHOD_POST, REQUEST_TYPE_JSON, REQUEST_TYPE_FORM, REQUEST_TYPE_DATA, REQUEST_TYPE_GRPC]
var HTTP_URL_ARG_TYPES = [HTTP_METHOD_GET, REQUEST_TYPE_PARAM, REQUEST_TYPE_FORM]
var HTTP_JSON_TYPES = [HTTP_METHOD_POST, REQUEST_TYPE_JSON, REQUEST_TYPE_GRPC]
var HTTP_FORM_TYPES = [REQUEST_TYPE_FORM, HTTP_METHOD_PUT, HTTP_METHOD_DELETE]
var HTTP_DATA_TYPES = [REQUEST_TYPE_DATA, HTTP_METHOD_PUT, HTTP_METHOD_DELETE]
var HTTP_FORM_DATA_TYPES = [REQUEST_TYPE_DATA, HTTP_METHOD_PUT, HTTP_METHOD_DELETE]
var HTTP_CONTENT_TYPES = [REQUEST_TYPE_PARAM, REQUEST_TYPE_FORM, REQUEST_TYPE_DATA, REQUEST_TYPE_JSON, REQUEST_TYPE_GRPC, REQUEST_TYPE_PLAIN, REQUEST_TYPE_TXML, REQUEST_TYPE_AXML, REQUEST_TYPE_HTML, REQUEST_TYPE_XHTML]
var CONTENT_TYPE_MAP = {
// 'PARAM': 'text/plain',
'FORM': 'application/x-www-form-urlencoded',
'DATA': 'multipart/form-data',
'JSON': 'application/json',
'GRPC': 'application/json',
'TEXT': 'text/plain',
'TXML': 'text/xml',
'AXML': 'application/xml',
'HTML': 'text/html',
'XHTML': 'application/xhtml+xml',
}
var CONTENT_VALUE_TYPE_MAP = {
'application/x-www-form-urlencoded': 'FORM',
'multipart/form-data': 'DATA',
'application/json': 'JSON',
'text/plain': 'TEXT',
'text/xml': 'TXML',
'application/xml': 'AXML',
'text/html': 'HTML',
'application/xhtml+xml': 'XHTML',
}
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 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 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')
var CUR_DATA = 'CUR_DATA' // CUR_DATA('[]/0/User/id')
var CTX_PUT = 'CTX_PUT' // CTX_PUT('key', val)
function get4Path(obj, path, defaultVal, msg, isDesc) {
var val = path == null || path === '' ? obj : JSONResponse.getValByPath(obj, StringUtil.split(path, '/'), true, isDesc)
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 DB_SELECT = 'DB_SELECT'
// var DB_COUNT = 'DB_COUNT'
var DB_INSERT = 'DB_INSERT'
var DB_UPDATE = 'DB_UPDATE'
var DB_DELETE = 'DB_DELETE'
var DB_API_MAP = {
[DB_SELECT]: '/get',
// [DB_COUNT]: '/head',
[DB_INSERT]: '/post',
[DB_UPDATE]: '/put',
[DB_DELETE]: '/delete'
}
var HTTP_GET = 'HTTP_GET'
var HTTP_POST = 'HTTP_POST'
var HTTP_PUT = 'HTTP_PUT'
var HTTP_PATCH = 'HTTP_PATCH'
var HTTP_DELETE = 'HTTP_DELETE'
var HTTP_HEAD = 'HTTP_HEAD'
var HTTP_METHOD_MAP = {
[HTTP_GET]: HTTP_METHOD_GET,
[HTTP_POST]: HTTP_METHOD_POST,
[HTTP_PUT]: HTTP_METHOD_PUT,
[HTTP_PATCH]: HTTP_METHOD_PATCH,
[HTTP_DELETE]: HTTP_METHOD_DELETE,
[HTTP_HEAD]: HTTP_METHOD_HEAD
}
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 RANDOM_BAD = 'RANDOM_BAD'
var RANDOM_BAD_BOOL = 'RANDOM_BAD_BOOL'
var RANDOM_BAD_NUM = 'RANDOM_BAD_NUM'
var RANDOM_BAD_STR = 'RANDOM_BAD_STR'
var RANDOM_BAD_IN = 'RANDOM_BAD_IN'
var RANDOM_BAD_ARR = 'RANDOM_BAD_ARR'
var RANDOM_BAD_OBJ = 'RANDOM_BAD_OBJ'
var ORDER_DB = 'ORDER_DB'
var ORDER_IN = 'ORDER_IN'
var ORDER_INT = 'ORDER_INT'
var ORDER_BAD = 'ORDER_BAD'
var ORDER_BAD_BOOL = 'ORDER_BAD_BOOL'
var ORDER_BAD_NUM = 'ORDER_BAD_NUM'
var ORDER_BAD_STR = 'ORDER_BAD_STR'
var ORDER_BAD_IN = 'ORDER_BAD_IN'
var ORDER_BAD_ARR = 'ORDER_BAD_ARR'
var ORDER_BAD_OBJ = 'ORDER_BAD_OBJ'
var ORDER_MAP = {}
var BAD_BOOLS = [null, undefined, false, true, -1, 0, 1, 2, 3.14, 'null', 'undefined', 'None', 'nil', 'false', 'true',
'-1', '0', '1', '2', '3.14', '', ' ', '\\t', '\\r', '\\n', '\\a', '\\b', '\\v', '\\f', 'a', 'dY', [], {}, '[]', '{}']
var BAD_NUMS = BAD_BOOLS.concat([
-2049, -1025, -13, 13, 1025, 2049, Number.NaN, Number.POSITIVE_INFINITY, Number.NEGATIVE_INFINITY, Number.MIN_SAFE_INTEGER,
Number.MAX_SAFE_INTEGER, Number.MIN_SAFE_INTEGER - 1, Number.MAX_SAFE_INTEGER + 1,
'-2049', '-1025', '-13', '13', '1025', '2049', 'Number.NaN', 'Number.POSITIVE_INFINITY', 'Number.NEGATIVE_INFINITY',
'Number.MIN_SAFE_INTEGER', 'Number.MAX_SAFE_INTEGER', '' + Number.MIN_SAFE_INTEGER, '' + Number.MAX_SAFE_INTEGER
])
var BAD_STRS = BAD_NUMS.concat([
'`', '~', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '-', '_', '=', '+', '[', ']', '{', '}', ';', ':',
"'", '\\"', ',', '.', '<', '>', '/', '?', '\\t\\r\\n\\a\\b\\v\\f', '`~!@#$%^&*()-_=+[]{};:\'\\",.<>/?',
'qwertyuiopasdfghjklzxcvbnm', 'MNBVCZLKJHGFDSAPOIUYTREWQ', 'ä½ å¥½', 'ÄãºÃ', '浣犲ソ', '�����',
'鐢辨湀瑕佸ソ濂藉涔犲ぉ澶╁悜涓?', '����Ҫ�¨²�ѧϰ������', '由月è¦�好好å¦ä¹ 天天å�‘上', 'ÓÉÔÂÒªºÃºÃѧϰÌìÌìÏòÉÏ',
'由月要好好学习天天向??', '锟斤拷锟斤拷要锟矫猴拷学习锟斤拷锟斤拷锟斤拷'
])
// FIXME 打开时直接卡死崩溃
var sl = Math.min(10, Math.floor(BAD_STRS.length/5))
for (var i = 0; i < sl; i ++) {
var v = BAD_STRS[i]
for (var j = 0; j < sl; j ++) {
BAD_STRS.push(v + BAD_STRS[j])
}
}
var sl2 = Math.min(5, Math.floor(sl/5))
for (var i = 0; i < sl2; i ++) {
var v = BAD_STRS[i]
for (var j = 0; j < sl2; j ++) {
var v2 = v + BAD_STRS[j]
for (var k = 0; k < sl2; k ++) {
BAD_STRS.push(v2 + BAD_STRS[k])
}
}
}
var BAD_ARRS = []
for (var i = 0; i < BAD_STRS.length; i ++) {
BAD_ARRS.push([BAD_STRS[i]])
}
// FIXME 打开时直接卡死崩溃
var al = Math.min(10, Math.floor(BAD_STRS.length/5))
for (var i = 0; i < al; i ++) {
var v = BAD_STRS[i]
for (var j = 0; j < al; j ++) {
BAD_ARRS.push([v, BAD_STRS[j]])
}
}
var al2 = Math.min(3, Math.floor(al/5))
for (var i = 0; i < al2; i ++) {
var v = BAD_STRS[i]
for (var j = 0; j < al2; j ++) {
var v2 = BAD_STRS[j]
for (var k = 0; k < al2; k ++) {
BAD_ARRS.push([v, v2, BAD_STRS[k]])
}
}
}
var BAD_OBJS = []
var ol = Math.min(10, Math.floor(BAD_STRS.length/5))
for (var i = 10; i < ol; i ++) { // 太多就导致 RANDOM_BAD 基本每次随机出来都是对象
var k = BAD_STRS[i]
var key = k == undefined ? 'undefined' : (typeof k == 'string' ? k : JSON.stringify(k))
for (var j = 0; j < ol; j ++) {
BAD_OBJS.push({[key]: BAD_STRS[j]})
}
}
// FIXME 打开时直接卡死崩溃
for (var i = 0; i < ol; i ++) {
var k = BAD_STRS[i]
var key = k == undefined ? 'undefined' : (typeof k == 'string' ? k : JSON.stringify(k))
for (var j = 0; j < ol; j ++) {
var val = BAD_STRS[j]
for (var i2 = 0; i2 < ol; i2 ++) {
var k2 = BAD_STRS[i2]
var key2 = k2 == undefined ? 'undefined' : (typeof k2 == 'string' ? k2 : JSON.stringify(k))
for (var j2 = 0; j2 < ol; j2 ++) {
BAD_OBJS.push({[key]: val, [key2]: BAD_STRS[j2]})
}
}
}
}
// var ol = Math.min(10, Math.floor(BAD_OBJS.length/5))
// for (var i = 0; i < ol; i ++) {
// var v = BAD_OBJS[BAD_OBJS.length - i]
// for (var j = 0; j < ol; j ++) {
// BAD_OBJS.push(Object.assign(v, BAD_OBJS[BAD_OBJS.length - j]))
// }
// }
// var ol2 = Math.min(2, Math.floor(ol/5))
// for (var i = 0; i < ol2; i ++) {
// var v = BAD_OBJS[BAD_OBJS.length - i]
// for (var j = 0; j < ol2; j ++) {
// var v2 = Object.assign(v, BAD_OBJS[BAD_OBJS.length - j])
// for (var k = 0; k < ol2; k ++) {
// BAD_OBJS.push(Object.assign(v2, BAD_OBJS[BAD_OBJS.length - k]))
// }
// }
// }
var BADS = BAD_STRS.concat(BAD_ARRS).concat(BAD_OBJS)
var PRIME_INTS = [
1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97
, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199
, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293
, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397
, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499
, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599
, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691
, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797
, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887
, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997
, 1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, 1093, 1097
, 1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163, 1171, 1181, 1187, 1193
, 1201, 1213, 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291, 1297
, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399
, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499
, 1511, 1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583, 1597
, 1601, 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, 1669, 1693, 1697, 1699
, 1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789
, 1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889
, 1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987, 1993, 1997, 1999
]
function randomPrimeInt() {
return PRIME_INTS[randomInt(0, PRIME_INTS.length - 1)]
}
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 = 0 // 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 randomBad(defaultArgs, ...args) {
if (defaultArgs == null) {
defaultArgs = BADS
}
if (args == null || args.length <= 0) {
return defaultArgs[randomInt(0, defaultArgs.length - 1)]
}
args = []
for (var i = 0; i < defaultArgs.length; i++) {
args.push(defaultArgs[i])
}
return args[randomInt(0, args.length - 1)]
}
function randomBadBool(...args) {
return randomBad(BAD_BOOLS, args)
}
function randomBadNum(...args) {
return randomBad(BAD_NUMS, args)
}
function randomBadStr(...args) {
return randomBad(BAD_STRS, args)
}
function randomBadArr(...args) {
return randomBad(BAD_ARRS, args)
}
function randomBadObj(...args) {
return randomBad(BAD_OBJS, args)
}
function orderInt(desc, index, min, max) {
if (min == null) {
min = 0 // 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 - 1 - index : index];
}
function orderBad(defaultArgs, desc, index, ...args) {
// alert('orderIn index = ' + index + '; args = ' + JSON.stringify(args));
if (defaultArgs == null) {
defaultArgs = BADS
}
index = index || 0;
if (args == null || args.length <= 0) {
return defaultArgs[desc ? defaultArgs.length - index : index]
}
args = []
for (var i = 0; i < defaultArgs.length; i++) {
args.push(defaultArgs[i])
}
return args[desc ? args.length - index : index]
}
function orderBadBool(desc, index, ...args) {
return orderBad(BAD_BOOLS, desc, index, ...args)
}
function orderBadNum(desc, index, ...args) {
return orderBad(BAD_NUMS, desc, index, ...args)
}
function orderBadStr(desc, index, ...args) {
return orderBad(BAD_STRS, desc, index, ...args)
}
function orderBadArr(desc, index, ...args) {
return orderBad(BAD_ARRS, desc, index, ...args)
}
function orderBadObj(desc, index, ...args) {
return orderBad(BAD_OBJS, desc, index, ...args)
}
function getOrderIndex(randomId, line, argCount, step) {
// 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;
}
if (argCount == null) {
argCount = 0;
}
if (step == null) {
step = 1;
}
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, ' '));
return orderIndex;
}
//这些全局变量不能放在data中,否则会报undefined错误
var BREAK_ALL = 'BREAK_ALL'
var BREAK_LAST = 'BREAK_LAST'
var baseUrl
var inputted
var handler
var errHandler
var docObj
var doc
var output
var isSingle = true
var currentTarget = vInput;
var isInputValue = false;
var isClickSelectInput = false;
var selectionStart = 0;
var selectionEnd = 0;
function newDefaultScript() {
return { // index.html 中 v-model 绑定,不能为 null
case: {
0: {
pre: { // 可能有 id
script: '' // index.html 中 v-model 绑定,不能为 null
},
post: {
script: ''
}
},
1560244940013: {
pre: { // 可能有 id
script: '' // index.html 中 v-model 绑定,不能为 null
},
post: {
script: ''
}
}
},
account: {
0: {
pre: {
script: ''
},
post: {
script: ''
}
},
82001: {
pre: {
script: ''
},
post: {
script: ''
}
}
},
global: {
0: {
pre: {
script: ''
},
post: {
script: ''
}
}
}
}
}
// APIJSON >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
var App = {
el: '#app',
data: {
baseview: 'formater',
view: 'output',
jsoncon: JSON.stringify(initJson),
jsonhtml: initJson,
compressStr: '',
error: {},
requestVersion: 3,
requestCount: 1,
urlComment: '一对多关联查询。可粘贴浏览器/抓包工具/接口工具 的 Network/Header/Content 等请求信息,自动填充到界面,格式为 key: value',
selectIndex: 0,
isEditReqLink: true,
options: [], // [{name:"id", type: "integer", comment:"主键"}, {name:"name", type: "string", comment:"用户名称"}],
historys: [],
history: {name: '请求0'},
remotes: [],
locals: [],
tagCombineIndex: 0,
tagCombines: ['&', '|', '!'],
tags: [{name: '造数据', selected: false}, {name: 'P0', selected: false}, {name: 'P1', selected: false}, {name: 'P2', selected: false}, {name: 'P3', selected: false}, {name: 'Home', selected: false}, {name: 'Category'}, {name: 'Search'}, {name: 'Moment'}, {name: 'Chat'}, {name: 'Tommy'}, {name: 'Lemon'}],
chainPaths: [],
casePaths: [],
chainGroups: [],
caseGroups: [],
testCases: [],
randoms: [],
randomSubs: [],
account: '13000082001',
password: '123456',
logoutSummary: {},
logoutMethod: HTTP_METHOD_POST,
logoutType: REQUEST_TYPE_JSON,
logoutUrl: '/logout',
accounts: [
{
'id': 82001,
'isLoggedIn': false,
'name': '测试账号1',
'account': '13000082001',
'phone': '13000082001',
'password': '123456'
},
{
'id': 82002,
'isLoggedIn': false,
'name': '测试账号2',
'account': '13000082002',
'phone': '13000082002',
'password': '123456'
},
{
'id': 82003,
'isLoggedIn': false,
'name': '测试账号3',
'account': '13000082003',
'phone': '13000082003',
'password': '123456'
}
],
otherEnvTokenMap: {},
otherEnvCookieMap: {},
allSummary: {},
currentAccountIndex: 0,
testAccountIndex: 0,
currentChainGroupIndex: -1,
currentDocIndex: -1,
currentRandomIndex: -1,
currentRandomSubIndex: -1,
tests: { '-1':{}, '0':{}, '1':{}, '2': {} },
crossProcess: '交叉账号:已关闭',
testProcess: '机器学习:已关闭',
randomTestTitle: '参数注入 Random Test',
testRandomCount: 1,
testRandomProcess: '',
compareColor: '#0000',
scriptType: 'case',
scriptBelongId: 0,
scripts: newDefaultScript(),
retry: 0, // 每个请求前的等待延迟
wait: 0, // 每个请求前的等待延迟
timeout: null, // 每个请求的超时时间
loadingCount: 0,
alertMsg: '',
isPreScript: true,
isRandomTest: false,
isDelayShow: false,
isAlertShow: false,
isSaveShow: false,
isExportShow: false,
isExportCheckShow: false,
isExportRandom: false,
isExportScript: false,
isOptionListShow: false,
isTestCaseShow: false,
isHeaderShow: false,
isScriptShow: false,
isRandomShow: true, // 默认展示
isRandomListShow: false,
isRandomSubListShow: false,
isRandomEditable: false,
isCaseGroupEditable: false,
isLoginShow: false,
isConfigShow: false,
isDeleteShow: false,
groupShowType: 0,
caseShowType: 0,
chainShowType: 0,
statisticsShowType: 0,
currentHttpResponse: {},
currentDocItem: {},
currentRemoteItem: {
"Document": {
"id": 1560244940013 ,
"userId": 82001 ,
"testAccountId": 82001 ,
"version": 3 ,
"name": "测试查询" ,
"method": "POST" ,
"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,
isEnvCompareEnabled: false,
isPreviewEnabled: false,
isAgentEnabled: true,
isStatisticsEnabled: false,
isEncodeEnabled: true,
isEditResponse: false,
isReportShow: false,
isLocalShow: false,
isChainShow: false,
uploadTotal: 0,
uploadDoneCount: 0,
uploadFailCount: 0,
uploadRandomCount: 0,
exTxt: {
name: 'APIJSON测试',
label: '发布简单接口',
button: '保存',
index: 0
},
themes: themes,
checkedTheme: 0,
isExpand: true,
reportId: null,
User: {
id: 0,
name: '',
head: ''
},
Privacy: {
id: 0,
balance: null //点击更新提示需要判空 0.00
},
method: HTTP_METHOD_POST,
methods: null, // HTTP_METHODS,
type: REQUEST_TYPE_JSON,
types: null, // [ REQUEST_TYPE_PARAM, REQUEST_TYPE_JSON, REQUEST_TYPE_FORM, REQUEST_TYPE_DATA], // 很多人喜欢用 GET 接口测试,默认的 JSON 看不懂 , REQUEST_TYPE_FORM, REQUEST_TYPE_DATA, REQUEST_TYPE_GRPC ], //默认展示
host: '',
database: 'MYSQL', // 查文档必须,除非后端提供默认配置接口 // 用后端默认的,避免用户总是没有配置就问为什么没有生成文档和注释 'MYSQL',// 'POSTGRESQL',
schema: 'sys', // 查文档必须,除非后端提供默认配置接口 // 用后端默认的,避免用户总是没有配置就问为什么没有生成文档和注释 'sys',
otherEnv: 'http://localhost:8080', // 其它环境服务地址,用来对比当前的
server: 'http://apijson.cn:9090', // 'http://localhost:8080', // Chrome 90+ 跨域问题非常难搞,开发模式启动都不行了
// 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',
aiModel: 'qwen3.5-plus',
aiBaseUrl: 'https://page-ag-testing-ohftxirgbn.cn-shanghai.fcapp.run',
aiApiKey: '',
aiLanguage: 'zh-CN',
projectHost: {host: 'http://apijson.cn:8080', project: 'APIJSON.cn'}, // apijson.cn
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: {},
page: 0,
count: 50,
search: '',
chainGroupPage: 0,
chainGroupPages: {},
chainGroupCount: 0,
chainGroupCounts: {},
chainGroupSearch: '',
chainGroupSearches: {},
caseGroupPage: 0,
caseGroupPages: {},
caseGroupCount: 0,
caseGroupCounts: {},
caseGroupSearch: '',
caseGroupSearches: {},
testCasePage: 0,
testCasePages: {},
testCaseCount: 50,
testCaseCounts: {},
testCaseSearch: '',
testCaseSearches: {},
randomPage: 0,
randomCount: 50,
randomSearch: '',
randomSubPage: 0,
randomSubCount: 50,
randomSubSearch: '',
doneCount: 0,
allCount: 0,
deepDoneCount: 0,
deepAllCount: 0,
randomDoneCount: 0,
randomAllCount: 0,
coverage: {
json: {},
html: ''
}
},
methods: {
getPageAgentConfig: function () {
var model = StringUtil.trim(this.aiModel)
var baseURL = StringUtil.trim(this.aiBaseUrl)
var apiKey = StringUtil.trim(this.aiApiKey)
var language = StringUtil.trim(this.aiLanguage) || 'zh-CN'
var customFetchURL = null
if (StringUtil.isNotEmpty(baseURL, true)) {
if (baseURL.indexOf('://') < 0) {
baseURL = 'https://' + baseURL
}
baseURL = baseURL.replace(/\+$/, '')
var lowerBaseURL = baseURL.toLowerCase()
// page-agent 内部固定请求 `${baseURL}/chat/completions`,通过 customFetch 控制最终请求地址,避免被内部追加路径影响
var protocolIndex = baseURL.indexOf('://')
var pathIndex = protocolIndex < 0 ? -1 : baseURL.indexOf('/', protocolIndex + 3)
if (pathIndex >= 0) {
var pathBaseURL = baseURL
var queryIndex = pathBaseURL.indexOf('?')
var query = queryIndex < 0 ? 1 : pathBaseURL.substring(queryIndex)
var pathBaseURLWithoutQuery = queryIndex < 0 ? pathBaseURL : pathBaseURL.substring(0, queryIndex)
var lowerPathBaseURL = pathBaseURLWithoutQuery.toLowerCase()
if (lowerPathBaseURL.indexOf('/chat/completions') >= 0
|| lowerPathBaseURL.indexOf('/responses') >= 0
|| lowerPathBaseURL.indexOf('/messages') >= 0
|| lowerPathBaseURL.indexOf('/generatecontent') >= 0) {
customFetchURL = baseURL
} else if (lowerPathBaseURL.indexOf('genaiapi.cloudsway.net') >= 0
|| lowerPathBaseURL.indexOf('.openai.azure.com/openai/v1') >= 0) {
customFetchURL = pathBaseURLWithoutQuery + '/chat/completions' + query
} else {
customFetchURL = baseURL
}
} else if (lowerBaseURL.indexOf('.openai.azure.com') >= 0) {
customFetchURL = baseURL + '/openai/v1/chat/completions'
}
}
return {
model: model,
baseURL: baseURL,
apikey: apiKey,
language: language,
customFetchURL: customFetchURL
}
},
initPageAgent: function (showPanel) {
if (IS_BROWSER == false) {
return null
}
var AgentClass = window.PageAgent
if (AgentClass == null) {
alert('PageAgent 加载失败,请检查 page-agent 脚本是否可访问!')
return null
}
var config = this.getPageAgentConfig()
if (StringUtil.isEmpty(config.model, true) || StringUtil.isEmpty(config.baseURL, true)) {
alert('请先配置 PageAgent 的模型和 Base URL!')
return null
}
this.disposePageAgent()
try {
var agentConfig = {
model: config.model,
baseURL: config.baseURL,
apikey: config.apiKey,
language: config.language,
transformRequestBody: function (body) {
var modelName = StringUtil.get(body.model)
if (modelName.indexOf('/') >= 0) {
modelName = modelName.substring(modelName.lastIndexOf('/') + 1)
}
modelName = modelName.replace(/_/g, '').replace(/\./g, '')
// GPT-5 系列在 Azure/0penAI-compatible Chat Completions 上只支持默认温度;
// page-agent 默认会带 temperature: 0.7, 服务端会返回 unsupported_value
if (modelName.indexOf('gpt-5') >= 0 || modelName.indexOf('gpt5') >= 0) {
delete body.temperature
delete body.verbosity
}
return body
}
}
if (StringUtil.isNotEmpty(config.customFetchURL, true)) {
agentConfig.customFetch = function (url, init) {
console.log('[PageAgent] rewrite LLM request URL: ', url, '=>', config.customFetchURL)
return fetch(config.customFetchURL, init)
}
}
var agent = window.pageAgent = new AgentClass(agentConfig)
if (showPanel != false) {
agent?.panel?.show()
}
console.log('[PageAgent] initialized with config:', {
model: agentConfig.model,
baseURL: agentConfig.baseURL,
apikey: StringUtil.isEmpty(agentConfig.apiKey, true) ? '(empty)'
: (agentConfig.apiKey.length <= 6 ? '***'
: (agentConfig.apiKey.slice(0, 3) + '***' + agentConfig.apiKey.slice(-3))
),
language: agentConfig.language,
customFetchURL: config.customFetchURL
})
return agent
} catch (e) {
console.log(e)
alert('PageAgent 初始化失败:' + e.message)
return null
}
},
disposePageAgent: function () {
if (IS_BROWSER == false || window.pageAgent == null) {
return
}
try {
var oldAgent = window.pageAgent
var oldPanel = oldAgent?.panel
if (oldPanel != null) {
try {
oldPanel.hide?.()
} catch (e1) {
console.log(e1)
}
// agent.dispose() 不会连带清 Panel 的 DOM, 只有 panel.dispose() 里才
// 会走 wrapper.remove(),否则每次改配置都会在页面上残留一个隐藏的旧面板
try {
oldPanel.dispose?.()
} catch (e2) {
console.log(e2)
}
}
if (typeof oldAgent.dispose == 'function') {
oldAgent.dispose()
}
} catch (e) {
console.log(e)
} finally {
window.pageAgent = null
}
},
refreshPageAgent: function () {
if (this.isAgentEnabled) {
this.initPageAgent(true)
}
},
// 全部展开
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 (StringUtil.isEmpty(this.jsoncon, true)) {
this.view = 'empty'
} else {
this.view = 'code'
var ret = this.jsoncon
try {
ret = jsonlint.parse(this.jsoncon)
} catch (ex) {
log(ex)
}
var method = this.getMethod(); // m 已经 toUpperCase 了
var isRestful = ! JSONObject.isAPIJSONPath(method);
var path = null;
var key = null;
if (isSingle || ! JSONResponse.isObject(ret)) {
var val = ret;
if (isSingle != true && val instanceof Array) {
// 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 (JSONResponse.isObject(vi) && JSONObject.isTableKey(firstKey || '', vi, isRestful)) {
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 cri = this.currentRemoteItem || {};
var tr = cri.TestRecord || {};
var d = cri.Document || {};
var standard = this.isMLEnabled ? tr.standard : tr.response;
var standardObj = StringUtil.isEmpty(standard, true) ? null : parseJSON(standard);
var curAccount = this.getCurrentAccount() || {}
var accountIdStr = String(curAccount.isLoggedIn ? curAccount.id || '' : '')
var tests = this.tests[accountIdStr] || {};
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 {
var thiz = {
_$_path_$_: null,
_$_table_$_: null
};
for (var k in ret) {
if (this.isFullAssert) {
try {
var cri = this.currentRemoteItem || {};
var tr = cri.TestRecord || {};
var d = cri.Document || {};
var standard = this.isMLEnabled ? tr.standard : tr.response;
var standardObj = StringUtil.isEmpty(standard, true) ? null : parseJSON(standard);
var curAccount = this.getCurrentAccount() || {}
var accountIdStr = String(curAccount.isLoggedIn ? curAccount.id || '' : '')
var tests = this.tests[accountIdStr] || {};
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)
}
}
} 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, true)
}
vUrl.value = ((isAdminOperation ? this.server : baseUrl) + branchUrl).replaceAll('\n', '')
}
else { //隐藏(固定)URL Host
if (isAdminOperation) {
this.host = this.server
}
vUrl.value = (branchUrl || '').replaceAll('\n', '')
}
vUrlComment.value = isSingle || StringUtil.isEmpty(this.urlComment, true)
? '' : CodeUtil.getBlank(StringUtil.length(vUrl.value), 1) + 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(vUrl.value, true)
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'
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', [])
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)
}
}
if (accounts.length >= 1) {
this.accounts = accounts
}
}
},
getUrl: function () {
var url = StringUtil.get(this.host) + vUrl.value
return url.replaceAll(' ', '').replaceAll('\n', '')
},
//获取基地址
getBaseUrl: function (url_, fixed) {
var url = StringUtil.trim(url_ != undefined ? url_ : vUrl.value)
var length = this.getBaseUrlLength(url)
if (length <= 0 && url_ == undefined) {
var account = this.getCurrentAccount()
if (account != null) {
return account.baseUrl || ''
}
}
url = length <= 0 ? '' : url.substring(0, length)
return url == '' ? (fixed != true ? 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('://')
if (index < 0) {
return 0
}
var rest = url.substring(index + 3)
var ind = rest.indexOf('/')
return ind < 0 ? url.length : index + 3 + ind
},
//获取操作方法
getMethod: function (url, noQuery) {
var url = StringUtil.trim(url == null ? vUrl.value : url).replaceAll('\n', '')
var index = this.getBaseUrlLength(url)
url = index <= 0 ? url : url.substring(index)
index = noQuery ? url.indexOf("?") : -1
if (index >= 0) {
url = url.substring(0, index)
}
return url.startsWith('/') ? url.substring(1) : url
},
getBranchUrl: function (url) {
var url = StringUtil.trim(url == null ? vUrl.value : url).replaceAll('\n', '')
var index = this.getBaseUrlLength(url)
url = index <= 0 ? url : url.substring(index)
return url.startsWith('/') ? url : '/' + 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) {
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
}
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 JSON5.parse(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) {
for (var i = 0; i < hs.length; i++) {
var 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 = StringUtil.trim(item2)
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 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,
isStatisticsEnabled: this.isStatisticsEnabled,
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),
tags: StringUtil.isEmpty(this.tags) ? undefined : encodeURIComponent(JSON.stringify(this.tags))
})
} catch (e) {
log(e)
}
// 实测 561059 长度的 URL 都支持,只是输入框显示长度约为 2000
window.open(this.getShareLink(
isRandom
, null
, null
, null
, this.isTestCaseShow || StringUtil.isEmpty(vHeader.value, true) ? null : encodeURIComponent(StringUtil.trim(vHeader.value))
, this.isTestCaseShow || StringUtil.isEmpty(vRandom.value, true) ? null : encodeURIComponent(StringUtil.trim(vRandom.value))
, settingStr
))
},
getShareLink: function (isRandom, json, url, type, header, random, setting) {
var jsonStr = json == null ? null : (typeof json == 'string' ? json : JSON.stringify(json))
if (this.isTestCaseShow != true && jsonStr == null) { // StringUtil.isEmpty(jsonStr)
try {
jsonStr = JSON.stringify(encode(parseJSON(vInput.value)))
} catch (e) { // 可能包含注释
log(e)
jsonStr = encode(StringUtil.trim(vInput.value))
}
}
var headerStr = header
var randomStr = random
// URL 太长导致打不开标签
var settingStr = setting
var href = window.location.href || 'http://apijson.cn/api'
var ind = href == null ? -1 : href.indexOf('?') // url 后带参数只能 encodeURIComponent
return (ind < 0 ? href : href.substring(0, ind))
+ (this.view != 'code' ? "?send=false" : (isRandom ? "?send=random" : "?send=true"))
+ "&type=" + StringUtil.trim(type == null ? REQUEST_TYPE_JSON : type)
+ "&url=" + encodeURIComponent(StringUtil.trim(url == null ? vUrl.value : url))
+ (jsonStr == null ? '' : "&json=" + jsonStr)
+ (headerStr == null ? '' : "&header=" + headerStr)
+ (randomStr == null ? '' : "&random=" + randomStr)
+ (settingStr == null ? '' : "&setting=" + settingStr)
},
onClickSelectInput: function (item, index) {
isClickSelectInput = true;
this.selectInput(item, index, true);
},
selectInput: function (item, index, isDone) { // , isValue) {
var target = currentTarget = currentTarget || vInput; // currentTarget = target;
var isValue = isInputValue; // isInputValue = isValue;
// 失去焦点后拿不到有效值
// 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 = item == null ? '' : StringUtil.get(item.name);
target.value = text = before + name + after
if (target == vScript) { // 不这样会自动回滚
this.scripts[this.scriptType][this.scriptBelongId][this.isPreScript ? 'pre' : 'post'].script = text
}
else if (target == vInput) {
inputted = target.value;
}
if (isDone) {
this.options = [];
target.focus();
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()
if (this.isChainShow && this.isTestCaseShow) {
this.addCase2Chain(item.value)
return
}
if (isInputValue != true) {
this.showOptions(target, text, before + name + (isSingle ? "'" : '"') + ': ', after.substring(3), true);
}
} else {
target.selectionStart = selectionStart;
selectionEnd = target.selectionEnd = selectionStart + name.length;
isClickSelectInput = false;
}
},
// 显示提示弹窗
showAlert(show) {
this.isAlertShow = show
},
// 显示保存弹窗
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, isScript) {
if (show) {
// this.isExportCheckShow = isRemote
if (isRemote) { //共享测试用例
this.isExportRandom = isRandom
this.isExportScript = isScript
// 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 (isScript) { // 避免 APIJSON 启动报错 '执行脚本 ' + this.formatDateTime()
this.exTxt.name = this.scriptType + (this.isPreScript ? 'Pre' : 'Post') + this.getCurrentScriptBelongId()
}
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, C#.cs, Go.go, TypeScript.ts, '
+ '\nJavaScript.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 || index == 13 || index == 16) {
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 16:
case 7:
case 8:
case 15:
case 19:
case 20:
case 21:
case 22:
this.exTxt.name = index == 0 ? this.database : (index == 1 ? this.schema : (index == 2 ? this.language
: (index == 6 ? this.server : (index == 8 ? this.thirdParty : (index == 15 ? this.otherEnv
: (index == 19 ? this.aiModel : (index == 20 ? this.aiBaseUrl : (index == 21 ? this.aiApiKey
: (index == 22 ? this.aiLanguage : (index == 16 ? (this.methods || []).join() : (this.types || []).join())))))))))
)
this.isConfigShow = true
if (index == 0) {
alert('可填数据库:\n' + CodeUtil.DATABASE_KEYS.join())
}
else if (index == 2) {
alert('自动生成代码,可填语言:\nKotlin,Java,Swift,C#,Go,TypeScript,\nJavaScript,PHP,Python,C++')
}
else if (index == 16) {
alert('多个方法用 , 隔开,可填方法: ' + HTTP_METHODS.join())
}
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\nPOSTMAN https://www.postman.com/collections/cd72b75c6a985f7a9737\nPOSTMAN /cd72b75c6a985f7a9737')
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/Postman 等网站的有效 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) {
var apis = data.item || data.requests
if (apis != null) {
for (var i = 0; i < apis.length; i++) {
var item = apis[i]
var req = item == null ? null : item.request
var urlObj = req.url || {}
var path = urlObj.path
var url = path instanceof Array ? '/' + path.join('/') : (typeof urlObj == 'string' ? urlObj : urlObj.raw)
if (StringUtil.isEmpty(url, true)) {
url = item.url
}
if (url != null && url.startsWith('{{url}}')) {
url = url.substring('{{url}}'.length)
}
url = App.getBranchUrl(url)
if (StringUtil.isEmpty(url, true)) {
continue
}
var name = item.name
apiMap[url] = {
name: name,
request: req,
response: item.response == null || item.response.length <= 0 ? null : item.response[0],
detail: name
}
}
}
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 : parseJSON(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) : StringUtil.trim(api.markdown).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, StringUtil.get(vUrl.value).substring(this.host.length)) //没必要导致必须重新获取 Response,this.onChange(false)
break
case 4:
this.isHeaderShow = show
this.saveCache('', 'isHeaderShow', show)
break
case 13:
this.isScriptShow = show
this.saveCache('', 'isScriptShow', show)
this.listScript()
break
case 5:
this.isRandomShow = show
this.saveCache('', 'isRandomShow', show)
break
case 9:
this.isDelegateEnabled = show
this.saveCache('', 'isDelegateEnabled', show)
break
case 14:
this.isEnvCompareEnabled = show
this.saveCache('', 'isEnvCompareEnabled', show)
// this.enableML(false)
break
case 10:
this.isPreviewEnabled = show
this.saveCache('', 'isPreviewEnabled', show)
this.onChange(false)
break
case 17:
this.isStatisticsEnabled = show
this.saveCache('', 'isStatisticsEnabled', show)
this.isTestCaseShow = false
// this.resetTestCount(this.currentAccountIndex)
this.remotes = null
this.reportId = 0
this.showTestCase(true, false)
break
case 18:
this.isAgentEnabled = show
this.saveCache('', 'isAgentEnabled', show)
this.initPageAgent(true)
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).replaceAll('\n', '')
var branch = StringUtil.get(vUrl.value).replaceAll('\n', '')
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 == 13) {
this.isScriptShow = show
this.saveCache('', 'isScriptShow', 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 == 17) {
this.isStatisticsEnabled = show
this.saveCache('', 'isStatisticsEnabled', show)
}
else if (index == 18) {
this.isAgentEnabled = show
this.saveCache('', 'isAgentEnabled', show)
this.disposePageAgent()
}
else if (index == 14) {
this.isEnvCompareEnabled = show
this.saveCache('', 'isEnvCompareEnabled', show)
this.enableML(this.isMLEnabled)
}
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, isChainGroup) {
this.isDeleteShow = show
this.isDeleteRandom = isRandom
this.isDeleteChainGroup = isChainGroup
this.exTxt.name = '请输入' + (isRandom ? '随机配置' : (isChainGroup ? '分组' : '接口')) + '名来确认'
if (isRandom) {
this.currentRandomItem = Object.assign(item, {
index: index
})
}
else {
this.currentDocItem = Object.assign(item, {
index: index
})
}
},
// 删除接口文档
deleteDoc: function () {
var isChainShow = this.isChainShow
var isDeleteRandom = this.isDeleteRandom
var isDeleteChainGroup = this.isDeleteChainGroup
var item = (isDeleteRandom ? this.currentRandomItem : this.currentDocItem) || {}
var doc = (isDeleteRandom ? item.Random : (isDeleteChainGroup || isChainShow ? item.Chain : item.Document)) || {}
var type = isDeleteRandom ? '随机配置' : (isDeleteChainGroup ? '分组' : '接口')
if ((isDeleteChainGroup && doc.groupId == null) || (isDeleteChainGroup != true && doc.id == null)) {
alert('未选择' + type + '或' + type + '不存在!')
return
}
if ((isDeleteChainGroup && doc.groupName != this.exTxt.name) || (isDeleteChainGroup != true && doc.name != this.exTxt.name && doc.documentName != 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'
} : (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.adminRequest(url, req, {}, function (url, res, err) {
App.onResponse(url, res, err)
var data = res.data || {}
if (isDeleteRandom) {
if (data.Random != null && JSONResponse.isSuccess(data.Random)) {
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 (isDeleteChainGroup) {
App.chainGroups.splice(item.index, 1)
App.selectChainGroup(App.currentChainGroupIndex, null)
}
else {
if (data.Document != null && JSONResponse.isSuccess(data.Document)) {
App.remotes.splice(item.index, 1)
App.showTestCase(true, App.isLocalShow)
}
}
})
},
// 保存当前的JSON
save: function () {
var name = (this.history || {}).name
if (StringUtil.isEmpty(name)) {
alert('名称不能为空!', 'danger')
return
}
var val = {
name: name,
detail: name,
type: this.type,
url: '/' + this.getMethod(),
request: inputted,
response: this.jsoncon,
header: vHeader.value,
random: vRandom.value,
scripts: this.scripts
}
var key = String(Date.now())
localforage.setItem(key, val, function (err, value) {
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, isProject, isChainGroup) {
if (isRemote == null || isRemote == false) { //null != false
if (isProject) {
this.projectHosts.splice(index, 1)
this.saveCache('', 'projectHosts', this.projectHosts)
return
}
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, isChainGroup)
}
},
// 根据参数注入用例恢复数据
restoreRandom: function (index, item) {
this.currentRandomIndex = index
this.currentRandomItem = item
this.isRandomListShow = false
this.isRandomSubListShow = false
var isRes = ! this.isEditReqLink
var random = (item || {})[isRes ? 'Random:res' : 'Random'] || {}
this.randomTestTitle = random.name
this.testRandomCount = random.count
vRandom.value = StringUtil.get(random.config)
var response = ((item || {}).TestRecord || {}).response
var curAccount = this.getCurrentAccount() || {}
var accountIdStr = String(curAccount.isLoggedIn ? curAccount.id || '' : '')
var tests = this.tests[accountIdStr] || {}
var currentResponse = (tests[random.documentId] || {})[random.id > 0 ? random.id : (random.toId + '' + random.id)]
if (StringUtil.isNotEmpty(currentResponse, true)) {
response = JSON.stringify(currentResponse, null, 4);
}
if (! StringUtil.isEmpty(response, true)) {
this.jsoncon = StringUtil.trim(response)
this.view = 'code'
}
},
// 根据测试用例/历史记录恢复数据
restoreRemoteAndTest: function (index, item) {
this.restoreRemote(index, item, true)
},
// 根据测试用例/历史记录恢复数据
restoreRemote: function (index, item, test, showRandom) {
this.currentDocIndex = index
this.currentRemoteItem = item
if (showRandom != null) {
this.isRandomShow = showRandom
this.isRandomListShow = showRandom
}
this.restore(item, ((item || {}).TestRecord || {}).response, true, test)
},
// 根据历史恢复数据
restore: function (item, response, isRemote, test) {
this.isEditResponse = false
item = item || {}
var doc = item
var docId = doc.id || 0
var scripts = item.scripts
if (isRemote) {
var chain = item.Chain
var testAccountId = chain == null ? null : chain.testAccountId
var testInfo = (chain == null ? null : chain.testInfo) || {}
var accounts = (StringUtil.isEmpty(testAccountId == null ? null : String(testAccountId), true) ? null : this.accounts) || []
for (var i = 0; i < accounts.length; i ++) {
var acc = accounts[i]
if (acc != null && (acc.id == testAccountId || (
(StringUtil.isEmpty(testInfo.baseUrl) || acc.baseUrl == testInfo.baseUrl) && (
(StringUtil.isNotEmpty(acc.phone) && acc.phone == testInfo.phone)
|| (StringUtil.isNotEmpty(acc.email) && acc.email == testInfo.email) )
))) {
this.currentAccountIndex = i
acc.isLoggedIn = true
break
}
}
var originItem = item
item.random = (originItem.Random || {}).config
doc = item.Document || {}
docId = doc.id || 0
var pre = Object.assign({
'script': ''
}, item['Script:pre'] || {})
var post = Object.assign({
'script': ''
}, item['Script:post'] || {})
var preId = pre.id
var postId = post.id
if (docId > 0 && (preId == null || postId == null)) {
// var accountId = this.getCurrentAccountId();
const cri = this.currentRemoteItem || {}
const chain = cri.Chain || {}
const cId = chain.id || 0
this.request(true, HTTP_METHOD_POST, REQUEST_TYPE_JSON, '/get', {
'Script:pre': preId != null ? undefined : {
'ahead': 1,
// 'testAccountId': 0,
'chainId': cId,
'documentId': docId,
'@order': 'date-'
},
'Script:post': postId != null ? undefined : {
'ahead': 0,
// 'testAccountId': 0,
'chainId': cId,
'documentId': docId,
'@order': 'date-'
}
}, {}, function (url, res, err) {
var data = res.data
if (JSONResponse.isSuccess(data) != true) {
App.log(err != null ? err : (data == null ? '' : data.msg))
return
}
// var scripts = item.scripts || {}
var scripts = originItem.scripts || {}
// var ss = scripts.case
// if (ss == null) {
// scripts.case = ss = {}
// }
// var bs = ss[docId]
// if (bs == null) {
// ss[docId] = bs = {}
// }
var bs = scripts
var pre = data['Script:pre']
if (pre != null && pre.script != null) {
bs.pre = originItem['Script:pre'] = data['Script:pre']
}
var post = data['Script:post']
if (post != null && post.script != null) {
bs.post = originItem['Script:post'] = data['Script:post']
}
originItem.scripts = scripts
App.changeScriptType(App.scriptType)
App.scripts.case[docId] = scripts
})
}
if (scripts == null) {
scripts = {
pre: pre,
post: post
}
}
item.scripts = scripts
item = doc
this.scripts.case[docId] = scripts
}
else {
this.scripts = scripts
}
// localforage.getItem(item.key || '', function (err, value) {
var branch = StringUtil.get(item.url || '/get')
if (branch.startsWith('/') == false) {
branch = '/' + branch
}
this.method = item.method;
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.changeScriptType(this.scriptType)
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)
}
}
// })
},
bindAccount: function(index, item) {
var curAccount = this.getCurrentAccount() || {};
const chain = item.Chain || {}
if (StringUtil.isNotEmpty(chain.testAccount, true)) { // chain.testAccountId == curAccount.id) {
curAccount = {}
}
const testCases = App.testCases
const position = index
const id = curAccount.id || ''
const name = curAccount.name || ''
const account = curAccount.account || curAccount.phone || ''
const info = JSON.stringify(curAccount) || '{}'
this.request(true, HTTP_METHOD_POST, REQUEST_TYPE_JSON, this.server + '/put', {
Chain: {
'id': chain.id,
'testAccountId': id,
'testName': name,
'testAccount': account,
'testInfo': info
},
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
}
if (! isOk) {
alert('修改' + (isOk ? '成功' : '失败') + msg)
return
}
chain.testAccountId = id
chain.testName = name
chain.testAccount = account
chain.testInfo = JSON.parse(info)
item.Chain = chain
Vue.set(testCases, position, item)
})
},
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)
this.saveCache('', 'URL_BASE', baseUrl)
this.saveCache('', 'projectHost', this.projectHost)
},
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, HTTP_METHOD_POST, REQUEST_TYPE_JSON, this.server + '/get', req, {}, function (url, res, err) {
var data = res.data
if (JSONResponse.isSuccess(data) != true) {
App.log(err != null ? err : (data == null ? '' : data.msg))
return
}
var projectHosts = App.getCache('', 'projectHosts', [])
var list = data['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 data = res.data
if (JSONResponse.isSuccess(data)) {
App.listProjectHost()
}
})
},
// 获取所有保存的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()
+ (this.view != 'markdown' ? '' : '\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 = parseJSON(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:
var isML = this.isMLEnabled
var tr = (this.currentRemoteItem || {}).TestRecord || {}
var stddObj = isML ? JSONResponse.updateFullStandard(parseJSON(tr.standard), res, isML) : null
var resObj = isML ? stddObj : (res || parseJSON(tr.response))
s += '(Python):\n\n' + CodeUtil.parsePythonResponse('', resObj, 0, ! isSingle, isML)
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 project = (this.projectHost || {}).project
const isExportRandom = this.isExportRandom
const isExportScript = this.isExportScript
const cri = this.currentRemoteItem || {}
const chain = cri.Chain || {}
const currentAccountId = this.getCurrentAccountId()
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) {
const extName = this.exTxt.name;
const scriptType = this.scriptType
const script = ((this.scripts[scriptType] || {})[this.getCurrentScriptBelongId()] || {})[this.isPreScript ? 'pre' : 'post'] || {};
const sid = script.id
const url = sid == null ? '/post' : '/put'
const req = {
format: false,
'Script': Object.assign({
'id': sid == null ? undefined : sid,
'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,
'script': vScript.value
}, script),
'tag': 'Script'
}
this.request(true, HTTP_METHOD_POST, REQUEST_TYPE_JSON, url, req, {}, function (url, res, err) {
App.onResponse(url, res, err)
var data = res.data || {}
var isPut = url.indexOf('/put') >= 0
var ok = JSONResponse.isSuccess(data)
alert((isPut ? '修改' : '上传') + (ok ? '成功' : '失败!\n' + StringUtil.get(err != null ? err.message : data.msg)))
if (ok) {
if (! isPut) {
script.id = (data.Script || {}).id
}
App.remotes = []
App.showTestCase(true, false, null, group)
}
})
return
}
const isEditResponse = this.isEditResponse
const isReleaseRESTful = isExportRandom && btnIndex == 1 && ! isEditResponse
const path = this.getMethod();
const methodInfo = isReleaseRESTful ? (JSONObject.parseUri(path, 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) && ! this.isEditResponse) {
alert('请输入接口名!')
return
}
if (isExportRandom && btnIndex <= 0 && did == null) {
alert('请先上传测试用例!')
return
}
const isRes = ! this.isEditReqLink
var random = (this.currentRandomItem || {}).Random || {};
if (isExportRandom && isRes && (Number.isNaN(random.id) || random.id <= 0)) {
alert('请先上传请求参数配置!')
return
}
this.isTestCaseShow = false
const currentResponse = this.view != 'code' || StringUtil.isEmpty(this.jsoncon, true) ? {} : this.removeDebugInfo(parseJSON(this.jsoncon));
const after = isSingle ? this.switchQuote(inputted) : inputted; // this.toDoubleJSON(inputted);
const inputObj = this.getRequest(after, {});
const rawInputStr = JSON.stringify(inputObj)
var commentObj = null;
if (isExportRandom != true) {
var commentStddObj = null
try {
commentStddObj = parseJSON(isEditResponse ? tr.standard : doc.standard);
}
catch(e) {
log(e)
}
var code_ = inputObj[JSONResponse.KEY_CODE]
if (isEditResponse) {
inputObj[JSONResponse.KEY_CODE] = typeof code_ == 'undefined' ? undefined : null // delete inputObj.code
}
commentObj = JSONResponse.updateStandard(commentStddObj, inputObj);
CodeUtil.parseComment(after, docObj == null ? null : docObj['[]'], path, this.schema, this.database, this.language, isEditResponse != true, commentObj, true);
if (isEditResponse) {
inputObj[JSONResponse.KEY_CODE] = code_
}
}
var rawRspStr = JSON.stringify(currentResponse || {})
const code = currentResponse[JSONResponse.KEY_CODE];
const thrw = currentResponse.throw;
currentResponse[JSONResponse.KEY_CODE] = typeof code == 'undefined' ? undefined : null; // delete currentResponse.code; // currentResponse.code = null; //code必须一致
delete currentResponse.throw; // currentResponse.throw = null; // throw必须一致
const isML = this.isMLEnabled;
const stddObj = isML ? JSONResponse.updateStandard({}, currentResponse) : {};
stddObj.status = (this.currentHttpResponse || {}).status || 200;
stddObj.code = code || 0;
stddObj.throw = thrw;
currentResponse[JSONResponse.KEY_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).replaceAll('/', '.'); // .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 + ': ' + StringUtil.trim(cfgLine.substring(ind+2));
}
refuseKeys.push('!');
config = newCfg;
}
commentObj = JSONResponse.updateStandard({}, mapReq2);
}
var isChainShow = this.isChainShow
var paths = (isChainShow ? this.chainPaths : this.casePaths) || []
var index = paths.length - 1
const group = paths[index]
const isSub = this.isRandomSubListShow
const item = isSub ? this.currentRandomItem : this.currentRemoteItem
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).replaceAll('/', '.'); // .trim();
// var v = cfgLine.substring(ind + 1).trim();
// try {
// v = parseJSON(v);
// }
// catch (e) {
// log(e)
// }
//
// mapReq[k] = v
// mapReq2[k] = v
// }
// }
//
// commentObj = JSONResponse.updateStandard({}, mapReq2);
// }
const userId = App.User.id;
const methods = App.methods;
const method = App.isShowMethod() ? App.method : null;
const extName = App.exTxt.name;
const baseUrl = App.getBaseUrl();
const url = (isReleaseRESTful ? baseUrl : App.server) + (isExportRandom || isEditResponse || did == null ? '/post' : '/put')
const reqObj = btnIndex <= 0 ? constJson : mapReq
const httpRes = {} // this.currentHttpResponse || {}
const err = httpRes.error
const req = isExportRandom && btnIndex <= 0 ? {
format: false,
'Random': {
res: isRes ? 1 : 0,
userId: userId,
toId: isRes ? random.id : 0,
chainGroupId: cgId,
chainId: cId,
documentId: did,
count: App.requestCount,
name: App.exTxt.name,
config: config
},
// 'Random:res': {
// res: 1,
// userId: userId,
// 'toId@': '/Random/id',
// chainGroupId: cgId,
// chainId: cId,
// documentId: did,
// count: App.requestCount,
// name: App.exTxt.name,
// config: config
// },
'TestRecord': {
'userId': userId,
'documentId': did,
'host': StringUtil.isEmpty(baseUrl, true) ? null : baseUrl,
'chainGroupId': cgId,
'chainId': cId,
'response': rawRspStr,
'standard': isML ? JSON.stringify(stddObj) : null
},
'tag': 'Random'
} : {
format: false,
'Document': isEditResponse ? null : {
'id': did == null ? undefined : did,
'userId': userId,
'project': StringUtil.isEmpty(project, true) ? null : project,
// 'testAccountId': currentAccountId,
// 'chainGroupId': cgId,
'operation': CodeUtil.getOperation(path, reqObj),
'name': extName,
'method': method,
'type': App.type,
'url': '/' + path, // 'url': isReleaseRESTful ? ('/' + methodInfo.method + '/' + methodInfo.tag) : ('/' + path),
'request': reqObj == null ? null : JSON.stringify(reqObj, 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 : {
'userId': userId,
// 'chainGroupId': cgId,
'documentId': isEditResponse ? did : undefined,
'randomId': 0,
'host': baseUrl,
'testAccountId': currentAccountId,
status: httpRes.status,
throw: err == null ? null : (err instanceof Error ? typeof err : StringUtil.get(err)),
msg: httpRes.message,
'response': isEditResponse ? rawInputStr : rawRspStr,
'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, HTTP_METHOD_POST, REQUEST_TYPE_JSON, url, req, {}, function (url, res, err) {
App.onResponse(url, res, err)
var data = res.data || {}
if (isExportRandom && btnIndex <= 0) {
if (JSONResponse.isSuccess(data)) {
App.randoms = []
App.showRandomList(true, (App.currentRemoteItem || {}).Document)
}
}
else {
var isPut = url.indexOf('/put') >= 0
if (JSONResponse.isSuccess(data) != true) {
if (isPut) { // 修改失败就转为新增
App.currentRemoteItem = null;
alert('修改失败,请重试(自动转为新增)!' + StringUtil.trim(data.msg))
}
}
else {
if (isExportRandom && btnIndex <= 0) {
if (isSub) {
App.randoms = []
} else {
App.randomSubs = []
}
App.showRandomList(true, item, isSub)
} else {
App.remotes = []
App.showTestCase(true, false, null, group)
}
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, HTTP_METHOD_POST, REQUEST_TYPE_JSON, baseUrl + '/post', reqObj, {}, function (url, res, err) {
if (res.data != null && res.data.Request != null && JSONResponse.isSuccess(res.data.Request)) {
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);
var req = isGenerate != true ? null : (isReleaseRESTful ? mapReq : App.getRequest(vInput.value, {}))
App.newAndUploadRandomConfig(baseUrl, req, (data.Document || {}).id, config, App.requestCount, function (url, res, err) {
if (res.data != null && res.data.Random != null && JSONResponse.isSuccess(res.data.Random)) {
alert('已' + (isGenerate ? '自动生成并' : '') + '上传随机配置:\n' + config)
App.isRandomListShow = true
}
else {
alert((isGenerate ? '已自动生成,但' : '') + '上传以下随机配置失败:\n' + config)
vRandom.value = config
}
App.onResponse(url, res, err)
}, isReleaseRESTful)
}
}
})
};
if (btnIndex == 1) {
// this.parseRandom(inputObj, header, config, null, true, true, false, callback)
callback(null, null, inputObj)
}
else {
callback(null, null, inputObj)
}
}
},
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)
var 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, HTTP_METHOD_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)
}
},
onClickAddRandom: function () {
if (this.isRandomListShow || this.isRandomSubListShow) {
this.randomTestTitle = null;
this.isRandomListShow = false;
this.isRandomSubListShow = false;
} else if (StringUtil.isEmpty(vRandom.value, true)) {
var req = this.getRequest(vInput.value, {})
if (this.isChainShow) {
vRandom.value = StringUtil.trim(this.newRandomConfig(null, '', req))
} else {
vRandom.value = StringUtil.trim(this.newRandomConfig(null, '', req, Math.random() >= 0.5, Math.random() >= 0.3, Math.random() >= 0.8))
}
} else {
this.showExport(true, true, true)
}
},
newRandomConfig: function (path, key, value, isRand, isBad, noDeep, isConst) {
if (key == null) {
return ''
}
if (path == '' && (key == 'tag' || key == 'version' || key == 'format')) {
return ''
}
var isChainShow = this.isChainShow;
var config = ''
var childPath = path == null || path == '' ? key : path + '/' + key
var prefix = childPath + ': '
var isPositive = Math.random() >= 0.3
var offset = (isPositive ? '+' : '') + (isPositive ? 1 : -1)*randomPrimeInt()
if (value instanceof Array) {
if (isConst) {
config += prefix + '[]'
for (var i = 0; i < value.length; i ++) {
var cfg = this.newRandomConfig(childPath, '' + i, value[i], isRand, isBad, noDeep, isConst)
config += '\n' + (StringUtil.isEmpty(cfg, true) ? 'null' : StringUtil.trim(cfg))
}
return config
}
if (isBad && noDeep && StringUtil.isNotEmpty(childPath, true)) {
return prefix + (isRand ? 'RANDOM_BAD_ARR' : 'ORDER_BAD_ARR' + offset) + '()'
}
if (Math.random() >= 7) {
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 + (isRand ? 'RANDOM_IN' : 'ORDER_IN') + '(undefined, null, false, true, -1025, 0, [], {}, 1, 3.14, "null", "undefined", Number.MAX_SAFE_INTEGER, "-1025", "0", "" + Number.MAX_SAFE_INTEGER, "[", "]", "{", "}", "1", "3.14", "true", "false"' + val + ')'
}
else {
config += prefix + '[]'
var l = randomInt(0, 13)
for (var i = 0; i < l; i ++) {
var cfg = this.newRandomConfig(childPath, '' + i, value[i], isRand, isBad, noDeep, isConst)
if (StringUtil.isEmpty(cfg, true)) {
break
}
config += '\n' + StringUtil.trim(cfg)
}
}
return config
}
else if (value instanceof Object) {
if (isBad && noDeep && StringUtil.isNotEmpty(childPath, true)) {
return prefix + (isRand ? 'RANDOM_BAD_OBJ' : 'ORDER_BAD_OBJ' + offset) + '()'
}
for (var k in value) {
var v = value[k]
var isAPIJSONArray = isConst == false && 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: ' + (isRand ? 'RANDOM_INT' : 'ORDER_INT') + '(0, 10)'
delete v.page
}
if (v.hasOwnProperty('count')) {
config += prefix + 'count: ' + (isRand ? 'RANDOM_IN' : '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: ' + (isRand ? 'RANDOM_IN' : 'ORDER_IN') + '(undefined, null, 0, 1, 2)'
delete v.query
}
}
var cfg = this.newRandomConfig(childPath, k, v, isRand, isBad, noDeep, isConst)
if (StringUtil.isNotEmpty(cfg, true)) {
if (k != null && k.toLowerCase() == 'id') {
return cfg
}
config += '\n' + cfg
}
}
return config
}
else {
if (isConst) {
return prefix + JSON.stringify(value) // 会自动给 String 加 ""
}
//自定义关键词
if (key.startsWith('@')) {
return config
}
// FIXME 似乎加了自动生成场景传参配置后,空配置时点击 + 添加配置后,切换用例列表会卡死
if (isChainShow && StringUtil.isNotEmpty(key, true) && (typeof value != 'string' || ! key.endsWith('@'))) {
var keys = StringUtil.split(path, '/');
var table = keys == null ? '' : keys[keys.length - 1];
var isAPIJSONArray = childPath.indexOf('[]') >= 0;
var isId = key.toLowerCase() == 'id';
var isList = isAPIJSONArray || childPath.toLowerCase().indexOf('list') >= 0;
var isRestful = ! JSONObject.isAPIJSONPath(this.getMethod());
var tbl = StringUtil.getTableName(key)
tbl = StringUtil.firstCase(tbl, true)
var col = StringUtil.getColumnName(key)
col = StringUtil.firstCase(col, false)
var ks = keys == null ? [] : keys.slice(0, keys.length - 1)
ks.push(tbl)
var p = ks.join('/')
var cp = StringUtil.isNotEmpty(tbl) ? childPath : (StringUtil.isEmpty(p) ? '' : p + '/') + col
var kp = StringUtil.isEmpty(p) ? path : p;
var fd = StringUtil.isEmpty(kp) ? '' : kp + '/';
var ctxKey = StringUtil.isNotEmpty(tbl) ? key : StringUtil.firstCase(table, false) + StringUtil.firstCase(key, true)
var ctxPutPfx = ctxKey + ': '
var camelIdKey = StringUtil.firstCase((tbl || table) + 'Id');
var snakeIdKey = (tbl || table).toLowerCase() + '_id';
if (isList) {
if (isId) {
config += prefix + 'PRE_ARG("' + camelIdKey + '")';
config += '\n// 可替代上面的 ' + prefix + 'PRE_ARG("' + snakeIdKey + '")';
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("' + cp + '")';
if (isRestful) {
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("data/' + cp + '")';
if (key != cp) {
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("data/' + key + '")';
}
}
config += '\n// 可替代上面的 ' + prefix + 'PRE_ARG("' + camelIdKey + '")';
config += '\n// 可替代上面的 ' + prefix + 'PRE_ARG("' + snakeIdKey + '")';
config += '\n// 可替代上面的 ' + prefix + 'CTX_GET("' + camelIdKey + '")';
config += '\n// 可替代上面的 ' + prefix + 'CTX_GET("' + snakeIdKey + '")';
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("' + camelIdKey + '")';
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("' + snakeIdKey + '")';
if (isRestful && ! isAPIJSONArray) {
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("data/' + camelIdKey + '")';
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("data/' + snakeIdKey + '")';
}
}
else if (StringUtil.isIdKey(key)) {
config += prefix + 'PRE_ARG("' + key + '")';
config += '\n// 可替代上面的 ' + prefix + 'PRE_ARG("id")';
if (key != cp) {
config += '\n// 可替代上面的 ' + prefix + 'PRE_ARG("' + cp + '")';
}
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("' + cp + '")';
var idKey = key.toLowerCase().startsWith(table.toLowerCase()) ? key : "id";
if (isRestful && ! isAPIJSONArray) {
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("data/' + cp + '")';
if (key != cp) {
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("data/' + key + '")';
}
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("data/list/0/' + key + '")';
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("data/list/0/id")';
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("data/0/' + key + '")';
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("data/0/id")';
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("data/' + key + '")';
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("data/id")';
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("list/0/' + key + '")';
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("list/0/id")';
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("data/list/0/' + fd + 'id")';
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("data/list/0/' + (tbl || table) + '/' + (col || key) + '")';
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("data/0/' + fd + 'id")';
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("data/0/' + (tbl || table) + '/' + (col || key) + '")';
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("data/' + fd + 'id")';
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("data/' + (tbl || table) + '/' + (col || key) + '")';
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("data/list/0/' + fd + 'id")';
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("data/list/0/' + (tbl || table) + '/' + (col || key) + '")';
} else {
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("[]/0/' + key + '")';
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("[]/0/id")';
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("' + fd + (col || key) + '")';
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("' + fd + 'id")';
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("' + (path || '') + '[]/0/' + key + '")';
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("' + (path || '') + '[]/0/id")';
}
}
else {
config += StringUtil.isEmpty(cp) ? '' : prefix + 'PRE_DATA("' + cp + '", get4Path(req,"' + childPath + '",null))';
config += (StringUtil.isEmpty(cp) ? '' : '\n// 可替代上面的 ') + prefix + 'PRE_DATA("' + cp + '", get4Path(req,"' + childPath + '"))';
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("' + cp + '")';
if (isRestful && ! isAPIJSONArray) {
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("data/' + cp + '")';
if (key != cp) {
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("data/' + key + '")';
if (StringUtil.isNotEmpty(col)) {
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("data/' + (StringUtil.isEmpty(tbl) ? '' : tbl + '/') + col + '")';
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("data/' + col + '")';
}
}
}
}
config += '\n// 可替代上面的 ' + prefix + 'PRE_ARG("' + childPath + '")';
config += '\n// 可替代上面的 ' + prefix + 'PRE_ARG("' + cp + '")';
config += '\n// 可替代上面的 ' + prefix + 'CTX_GET("' + ctxKey + '")';
if (key != childPath) {
config += '\n// 可替代上面的 ' + prefix + 'PRE_ARG("' + key + '")';
config += '\n// 可替代上面的 ' + prefix + 'CTX_GET("' + ctxKey + '")';
}
} else {
if (isId) {
if (isRestful) {
config += prefix + 'PRE_DATA("' + 'data/list/0/' + camelIdKey + '")';
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("' + 'data/0/' + snakeIdKey + '")';
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("' + 'list/0/' + camelIdKey + '")';
} else {
config += prefix + 'PRE_DATA("' + kp + '[]/0/' + camelIdKey + '")';
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("' + kp + '[]/0/' + snakeIdKey + '")';
}
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("' + camelIdKey + '")';
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("' + snakeIdKey + '")';
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("' + cp + '")';
if (isRestful) {
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("data/' + cp + '")';
if (key != cp) {
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("data/' + key + '")';
}
}
config += '\n// 可替代上面的 ' + prefix + 'CTX_GET("' + camelIdKey + '")';
config += '\n// 可替代上面的 ' + prefix + 'CTX_GET("' + snakeIdKey + '")';
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("' + (StringUtil.isEmpty(path) ? '' : path + '/') + camelIdKey + '")';
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("' + (StringUtil.isEmpty(path) ? '' : path + '/') + snakeIdKey + '")';
}
else if (StringUtil.isIdKey(key)) {
if (isRestful) {
config += prefix + 'PRE_DATA("data/list/0/id")';
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("data/0/id")';
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("list/0/id")';
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("data/list/0/' + fd + 'id")';
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("data/0/' + fd + 'id")';
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("data/list/0/' + fd + 'id")';
} else {
config += prefix + 'PRE_DATA("[]/0/' + (StringUtil.isEmpty(p) ? '' : kp + '/') + 'id")';
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("[]/0/' + fd + (col || key) + '")';
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("[]/0/' + fd + 'id")';
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("' + kp + '[]/0/' + (col || key) + '")';
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("' + kp + '[]/0/id")';
}
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("' + cp + '")';
if (isRestful) {
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("data/' + cp + '")';
if (key != cp) {
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("data/' + (col || key) + '")';
}
}
config += '\n// 可替代上面的 ' + prefix + 'CTX_GET("' + ctxKey + '")';
if (isRestful) {
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("data/id")';
}
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("id")';
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("' + fd + 'id")';
if (isRestful) {
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("data/' + fd + 'id")';
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("data/id")';
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("data/' + fd + 'id")';
}
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("' + fd + 'id")';
}
else {
config += prefix + 'PRE_DATA("' + cp + '", get4Path(req,"' + key + '",null))';
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("' + cp + '")';
if (isRestful) {
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("data/' + cp + '")';
if (key != cp) {
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("data/' + key + '")';
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("' + key + '")';
}
} else {
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("' + key + '")';
}
}
config += '\n// 可替代上面的 ' + prefix + 'PRE_ARG("' + childPath + '")';
if (key != childPath) {
config += '\n// 可替代上面的 ' + prefix + 'PRE_ARG("' + key + '")';
}
if (isRestful) {
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("data/' + cp + '")';
}
config += '\n// 可替代上面的 ' + prefix + 'CTX_GET("' + ctxKey + '")';
if (isRestful) {
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("data/list/0/' + cp + '")';
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("data/0/' + cp + '")';
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("list/0/' + cp + '")';
config += '\n// 可替代上面的 ' + ctxPutPfx + 'CTX_PUT("[]/0/' + cp + '", "PRE_DATA")';
config += '\n// 可替代上面的 ' + ctxPutPfx + 'CTX_PUT("data/0/' + cp + '", "PRE_DATA")';
config += '\n// 可替代上面的 ' + ctxPutPfx + 'CTX_PUT("list/0'/ + cp + '", "PRE_DATA")';
} else {
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("[]/0/' + cp + '")';
config += '\n// 可替代上面的 ' + prefix + 'PRE_DATA("' + kp + '[]/0/' + (col || key) + '")';
config += '\n// 可替代上面的 ' + ctxPutPfx + 'CTX_PUT("' + kp + '[]/0/' + (col || key) + '", "PRE_DATA")';
config += '\n// 可替代上面的 ' + ctxPutPfx + 'CTX_PUT("[]/0/' + cp + '", "PRE_DATA")';
}
}
config += '\n// 可替代上面的 ' + ctxPutPfx + 'CTX_PUT("' + key + '", App.getCurrentAccount())';
config += '\n// 可替代上面的 ' + ctxPutPfx + 'CTX_PUT("' + cp + '", "PRE_DATA")';
config += '\n// 可替代上面的 ' + ctxPutPfx + 'CTX_PUT("' + childPath + '", "PRE_ARG")';
if (key != childPath) {
config += '\n// 可替代上面的 ' + ctxPutPfx + 'CTX_PUT("' + key + '", "PRE_DATA")';
config += '\n// 可替代上面的 ' + ctxPutPfx + 'CTX_PUT("' + key + '", "PRE_ARG")';
}
}
else if (typeof value == 'boolean') {
if (isBad) {
return prefix + (isRand ? 'RANDOM_BAD_BOOL' : 'ORDER_BAD_BOOL' + offset) + '()'
}
config += prefix + (isRand ? 'RANDOM_IN' : 'ORDER_IN') + '(undefined, null, false, true)'
}
else if (typeof value == 'number') {
if (isBad) {
return prefix + (isRand ? 'RANDOM_BAD_NUM' : 'ORDER_BAD_NUM' + offset) + '()'
}
var isId = key == 'id' || key.endsWith('Id') || key.endsWith('_id') || key.endsWith('_ID')
if (isId) {
config += prefix + (isRand ? 'RANDOM_IN' : 'ORDER_IN') + '(undefined, null, ' + value + ')'
if (value >= 1000000000) { //PHP 等语言默认精确到秒 1000000000000) {
config += '\n// 可替代上面的 ' + prefix + 'RANDOM_INT(' + Math.round(0.9 * value) + ', ' + Math.round(1.1 * value) + ')'
}
else {
config += '\n// 可替代上面的 ' + prefix + '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
? (isRand ? 'RANDOM_INT' : '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 + (hasDot ? 'RANDOM_NUM' : 'RANDOM_INT') + '(' + (100 * value) + ', 0)'
}
else if (value > 0 && value < 1) { // 0-1 比例
config += '\n// 可替代上面的 ' + prefix + 'RANDOM_NUM(0, 1)'
}
else if (value >= 0 && value <= 100) { // 10% 百分比
config += '\n// 可替代上面的 ' + prefix + 'RANDOM_INT(0, 100)'
}
else {
config += '\n// 可替代上面的 ' + prefix + (hasDot != true && value < 10 ? (isRand ? 'RANDOM_INT' : 'ORDER_INT') + '(0, 9)' : ((hasDot ? 'RANDOM_NUM' : 'RANDOM_INT') + '(0, ' + 100 * value + ')'))
}
}
}
}
else if (typeof value == 'string') {
if (isBad) {
return prefix + (isRand ? 'RANDOM_BAD_STR' : 'ORDER_BAD_STR' + offset) + '()'
}
//引用赋值 || 远程函数 || 匹配条件范围
if (key.endsWith('@') || key.endsWith('()') || key.endsWith('{}')) {
return config
}
config += prefix + (isRand ? 'RANDOM_IN' : 'ORDER_IN') + '(undefined, null, ""' + (value == '' ? ')' : ', "' + value + '")')
}
else {
if (isBad) {
return prefix + (isRand ? 'RANDOM_BAD' : 'ORDER_BAD' + offset) + '()'
}
config += prefix + (isRand ? 'RANDOM_IN' : '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 16:
this.methods = StringUtil.split(this.exTxt.name, ',', true)
this.saveCache('', 'methods', this.methods)
break
case 7:
this.types = StringUtil.split(this.exTxt.name, ',', true)
this.saveCache('', 'types', this.types)
break
case 15:
this.otherEnv = StringUtil.get(this.exTxt.name)
this.saveCache('', 'otherEnv', this.otherEnv)
break
case 19:
this.aiModel = StringUtil.get(this.exTxt.name)
this.saveCache('', 'aiModel', this.aiModel)
this.refreshPageAgent()
break
case 20:
this.aiBaseUrl = StringUtil.get(this.exTxt.name)
this.saveCache('', 'aiBaseUrl', this.aiBaseUrl)
this.refreshPageAgent()
break
case 21:
this.aiApiKey = StringUtil.get(this.exTxt.name)
this.saveCache('', 'aiApiKey', this.aiApiKey)
this.refreshPageAgent()
break
case 22:
this.aiLanguage = StringUtil.get(this.exTxt.name)
this.saveCache('', 'aiLanguage', this.aiLanguage)
this.refreshPageAgent()
break
case 8:
var thirdParty = this.exTxt.name
this.getThirdPartyApiList(thirdParty, 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_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.resetUploading()
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, HTTP_METHOD_GET, REQUEST_TYPE_PARAM, docUrl, {}, header, swaggerCallback)
}
}
else if (platform == PLATFORM_RAP || platform == PLATFORM_YAPI || platform == PLATFORM_POSTMAN) {
var isRap = platform == PLATFORM_RAP
var isPostman = isRap != true && platform == PLATFORM_POSTMAN
var itemCallback = function (url, res, err) {
try {
App.onResponse(url, res, err)
} catch (e) {}
var data = res.data == null ? null : (isPostman ? (res.data.item || res.data.requests) : res.data.data)
if (isRap || isPostman) {
var modules = data == null ? null : (isRap ? data.modules : data)
if (modules != null) {
for (var i = 0; i < modules.length; i++) {
var it = modules[i] || {}
if (isPostman) {
App.uploadPostmanApi(it)
continue
}
var interfaces = it.interfaces || []
for (var j = 0; j < interfaces.length; j++) {
App.uploadRapApi(interfaces[j])
}
}
}
}
else {
App.uploadYApi(data)
}
}
if (isJSONData) {
App.resetUploading()
itemCallback(itemUrl, { data: jsonData }, null)
}
else {
App.request(false, HTTP_METHOD_GET, 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 == null ? null : (isPostman ? res.data.item : res.data.data)
if (apis == null) { // || apis.length <= 0) {
App.isSyncing = false
alert('没有查到 ' + (isRap ? 'Rap' : 'YApi') + ' 文档!请开启跨域代理,并检查 URL 是否正确!')
return
}
App.exTxt.button = '...'
App.resetUploading()
if (isPostman) {
itemCallback(itemUrl, { data: res.data }, null)
return
}
for (var url in apis) {
var 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, HTTP_METHOD_GET, REQUEST_TYPE_PARAM, itemUrl + '?id=' + listItem1._id, {}, header, itemCallback)
}
}
})
}
}
else {
alert('第三方平台只支持 Postman, Swagger, Rap, YApi !')
}
return true
})
break
}
},
resetUploading: function() {
App.uploadTotal = 0 // apis.length || 0
App.uploadDoneCount = 0
App.uploadFailCount = 0
App.uploadRandomCount = 0
},
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) {
if (isJSONData) {
listCallback(platform, docUrl, listUrl, itemUrl, itemUrl, { data: jsonData }, null)
}
else {
App.request(false, HTTP_METHOD_GET, 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_SWAGGER) {
if (isJSONData) {
listCallback(platform, docUrl, listUrl, itemUrl, itemUrl, { data: jsonData }, null)
}
else {
App.request(false, HTTP_METHOD_GET, 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, HTTP_METHOD_GET, 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') + ' 文档!' +
'\n请开启跨域代理,并检查 URL 是否正确!' +
'\nYApi/Rap/Swagger/Postman 网站的 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).replaceAll('//', '/')
// if (p == null) {
// continue
// }
App.request(false, HTTP_METHOD_GET, 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 : StringUtil.trim(tp.substring(index + 1))
var jsonData = null
try {
jsonData = parseJSON(docUrl)
}
catch (e) {}
var host = this.getBaseUrl()
var listUrl = null
var itemUrl = null
if (platform == PLATFORM_POSTMAN) {
if (docUrl.startsWith('/') || docUrl.indexOf('://') < 0) {
docUrl = 'https://www.postman.com' + (docUrl.startsWith('/collections') ? '' : '/collections') + (docUrl.startsWith('/') ? '' : '/') + docUrl
}
listUrl = docUrl
}
else 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') : StringUtil.trim(docUrl.substring(0, index))
itemUrl = index < 0 ? docUrl + (isRap ? '/repository/get' : '/api/interface/get') : StringUtil.trim(docUrl.substring(index + 1))
if (listUrl.startsWith('/')) {
listUrl = host + listUrl
}
if (itemUrl.startsWith('/')) {
itemUrl = host + itemUrl
}
}
callback(platform, jsonData, docUrl, listUrl, itemUrl)
},
/**上传 Postman API
* @param docItem
* @param callback
*/
uploadPostmanApi: 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 request = api.request || {}
var response = api.response || []
var body = request.body || {}
var json = body.raw || api.rawModeData
var options = body.options || {}
var language = (options.raw || {}).language
var method = api.method || request.method
var type = REQUEST_TYPE_JSON
switch (method || '') {
case 'GET':
type = REQUEST_TYPE_PARAM
break
case 'POST':
switch (language || '') {
case 'form-data': // FIXME
type = REQUEST_TYPE_DATA
break
case 'form-url-encoded': // FIXME
type = REQUEST_TYPE_FORM
break
// case 'json': //JSON
default:
type = REQUEST_TYPE_JSON
break
}
break
default:
type = REQUEST_TYPE_JSON
break
}
var urlObj = request.url || {}
var path = urlObj.path
var url = path instanceof Array ? '/' + path.join('/') : (typeof urlObj == 'string' ? urlObj : urlObj.raw)
if (StringUtil.isEmpty(url, true)) {
url = api.url
}
if (url != null && url.startsWith('{{url}}')) {
url = url.substring('{{url}}'.length)
}
var parameters = api.queryParams || request.queryParams || (urlObj instanceof Object ? urlObj.query : null)
var parameters2 = []
if (parameters != null && parameters.length > 0) {
for (var k = 0; k < parameters.length; k++) {
var paraItem = parameters[k] || {}
var name = paraItem.key || ''
if (StringUtil.isEmpty(name, true)) {
continue
}
var val = paraItem.value
if (val == '{{' + name + '}}') {
val = null
}
//转成和 Swagger 一样的字段及格式
paraItem.name = name
paraItem.type = paraItem.type == 'Number' ? 'integer' : StringUtil.toLowerCase(paraItem.type)
paraItem.default = val
parameters2.push(paraItem)
}
}
var header = ''
var headers = request.header || api.headerData || []
if (headers != null && headers.length > 0) {
for (var k = 0; k < headers.length; k++) {
var paraItem = headers[k] || {}
var name = paraItem.key || ''
if (StringUtil.isEmpty(name, true)) {
continue
}
var val = paraItem.value
header += (k <= 0 ? '' : '\n') + name + ': ' + StringUtil.trim(val)
+ (StringUtil.isEmpty(paraItem.description, true) ? '' : ' // ' + paraItem.description)
}
}
if (StringUtil.isEmpty(header, true)) {
header = api.headers
}
return this.uploadThirdPartyApi(method, type, api.name || request.name, url, parameters2, json, header
, api.description || request.description, null, response == null ? null : response[0])
},
/**上传 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, method == 'get' ? REQUEST_TYPE_PARAM : REQUEST_TYPE_JSON
, api.summary, url, parameters2, null, 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 method = HTTP_METHOD_POST
var type
switch ((api.summary || {}).requestParamsType || '') {
case 'QUERY_PARAMS':
method = HTTP_METHOD_GET
type = REQUEST_TYPE_PARAM
break
case 'BODY_PARAMS':
method = HTTP_METHOD_POST
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:
method = HTTP_METHOD_POST
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 + ': ' + StringUtil.trim(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(method, type, api.name, api.url, parameters2, null, 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 + ': ' + StringUtil.trim(item.value)
+ (StringUtil.isEmpty(item.description, true) ? '' : ' // ' + StringUtil.trim(item.description))
}
var typeAndParam = this.parseYApiTypeAndParam(api)
return this.uploadThirdPartyApi(
typeAndParam.method, typeAndParam.type, api.title, api.path, typeAndParam.param, null, 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) : StringUtil.trim(api.markdown).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 : parseJSON(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
}
},
generateValue: function (t, n, isSQL) {
if (t == 'boolean') {
return true
}
if (t == 'integer') {
return n == 'pageSize' ? 10 : 1
}
if (t == 'number') {
return n == 'pageSize' ? 10 : 1
}
if (t == 'string') { // TODO
return ''
}
if (t == 'object') {
return {}
}
if (t == 'array') {
return []
}
var suffix = n != null && n.length >= 3 ? n.substring(n.length - 3).toLowerCase() : null
if (suffix == 'dto') {
return {}
}
return null
},
//上传第三方平台的 API 至 APIAuto
uploadThirdPartyApi: function(method, type, name, url, parameters, json, header, description, creator, data) {
if (typeof json == 'string') {
json = parseJSON(json)
}
const reqObj = json || {}
var req = '{'
var isJSONEmpty = json == null || Object.keys(json).length <= 0
if (parameters != null && parameters.length > 0) {
for (var k = 0; k < parameters.length; k++) {
var paraItem = parameters[k] || {}
var n = paraItem.name || '' //传进来前已过滤,这里只是避免万一为 null 导致后面崩溃
var val = paraItem.default
var t = paraItem.type || typeof val
if (val == undefined) {
val = this.generateValue(t, n)
reqObj[n] = val
}
reqObj[n] = val
if (typeof val == 'string' && (StringUtil.isEmpty(t, true) || t == 'string')) {
val = isJSONEmpty ? ('"' + val.replace(/"/g, '\\"') + '"') : val
}
else if (val instanceof Object) {
val = JSON.stringify(val, null, ' ')
}
if (isJSONEmpty) {
req += '\n "' + n + '": ' + val + (k < parameters.length - 1 ? ',' : '')
+ ' // ' + (paraItem.required ? '必填。 ' : '') + StringUtil.trim(paraItem.description)
} else {
url += (k <= 0 && url.indexOf('?') < 0 ? '?' : '&') + n + '=' + (val == null ? '' : val)
}
}
}
req += '\n}'
if (isJSONEmpty != true) {
req = JSON.stringify(json, null, ' ')
}
var commentObj = JSONResponse.updateStandard({}, reqObj);
CodeUtil.parseComment(req, null, url, this.schema, this.database, this.language, true, commentObj, true)
var standard = this.isMLEnabled ? JSONResponse.updateStandard({}, data) : null
name = StringUtil.get(name)
if (name.length > 100) {
name = name.substring(0, 60) + ' ... ' + name.substring(70, 100)
}
var currentAccountId = this.getCurrentAccountId()
const baseUrl = this.getBaseUrl(url)
const path = this.getBranchUrl(url)
var callback = function (url, res, err) {
var data = res.data
var did = data.Document == null ? null : data.Document.id
const isRandom = did != null && did > 0
var config = isRandom ? StringUtil.trim(App.newRandomConfig(null, '', reqObj, false, null, null, true)) : null
App.request(true, HTTP_METHOD_POST, REQUEST_TYPE_JSON, App.server + '/post', {
format: false,
'Document': isRandom ? undefined : {
'creator': creator,
'testAccountId': currentAccountId,
'method': StringUtil.isEmpty(method, true) ? null : StringUtil.toUpperCase(method, true),
'operation': CodeUtil.getOperation(path.substring(1), reqObj),
'type': type,
'name': StringUtil.get(name),
'url': path,
'request': reqObj == null ? null : JSON.stringify(reqObj, null, ' '),
'standard': commentObj == null ? null : JSON.stringify(commentObj, null, ' '),
'header': StringUtil.isEmpty(header, true) ? null : StringUtil.trim(header),
'detail': StringUtil.trim(description).replaceAll('*/', '* /')
},
'Random': isRandom ? {
toId: 0,
documentId: did,
count: 1,
name: '常量取值 ' + App.formatDateTime(),
config: config
} : undefined,
'TestRecord': {
'randomId': 0,
'host': StringUtil.isEmpty(baseUrl, true) ? null : baseUrl,
'testAccountId': currentAccountId,
'response': data == null ? '' : JSON.stringify(data, null, ' '),
'standard': standard == null ? '' : JSON.stringify(standard, null, ' '),
},
'tag': isRandom ? 'Random' : 'Document'
}, {}, function (url, res, err) {
//太卡 App.onResponse(url, res, err)
var data = res.data || {}
var tblObj = isRandom ? data.Random : data.Document
if (tblObj.id != null && tblObj.id > 0) {
App.uploadDoneCount ++
if (isRandom) {
App.uploadRandomCount ++
}
} else {
App.uploadFailCount ++
}
if (isRandom != true) {
App.newAndUploadRandomConfig(baseUrl, reqObj, tblObj.id, null, 5)
}
App.exTxt.button = 'All:' + App.uploadTotal + '\nDone:' + App.uploadDoneCount + '\nFail:' + App.uploadFailCount
if (App.uploadDoneCount + App.uploadFailCount >= App.uploadTotal) {
alert('导入完成,其中 ' + App.uploadRandomCount + ' 个用例已存在,改为生成和上传了参数注入配置')
App.isSyncing = false
App.testCasePage = 0
App.isRandomShow = true
App.isRandomListShow = true
App.showTestCase(false, false)
App.remotes = []
App.showTestCase(true, false)
}
})
}
if (JSONObject.isAPIJSONPath(path)) {
callback(url, {}, null)
}
else {
this.request(true, HTTP_METHOD_POST, REQUEST_TYPE_JSON, this.server + '/get/Document?format=false&@role=OWNER', {
url: path,
method: StringUtil.isEmpty(method, true) ? null : StringUtil.toUpperCase(method, true)
}, {}, callback)
}
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()) + ':' + this.fillZero(date.getSeconds())
},
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;
},
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, noShowCase) {
this.isReportShow = false
var accounts = this.accounts
var num = accounts == null ? 0 : accounts.length
if (index < 0 || index >= num) {
item = this.getCurrentAccount()
if (item != null && item.isLoggedIn) {
//logout FIXME 没法自定义退出,浏览器默认根据url来管理session的
this.logout(false, function (url, res, err) {
App.onResponse(url, res, err)
item.isLoggedIn = false
App.saveAccounts()
// App.changeScriptType(App.scriptType)
// App.listScript()
if (callback != null) {
callback(false, index, err)
}
});
item.isLoggedIn = false
} else {
if (callback != null) {
callback(false, index)
}
}
this.currentAccountIndex = index
// this.changeScriptType(App.scriptType)
// this.listScript()
var accountIdStr = String(item != null && item.isLoggedIn ? item.id || '' : '')
var tests = App.doneCount >= App.allCount && noShowCase != true && this.isCrossEnabled && this.isStatisticsEnabled
&& this.reportId != null && this.reportId > 0 ? this.tests[accountIdStr] : null
if (StringUtil.isNotEmpty(tests)) {
this.showCompare4TestCaseList(true)
if (App.deepDoneCount >= App.deepAllCount && ! this.isTestCaseShow) {
this.showCompare4RandomList(true, false)
this.showCompare4RandomList(true, true)
}
}
return
}
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.saveAccounts()
// App.changeScriptType(App.scriptType)
// App.listScript()
if (callback != null) {
callback(false, index, err)
}
});
// this.currentAccountIndex = -1
// this.changeScriptType(App.scriptType)
}
else {
//login
this.login(false, function (url, res, err) {
App.onResponse(url, res, err)
var data = res.data || {}
var user = data.user || data.userObj || data.userObject || data.userRsp || data.userResp || data.userBean || data.userData || data.data || data.User || data.Data
if (user == null) {
if (callback != null) {
callback(false, index, err)
}
}
else {
var headers = res.headers || {}
baseUrl = App.getBaseUrl(vUrl.value)
item.baseUrl = item.baseUrl || baseUrl
item.id = user.id || user.userId || user.user_id || user.userid // TODO 工具函数直接遍历 key 判断可能的名称
item.name = user.name || user.nickname || user.nickName || user.user_name || user.username || user.userName
// item.phone = user.phone = user.mobile || user.mobileNo || user.mobileNum || user.mobileNumber || user.phone || user.phoneNo || user.phoneNum || user.phoneNumber || user.mobile_no || user.mobile_num || user.mobile_number || user.phone_no || user.phone_num || user.phone_number
item.remember = data.remember
item.isLoggedIn = true
item.token = headers.token || headers.Token || data.token || data.Token || user.token || user.Token || user.accessToken || user.access_token || data.accessToken || data.access_token
item.cookie = res.cookie || headers.cookie || headers.Cookie || headers['set-cookie'] || headers['Set-Cookie']
App.accounts[App.currentAccountIndex] = item
App.saveAccounts()
// App.changeScriptType(App.scriptType)
// App.listScript()
if (callback != null) {
callback(true, index, err)
}
if (App.doneCount >= App.allCount && noShowCase != true && App.isStatisticsEnabled && App.reportId != null && App.reportId > 0) {
if (item != null) {
item.isLoggedIn = true
}
var accountIdStr = String(item != null && item.isLoggedIn ? item.id || '' : '')
var tests = App.tests[accountIdStr]
if (JSONObject.isEmpty(tests) != true) {
App.showCompare4TestCaseList(true)
if (App.deepDoneCount >= App.deepAllCount && ! App.isTestCaseShow) {
App.showCompare4RandomList(true, false)
App.showCompare4RandomList(true, true)
}
}
}
}
});
}
}
// if (this.isStatisticsEnabled && this.reportId != null && this.reportId > 0) {
// if (item != null) {
// item.isLoggedIn = true
// }
//
// var accountIdStr = String(item != null && item.isLoggedIn ? item.id || '' : '')
// var tests = this.tests[accountIdStr]
// if (JSONObject.isEmpty(tests) != true) {
// this.showCompare4TestCaseList(true)
// if (! this.isTestCaseShow) {
// this.showCompare4RandomList(true, false)
// this.showCompare4RandomList(true, true)
// }
// }
// }
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
// this.changeScriptType(App.scriptType)
// this.listScript()
//目前还没做到同一标签页下测试账号切换后,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.saveAccounts()
},
addAccountTab: function () {
this.showLogin(true, false)
},
showCompare4TestCaseList: function (show, isCheckAccount) {
var testCases = show ? App.testCases : null
var allCount = testCases == null ? 0 : testCases.length
App.allCount = allCount
if (allCount > 0) {
const accounts = this.accounts || []
const curAccount = accounts[this.currentAccountIndex] || {}
const isLoggedIn = curAccount.isLoggedIn
// var accountIndex = isLoggedIn || this.isCrossEnabled != true ? this.currentAccountIndex : -1
var accountIndex = this.currentAccountIndex || 0
// this.currentAccountIndex = accountIndex //解决 onTestResponse 用 -1 存进去, handleTest 用 currentAccountIndex 取出来为空
// var account = this.accounts[curAccount.id]
// baseUrl = this.getBaseUrl()
var reportId = this.reportId
if (reportId == null || Number.isNaN(reportId)) {
reportId = null
}
var accountIdStr = String(curAccount.isLoggedIn ? curAccount.id || '' : '')
var tests = this.tests[accountIdStr] // FIXME account.phone + '@' + (account.baseUrl || baseUrl)]
var hasTests = JSONObject.isEmpty(tests) != true
if (hasTests || this.isChainShow || (reportId != null && reportId >= 0)) {
const lastAccountIndex = accountIndex || 0
const isML = this.isMLEnabled
for (var i = 0; i < allCount; i++) {
var item = testCases[i]
var d = item == null ? null : item.Document
if (d == null || d.id == null) {
continue
}
var chain = isCheckAccount ? item.Chain : null
var testInfo = chain == null ? null : chain.testInfo
var testAccount = testInfo == null ? null : testInfo.account
if (StringUtil.isNotEmpty(testAccount, true)) {
var map = {}
var find = false
for (var i = 0; i < accounts.length; i ++) {
var acc = accounts[i]
if (acc != null && (acc.id == chain.testAccountId || (
(StringUtil.isEmpty(testInfo.baseUrl) || acc.baseUrl == testInfo.baseUrl) && (
(StringUtil.isEmpty(testInfo.phone) && StringUtil.isEmpty(testInfo.email))
|| (StringUtil.isNotEmpty(acc.phone) && acc.phone == testInfo.phone)
|| (StringUtil.isNotEmpty(acc.email) && acc.email == testInfo.email) )
))) {
if (! map[acc.id]) {
chain.testAccountId = acc.id
accountIndex = i
acc.isLoggedIn = true
// acc.isLoggedIn = ! acc.isLoggedIn
// this.onClickAccount(i, acc, null, true)
}
find = true
break
}
}
if (! find) {
testInfo.isLoggedIn = ! testInfo.isLoggedIn
chain.testAccountId = testInfo.testAccountId
accounts.push(testInfo)
// this.saveAccounts()
var isStatisticsEnabled = this.isStatisticsEnabled
this.isStatisticsEnabled = false
accountIndex = accounts.length - 1
this.onClickAccount(accountIndex, testInfo, null, true)
this.isStatisticsEnabled = isStatisticsEnabled
}
map[chain.testAccountId] = true
accountIndex = lastAccountIndex || 0
curAccount.isLoggedIn = isLoggedIn
}
if (this.isReportShow && reportId != null && reportId >= 0) {
var tr = item.TestRecord || {}
var rsp = parseJSON(tr.response)
tests[d.id] = [rsp]
var cmp = parseJSON(tr.compare)
if (StringUtil.isEmpty(cmp) || cmp.code != JSONResponse.COMPARE_ERROR) {
var oldTr = item['TestRecord:old'] || {}
var stdd = parseJSON(isML ? oldTr.standard : oldTr.response, null, true)
cmp = (StringUtil.isEmpty(stdd) ? null : JSONResponse.compareResponse({
status: oldTr.status,
message: StringUtil.trim(oldTr.throw) + ' ' + StringUtil.trim(oldTr.msg),
data: rsp
}, stdd, rsp, '', isML)) || cmp
if (StringUtil.isEmpty(cmp)) {
cmp = JSONResponse.compareWithBefore(null, null)
}
}
this.onTestResponse(null, allCount, testCases, i, item, d, item.Random, tr, rsp, null, cmp, false, accountIndex, true);
continue
}
if (! hasTests) {
continue
}
this.compareResponse(null, allCount, testCases, i, item, (tests[d.id] || {})[0], false, accountIndex, true)
}
}
}
},
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.isChainItemShow() // || this.chainPaths.length <= 0)
},
isChainItemShow: function () {
return this.chainShowType != 2 || (this.chainGroups.length <= 0 && this.chainPaths.length > 0)
},
changeTagCombine: function () {
this.tagCombineIndex = (this.tagCombineIndex + 1) % this.tagCombines.length
if (this.isChainShow) {
this.selectChainGroup(this.currentChainGroupIndex)
} else {
this.onFilterChange('testCase')
}
},
removeTag: function (ind, tag, index, item, isDoc) {
if (! this.isCaseGroupEditable) {
this.isCaseGroupEditable = true
this.changeTag(index, item, isDoc)
return
}
var chain = (item || {})[isDoc ? 'Document' : 'Chain'] || {}
var tagList = chain.tagList || [];
tagList.splice(ind, 1)
this.setTag(index, chain, tagList, null, isDoc)
},
changeTag: function (index, group, isDoc) {
this.isCaseGroupEditable = true
if (isDoc) {
this.currentDocIndex = index
} else {
this.currentChainGroupIndex = index
}
var chain = (group || {})[isDoc ? 'Document' : 'Chain'] || {}
var tagList = chain.tagList || []
var tags = this.tags || []
for (var j = 0; j < tags.length; j ++) {
var tag = tags[j] || {}
tag.selected = false
}
for (var i = 0; i < tagList.length; i ++) {
var name = tagList[i]
if (StringUtil.isEmpty(name, true)) {
continue
}
var find = false
for (var j = 0; j < tags.length; j ++) {
var tag = tags[j] || {}
if (tag.name == name) {
tag.selected = true
find = true
break
}
}
if (! find) {
tags.push({name: name, selected: true})
}
}
this.tags = tags
alert('已进入编辑模式,点击底部标签即可添加/移除,点列表项标签也可移除')
},
setTag(index, item, tagList, isAdd, isDoc) {
var table = isDoc ? 'Document' : 'Chain'
var chain = item || {} // (item || {}).Chain || {}
this.request(true, HTTP_METHOD_POST, REQUEST_TYPE_JSON, this.server + '/put', {
[table]: {
'id': chain.id,
'groupId': isDoc ? undefined : chain.groupId,
'groupId{}': isDoc ? undefined : [chain.groupId],
'groupName': isDoc ? undefined : chain.groupName,
'tagList': tagList
},
tag: isDoc ? 'Document' : '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' : (isDoc ? '\nid: ' + chain.id : '!\ngroupId: ' + chain.groupId))
+ (isDoc ? '\nname: ' + chain.name : '\ngroupName: ' + chain.groupName) + '\n' + msg
)
App.isCaseGroupEditable = ! isOk
if (isOk) {
if (isDoc) {
App.onFilterChange('testCase')
} else {
App.selectChainGroup(App.currentChainGroupIndex, null)
}
}
})
},
selectTag: function (index, tag, isDoc) {
tag.selected = ! tag.selected
var groupIndex = isDoc ? this.currentDocIndex : this.currentChainGroupIndex
if (this.isCaseGroupEditable != true || groupIndex < 0) {
if (isDoc) {
this.onFilterChange('testCase')
} else {
this.selectChainGroup(groupIndex)
}
return
}
var group = (isDoc ? this.testCases[groupIndex] : this.chainGroups[groupIndex]) || {}
var chain = (isDoc ? group.Document : group.Chain) || {}
var tagList = chain.tagList || []
if (tag.selected) {
for (var i = 0; i < tagList.length; i ++) {
var name = tagList[i]
if (name == tag.name) {
return
}
}
tagList.push(tag.name)
if (this.isCaseGroupEditable) {
tag.selected = false
}
} else {
var ind = tagList.indexOf(tag.name)
if (ind >= 0) {
tagList.splice(ind, 1)
}
}
this.setTag(groupIndex, chain, tagList, tag.selected, isDoc)
},
selectChainGroup: function (index, group) {
this.currentChainGroupIndex = index
this.currentDocIndex = -1
this.isCaseGroupEditable = false
if (group == null) {
if (index == null) {
index = this.chainPaths.length - 1
group = this.chainPaths[index]
} else {
this.chainPaths = []
}
} else {
this.chainPaths = [group] // .push(group)
}
this.casePaths = this.chainPaths
var groupId = group == null ? 0 : group.groupId
if (groupId != null && groupId > 0) { // group != null && groupId == 0) {
// this.chainGroups = []
this.remotes = this.testCases = (this.chainGroups[index] || {})['[]'] || []
// this.showTestCase(true, false, null)
return
}
var isMLEnabled = this.isMLEnabled
var userId = this.User.id
var project = this.projectHost.project
var reportId = this.reportId
baseUrl = this.getBaseUrl(vUrl.value, true)
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] || ''
var logic = this.tagCombines[this.tagCombineIndex] || '&'
var tagList = this.tags || []
var tags = []
for (var i = 0; i < tagList.length; i ++) {
var tag = tagList[i] || {}
if (tag.selected) {
tags.push(tag.name)
}
}
search = StringUtil.split(search)
var notShowReport = ! this.isShowReport()
var req = {
format: false,
'[]': {
'count': count || 0,
'page': page || 0,
'Chain': {
'userId': userId,
'toGroupId': groupId,
'groupName%$': search,
['tagList' + logic + '<>']: tags == null || tags.length <= 0 ? null : tags,
'@raw': '@column',
'@column': "groupId;any_value(groupName):groupName;any_value(tagList):tagList;count(*):count",
'@group': 'groupId',
'@order': 'groupId-',
// 'documentId>': 0
},
'[]': {
'count': 0, //200 条测试直接卡死 0,
'page': 0,
'join': '&/Document',
'Chain': {
// TODO 后续再支持嵌套子组合 'toGroupId': groupId,
'userId': userId,
'groupId@': '[]/Chain/groupId',
'@column': "id,groupId,documentId,documentName,randomId,rank,testAccountId,testName,testInfo",
'@order': 'rank+,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,
'project': StringUtil.isEmpty(project, true) ? null : project,
'operation$': search,
'name%$': search,
'url%$': search,
// 'group{}': group == null || StringUtil.isNotEmpty(groupUrl) ? null : 'length(group)<=0',
// 'group{}': group == null ? null : (group.groupName == null ? "=null" : [group.groupName]),
'@combine': StringUtil.isEmpty(search) ? null : 'operation$,name%$,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',
'count>=': 1,
'res': 0,
'toId': 0,
'chainId@': '/Chain/id',
'documentId@': '/Document/id',
'userId': userId,
'@order': 'date-'
},
'Random:res': {
// 'id@': '/Chain/randomId',
'res': 1,
'toId@': '/Random/id',
'chainId@': '/Chain/id',
'documentId@': '/Document/id',
'userId': userId,
'@order': 'date-'
},
'TestRecord': {
'chainId@': '/Chain/id',
'documentId@': '/Document/id',
'userId': userId,
'host': StringUtil.isEmpty(baseUrl, true) ? null : baseUrl,
'testAccountId': this.getCurrentAccountId(),
'randomId': 0,
'reportId': notShowReport ? null : reportId,
'invalid': notShowReport ? 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,
'chainId@': '/Chain/id',
'documentId@': '/Document/id',
'@order': 'date-'
},
'Script:post': {
'ahead': 0,
// 'testAccountId': 0,
'chainId@': '/Chain/id',
'documentId@': '/Document/id',
'@order': 'date-'
}
},
},
'Chain-tagList[]': {
'count': 0,
'Chain': {
'userId': userId,
'@column': "groupId;any_value(tagList):tagList",
'@group': 'groupId',
'tagList[>': 0
}
},
'@role': IS_NODE ? null : 'LOGIN',
key: IS_NODE ? this.key : undefined // 突破常规查询数量限制
}
if (IS_BROWSER) {
this.onChange(false)
}
this.request(true, HTTP_METHOD_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
}
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 = item['[]'] || []
var tagLists = data['Chain-tagList[]'] || []
var tags = App.tags || []
for (var i = 0; i < tagLists.length; i ++) {
var tagList = tagLists[i] || []
for (var j = 0; j < tagList.length; j ++) {
var name = tagList[j]
if (StringUtil.isEmpty(name, true)) {
continue
}
var find = false
for (var k = 0; k < tags.length; k ++) {
var tag = tags[k] || {}
if (tag.name == name) {
find = true
break
}
}
if (! find) {
tags.push({name: name})
}
}
}
App.tags = tags
App.isTestCaseShow = true
// 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] || {}).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 nextIndex = this.currentDocIndex
var nextChain = nextIndex == null || nextIndex < 0 ? null : (this.testCases[nextIndex] || {}).Chain
var nextRank = nextChain == null ? null : nextChain.rank
var groupName = group.groupName
var isAdd = true
var reqObj = this.testCases == null || this.testCases.length <= 0 ? null : this.getRequest()
var config = reqObj == null ? '' : StringUtil.trim(this.newRandomConfig(null, '', reqObj))
this.request(true, HTTP_METHOD_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,
'documentName': item.name
},
Random: {
toId: 0,
documentId: item.id,
count: 1,
name: '参数传递 ' + App.formatDateTime(),
config: config
},
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
if (isOk) {
// App.remotes = App.testCases = []
// App.showTestCase(true, false, null)
App.selectChainGroup(App.currentChainGroupIndex, null)
}
})
},
onClickPath: function (index, path) {
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) {
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) {
if (this.isChainShow) {
this.selectChainGroup(index, group)
return
}
this.isCaseGroupEditable = false
if (group == null) {
if (index == null) {
index = this.casePaths.length - 1
group = this.casePaths[index]
} else {
this.casePaths = []
}
} else {
this.casePaths.push(group)
}
var groupUrl = group == null ? '' : (group.groupUrl || '')
if (group != null && StringUtil.isEmpty(groupUrl)) {
this.caseGroups = []
this.remotes = App.testCases = []
this.showTestCase(true, false, null)
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] || ''
search = StringUtil.split(search)
var req = {
format: false,
'Document[]': {
'count': count || 0,
'page': page || 0,
'Document': {
'@from@': {
'Document': {
'@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('%', '\\%') + '/%'],
'@combine': StringUtil.isEmpty(search) ? null : 'group%$,url%$',
'@null': 'sqlauto', //'sqlauto{}': '=null',
'url{}': 'length(url)>0',
'url&$': StringUtil.isEmpty(groupUrl) ? null : [groupUrl.replaceAll('_', '\\_').replaceAll('%', '\\%') + '/%']
// 'group{}': group == null || StringUtil.isNotEmpty(groupUrl) ? null : 'length(group)<=0' // SQL WHERE 条件不用别名
// '@having': "length(url)>0" // StringUtil.isEmpty(groupUrl) ? "length(url)>0" : "(url = '" + groupUrl.replaceAll("'", "\\'") + "')"
}
},
'groupUrl&$': StringUtil.isEmpty(groupUrl) ? null : [groupUrl.replaceAll('_', '\\_').replaceAll('%', '\\%') + '/%'],
'groupName%$': search,
'groupUrl%$': search,
'@combine': StringUtil.isEmpty(search) ? null : 'groupName%$,groupUrl%$',
'@column': "groupName,groupUrl;any_value(groupName):rawName;length(groupName):groupNameLen;length(groupUrl):groupUrlLen;count(*):count",
'@group': 'groupName,groupUrl',
'@order': 'groupNameLen+,groupName-,groupUrlLen+,groupUrl+',
}
},
'@role': IS_NODE ? null : 'LOGIN',
key: IS_NODE ? this.key : undefined // 突破常规查询数量限制
}
if (IS_BROWSER) {
this.onChange(false)
}
this.request(true, HTTP_METHOD_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.caseGroupCount = 50
App.caseGroupPage = 0
App.caseGroupSearch = ''
App.caseGroupCounts = {}
App.caseGroupPages = {}
App.caseGroupSearches = {}
App.saveCache(App.server, 'caseGroupCount', App.caseGroupCount)
App.saveCache(App.server, 'caseGroupPage', App.caseGroupPage)
App.saveCache(App.server, 'caseGroupSearch', App.caseGroupSearch)
App.saveCache(App.server, 'caseGroupCounts', App.caseGroupCounts)
App.saveCache(App.server, 'caseGroupPages', App.caseGroupPages)
App.saveCache(App.server, 'caseGroupSearches', App.caseGroupSearches)
}
return
}
App.caseGroups = data['Document[]'] || []
App.remotes = App.testCases = []
App.showTestCase(true, false, null)
})
},
switchCaseShowType: function () {
if (this.isLocalShow) {
alert('只有远程用例才能切换!')
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)
}
},
onClickPathRoot: function () {
var isChainShow = this.isChainShow
// 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
this.isLocalShow = type == 2
this.testCases = this.remotes = []
if (type == 1 && StringUtil.isEmpty(this.chainGroups)) {
this.selectChainGroup(-1, null)
}
else if (type == 0 && StringUtil.isEmpty(this.caseGroups)) {
this.selectCaseGroup(-1, null)
}
else {
this.showTestCase(true, this.isLocalShow)
}
}
else if (isChainShow) {
this.selectChainGroup(-1, null)
}
else {
this.selectCaseGroup(-1, null)
}
},
getCaseCountStr: function() {
if (this.isLocalShow) {
return '(' + StringUtil.length(this.testCases) + ')'
}
var isChainShow = this.isChainShow
var isCaseGroupShow = this.isCaseGroupShow()
var isCaseItemShow = this.isCaseItemShow()
var caseGroups = (isChainShow ? this.chainGroups : this.caseGroups)
return '(' + (isCaseGroupShow ? StringUtil.length(caseGroups) : '')
+ (isCaseGroupShow && isCaseItemShow ? '|' : '')
+ (isCaseItemShow ? StringUtil.length(this.testCases) : '') + ')';
},
//显示远程的测试用例文档
showTestCase: function (show, isLocal, callback, group) {
this.isTestCaseShow = show
this.isLocalShow = isLocal
if (IS_BROWSER) {
vOutput.value = show ? '' : (output || '')
this.showDoc()
}
if (isLocal) {
this.testCases = this.locals || []
return
}
this.testCases = this.remotes || []
this.getCurrentSummary().summaryType = 'total' // this.onClickSummary('total', true)
if (show) {
var testCases = this.testCases
var allCount = testCases == null ? 0 : testCases.length
this.allCount = allCount
if (allCount > 0) {
if (! (this.isAllSummaryShow() || this.isCurrentSummaryShow())) {
this.showCompare4TestCaseList(show, this.isChainShow)
}
return;
}
var project = (this.projectHost || {}).project
// this.isTestCaseShow = false
var reportId = this.reportId
var methods = this.methods
var types = this.types
var isChainShow = this.isChainShow
var paths = isChainShow ? this.chainPaths : this.casePaths
var index = paths.length - 1
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
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.split(search)
var url = this.server + '/get'
var userId = this.User.id
var logic = this.tagCombines[this.tagCombineIndex] || '&'
var tagList = (isChainShow ? null : this.tags) || []
var tags = []
for (var i = 0; i < tagList.length; i ++) {
var tag = tagList[i] || {}
if (tag.selected) {
tags.push(tag.name)
}
}
var notShowReport = ! this.isShowReport()
this.coverage = {}
this.view = 'markdown'
var req = {
format: false,
'[]': {
'count': count || 100, //200 条测试直接卡死 0,
'page': page || 0,
'join': isChainShow ? '&/Document,@/Random' : '@/TestRecord,@/Script:pre,@/Script:post',
'Chain': isChainShow ? {
// TODO 后续再支持嵌套子组合 'toGroupId': groupId,
'groupId': groupId,
'@column': "id,groupId,documentId,randomId,documentName,randomName,rank,testAccountId,testName,testInfo", // ;unix_timestamp(rank):rank",
'@order': 'rank+,id+',
'documentId>': 0
} : 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': userId,
'project': StringUtil.isEmpty(project, true) ? null : project,
'operation$': search,
'name%$': search,
['tagList' + logic + '<>']: tags == null || tags.length <= 0 ? null : tags,
'url%$': search,
'url|$': StringUtil.isEmpty(groupUrl) ? null : [groupUrl, groupUrl.replaceAll('_', '\\_').replaceAll('%', '\\%') + '/%'],
// 'group{}': group == null || StringUtil.isNotEmpty(groupUrl) ? null : 'length(group)<=0',
// 'group{}': group == null ? null : (group.groupName == null ? "=null" : [group.groupName]),
'@combine': search == null ? null : 'operation$,name%$,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': isChainShow ? {
// 'id@': '/Chain/randomId',
'res': 0,
'toId': 0, // null,
'chainId@': '/Chain/id',
// 'documentId@': '/Document/documentId',
'userId': userId,
'@order': 'date-'
} : null,
'Random:res': isChainShow ? {
// 'id@': '/Chain/randomId',
'res': 1,
'toId@': '/Random/id',
'chainId@': '/Chain/id',
'documentId@': '/Document/id',
'userId': userId,
'@order': 'date-'
} : null,
'TestRecord': {
'chainId@': isChainShow ? '/Chain/id' : null,
'chainId': isChainShow ? null : 0,
'documentId@': '/Document/id',
'userId': userId,
'host': StringUtil.isEmpty(baseUrl, true) ? null : baseUrl,
'testAccountId': this.getCurrentAccountId(),
'randomId': 0,
'reportId': notShowReport || reportId <= 0 ? null : reportId,
'invalid': notShowReport ? 0 : null,
'@order': 'id-,date-',
'@column': 'id,userId,documentId,testAccountId,reportId,duration,minDuration,maxDuration,status,throw,msg,response' + (this.isStatisticsEnabled ? ',compare' : '')+ (this.isMLEnabled ? ',standard' : ''),
'standard{}': this.isMLEnabled ? (this.database == 'SQLSERVER' ? 'len(standard)>2' : 'length(standard)>2') : null //用 MySQL 5.6 '@having': this.isMLEnabled ? 'json_length(standard)>0' : null
},
'TestRecord:old': notShowReport || reportId <= 0 ? undefined : {
'id<@': '/TestRecord/id',
'chainId@': isChainShow ? '/Chain/id' : null,
'chainId': isChainShow ? null : 0,
'documentId@': '/Document/id',
'userId': userId,
'host': StringUtil.isEmpty(baseUrl, true) ? null : baseUrl,
'testAccountId': this.getCurrentAccountId(),
'randomId': 0,
'reportId<': reportId, // reportId <= 0 ? null : reportId,
'invalid': null, // reportId == null ? 0 : null,
'@order': 'id-,date-',
'@column': 'id,userId,documentId,testAccountId,reportId,duration,minDuration,maxDuration,response' + (this.isStatisticsEnabled ? ',compare' : '')+ (this.isMLEnabled ? ',standard' : ''),
'standard{}': this.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,
'chainId@': isChainShow ? '/Chain/id' : null,
'chainId': isChainShow ? null : 0,
'documentId@': '/Document/id',
'@order': 'date-'
},
'Script:post': {
'ahead': 0,
// 'testAccountId': 0,
'chainId@': isChainShow ? '/Chain/id' : null,
'chainId': isChainShow ? null : 0,
'documentId@': '/Document/id',
'@order': 'date-'
}
},
'@role': IS_NODE ? null : 'LOGIN',
key: IS_NODE ? this.key : undefined // 突破常规查询数量限制
}
if (IS_BROWSER) {
this.onChange(false)
}
this.request(true, HTTP_METHOD_POST, REQUEST_TYPE_JSON, url, req, {}, function (url, res, err) {
App.isTestCaseShow = false
if (callback) {
callback(url, res, err)
return
}
App.onTestCaseListResponse(show, url, res, err)
})
} else if (callback != null) {
callback(null, {}, null)
}
},
lastCaseReqTime: 0,
onTestCaseListResponse: function(show, url, res, err) {
var time = res == null || res.config == null || res.config.metadata == null ? 0 : (res.config.metadata.startTime || 0)
if (time < this.lastCaseReqTime) {
return
}
this.lastCaseReqTime = time;
this.onResponse(url, res, err)
var data = res.data
if (JSONResponse.isSuccess(data)) {
this.isTestCaseShow = true
this.isLocalShow = false
this.testCases = App.remotes = data['[]']
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 || '')
this.showDoc()
}
this.showCompare4TestCaseList(show, this.isChainShow)
//this.onChange(false)
} else if (IS_BROWSER) { // 解决一旦错了,就只能清缓存
this.testCaseCount = 50
this.testCasePage = 0
this.testCaseSearch = ''
this.testCasePages = {}
this.testCaseCounts = {}
this.testCaseSearches = {}
this.saveCache(this.server, 'testCasePage', this.testCasePage)
this.saveCache(this.server, 'testCaseCount', this.testCaseCount)
this.saveCache(this.server, 'testCaseSearch', this.testCaseSearch)
this.saveCache(this.server, 'testCasePages', null)
this.saveCache(this.server, 'testCaseCounts', null)
this.saveCache(this.server, 'testCaseSearches', null)
}
},
onClickLogoutSummary: function (color) {
this.onClickSummary(color, false, -1)
},
onClickAllSummary: function (color) {
this.onClickSummary(color, false, this.accounts.length) // this.currentAccountIndex)
},
onClickCurrentSummary: function (color) {
this.onClickSummary(color, false, this.currentAccountIndex)
},
onClickSummary: function (color, isRandom, accountIndex) {
var isCur = this.currentAccountIndex == accountIndex
if (! isCur) {
this.onClickAccount(accountIndex, accountIndex < 0 ? this.logoutSummary : this.accounts[accountIndex])
}
// this.currentAccountIndex = accountIndex
// this.isTestCaseShow = false
var isSub = this.isRandomSubListShow
var arr = isRandom ? (isSub ? this.currentRandomItem.subs : this.currentRemoteItem.randoms) : this.remotes;
var list = []
if (color == null || color == 'total') {
list = arr
if (isCur) {
this.statisticsShowType = (this.statisticsShowType + 1)%3;
}
} else if (arr != null) {
for (var i = 0; i < arr.length; i++) {
var obj = arr[i]
if (obj == null) {
continue
}
var count = isRandom && obj.Random != null ? obj.Random.count : (isRandom ? null : obj.totalCount)
if (count != null && count > (isRandom ? 1 : 0)) {
var sum = obj[color + 'Count']
if (sum != null && sum > 0) {
list.push(obj)
}
continue
}
if (obj.compareColor == color) {
list.push(obj)
}
}
}
if (isRandom) {
if (isSub) {
this.currentRandomItem.summaryType = color
this.randomSubs = list
} else {
this.currentRemoteItem.summaryType = color
this.randoms = list
}
} else {
var summary = this.getSummary(accountIndex) || {}
summary.summaryType = color
this.testCases = list
this.isTestCaseShow = true
// this.showTestCase(true, false)
}
},
showCompare4RandomList: function (show, isSub) {
this.getCurrentRandomSummary().summaryType = 'total'
var randoms = show ? (isSub ? this.randomSubs : this.randoms) : null
var randomCount = randoms == null ? 0 : randoms.length
if (randomCount > 0) {
var curAccount = this.accounts[this.currentAccountIndex] || {}
var accountIndex = curAccount.isLoggedIn ? this.currentAccountIndex : -1
this.currentAccountIndex = accountIndex //解决 onTestResponse 用 -1 存进去, handleTest 用 currentAccountIndex 取出来为空
var docId = ((this.currentRemoteItem || {}).Document || {}).id
var accountIdStr = String(curAccount.isLoggedIn ? curAccount.id || '' : '')
var tests = (this.tests[accountIdStr] || {})[docId]
if (JSONObject.isEmpty(tests) != true) {
// if (! isSub) {
// this.resetCount(this.currentRemoteItem, true, isSub, accountIndex)
// }
for (var i = 0; i < randomCount; i++) {
var item = randoms[i]
var r = item == null ? null : item.Random
if (r == null || r.id == null) {
continue
}
this.resetCount(item, true, isSub, accountIndex)
var subCount = r.count || 0
if (subCount == 1) {
this.compareResponse(null, randomCount, randoms, i, item, tests[r.id], true, accountIndex, true)
}
else if (subCount > 1) {
var subRandoms = item['[]'] || []
var subSize = Math.min(subRandoms.length, subCount)
for (var j = 0; j < subSize; j++) {
var subItem = subRandoms[j]
var sr = subItem == null ? null : subItem.Random
if (sr == null || sr.id == null) {
continue
}
this.compareResponse(null, subSize, subRandoms, j, subItem, tests[sr.id > 0 ? sr.id : (sr.toId + '' + sr.id)], true, accountIndex, true)
}
}
}
}
}
},
isShowReport: function () {
return this.isReportShow && this.reportId != null && ! (IS_NODE || typeof App.autoTestCallback == 'function')
},
//显示远程的随机配置文档
showRandomList: function (show, item, isSub, callback) {
this.isRandomEditable = false
this.isRandomListShow = show && ! isSub
this.isRandomSubListShow = show && isSub
if (! isSub) {
this.randomSubs = []
}
if (IS_BROWSER) {
vOutput.value = show ? '' : (output || '')
this.showDoc()
}
var randoms = []
if (this.randomPage == 0 && ! isSub) {
randoms = (this.currentRemoteItem || {}).randoms || []
}
else if (this.randomSubPage == 0 && isSub) {
randoms = (this.currentRandomItem || {}).subs || []
}
if (isSub) {
this.randomSubs = randoms
}
else {
this.randoms = randoms
}
this.getCurrentRandomSummary().summaryType = 'total' // this.onClickSummary('total', true)
if (! this.isRandomSummaryShow()) {
this.showCompare4RandomList(show, isSub)
}
if (show && this.isRandomShow && randoms.length <= 0 && item != null && item.id != null) {
this.isRandomListShow = false
var subSearch = StringUtil.split(this.randomSubSearch)
var search = isSub ? subSearch : StringUtil.split(this.randomSearch)
var url = this.server + '/get'
baseUrl = this.getBaseUrl(vUrl.value, true)
const cri = this.currentRemoteItem || {}
const chain = cri.Chain || {}
const cId = chain.id || 0
const currentAccountId = this.getCurrentAccountId()
var reportId = this.reportId
var notShowReport = ! this.isShowReport()
var req = {
'[]': {
'count': (isSub ? this.randomSubCount : this.randomCount) || 100,
'page': (isSub ? this.randomSubPage : this.randomPage) || 0,
'Random': {
'res': 0,
'toId': isSub ? item.id : 0,
'chainId': cId,
'documentId': isSub ? null : item.id,
'@order': "date-",
'name%$': search
},
'Random:res': {
'res': 1,
'toId@': '/Random/id',
'chainId': cId,
'documentId': isSub ? null : item.id,
'@order': "date-"
},
'TestRecord': {
'randomId@': '/Random/id',
'testAccountId': currentAccountId,
'host': StringUtil.isEmpty(baseUrl, true) ? null : baseUrl,
'reportId<=': notShowReport || reportId <= 0 ? null : reportId,
'invalid': notShowReport ? 0 : reportId,
'@order': 'id-,date-'
},
'TestRecord:old': notShowReport || reportId <= 0 ? undefined : {
'id<@': '/TestRecord/id',
'randomId@': '/Random/id',
'testAccountId': currentAccountId,
'host': StringUtil.isEmpty(baseUrl, true) ? null : baseUrl,
'reportId<': reportId,
'invalid': 0,
'@order': 'id-,date-'
},
'[]': isSub ? null : {
'count': this.randomSubCount || 100,
'page': this.randomSubPage || 0,
'Random': {
'toId@': '[]/Random/id',
'res': 0,
'chainId': cId,
'documentId': item.id,
'@order': "date-",
'name%$': subSearch
},
'Random:res': {
'res': 1,
'toId@': '/Random/id',
'chainId': cId,
'documentId': item.id,
'@order': "date-"
},
'TestRecord': {
'randomId@': '/Random/id',
'testAccountId': currentAccountId,
'host': StringUtil.isEmpty(baseUrl, true) ? null : baseUrl,
'reportId<=': notShowReport || reportId <= 0 ? null : reportId,
'invalid': notShowReport ? null : 0,
'@order': 'id-,date-'
},
'TestRecord:old': notShowReport || reportId <= 0 ? undefined : {
'id<@': '/TestRecord/id',
'randomId@': '/Random/id',
'testAccountId': currentAccountId,
'host': StringUtil.isEmpty(baseUrl, true) ? null : baseUrl,
'reportId<': reportId,
'invalid': 0,
'@order': 'id-,date-'
}
}
},
key: IS_NODE ? this.key : undefined // 突破常规查询数量限制
}
if (IS_BROWSER) {
this.onChange(false)
}
this.request(true, HTTP_METHOD_POST, REQUEST_TYPE_JSON, url, req, {}, function (url, res, err) {
if (callback) {
callback(url, res, err)
return
}
App.onRandomListResponse(show, isSub, url, res, err)
})
} else if (callback) {
callback(null, {}, null)
}
},
onRandomListResponse: function (show, isSub, url, res, err) {
res = res || {}
App.onResponse(url, res, err)
var data = res.data
if (JSONResponse.isSuccess(data)) {
App.isRandomListShow = ! isSub
App.isRandomSubListShow = isSub
if (isSub) {
if (App.currentRandomItem == null) {
App.currentRandomItem = {}
}
App.randomSubs = App.currentRandomItem.subs = App.currentRandomItem['[]'] = data['[]']
}
else {
if (App.currentRemoteItem == null) {
App.currentRemoteItem = {}
}
App.randoms = App.currentRemoteItem.randoms = data['[]']
}
this.getCurrentRandomSummary().summaryType = 'total' // App.onClickSummary('total', true)
if (IS_BROWSER) {
vOutput.value = show ? '' : (output || '')
App.showDoc()
}
// if (! this.isRandomSummaryShow()) {
App.showCompare4RandomList(show, isSub)
// }
//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 = parseJSON(cache)
} catch(e) {
this.log('login this.send >> try { cache = parseJSON(cache) } catch(e) {\n' + e.message)
}
cache = cache || {}
var val = key == null ? cache : cache[key]
return val == null && defaultValue != null ? defaultValue : val
},
getCurrentDocumentId: function() {
var d = (this.currentRemoteItem || {}).Document
return d == null ? null : d.id;
},
getCurrentRandomId: function() {
var r = (this.currentRandomItem || {}).Random
return r == null ? null : r.id;
},
getCurrentScriptBelongId: function() {
return this.getScriptBelongId(this.scriptType)
},
getScriptBelongId: function(scriptType) {
var st = scriptType;
var bid = st == 'global' ? 0 : ((st == 'account' ? this.getCurrentAccountId() : this.getCurrentDocumentId()) || 0)
return bid
},
listScript: function() {
var req = {
'Script:pre': {
'ahead': 1,
'testAccountId': 0,
'documentId': 0,
'@order': 'date-'
},
'Script:post': {
'ahead': 0,
'testAccountId': 0,
'documentId': 0,
'@order': 'date-'
}
}
var accounts = this.accounts || []
for (let i = 0; i < accounts.length; i++) {
var a = accounts[i]
var id = a == null ? null : a.id
if (id == null) {
continue
}
req['account_' + id] = { // 用数字被居然强制格式化到 JSON 最前
'Script:pre': {
'ahead': 1,
'testAccountId': id,
'documentId': 0,
'@order': 'date-'
},
'Script:post': {
'ahead': 0,
'testAccountId': id,
'documentId': 0,
'@order': 'date-'
}
}
}
this.request(true, HTTP_METHOD_POST, REQUEST_TYPE_JSON, '/get', req, {}, function (url, res, err) {
var data = res.data
if (JSONResponse.isSuccess(data) != true) {
App.log(err != null ? err : (data == null ? '' : data.msg))
return
}
var scripts = App.scripts || {}
var ss = scripts.global
if (ss == null) {
scripts.global = ss = {}
}
var bs = ss['0'] || {}
if (bs == null) {
ss['0'] = bs = {}
}
var pre = data['Script:pre']
if (pre != null && pre.script != null) {
bs.pre = data['Script:pre']
}
var post = data['Script:post']
if (post != null && post.script != null) {
bs.post = data['Script:post']
}
// delete data['Script:pre']
// delete data['Script:post']
var cs = scripts.account
if (cs == null) {
scripts.account = cs = {}
}
for (let key in data) {
var val = data[key]
var pre = val == null || key.startsWith('account_') != true ? null : val['Script:pre']
if (pre == null) {
continue
}
var post = val['Script:post']
var bs = cs[key.substring('account_'.length)]
if (pre != null) { // && pre.script != null) {
bs.pre = pre
}
if (post != null) { // && post.script != null) {
bs.post = post
}
}
App.scripts = Object.assign(newDefaultScript(), scripts)
var cri = App.currentRemoteItem || {}
if (App.currentDocIndex >= 0 && StringUtil.isNotEmpty((cri.Document))) { // || {}).request)) {
App.restoreRemote(App.currentDocIndex, cri)
}
})
},
/**登录确认
*/
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
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.isHeaderShow = true
this.isRandomShow = true
this.isRandomListShow = false
if (IS_BROWSER && ! isAdmin) {
this.prevMethod = this.method
this.prevType = this.type
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 = HTTP_METHOD_POST
this.type = REQUEST_TYPE_JSON
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 = HTTP_METHOD_POST
this.type = REQUEST_TYPE_JSON
this.showTestCase(false, this.isLocalShow)
if (IS_BROWSER) {
this.onChange(false)
}
},
setRememberLogin: function (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.isEditResponse = false
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: isAdminOperation ? {
key: IS_NODE ? this.key : undefined // 突破常规查询数量限制
} : {
'@database': StringUtil.isEmpty(this.database, true) ? undefined : this.database,
'@schema': schemas == null || schemas.length != 1 ? undefined : this.schema
}
}
if (isAdminOperation) {
this.isLoginShow = false
this.request(isAdminOperation, HTTP_METHOD_POST, REQUEST_TYPE_JSON, this.server + '/login', req, this.getHeader(vHeader.value), function (url, res, err) {
if (callback) {
callback(url, res, err)
return
}
App.onLoginResponse(isAdminOperation, req, url, res, err);
})
}
else {
function recover() {
App.isLoginShow = false
if (App.prevUrl != null) {
App.method = App.prevMethod || HTTP_METHOD_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
}
}
const baseUrl = this.getBaseUrl()
if (IS_BROWSER && callback == null) {
var accounts = this.accounts || []
for (var i in accounts) {
var item = accounts[i]
if (item != null && baseUrl == item.baseUrl && ( (StringUtil.isNotEmpty(item.phone) && req.phone == item.phone)
|| (StringUtil.isNotEmpty(item.email) && req.email == item.email) ) ) {
recover()
alert(req.phone + '/' + req.email + ' 已在测试账号中!')
// this.currentAccountIndex = i
item.remember = vRemember.checked
this.onClickAccount(i, item)
return
}
}
}
// this.scripts = this.scripts || newDefaultScript()
const isLoginShow = this.isLoginShow
var curUser = this.getCurrentAccount() || {}
const loginMethod = (isLoginShow ? this.method : curUser.loginMethod) || HTTP_METHOD_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 loginRandom = (isLoginShow ? vRandom.value : curUser.loginRandom) || ''
const loginHeader = (isLoginShow ? this.getHeader(vHeader.value) : curUser.loginHeader) || {}
function loginCallback(url, res, err, random) {
recover()
if (callback) {
callback(url, res, err)
} else {
App.onLoginResponse(isAdminOperation, req, url, res, err, loginMethod, loginType, loginUrl, loginReq, loginRandom, loginHeader)
}
if (App.prevUrl != null) {
App.method = App.prevMethod || HTTP_METHOD_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) {
this.isLoginShow = false
this.testRandomWithText(true, loginCallback)
return
}
// this.scripts = newDefaultScript()
this.parseRandom(loginReq, loginHeader, loginRandom, 0, true, false, false, function(randomName, constConfig, constJson, constHeader) {
App.request(isAdminOperation, loginMethod, loginType, baseUrl + loginUrl, constJson, constHeader, function (url, res, err) {
if (App.isEnvCompareEnabled != true) {
loginCallback(url, res, err, null, loginMethod, loginType, loginUrl, constJson, constHeader)
return
}
App.request(isAdminOperation, loginMethod, loginType, App.getBaseUrl(App.otherEnv) + loginUrl
, loginReq, constHeader, function(url_, res_, err_) {
var data = res_.data
var user = data.user || data.userObj || data.userObject || data.userRsp || data.userResp || data.userBean || data.userData || data.data || data.User || data.Data
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
}
App.onResponse(url_, res_, err_);
App.onLoginResponse(isAdminOperation, req, url, res, err, loginMethod, loginType, loginUrl, constJson, loginRandom, constHeader)
}, App.scripts)
})
})
}
},
onLoginResponse: function(isAdmin, req, url, res, err, loginMethod, loginType, loginUrl, loginReq, loginRandom, loginHeader) {
res = res || {}
if (isAdmin) {
var data = res.data || {}
var user = data.user || data.userObj || data.userObject || data.userRsp || data.userResp || data.userBean || data.userData || data.data || data.User || data.Data
if (user == null) {
alert('登录失败,请检查网络后重试。\n' + data.msg + '\n详细信息可在浏览器控制台查看。')
App.onResponse(url, res, err)
}
else {
if (user != null) {
var headers = res.headers || {}
user.isLoggedIn = true
user.remember = data.remember == null ? user.remember : data.remember
user.phone = req.mobile || req.mobileNo || req.mobileNum || req.mobileNumber || req.phone || req.phoneNo || req.phoneNum || req.phoneNumber || req.mobile_no || req.mobile_num || req.mobile_number || req.phone_no || req.phone_num || req.phone_number || user.phone
user.email = req.email || user.email
user.password = req.password || user.password
user.token = headers.token || headers.Token || data.token || data.Token || user.token || user.Token || user.accessToken || user.access_token || data.accessToken || data.access_token || user.token
user.cookie = res.cookie || headers.cookie || headers.Cookie || headers['set-cookie'] || headers['Set-Cookie'] || user.cookie
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) {
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) {
App.selectCaseGroup(-1, null)
}
App.showTestCase(true, false)
}
}
} else {
App.onResponse(url, res, err)
//由login按钮触发,不能通过callback回调来实现以下功能
var data = res.data || {}
if (JSONResponse.isSuccess(data)) {
var headers = res.headers || {}
var user = data.user || data.userObj || data.userObject || data.userRsp || data.userResp || data.userBean || data.userData || data.data || data.User || data.Data
App.accounts.push({
isLoggedIn: true,
baseUrl: App.getBaseUrl(),
id: user.id,
name: user.name || user.nickname || user.nickName || user.user_name || user.username || user.userName,
account: req.account || req.phone || req.email,
phone: req.phone || user.phone,
email: req.email || user.email,
password: req.password,
remember: data.remember,
logoutMethod: App.logoutMethod,
logoutType: App.logoutType,
logoutUrl: App.logoutUrl,
loginMethod: loginMethod,
loginType: loginType,
loginUrl: loginUrl,
loginReq: loginReq,
loginRandom: loginRandom,
loginHeader: loginHeader,
cookie: res.cookie || headers.cookie,
token: headers.token || headers.Token || data.token || data.Token || user.token || user.Token || user.accessToken || user.access_token || data.accessToken || data.access_token
})
var lastItem = App.accounts[App.currentAccountIndex]
if (lastItem != null) {
lastItem.isLoggedIn = false
}
App.currentAccountIndex = App.accounts.length - 1
App.saveAccounts()
App.listScript()
}
}
},
/**注册
*/
register: function (isAdminOperation) {
// this.scripts = newDefaultScript()
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 data = res.data
if (JSONResponse.isSuccess(data)) {
alert('注册成功')
var privacy = data.Privacy || {}
App.account = privacy.phone
App.loginType = 'login'
}
}, this.scripts)
},
/**重置密码
*/
resetPassword: function (isAdminOperation) {
// this.scripts = newDefaultScript()
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 data = res.data
if (JSONResponse.isSuccess(data)) {
alert('重置密码成功')
var privacy = data.Privacy || {}
App.account = privacy.phone
App.loginType = 'login'
}
}, this.scripts)
},
/**退出
*/
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, HTTP_METHOD_POST, REQUEST_TYPE_JSON, this.server + '/logout'
, req, this.getHeader(vHeader.value), 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 {
var account = this.getCurrentAccount() || {}
const logoutMethod = account.logoutMethod || this.logoutMethod || '/logout'
const logoutType = account.logoutType || this.logoutType || '/logout'
const logoutUrl = account.logoutUrl || this.logoutUrl || '/logout'
const logoutHeader = account.logoutHeader || this.logoutHeader || this.getHeader(vHeader.value)
const logoutReq = account.logoutReq || {id: account.id}
// this.scripts = newDefaultScript()
// this.showUrl(isAdminOperation, '/logout')
// vInput.value = JSON.stringify(req, null, ' ')
// this.method = HTTP_METHOD_POST
// this.type = REQUEST_TYPE_JSON
// this.showTestCase(false, this.isLocalShow)
// this.onChange(false)
// this.send(isAdminOperation, function (url, res, err) {
this.request(isAdminOperation, logoutMethod, logoutType, this.getBaseUrl() + logoutUrl
, logoutReq, logoutHeader, function (url, res, err) {
if (App.isEnvCompareEnabled != true) {
if (callback) {
callback(url, res, err)
}
return
}
App.request(isAdminOperation, logoutMethod, logoutType, App.getBaseUrl(App.otherEnv) + logoutUrl
, logoutReq, logoutHeader, function (url_, res_, err_) {
if (callback) {
callback(url, res, err)
return
}
})
}, this.scripts)
}
},
/**获取验证码
*/
getVerify: function (isAdminOperation) {
// this.scripts = newDefaultScript()
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 = JSONResponse.isSuccess(data) ? 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
}
}, this.scripts)
},
clearUser: function () {
this.User.id = 0
this.Privacy = {}
this.casePaths = []
this.caseGroups = []
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) {
if (IS_NODE) {
return;
}
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 = parseJSON(currentItem.standard);
} catch (e3) {
log(e3)
}
var isAPIJSONRouter = false;
try {
var apijson = parseJSON(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.schema, this.database, this.language, this.isEditResponse != true, standardObj, null, true, isAPIJSONRouter, this.search));
var c = isSingle ? '' : StringUtil.trim(CodeUtil.parseComment(after, docObj == null ? null : docObj['[]'], m, this.schema, this.database, this.language, this.isEditResponse != true, standardObj, null, null, isAPIJSONRouter, this.search));
//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)
? '' : CodeUtil.getBlank(StringUtil.length(vUrl.value), 1) + 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 = CodeUtil.getBlank(StringUtil.length(vUrl.value), 1) + 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();
if (IS_NODE || document.activeElement == vOption || this.options.length > 0) {
return;
}
inputted = StringUtil.get(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);
var list = docObj == null ? null : docObj['[]'];
if (list != null && list.length > 0) {
this.onDocumentListResponse('', {data: docObj}, null, function (d) {
App.setDoc(d);
});
}
},
isShowMethod: function() {
return this.methods == null || this.methods.length != 1
},
isShowType: function() {
return this.types == null || this.types.length != 1
},
/**请求类型切换
*/
changeMethod: function (method) {
if (StringUtil.isNotEmpty(method)) {
CodeUtil.method = this.method = method
} else {
var methods = this.methods
var count = methods == null ? 0 : methods.length
if (count <= 0) {
methods = HTTP_METHODS
count = HTTP_METHODS.length
}
if (count > 1) {
var index = methods.indexOf(this.method) + 1
CodeUtil.method = this.method = methods[index % count]
}
}
this.onChange(false);
},
/**获取显示的请求方法名称
*/
getMethodName: function (method, type) {
method = StringUtil.trim(method)
if (method.length > 0) {
return method
}
return [HTTP_METHOD_GET, REQUEST_TYPE_PARAM].indexOf(type) < 0 ? HTTP_METHOD_POST : HTTP_METHOD_GET
},
/**获取显示的请求类型名称
*/
getTypeName: function (type, method) {
var t = type
if (StringUtil.isEmpty(t, true)) {
if (StringUtil.isEmpty(method, true)) {
t = REQUEST_TYPE_JSON
}
else if (method == HTTP_METHOD_GET) {
t = REQUEST_TYPE_PARAM
}
else if (method == HTTP_METHOD_POST) {
t = REQUEST_TYPE_JSON
}
else {
t = REQUEST_TYPE_DATA
}
}
// var methods = this.methods
// if (this.isShowMethod()) {
// return t
// }
//
// var ts = this.types
// 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 (type) {
if (StringUtil.isNotEmpty(type)) {
CodeUtil.type = this.type = type
} else {
var types = this.types
var count = types == null ? 0 : types.length
if (count <= 0) {
types = HTTP_CONTENT_TYPES
count = HTTP_CONTENT_TYPES.length
}
if (count > 1) {
var index = types.indexOf(this.type) + 1
this.type = types[index % count]
CodeUtil.type = this.type;
}
}
var url = StringUtil.trim(vUrl.value).replaceAll('\n', '')
var index = url.indexOf('?')
if (index >= 0) {
var paramObj = getRequestFromURL(url.substring(index), true)
vUrl.value = url.substring(0, index)
if (paramObj != null && JSONObject.isEmpty(paramObj) == false) {
var originVal = this.getRequest(vInput.value, {});
var isConflict = false;
if (JSONObject.isEmpty(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);
},
changeScriptType: function (type) {
type = type || 'case'
if (type == 'account') {
var id = this.getCurrentAccountId()
if (id == null || id <= 0) {
type = 'case'
}
}
this.scriptBelongId = 0 // 解决可能的报错
this.scriptType = type
var bid = this.getCurrentScriptBelongId()
var scripts = this.scripts
if (scripts == null) {
scripts = newDefaultScript()
this.scripts = scripts
}
var ss = scripts[type]
if (ss == null) {
ss = {
0: {
pre: { // 可能有 id
script: '' // index.html 中 v-model 绑定,不能为 null
},
post: {
script: ''
}
},
[bid]: {
pre: { // 可能有 id
script: '' // index.html 中 v-model 绑定,不能为 null
},
post: {
script: ''
}
}
}
scripts[type] = ss
}
var bs = ss[bid]
if (bs == null) {
bs = {
pre: { // 可能有 id
script: '' // index.html 中 v-model 绑定,不能为 null
},
post: {
script: ''
}
}
ss[bid] = bs
}
var pre = bs.pre
if (pre == null) {
pre = {
script: ''
}
bs.pre = pre
}
if (pre.script == null) {
pre.script = ''
}
var post = bs.post
if (post == null) {
post = {
script: ''
}
bs.post = post
}
if (post.script == null) {
post.script = ''
}
this.scriptBelongId = bid
},
changeScriptPriority: function (isPre) {
this.isPreScript = isPre == true
this.changeScriptType(this.scriptType)
},
/**
* 删除注释
*/
removeComment: function (json) {
var reg = /("([^\\\"]*(\\.)?)*")|('([^\\\']*(\\.)?)*')|(\/{2,}.*?(\r|\n))|(\/\*(\n|.)*?\*\/)/g // 正则表达式
try {
return StringUtil.get(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, caseScript_, accountScript_, globalScript_, ignorePreScript) {
if (this.isTestCaseShow) {
alert('请先输入请求内容!')
return
}
if (StringUtil.isEmpty(this.host, 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,很可能访问出错!')
}
}
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
errHandler = function () {
vOutput.value = "requesting... \nURL = " + url + "\n\n可能" + ERR_MSG
}
setTimeout(errHandler, 5000)
this.view = 'output';
var caseScript = (caseScript_ != null ? caseScript_ : ((this.scripts || {}).case || {})[this.getCurrentDocumentId() || 0]) || {}
var method = this.isShowMethod() ? this.method : null
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 (StringUtil.isNotEmpty(bu, true) && baseUrls.indexOf(bu) < 0) {
baseUrls.push(bu)
this.saveCache('', 'baseUrls', baseUrls)
var projectHosts = this.projectHosts || []
var projectHost = this.projectHost || {}
var find = false
for (var j = 0; j < projectHosts.length; j ++) {
var pjt = projectHosts[j]
if (pjt == null || StringUtil.isEmpty(pjt.host, true)) {
continue
}
if (pjt.url == projectHost.host) {
find = true
break
}
}
if (find != true) {
projectHosts.push({host: bu, project: projectHost.project})
this.projectHosts = projectHosts
this.saveCache('', 'projectHosts', projectHosts)
}
}
this.locals = this.locals || []
if (this.locals.length >= 1000) { //最多1000条,太多会很卡
this.locals.splice(900, this.locals.length - 900)
}
var path = this.getMethod()
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,
'type': this.type,
'url': '/' + path,
'request': req == null ? null : JSON.stringify(req, null, ' '),
'header': vHeader.value,
'scripts': this.scripts
}
})
this.saveCache('', 'locals', this.locals)
},
adminRequest: function (url, req, header, callback) {
this.requestPost(true, url, req, header, callback)
},
requestGet: function (isAdminOperation, url, req, header, callback, caseScript_, accountScript_, globalScript_, ignorePreScript, timeout_, wait_, retry_) {
this.request(isAdminOperation, HTTP_METHOD_GET, REQUEST_TYPE_PARAM, url, req, header, callback, caseScript_, accountScript_, globalScript_, ignorePreScript, timeout_, wait_, retry_)
},
requestPost: function (isAdminOperation, url, req, header, callback, caseScript_, accountScript_, globalScript_, ignorePreScript, timeout_, wait_, retry_) {
this.request(isAdminOperation, HTTP_METHOD_POST, REQUEST_TYPE_JSON, url, req, header, callback, caseScript_, accountScript_, globalScript_, ignorePreScript, timeout_, wait_, retry_)
},
//请求
request: function (isAdminOperation, method, type, url, req, header, callback, caseScript_, accountScript_, globalScript_, ignorePreScript, timeout_, wait_, retry_) {
this.loadingCount ++
if (url != null && url.indexOf('://') <= 0) {
url = (isAdminOperation ? this.server : this.getBaseUrl()) + url
}
const isEnvCompare = this.isEnvCompareEnabled
const scripts = (isAdminOperation || caseScript_ == null ? null : this.scripts) || {}
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 retry = retry_ != null ? retry_ : (this.retry || 0)
var evalPostScript = function () {}
const onHttpResponse = function (res) {
if (! isAdminOperation) {
App.currentHttpResponse = res
}
clearTimeout(errHandler)
var postEvalResult = evalPostScript(method, type, url, req, header, callback, 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}
if (! isAdminOperation) {
App.currentHttpResponse = res
}
var postEvalResult = evalPostScript(method, type, url, req, header, callback, 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, res, err)
}
var retryReq = function (err) {
if (retry == null || retry < 0) {
onHttpCatch(err)
return false
}
retry --
try {
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(err)
}
return true
}
var sendRequest = function (isAdminOperation, method, type, url, req, header, callback) {
var hs = ""
if (isDelegate && header != null) {
for (var k in header) {
var v = k == null ? null : header[k]
if (k == null || k.toLowerCase() == 'apijson-delegate-id') {
continue
}
hs += '\n' + k + ': ' + (v instanceof Object ? JSON.stringify(v) : StringUtil.trim(v))
}
}
var isParam = HTTP_URL_ARG_TYPES.indexOf(type) >= 0
if (req != null && JSONResponse.getType(req) == 'object') { // 支持 URL 里有 Path Variable,例如 http://apijson.cn:8080/{method}/{table}
var ind = -1 // 支持 ?id={id} 这种动态参数 url.indexOf('?')
var uri = ind < 0 ? url : url.substring(0, ind)
var newReq = {}
for (var k in req) {
var v = k == null ? null : req[k]
var kind = uri.indexOf('{' + k + '}')
if (kind >= 0) {
if (v instanceof Array) {
var multiInd = uri.indexOf(':=')
}
uri = uri.replaceAll('${' + k + '}', v).replaceAll('{{' + k + '}}', v).replaceAll('{' + k + '}', v)
continue
}
newReq[k] = v
}
url = uri + (ind < 0 ? '' : url.substring(ind))
req = newReq
}
var interceptors = axios.interceptors
if (interceptors != null) {
interceptors.request.use(function (config) {
config.metadata = {isChainShow: App.isChainShow, startTime: new Date().getTime()}
return config;
}, function (error) {
return Promise.reject(error);
});
interceptors.response.use(function (response) {
response.config.metadata.endTime = new Date().getTime()
response.duration = response.config.metadata.endTime - response.config.metadata.startTime
return response;
}, function (error) {
error.config.metadata.endTime = new Date().getTime();
error.duration = error.config.metadata.endTime - error.config.metadata.startTime;
return Promise.reject(error);
});
}
// Object.defineProperty(req, 'constructor', {
// value: 'getInstance',
// enumerable: true,
// configurable: false,
// writable: true
// })
header = header || {}
var isJSON = HTTP_JSON_TYPES.indexOf(type) >= 0;
if (isJSON && JSONResponse.isObject(req) && (req.constructor != null || req.package != null || req.class != null || req.method != null || req.prototype != null)) {
req = JSON.stringify(req)
header['Content-Type'] = 'application/json'
}
var contentType = header['Content-Type'] || header['content-type']
if (StringUtil.isEmpty(contentType) && [REQUEST_TYPE_FORM, REQUEST_TYPE_DATA, REQUEST_TYPE_PLAIN, REQUEST_TYPE_TXML, REQUEST_TYPE_AXML, REQUEST_TYPE_HTML, REQUEST_TYPE_XHTML].includes(type)) {
header['Content-Type'] = CONTENT_TYPE_MAP[type]
}
// axios.defaults.withcredentials = true
axios({
method: method != null ? method : (HTTP_METHODS.indexOf(type) >= 0 ? type.toLowerCase() : (type == REQUEST_TYPE_PARAM ? 'get' : 'post')),
url: (isDelegate ? (
App.server + '/delegate?$_type=' + (type || REQUEST_TYPE_JSON)
+ (StringUtil.isEmpty(App.delegateId, true) ? '' : '&$_delegate_id=' + App.delegateId)
+ '&$_delegate_url=' + encodeURIComponent(url)
+ (StringUtil.isEmpty(hs, true) ? '' : '&$_headers=' + encodeURIComponent(StringUtil.trim(hs)))
) : (
App.isEncodeEnabled ? encodeURI(url) : url
)
),
params: isParam ? req : null,
data: isJSON ? req : (HTTP_FORM_DATA_TYPES.indexOf(type) >= 0 ? toFormData(req) : null),
headers: header, //Accept-Encoding(HTTP Header 大小写不敏感,SpringBoot 接收后自动转小写)可能导致 Response 乱码
withCredentials: true, //Cookie 必须要 type == REQUEST_TYPE_JSON
// crossDomain: true
timeout: timeout
})
.then(onHttpResponse)
.catch(onHttpCatch)
}
var evalScript = isAdminOperation || caseScript_ == null ? function () {}
: function (isPre, script, method, type, url, req, header, callback, res, err) {
var logger = console.log
console.log = function(msg) {
logger(msg)
vOutput.value = StringUtil.get(msg)
}
App.view = 'output'
vOutput.value = ''
script = StringUtil.get(script)
var isTest = false;
var isInject = false;
var data = res == null ? null : res.data
try {
// var s = `(function () {
// var App = ` + App + `;
//
// var type = ` + type + `;
// var url = ` + url + `;
// var req = ` + (req == null ? null : JSON.stringify(req)) + `;
// var header = ` + (header == null ? null : JSON.stringify(header)) + `;
//
// ` + (isPre ? '' : `
// // var res = ` + (res == null ? null : JSON.stringify(res)) + `;
// var data = ` + (res == null || res.data == null ? null : JSON.stringify(res.data)) + `;
// var err = ` + (err == null ? null : JSON.stringify(err)) + `;
//
// `) + code + `
// })()`
//
// eval(s)
var result = eval(script)
console.log = logger
return result
}
catch (e) {
console.log(e);
console.log = logger
App.loadingCount --
e.message = '执行脚本报错:\n' + e.message // + '; 脚本:\n' + StringUtil.limitLength(script, 300, 'middle')
// TODO if (isPre) {
App.view = 'error'
App.error = {
msg: e.message + '\n\n' + (data == null || typeof data == 'string' ? StringUtil.get(data) : JSON.stringify(data, null, 4))
}
if (callback != null) {
callback(url, res, e)
} else {
// catch 中也 evalScript 导致死循环
// if (isPre != true) {
// throw e
// }
App.onResponse(url, null, Object.assign({response: res, message: e.message})) // this.onResponse is not a function
// callback = function (url, res, err) {} // 仅仅为了后续在 then 不执行 onResponse
}
}
return BREAK_ALL
}
// const preScript = function () {
// if (isAdminOperation) {
// return
// }
var preScript = ''
var globalPreScript = isAdminOperation || ignorePreScript || caseScript_ == null ? null : StringUtil.trim((globalScript.pre || {}).script)
if (StringUtil.isNotEmpty(globalPreScript, true)) {
preScript += globalPreScript + '\n\n' // evalScript(true, globalPreScript)
}
var accountPreScript = isAdminOperation || ignorePreScript || caseScript_ == null ? null : StringUtil.trim((accountScript.pre || {}).script)
if (StringUtil.isNotEmpty(accountPreScript, true)) {
preScript += accountPreScript + '\n\n' // evalScript(true, accountPreScript)
}
var casePreScript = isAdminOperation || ignorePreScript || caseScript_ == null ? null : StringUtil.trim((caseScript.pre || {}).script)
if (StringUtil.isNotEmpty(casePreScript, true)) {
preScript += casePreScript + '\n\n' // evalScript(true, casePreScript)
}
var preEvalResult = null;
if (StringUtil.isNotEmpty(preScript, true)) {
preEvalResult = evalScript(true, preScript, method, type, url, req, header, callback)
}
// }
evalPostScript = isAdminOperation || caseScript_ == null ? function () {}
: function (method, type, url, req, header, callback, res, err) {
var postScript = ''
var casePostScript = StringUtil.trim((caseScript.post || {}).script)
if (StringUtil.isNotEmpty(casePostScript, true)) {
postScript += casePostScript + '\n\n' // evalScript(false, casePostScript, res, err)
}
var accountPostScript = StringUtil.trim((accountScript.post || {}).script)
if (StringUtil.isNotEmpty(accountPostScript, true)) {
postScript += accountPostScript + '\n\n' // evalScript(false, accountPostScript, res, err)
}
var globalPostScript = StringUtil.trim((globalScript.post || {}).script)
if (StringUtil.isNotEmpty(globalPostScript, true)) {
postScript += globalPostScript + '\n\n' // evalScript(false, globalPostScript, res, err)
}
if (StringUtil.isNotEmpty(postScript, true)) {
if (StringUtil.isNotEmpty(preScript, true)) { // 如果有副作用代码,则通过判断 if (isPre) {..} 在里面执行
postScript = preScript + '\n\n// request >>>>>>>>>>>>>>>>>>>>>>>>>> response \n\n' + postScript
}
return evalScript(false, postScript, method, type, url, req, header, callback, res, err)
}
return null;
}
if (preEvalResult == BREAK_ALL) {
return
}
type = type || REQUEST_TYPE_JSON
url = StringUtil.noBlank(url)
if (url.startsWith('/')) {
url = (isAdminOperation ? this.server : this.getBaseUrl()) + url
}
var isDelegate = (isAdminOperation == false && this.isDelegateEnabled)
|| (isAdminOperation && (url.indexOf('://apijson.cn:9090') > 0 || url.indexOf('.devin.ai') > 0))
if (header == null) {
header = {};
}
var curUser = isAdminOperation ? this.User : this.getCurrentAccount()
if (StringUtil.isEmpty(header.authorization)) {
if (curUser != null && StringUtil.isNotEmpty(curUser.authorization)) {
header.authorization = curUser.authorization;
} else if (curUser != null && StringUtil.isNotEmpty(curUser.token)) {
header.authorization = curUser.token;
} else if (StringUtil.isNotEmpty(header.Authorization)) {
header.authorization = header.Authorization;
} else if (StringUtil.isNotEmpty(header['X-Authorization'])) {
header.authorization = header['X-Authorization'];
} else if (StringUtil.isNotEmpty(header['x-authorization'])) {
header.authorization = header['x-authorization'];
}
}
// header.Authorization = header['X-Authorization'] = header['x-authorization'] = undefined;
delete header.Authorization;
delete header['X-Authorization'];
delete header['x-authorization'];
if (header != null && header.Cookie != null) {
if (isDelegate) {
header['Set-Cookie'] = header.Cookie
delete header.Cookie
}
else if (IS_BROWSER) {
document.cookie = header.Cookie
}
} else if (IS_NODE) {
if (curUser != null && curUser.isLoggedIn && curUser[isEnvCompare ? 'phone' : 'cookie'] != null) {
// Node 环境内通过 headers 设置 Cookie 无效
header.Cookie = isEnvCompare ? this.otherEnvCookieMap[curUser.phone + '@' + baseUrl] : curUser.cookie
}
}
var delegateId = isEnvCompare ? this.otherEnvDelegateId : this.delegateId
if (isDelegate && delegateId != null && (header == null || header['Apijson-Delegate-Id'] == null)) {
if (header == null) {
header = {};
}
header['Apijson-Delegate-Id'] = delegateId
}
if (IS_NODE) {
if (DEBUG) {
log('req = ' + JSON.stringify(req, null, ' '))
}
// 低版本 node 报错 cannot find module 'node:url' ,高版本报错 TypeError: axiosCookieJarSupport is not a function
// const axiosCookieJarSupport = require('axios-cookiejar-support').default;
// const tough = require('tough-cookie');
// axiosCookieJarSupport(axios);
// const cookieJar = new tough.CookieJar();
// axios.defaults.jar = cookieJar;
// axios.defaults.withCredentials = true;
// const {parse, stringify, toJSON, fromJSON} = require('flatted');
// JSON.stringify = stringify;
// JSON.parse = parse;
// const CircularJSON = require('circular-json');
// JSON.stringify = CircularJSON.stringify;
// JSON.parse = CircularJSON.parse;
}
if (preEvalResult == BREAK_LAST) {
return
}
retryReq()
},
lastReqTime: 0,
/**请求回调
*/
onResponse: function (url, res, err) {
if (res == null) {
res = {}
} else {
var time = res.config == null || res.config.metadata == null ? null : res.config.metadata.startTime;
if (time != null && time > 0 && time < this.lastReqTime) {
return
}
this.lastReqTime = time == null || time <= 0 ? 0 : time;
}
if (DEBUG) {
log('onResponse url = ' + url + '\nerr = ' + err + '\nreq = \n'
+ (res.request == null || res.request.data == null ? 'null' : JSON.stringify(res.request.data))
+ '\n\nres = \n' + (res.data == null ? 'null' : JSON.stringify(res.data))
)
}
if (err != null) {
if (IS_BROWSER) {
var errObj = err instanceof Array == false && err instanceof Object ? err : {}
var data = res.data || (errObj.response || {}).data
var msg = typeof data == 'string' ? StringUtil.trim(data) : JSON.stringify(data, null, ' ')
// this.jsoncon = msg
msg = "Response:\nurl = " + url + "\nerror = " + err.message + (StringUtil.isEmpty(msg) ? '' : '\n\n' + msg) + '\n\n' + ERR_MSG
// vOutput.value = "Response:\nurl = " + url + "\nerror = " + err.message;
this.view = 'error';
this.error = {
msg: msg
}
this.output = msg
}
}
else {
if (IS_BROWSER) {
var data = res.data || {}
var isStr = typeof data == 'string'
if (isSingle && (isStr != true) && data instanceof Object && (data instanceof Array == false) && JSONResponse.isSuccess(data)) { //不格式化错误的结果
data = JSONResponse.formatObject(data);
}
this.jsoncon = isStr ? data : JSON.stringify(data, null, ' ')
this.view = 'code' // isStr ? 'output' : 'code'
vOutput.value = isStr ? data : ''
}
// 会导致断言用了这个
// 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.trim(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 (StringUtil.trim(paste).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 = StringUtil.trim(l.substring(ind + 1));
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.method = value
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.method = t
this.type = t == 'GET' ? 'PARAM' : (t == 'POST' ? 'JSON' : t);
l = StringUtil.trim(l.substring(ind));
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 {
target.value = StringUtil.toHeader(paste, target == vRandom);
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 isEnter = keyCode == 13
if (type == 'ask') {
if (isEnter) {
event.preventDefault();
if (event.shiftKey) {
vAskAI.value = StringUtil.trim(vAskAI.value) + '\n'
return
}
var query = vAskAI.value = StringUtil.trim(vAskAI.value)
var isRes = false;
if (StringUtil.isEmpty(query)) {
var view = this.view;
var isCode = view == 'code'
// 太长 var output = view == 'error' || view == 'output' ? this.output : null;
var output = view == 'error' ? this.output : null;
var d = view == 'markdown' || view == 'html' ? doc : null;
var res = isCode ? JSON.parse(this.jsoncon) : null;
// res = this.removeDebugInfo(res);
if (JSONResponse.isObject(res)) {
delete res['trace:stack']
delete res['debug:info|help']
}
var resStr = res == null ? null : JSON.stringify(res)
var headers = isCode ? (this.currentHttpResponse || {}).headers : null
var headerStr = ''
if (headers != null) {
for (var k in headers) {
var v = headers[k];
headerStr += '\n' + k + ': ' + StringUtil.trim(v);
}
}
var curItem = (this.isTestCaseShow != true ? this.currentRandomItem : this.remotes[this.currentDocIndex]) || {}
var curDoc = curItem.Document || {}
var curRecord = curItem.TestRecord || {}
var curRandom = curItem.Random || {}
// var isRandom = this.isTestCaseShow != true && this.isRandomShow == true
// var tests = this.tests[String(curAccount.id)] || {}
// var currentResponse = (tests[isRandom ? random.documentId : document.id] || {})[
// isRandom ? (random.id > 0 ? random.id : (random.toId + '' + random.id)) : 0
// ]
//
// resStr = currentResponse != null ? JSON.stringify(currentResponse) : curRecord.response;
if (this.isTestCaseShow != true) {
vAskAI.value = "### Request:\n" + this.method + " " + this.type + " " + this.getUrl()
+ (StringUtil.isEmpty(vHeader.value) ? '' : "\n" + StringUtil.trim(vHeader.value))
+ (StringUtil.isEmpty(vInput.value) ? '' : "\n\n```js\n" + StringUtil.trim(vInput.value) + '\n```')
+ (isCode ? "\n\n### Response: " : '')
+ (StringUtil.isEmpty(headerStr) ? '' : '\n' + StringUtil.trim(headerStr))
+ (StringUtil.isEmpty(resStr) ? '' : "\n\n```js\n" + resStr + '\n```')
+ (StringUtil.isEmpty(vAskAI.value) ? '' : '\n\n' + StringUtil.trim(vAskAI.value)) + '\n'
+ (StringUtil.isEmpty(output) ? '' : '\n\n### 提示信息: \n' + StringUtil.trim(output))
// 太长 + (StringUtil.isEmpty(d) ? '' : '\n\n### 文档: \n' + d)
+ '\n'
} else {
vAskAI.value = "### Request:\n" + curDoc.method + " " + curDoc.type + " " + (this.getBaseUrl() + curDoc.url)
+ (StringUtil.isEmpty(curDoc.header) ? '' : "\n" + StringUtil.trim(curDoc.header))
+ (StringUtil.isEmpty(curDoc.request) ? '' : "\n\n```js\n" + StringUtil.trim(curDoc.request) + '\n```')
+ (isCode ? "\n\n### Response: " : '')
+ (StringUtil.isEmpty(curRecord.header) ? '' : '\n' + StringUtil.trim(curRecord.header))
+ (StringUtil.isEmpty(resStr) ? '' : "\n\n```js\n" + resStr + '\n```')
+ (StringUtil.isEmpty(vAskAI.value) ? '' : '\n\n' + StringUtil.trim(vAskAI.value)) + '\n'
+ (StringUtil.isEmpty(output) ? '' : '\n\n### 提示信息: \n' + StringUtil.trim(output))
// 太长 + (StringUtil.isEmpty(d) ? '' : '\n\n### 文档: \n' + d)
+ '\n'
}
isRes = true;
}
const user_query = StringUtil.trim(vAskAI.value);
if (StringUtil.isEmpty(user_query)) {
alert('请输入问题!')
return;
}
function onMessage(item) {
var data2 = item == null ? null : item.data
if (data2 == null || item.type != 'chunk') {
return;
}
var answer = StringUtil.get(typeof data2 == 'string' ? data2 : (data instanceof Array ? data2.join() : JSON.stringify(data2)))
.replaceAll('/wiki/Tencent/APIJSON#', 'https://deepwiki.com/Tencent/APIJSON/').replaceAll('/wiki/TommyLemon/APIAuto#', 'https://deepwiki.com/TommyLemon/APIAuto/');
App.view = 'markdown';
vOutput.value += answer;
markdownToHTML(vOutput.value)
}
function queryResult() {
App.request(true, HTTP_METHOD_GET, REQUEST_TYPE_PARAM, 'https://api.devin.ai/ada/query/' + App.uuid, {}, {}, function (url, res, err) {
// App.onResponse(url, res, err)
var data = res.data || {}
// var isOk = JSONResponse.isSuccess(data)
var msg = ''; // isOk ? '' : ('\nmsg: ' + StringUtil.get(data.msg))
if (err != null) {
msg += '\nerr: ' + err.message
vOutput.value = err.message
App.view = 'error';
return
}
var queries = data.queries || []
var last = queries[queries.length - 1] || {}
var query = last.user_query || user_query
var response = last.response || []
var answer = '#### ' + query + '\n
';
for (var i = 0; i < response.length; i ++) {
// onMessage(response[i])
var item = response[i];
var data2 = item == null ? null : item.data;
if (data2 == null || item.type != 'chunk') {
continue;
}
answer += '\n' + StringUtil.trim(typeof data2 == 'string' ? data2 : (data2 instanceof Array ? data2.join() : JSON.stringify(data2)))
.replaceAll('/wiki/Tencent/APIJSON#', 'https://deepwiki.com/Tencent/APIJSON/').replaceAll('/wiki/TommyLemon/APIAuto#', 'https://deepwiki.com/TommyLemon/APIAuto/');
}
answer += '\n
\n';
App.view = 'markdown';
vOutput.value = answer;
markdownToHTML(answer); // vOutput.value)
})
// App.uuid = null; // 解决第一次后的都不生效
vAskAI.value = '';
}
function askAI() {
vOutput.value = '#### ' + user_query + '\n
';
App.loadingCount ++;
const ws = new WebSocket('wss://api.devin.ai/ada/ws/query/' + App.uuid);
// 连接成功
ws.onopen = () => {
console.log('WebSocket connected');
// 这里通常不需要主动发送内容,除非协议需要
};
// 收到消息
ws.onmessage = (event) => {
try {
const data = JSON.parse(event.data);
console.log('Message:', data);
onMessage(data)
if (data.type === 'chunk') {
console.log('Chunk Data:', data.data);
}
} catch (err) {
console.error('Failed to parse message:', event.data);
}
};
// 连接关闭
ws.onclose = () => {
console.log('WebSocket closed');
App.loadingCount --;
queryResult();
};
// 错误处理
ws.onerror = (err) => {
console.error('WebSocket error:', err);
queryResult();
};
}
// 可能少调用了 https://api2.amplitude.com/2/httpapi 导致不能同一个会话二次请求
// if (StringUtil.isEmpty(this.uuid, true)) {
try {
this.uuid = crypto.randomUUID();
} catch (e) {
console.error('Failed to generate UUID:', e);
this.uuid = '';
}
if (StringUtil.isEmpty(this.uuid, true)) {
this.uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
// }
this.request(true, HTTP_METHOD_POST, REQUEST_TYPE_JSON, 'https://api.devin.ai/ada/query', {
"engine_id": vDeepSearch.checked ? "agent" : "multihop",
"user_query": "
\n" + user_query,
"keywords": [],
"repo_names": JSONObject.isAPIJSONPath(this.getMethod()) ? [
"Tencent/APIJSON", "TommyLemon/APIAuto"
] : ["TommyLemon/APIAuto"],
"additional_context": "",
"query_id": this.uuid,
"use_notes": false,
"generate_summary": false
}, {}, function (url, res, err) {
App.onResponse(url, res, err)
var data = res.data || {}
// var isOk = JSONResponse.isSuccess(data)
var msg = ''; // isOk ? '' : ('\nmsg: ' + StringUtil.get(data.msg))
if (err != null) {
msg += '\nerr: ' + err.message
vOutput.value = err.message
App.view = 'error';
return
}
askAI();
})
}
return
}
if (type == 'option') {
if (isEnter) {
this.selectInput(item);
}
return
}
if (type == 'project') {
if (isEnter || item.host == (this.projectHost || {}).host) {
this.projectHost = {project: item.project}
this.saveCache('', 'projectHost', this.projectHost)
}
return
}
var project = (this.projectHost || {}).project
if (isFilter && (type == 'caseGroup' || type == 'chainGroup')) {
this.isCaseGroupEditable = true
// this.isChainGroupEditable = true
}
var obj = event.srcElement ? event.srcElement : event.target;
if ($(obj).attr('id') == 'vUrl') {
vUrl.value = StringUtil.trim(vUrl.value).replaceAll('\n', '')
vUrlComment.value = ''
this.currentDocItem = null
this.currentRemoteItem = null
}
if (isEnter) { // enter
if (isFilter) {
if (['chainGroup', 'caseGroup', 'testCase', 'random', 'randomSub'].indexOf(type) >= 0) {
this.reportId = 0;
}
this.onFilterChange(type)
return
}
if (type == null) {
// 无效,这时已经换行了 if (event.target == vUrl) {
// event.preventDefault();
// }
this.send(false);
return
}
if (type == 'chainTagAdd') {
var name = StringUtil.trim(item.name)
if (StringUtil.isEmpty(name)) {
alert('请输入有效标签名!')
return
}
var tags = this.tags = this.tags || []
for (var j = 0; j < tags.length; j ++) {
var tag = tags[j] || {}
if (tag.name == name) {
if (find) {
alert(name + ' 已存在,请勿重复添加!')
return
}
}
}
tags.push({name: name})
}
else 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()
}
//修改 Chain
this.request(true, HTTP_METHOD_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
App.selectChainGroup(App.currentChainGroupIndex, null)
})
return
}
if (type == 'chainAdd') {
var groupName = item == null ? null : item.groupName
if (StringUtil.isEmpty(groupName)) {
alert('请输入名称!')
return
}
var search = StringUtil.split(groupName)
var methods = this.methods
var types = this.types
// Document
this.request(true, HTTP_METHOD_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,
'project': StringUtil.isEmpty(project, true) ? null : project,
'operation$': search,
'name%$': 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 : 'operation$,name%$,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)
return
}
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()
currentTarget = vChainAdd
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
// if (StringUtil.isEmpty(url)) {
// alert('请选择有效的选项!item.url == null !')
// return
// }
//修改 Document
this.request(true, HTTP_METHOD_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)",
'url{}': [groupUrl],
'group{}': rawName == null ? "=null" : [rawName]
},
tag: 'Document-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('修改' + (isOk ? '成功' : '失败') + '!\ngroupUrl: ' + item.groupUrl + '\ngroupName: ' + item.groupName + '\nrawName: ' + item.rawName + msg)
App.isCaseGroupEditable = ! isOk
})
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, HTTP_METHOD_POST, REQUEST_TYPE_JSON, this.server + '/put', {
Random: {
id: r.id,
count: r.count,
name: r.name
},
tag: 'Random'
}, {}, 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('修改' + (isOk ? '成功' : '失败') + '!\nurl: ' + item.url + '\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 'chainGroup':
page = this.chainGroupPage
break
case 'caseGroup':
page = this.caseGroupPage
break
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 'chainGroup':
this.chainGroupPage = page
break
case 'caseGroup':
this.caseGroupPage = page
break
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 'chainGroup':
this.chainGroupPage ++
break
case 'caseGroup':
this.caseGroupPage ++
break
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 || ''
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 == '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(this.currentChainGroupIndex, null)
}
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)
// this.saveCache(this.server, 'caseGroupSearch', this.caseGroupSearch)
}
this.saveCache(this.server, 'caseGroupPages', this.caseGroupPages)
this.saveCache(this.server, 'caseGroupCounts', this.caseGroupCounts)
// this.saveCache(this.server, 'caseGroupSearches', this.caseGroupSearches)
this.selectCaseGroup()
}
else {
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)
this.saveCache(this.server, 'testCaseCount', this.testCaseCount)
}
this.saveCache(this.server, 'testCasePages', this.testCasePages)
this.saveCache(this.server, 'testCaseCounts', this.testCaseCounts)
// this.saveCache(this.server, 'testCaseSearches', this.testCaseSearches)
this.resetTestCount(this.currentAccountIndex)
this.isStatisticsEnabled = false
this.remotes = null
this.showTestCase(true, false)
}
}
else if (type == 'random') {
this.saveCache(this.server, 'randomPage', this.randomPage)
this.saveCache(this.server, 'randomCount', this.randomCount)
this.resetTestCount(this.currentAccountIndex, true)
var cri = this.currentRemoteItem || {}
cri.randoms = null
this.randoms = null
this.showRandomList(true, cri.Document, false)
}
else if (type == 'randomSub') {
this.saveCache(this.server, 'randomSubPage', this.randomSubPage)
this.saveCache(this.server, 'randomSubCount', this.randomSubCount)
this.resetTestCount(this.currentAccountIndex, true, true)
var cri = this.currentRandomItem || {}
this.randomSubs = null
this.showRandomList(true, cri.Random, true)
}
else {
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)
// });
}
},
/**转为请求代码
* @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, parseJSON(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, parseJSON(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, parseJSON(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, parseJSON(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, parseJSON(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, parseJSON(rq))
// + '\n ``` \n';
// break;
case CodeUtil.LANGUAGE_GO:
s += '\n#### <= Web-Go: 对象 key: value 会被强制排序,每个 key: value 最后都要加逗号 ","'
+ ' \n ```go \n'
+ CodeUtil.parseGoRequest(null, parseJSON(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, parseJSON(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, parseJSON(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, parseJSON(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/glennliao/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;
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 © 2017-' + new Date().getFullYear() + ' Tommy Lemon'
+ '
粤ICP备18005508号-1'
+ '