feat: req_body json 支持指针位置可视化插入表达式

This commit is contained in:
gaoxiaolin.gao 2018-05-23 11:15:23 +08:00
parent e5aff7a41c
commit 0dc6c7fb64
12 changed files with 132 additions and 83 deletions

View File

@ -3,13 +3,14 @@
* 支持自定义域名邮箱登录
* 测试用例支持导入不同项目接口
* 完善可视化表达式,可根据焦点编辑表达式
* req_body json 支持指针位置可视化插入表达式
#### Bug Fixed
* postman headers 为 null 时报错
* 导入postman headers 为 null 时报错
* format-data 数据解析不成功
* 导出的接口顺序希望按照api的接口顺序
* 导出的接口顺序按照api的接口顺序

View File

@ -1,22 +1,24 @@
import React from 'react'
import mockEditor from './mockEditor'
import PropTypes from 'prop-types'
import './AceEditor.scss'
import React from 'react';
import mockEditor from './mockEditor';
import PropTypes from 'prop-types';
import './AceEditor.scss';
const ModeMap = {
'javascript' : 'ace/mode/javascript',
'json' : 'ace/mode/json',
'text' : 'ace/mode/text',
'xml' : 'ace/mode/xml',
'html' : 'ace/mode/html'
}
javascript: 'ace/mode/javascript',
json: 'ace/mode/json',
text: 'ace/mode/text',
xml: 'ace/mode/xml',
html: 'ace/mode/html'
};
function getMode(mode){
return ModeMap[mode] || ModeMap.text
const defaultStyle = { width: '100%', height: '200px' }
function getMode(mode) {
return ModeMap[mode] || ModeMap.text;
}
class AceEditor extends React.PureComponent {
constructor(props){
constructor(props) {
super(props);
}
@ -30,40 +32,49 @@ class AceEditor extends React.PureComponent {
style: PropTypes.object,
fullScreen: PropTypes.bool,
insertCode: PropTypes.func
}
};
componentDidMount(){
componentDidMount() {
this.editor = mockEditor({
container: this.editorElement,
data: this.props.data,
onChange: this.props.onChange,
readOnly: this.props.readOnly,
fullScreen: this.props.fullScreen
})
});
let mode = this.props.mode || 'javascript';
this.editor.editor.getSession().setMode(getMode(mode));
if(typeof this.props.callback === 'function'){
this.props.callback(this.editor.editor)
if (typeof this.props.callback === 'function') {
this.props.callback(this.editor.editor);
}
}
componentWillReceiveProps(nextProps) {
if (!this.editor) return;
if (nextProps.data !== this.props.data && this.editor.getValue() !== nextProps.data) {
this.editor.setValue(nextProps.data);
let mode = nextProps.mode || 'javascript';
this.editor.editor.getSession().setMode(getMode(mode));
this.editor.editor.clearSelection();
}
}
componentWillReceiveProps(nextProps){
if(!this.editor) return;
if(nextProps.data !== this.props.data && this.editor.getValue() !== nextProps.data){
this.editor.setValue(nextProps.data);
let mode = nextProps.mode || 'javascript';
this.editor.editor.getSession().setMode(getMode(mode));
this.editor.editor.clearSelection();
}
}
render() {
return <div className={this.props.className} style={this.props.className ? undefined : this.props.style || {width: '100%', height: '200px'}} ref={editor=>{
this.editorElement=editor
}} ></div>
return (
<div
className={this.props.className}
style={
this.props.className ? undefined : this.props.style || defaultStyle
}
ref={editor => {
this.editorElement = editor;
}}
/>
);
}
}
export default AceEditor;
export default AceEditor;

View File

@ -175,6 +175,7 @@ function run(options) {
editor.clearSelection();
});
return mockEditor;
}

View File

@ -85,7 +85,7 @@ export default class Run extends Component {
test_script: '',
hasPlugin: true,
inputValue: '',
cursurPosition: -1,
cursurPosition: { row: 1, column: -1 },
envModalVisible: false,
test_res_header: null,
test_res_body: null,
@ -178,19 +178,16 @@ export default class Run extends Component {
}
initEnvState(case_env, env) {
let headers = this.handleReqHeader(case_env, env);
this.setState(
{
req_headers: headers,
env: env
},
() => {
let s = !_.find(env, item => item.name === this.state.case_env);
if (!this.state.case_env || s) {
this.setState({
case_env: this.state.env[0].name
});
@ -220,7 +217,7 @@ export default class Run extends Component {
this.initState(nextProps.data);
}
if (nextProps.data.env !== this.props.data.env) {
this.initEnvState(this.state.case_env,nextProps.data.env);
this.initEnvState(this.state.case_env, nextProps.data.env);
}
}
}
@ -331,10 +328,22 @@ export default class Run extends Component {
// 模态框的相关操作
showModal = (val, index, type) => {
let oTxt1 = document.getElementById(`${type}_${index}`);
let cursurPosition = oTxt1.selectionStart;
let inputValue = this.getInstallValue(val || '', cursurPosition).val
let inputValue = '';
let cursurPosition;
if (type === 'req_body_other') {
// req_body
let editor = this.aceEditor.editor.editor;
cursurPosition = editor.session.doc.positionToIndex(editor.selection.getCursor());
// 获取选中的数据
inputValue = this.getInstallValue(val || '', cursurPosition).val;
} else {
// 其他input 输入
let oTxt1 = document.getElementById(`${type}_${index}`);
cursurPosition = oTxt1.selectionStart;
inputValue = this.getInstallValue(val || '', cursurPosition).val;
// cursurPosition = {row: 1, column: position}
}
this.setState({
modalVisible: true,
inputIndex: index,
@ -347,45 +356,57 @@ export default class Run extends Component {
// 点击插入
handleModalOk = val => {
const { inputIndex, modalType } = this.state;
this.changeInstallParam(modalType, val, inputIndex);
if (modalType === 'req_body_other') {
this.changeInstallBody(modalType, val);
} else {
this.changeInstallParam(modalType, val, inputIndex);
}
this.setState({ modalVisible: false });
};
handleModalCancel = () => {
this.setState({ modalVisible: false, cursurPosition: -1 });
// 根据鼠标位置往req_body中动态插入数据
changeInstallBody = (type, value) => {
const pathParam = deepCopyJson(this.state[type]);
// console.log(pathParam)
let oldValue = pathParam || '';
let newValue = this.getInstallValue(oldValue, this.state.cursurPosition);
let left = newValue.left;
let right = newValue.right;
this.setState({
[type]: `${left}${value}${right}`
});
};
// 获取截取的字符串
getInstallValue = (oldValue, cursurPosition) => {
let left = oldValue.substr(0, cursurPosition);
let right = oldValue.substr(cursurPosition);
let leftPostion = left.lastIndexOf('{{');
let leftPostion2 = left.lastIndexOf('}}');
let rightPostion = right.indexOf('}}');
// console.log(leftPostion, leftPostion2,rightPostion, rightPostion2);
let val = '';
// 需要切除原来的变量
if (leftPostion !== -1 && rightPostion !==-1 && leftPostion > leftPostion2) {
if (leftPostion !== -1 && rightPostion !== -1 && leftPostion > leftPostion2) {
left = left.substr(0, leftPostion);
right = right.substr(rightPostion + 2);
val = oldValue.substring(leftPostion, cursurPosition+rightPostion+2)
val = oldValue.substring(leftPostion, cursurPosition + rightPostion + 2);
}
return {
left,
right,
val
};
}
};
// 根据鼠标位置动态插入数据
changeInstallParam = (name, v, index, key) => {
key = key || 'value';
const pathParam = deepCopyJson(this.state[name]);
let oldValue = pathParam[index][key] || '';
let newValue = this.getInstallValue(oldValue, this.state.cursurPosition)
let newValue = this.getInstallValue(oldValue, this.state.cursurPosition);
let left = newValue.left;
let right = newValue.right;
pathParam[index][key] = `${left}${v}${right}`;
@ -394,6 +415,11 @@ export default class Run extends Component {
});
};
// 取消参数插入
handleModalCancel = () => {
this.setState({ modalVisible: false, cursurPosition: -1 });
};
// 环境变量模态框相关操作
showEnvModal = () => {
this.setState({
@ -648,8 +674,22 @@ export default class Run extends Component {
<div
style={{ display: checkRequestBodyIsRaw(method, req_body_type) ? 'block' : 'none' }}
>
{req_body_type === 'json' && (
<div className="adv-button">
<Button
onClick={() => this.showModal(this.state.req_body_other, 0, 'req_body_other')}
>
高级参数设置
</Button>
<Tooltip title="高级参数设置只在json字段中生效">
{' '}<Icon type="question-circle-o" />
</Tooltip>
</div>
)}
<AceEditor
className="pretty-editor"
ref={editor => (this.aceEditor = editor)}
data={this.state.req_body_other}
mode={req_body_type === 'json' ? null : 'text'}
onChange={this.handleRequestBody}

View File

@ -3,7 +3,9 @@
.adv-button {
margin-bottom: 8px;
}
.pretty-editor {
border: 1px solid #d9d9d9;
border-radius: 4px;

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

View File

@ -32,11 +32,14 @@
YApi中支持项目迁移到不同的分组中。
<img src="./images/project-remove.png" />
迁移权限: 只有管理员和该项目的owner有权限对位置进行修改。项目owner主要有创建该项目的人、项目中的组长、创建分组的人、分组中的组长。
> Tips: owner权限判断的优先级是 项目权限 > 分组权限
## 项目拷贝
该功能在 v1.3.12 版本上线,项目克隆功能可复制项目全部接口到一个新项目,如下图所示,点击红色框里面的 icon 使用。
YApi支持项目复制功能但是无法复制项目中的测试集合list。
@ -177,8 +180,3 @@ context.promise = new Promise(function(resolve){
## token配置
每个项目都有唯一的标识token用户可以使用这个token值来请求项目的所有资源数据。目前用到的地方是接口的<a href="./case.md">自动化测试</a>,用户不需要登录就可以访问接口测试结果信息。
## 项目克隆
该功能在 v1.3.12 版本上线,项目克隆功能可复制项目全部接口到一个新项目,如下图所示,点击红色框里面的 icon 使用。
![](clone-project.png.png)

View File

@ -10,10 +10,14 @@
</div></div><nav class="m-header-nav js-nav"><ul class="m-header-items"><li class="item active"><a class="href" href="index.html">教程</a></li><li class="item "><a class="href" href="../devops/index.html">内网部署</a></li></ul></nav><div id="js-nav-btn" class="m-header-btn ui-font-ydoc"></div></header><div class="m-content" id="js-content"><div id="markdown-body" class="m-content-container markdown-body"><h3 id="v1.3.16">v1.3.16</h3>
<ul>
<li>支持自定义域名邮箱登录</li>
<li>测试用例支持导入不同项目接口</li>
<li>完善可视化表达式,可根据焦点编辑表达式</li>
</ul>
<h4>Bug Fixed</h4>
<ul>
<li>postman headers 为 null 时报错</li>
<li>format-data 数据解析不成功</li>
<li>导出的接口顺序希望按照api的接口顺序</li>
</ul>
<h3 id="v1.3.15">v1.3.15</h3>
<ul>

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

View File

@ -38,7 +38,7 @@
<pre><code>{
&#x22;name&#x22;: &#x22;${query.name}&#x22;, //&#x8BF7;&#x6C42;&#x7684;url&#x662F;/path?name=xiaoming, &#x8FD4;&#x56DE;&#x7684;name&#x5B57;&#x6BB5;&#x662F;xiaoming
&#x22;type&#x22;: &#x22;${body.type}&#x22;, //&#x8BF7;&#x6C42;&#x7684;requestBody type=1,&#x8FD4;&#x56DE;&#x7684;type&#x5B57;&#x6BB5;&#x662F;1
&#x22;value&#x22;: &#x22;${body.fields.value}&#x22; // &#x5F53;header&#x662F;Content-Type: multipart/form-data &#x65F6;&#x83B7;&#x53D6;body&#x4E2D;&#x7684;&#x503C; &#xFF08;v1.3.16+&#x652F;&#x6301;&#xFF09;
}
</code></pre>

View File

@ -29,11 +29,13 @@
<img src="./images/usage/project_setting_logo.png">
<h2 id="项目迁移">项目迁移</h2>
<p>YApi中支持项目迁移到不同的分组中。</p>
<img src="./images/project-remove.png">
<p>迁移权限: 只有管理员和该项目的owner有权限对位置进行修改。项目owner主要有创建该项目的人、项目中的组长、创建分组的人、分组中的组长。</p>
<blockquote>
<p>Tips: owner权限判断的优先级是 项目权限 &gt; 分组权限</p>
</blockquote>
<h2 id="项目拷贝">项目拷贝</h2>
<p>该功能在 v1.3.12 版本上线,项目克隆功能可复制项目全部接口到一个新项目,如下图所示,点击红色框里面的 icon 使用。</p>
<p>YApi支持项目复制功能但是无法复制项目中的测试集合list。</p>
<p>操作: 点击下图左上角的复制按钮,在弹窗中写入复制项目名称点击确定就可以完成项目复制</p>
<img src="./images/usage/projectCopy.png">
@ -110,6 +112,9 @@
<pre><code>context.responseBody.a = 2;
</code></pre>
<blockquote>
<p>v1.3.16+新增context.href和context.hostname</p>
</blockquote>
<h3 id="请求配置-工具函数">工具函数</h3>
<pre><code>context.utils = {
_ //underscore &#x51FD;&#x6570;,&#x8BE6;&#x7EC6; API &#x67E5;&#x770B;&#x5B98;&#x7F51; http://underscorejs.org/
@ -142,9 +147,6 @@
</blockquote>
<h2 id="token配置">token配置</h2>
<p>每个项目都有唯一的标识token用户可以使用这个token值来请求项目的所有资源数据。目前用到的地方是接口的<a href="./case.html">自动化测试</a>,用户不需要登录就可以访问接口测试结果信息。</p>
<h2 id="项目克隆">项目克隆</h2>
<p>该功能在 v1.3.12 版本上线,项目克隆功能可复制项目全部接口到一个新项目,如下图所示,点击红色框里面的 icon 使用。</p>
<p><img src="clone-project.png.png" alt=""></p>
</div><div class="m-content-container m-paging"><div class="m-paging-prev m-paging-item"><a href="manage.html" class="href"><span class="ui-font-ydoc"></span>权限</a></div><div class="m-paging-next m-paging-item"><a href="api.html" class="href">接口操作<span class="ui-font-ydoc"></span></a></div></div></div></div></div><div><div class="m-mask js-mask">
<div class="container">
<img src="" alt="" class="img js-mask-img" />

View File

@ -200,7 +200,7 @@ window.ydoc_plugin_search_json = {
{
"title": "项目拷贝",
"url": "/documents/project.html#项目拷贝",
"content": "项目拷贝YApi支持项目复制功能但是无法复制项目中的测试集合list。操作 点击下图左上角的复制按钮在弹窗中写入复制项目名称点击确定就可以完成项目复制Tips: 如果你在该分组下有新建项目的权限,那你也同时拥有复制项目的权限\n"
"content": "项目拷贝该功能在 v1.3.12 版本上线,项目克隆功能可复制项目全部接口到一个新项目,如下图所示,点击红色框里面的 icon 使用。YApi支持项目复制功能但是无法复制项目中的测试集合list。操作 点击下图左上角的复制按钮在弹窗中写入复制项目名称点击确定就可以完成项目复制Tips: 如果你在该分组下有新建项目的权限,那你也同时拥有复制项目的权限\n"
},
{
"title": "删除项目",
@ -225,7 +225,7 @@ window.ydoc_plugin_search_json = {
{
"title": "返回数据示例",
"url": "/documents/project.html#请求配置-返回数据示例",
"content": "返回数据示例在上面的示例请求完成后,假设返回 responseBody={a:1},公共变量 context 包含以下属性context = { pathname: '/api/user',\n query: {\n id: 1\n },\n requestHeader: {\n xxx: 'xxx'\n },\n method: 'POST',\n requestBody: {\n type:1\n },\n responseData: {\n a:1\n },\n responseHeader: {\n content-type: 'application/json'\n ...\n }\n}\n假设我们需要修改响应数据 responseBody a 的值为 2可以填写如下自定义脚本context.responseBody.a = 2;\n"
"content": "返回数据示例在上面的示例请求完成后,假设返回 responseBody={a:1},公共变量 context 包含以下属性context = { pathname: '/api/user',\n query: {\n id: 1\n },\n requestHeader: {\n xxx: 'xxx'\n },\n method: 'POST',\n requestBody: {\n type:1\n },\n responseData: {\n a:1\n },\n responseHeader: {\n content-type: 'application/json'\n ...\n }\n}\n假设我们需要修改响应数据 responseBody a 的值为 2可以填写如下自定义脚本context.responseBody.a = 2;\nv1.3.16+新增context.href和context.hostname\n"
},
{
"title": "工具函数",
@ -241,11 +241,6 @@ window.ydoc_plugin_search_json = {
"title": "token配置",
"url": "/documents/project.html#token配置",
"content": "token配置每个项目都有唯一的标识token用户可以使用这个token值来请求项目的所有资源数据。目前用到的地方是接口的自动化测试用户不需要登录就可以访问接口测试结果信息。"
},
{
"title": "项目克隆",
"url": "/documents/project.html#项目克隆",
"content": "项目克隆该功能在 v1.3.12 版本上线,项目克隆功能可复制项目全部接口到一个新项目,如下图所示,点击红色框里面的 icon 使用。"
}
]
},
@ -277,7 +272,7 @@ window.ydoc_plugin_search_json = {
{
"title": "项目拷贝",
"url": "/documents/project.html#项目拷贝",
"content": "项目拷贝YApi支持项目复制功能但是无法复制项目中的测试集合list。操作 点击下图左上角的复制按钮在弹窗中写入复制项目名称点击确定就可以完成项目复制Tips: 如果你在该分组下有新建项目的权限,那你也同时拥有复制项目的权限\n"
"content": "项目拷贝该功能在 v1.3.12 版本上线,项目克隆功能可复制项目全部接口到一个新项目,如下图所示,点击红色框里面的 icon 使用。YApi支持项目复制功能但是无法复制项目中的测试集合list。操作 点击下图左上角的复制按钮在弹窗中写入复制项目名称点击确定就可以完成项目复制Tips: 如果你在该分组下有新建项目的权限,那你也同时拥有复制项目的权限\n"
},
{
"title": "删除项目",
@ -302,7 +297,7 @@ window.ydoc_plugin_search_json = {
{
"title": "返回数据示例",
"url": "/documents/project.html#请求配置-返回数据示例",
"content": "返回数据示例在上面的示例请求完成后,假设返回 responseBody={a:1},公共变量 context 包含以下属性context = { pathname: '/api/user',\n query: {\n id: 1\n },\n requestHeader: {\n xxx: 'xxx'\n },\n method: 'POST',\n requestBody: {\n type:1\n },\n responseData: {\n a:1\n },\n responseHeader: {\n content-type: 'application/json'\n ...\n }\n}\n假设我们需要修改响应数据 responseBody a 的值为 2可以填写如下自定义脚本context.responseBody.a = 2;\n"
"content": "返回数据示例在上面的示例请求完成后,假设返回 responseBody={a:1},公共变量 context 包含以下属性context = { pathname: '/api/user',\n query: {\n id: 1\n },\n requestHeader: {\n xxx: 'xxx'\n },\n method: 'POST',\n requestBody: {\n type:1\n },\n responseData: {\n a:1\n },\n responseHeader: {\n content-type: 'application/json'\n ...\n }\n}\n假设我们需要修改响应数据 responseBody a 的值为 2可以填写如下自定义脚本context.responseBody.a = 2;\nv1.3.16+新增context.href和context.hostname\n"
},
{
"title": "工具函数",
@ -318,11 +313,6 @@ window.ydoc_plugin_search_json = {
"title": "token配置",
"url": "/documents/project.html#token配置",
"content": "token配置每个项目都有唯一的标识token用户可以使用这个token值来请求项目的所有资源数据。目前用到的地方是接口的自动化测试用户不需要登录就可以访问接口测试结果信息。"
},
{
"title": "项目克隆",
"url": "/documents/project.html#项目克隆",
"content": "项目克隆该功能在 v1.3.12 版本上线,项目克隆功能可复制项目全部接口到一个新项目,如下图所示,点击红色框里面的 icon 使用。"
}
]
},
@ -418,7 +408,7 @@ window.ydoc_plugin_search_json = {
{
"title": "原理",
"url": "/documents/mock.html#方式1.-mockjs-原理",
"content": "原理基于 mockjs跟 Mockjs 区别是 yapi 基于 json + 注释 定义 mock 数据,无法使用 mockjs 原有的函数功能。正则表达式需要基于 rule 书写,示例如下:\n{ \"name|regexp\": \"[a-z0-9_]+?\",\n \"type|regexp\": \"json|text|xml\"\n}\n\n支持替换请求的 query, body 参数\n{ \"name\": \"${query.name}\", //请求的url是/path?name=xiaoming, 返回的name字段是xiaoming\n \"type\": \"${body.type}\", //请求的requestBody type=1,返回的type字段是1\n \"value\": \"${body.fields.value}\" // 当header是Content-Type: multipart/form-data 时获取body中的值 v1.3.16+支持)\n}\n\n示例\n/** * 这是一个接口返回数据示例\n */\n\n{\n \"errcode\": 0,\n \"errmsg\": \"@word\",\n \"data\": {\n \"id\": \"@id\", //@id 随机生成 id\n \"name\": \"@name\" //@name 随机生成用户名\n }\n}\n\n详细使用文档请查看Mockjs 官网"
"content": "原理基于 mockjs跟 Mockjs 区别是 yapi 基于 json + 注释 定义 mock 数据,无法使用 mockjs 原有的函数功能。正则表达式需要基于 rule 书写,示例如下:\n{ \"name|regexp\": \"[a-z0-9_]+?\",\n \"type|regexp\": \"json|text|xml\"\n}\n\n支持替换请求的 query, body 参数\n{ \"name\": \"${query.name}\", //请求的url是/path?name=xiaoming, 返回的name字段是xiaoming\n \"type\": \"${body.type}\", //请求的requestBody type=1,返回的type字段是1\n \n}\n\n示例\n/** * 这是一个接口返回数据示例\n */\n\n{\n \"errcode\": 0,\n \"errmsg\": \"@word\",\n \"data\": {\n \"id\": \"@id\", //@id 随机生成 id\n \"name\": \"@name\" //@name 随机生成用户名\n }\n}\n\n详细使用文档请查看Mockjs 官网"
},
{
"title": "方式2. json-schema",
@ -465,7 +455,7 @@ window.ydoc_plugin_search_json = {
{
"title": "原理",
"url": "/documents/mock.html#方式1.-mockjs-原理",
"content": "原理基于 mockjs跟 Mockjs 区别是 yapi 基于 json + 注释 定义 mock 数据,无法使用 mockjs 原有的函数功能。正则表达式需要基于 rule 书写,示例如下:\n{ \"name|regexp\": \"[a-z0-9_]+?\",\n \"type|regexp\": \"json|text|xml\"\n}\n\n支持替换请求的 query, body 参数\n{ \"name\": \"${query.name}\", //请求的url是/path?name=xiaoming, 返回的name字段是xiaoming\n \"type\": \"${body.type}\", //请求的requestBody type=1,返回的type字段是1\n \"value\": \"${body.fields.value}\" // 当header是Content-Type: multipart/form-data 时获取body中的值 v1.3.16+支持)\n}\n\n示例\n/** * 这是一个接口返回数据示例\n */\n\n{\n \"errcode\": 0,\n \"errmsg\": \"@word\",\n \"data\": {\n \"id\": \"@id\", //@id 随机生成 id\n \"name\": \"@name\" //@name 随机生成用户名\n }\n}\n\n详细使用文档请查看Mockjs 官网"
"content": "原理基于 mockjs跟 Mockjs 区别是 yapi 基于 json + 注释 定义 mock 数据,无法使用 mockjs 原有的函数功能。正则表达式需要基于 rule 书写,示例如下:\n{ \"name|regexp\": \"[a-z0-9_]+?\",\n \"type|regexp\": \"json|text|xml\"\n}\n\n支持替换请求的 query, body 参数\n{ \"name\": \"${query.name}\", //请求的url是/path?name=xiaoming, 返回的name字段是xiaoming\n \"type\": \"${body.type}\", //请求的requestBody type=1,返回的type字段是1\n \n}\n\n示例\n/** * 这是一个接口返回数据示例\n */\n\n{\n \"errcode\": 0,\n \"errmsg\": \"@word\",\n \"data\": {\n \"id\": \"@id\", //@id 随机生成 id\n \"name\": \"@name\" //@name 随机生成用户名\n }\n}\n\n详细使用文档请查看Mockjs 官网"
},
{
"title": "方式2. json-schema",
@ -1162,7 +1152,7 @@ window.ydoc_plugin_search_json = {
{
"title": "v1.3.16",
"url": "/documents/CHANGELOG.html#v1.3.16",
"content": "v1.3.16支持自定义域名邮箱登录\nBug Fixedpostman headers 为 null 时报错\n"
"content": "v1.3.16支持自定义域名邮箱登录\n测试用例支持导入不同项目接口\n完善可视化表达式可根据焦点编辑表达式\nBug Fixedpostman headers 为 null 时报错\nformat-data 数据解析不成功\n导出的接口顺序希望按照api的接口顺序\n"
},
{
"title": "v1.3.15",
@ -1309,7 +1299,7 @@ window.ydoc_plugin_search_json = {
{
"title": "v1.3.16",
"url": "/documents/CHANGELOG.html#v1.3.16",
"content": "v1.3.16支持自定义域名邮箱登录\nBug Fixedpostman headers 为 null 时报错\n"
"content": "v1.3.16支持自定义域名邮箱登录\n测试用例支持导入不同项目接口\n完善可视化表达式可根据焦点编辑表达式\nBug Fixedpostman headers 为 null 时报错\nformat-data 数据解析不成功\n导出的接口顺序希望按照api的接口顺序\n"
},
{
"title": "v1.3.15",