mirror of
https://github.com/YMFE/yapi.git
synced 2024-12-15 05:10:47 +08:00
Merge branch 'dev' of http://gitlab.corp.qunar.com/mfe/yapi into dev
This commit is contained in:
commit
39cae5ffe9
@ -1,4 +1,12 @@
|
||||
|
||||
## 1.1.2
|
||||
### Features
|
||||
* 接口运行增加了 query 和 body 的 enable 选项,可选择是否请求该字段
|
||||
* Mock 支持了时间戳占位符 @timestamp
|
||||
|
||||
### Bug Fixed
|
||||
* 修复了接口集运行功能会忽略 domain path 的 bug
|
||||
|
||||
## 1.1.1
|
||||
### Features
|
||||
* 添加插件开发文档
|
||||
|
10
README.md
10
README.md
@ -19,17 +19,17 @@ YApi 是<strong>高效</strong>、<strong>易用</strong>、<strong>功能强大
|
||||
* nodejs(7.6+)
|
||||
* mongodb(2.6+)
|
||||
#### 安装
|
||||
使用我们提供的 yapi-cli 工具,部署 YApi 平台是非常容易的。执行 yapi-cli server 启动可视化部署程序,输入相应的配置和点击开始部署,就能完成整个网站的部署。部署完成之后,可按照提示信息,执行 node/{网站路径/server/app.js} 启动服务器。在浏览器打开指定url, 点击登录输入您刚才设置的管理员邮箱,默认密码为 ymfe.org 登录系统(默认密码可在个人中心修改)。
|
||||
使用我们提供的 yapi-cli 工具,部署 YApi 平台是非常容易的。执行 yapi server 启动可视化部署程序,输入相应的配置和点击开始部署,就能完成整个网站的部署。部署完成之后,可按照提示信息,执行 node/{网站路径/server/app.js} 启动服务器。在浏览器打开指定url, 点击登录输入您刚才设置的管理员邮箱,默认密码为 ymfe.org 登录系统(默认密码可在个人中心修改)。
|
||||
|
||||
npm install -g yapi-cli --registry https://registry.npm.taobao.org
|
||||
yapi-cli server
|
||||
yapi server
|
||||
|
||||
#### 升级
|
||||
升级项目版本是非常容易的,并且不会影响已有的项目数据,只会同步 vendors 目录下的源码文件。
|
||||
cd {项目目录}
|
||||
yapi-cli ls //查看版本号列表
|
||||
yapi-cli update //更新到最新版本
|
||||
yapi-cli update -v {Version} //更新到指定版本
|
||||
yapi ls //查看版本号列表
|
||||
yapi update //更新到最新版本
|
||||
yapi update -v {Version} //更新到指定版本
|
||||
|
||||
|
||||
### 在线 Demo
|
||||
|
@ -1,7 +1,7 @@
|
||||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import Mock from 'mockjs'
|
||||
import { Button, Input, Select, Alert, Spin, Icon, Collapse, Tooltip, message, AutoComplete, Switch } from 'antd'
|
||||
import { Button, Input, Checkbox, Select, Alert, Spin, Icon, Collapse, Tooltip, message, AutoComplete, Switch } from 'antd'
|
||||
import { autobind } from 'core-decorators';
|
||||
import constants from '../../constants/variable.js'
|
||||
|
||||
@ -202,8 +202,8 @@ export default class Run extends Component {
|
||||
pathParam.forEach(item => {
|
||||
path = path.replace(`:${item.name}`, item.value || `:${item.name}`);
|
||||
});
|
||||
if(urlObj.pathname){
|
||||
if(urlObj.pathname[urlObj.pathname.length - 1] !== '/'){
|
||||
if (urlObj.pathname) {
|
||||
if (urlObj.pathname[urlObj.pathname.length - 1] !== '/') {
|
||||
urlObj.pathname += '/'
|
||||
}
|
||||
}
|
||||
@ -331,12 +331,14 @@ export default class Run extends Component {
|
||||
}
|
||||
|
||||
@autobind
|
||||
changeQuery(v, index, isKey) {
|
||||
changeQuery(v, index, key) {
|
||||
key = key || 'value';
|
||||
const query = json_parse(JSON.stringify(this.state.query));
|
||||
if (isKey) {
|
||||
query[index].name = v;
|
||||
if (key == 'enable') {
|
||||
query[index].enable = v;
|
||||
} else {
|
||||
query[index].value = v;
|
||||
query[index].enable = true;
|
||||
}
|
||||
this.setState({ query });
|
||||
}
|
||||
@ -382,13 +384,20 @@ export default class Run extends Component {
|
||||
}
|
||||
|
||||
@autobind
|
||||
changeBody(v, index) {
|
||||
changeBody(v, index, key) {
|
||||
const bodyForm = json_parse(JSON.stringify(this.state.bodyForm));
|
||||
if (bodyForm[index].type === 'file') {
|
||||
bodyForm[index].value = 'file_' + index
|
||||
} else {
|
||||
bodyForm[index].value = v
|
||||
key = key || 'value';
|
||||
if (key === 'value') {
|
||||
bodyForm[index].enable = true;
|
||||
if (bodyForm[index].type === 'file') {
|
||||
bodyForm[index].value = 'file_' + index
|
||||
} else {
|
||||
bodyForm[index].value = v
|
||||
}
|
||||
} else if (key === 'enable') {
|
||||
bodyForm[index].enable = v
|
||||
}
|
||||
|
||||
this.setState({ bodyForm });
|
||||
}
|
||||
@autobind
|
||||
@ -445,9 +454,10 @@ export default class Run extends Component {
|
||||
arrToObj(arr) {
|
||||
const obj = {};
|
||||
arr.forEach(item => {
|
||||
if (item.name && item.type !== 'file') {
|
||||
obj[item.name] = handleMockWord(item.value);
|
||||
}
|
||||
if (item)
|
||||
if (item.name && item.type !== 'file' && item.enable) {
|
||||
obj[item.name] = handleMockWord(item.value);
|
||||
}
|
||||
})
|
||||
return obj;
|
||||
}
|
||||
@ -455,7 +465,7 @@ export default class Run extends Component {
|
||||
getFiles(bodyForm) {
|
||||
const files = {};
|
||||
bodyForm.forEach(item => {
|
||||
if (item.name && item.type === 'file') {
|
||||
if (item.name && item.enable === true && item.type === 'file') {
|
||||
files[item.name] = item.value
|
||||
}
|
||||
})
|
||||
@ -464,7 +474,7 @@ export default class Run extends Component {
|
||||
getQueryObj(query) {
|
||||
const queryObj = {};
|
||||
query.forEach(item => {
|
||||
if (item.name) {
|
||||
if (item.name && item.enable) {
|
||||
queryObj[item.name] = handleMockWord(item.value);
|
||||
}
|
||||
})
|
||||
@ -487,7 +497,7 @@ export default class Run extends Component {
|
||||
readOnly: true,
|
||||
onChange: function () { }
|
||||
})
|
||||
|
||||
|
||||
|
||||
mockEditor({
|
||||
container: 'res-headers-pretty',
|
||||
@ -649,7 +659,12 @@ export default class Run extends Component {
|
||||
query.map((item, index) => {
|
||||
return (
|
||||
<div key={index} className="key-value-wrap">
|
||||
<Input disabled value={item.name} onChange={e => this.changeQuery(e, index, true)} className="key" />
|
||||
<Input disabled value={item.name} className="key" />
|
||||
|
||||
{item.required == 1 ?
|
||||
<Checkbox checked={true} disabled >enable</Checkbox> :
|
||||
<Checkbox checked={item.enable} onChange={e => this.changeQuery(e.target.checked, index, 'enable')}>enable</Checkbox>
|
||||
}
|
||||
<span className="eq-symbol">=</span>
|
||||
<AutoComplete
|
||||
value={item.value}
|
||||
@ -710,12 +725,13 @@ export default class Run extends Component {
|
||||
return (
|
||||
<div key={index} className="key-value-wrap">
|
||||
<Input disabled value={item.name} onChange={e => this.changeBody(e, index, 'key')} className="key" />
|
||||
<span>[</span>
|
||||
<Select disabled value={item.type} onChange={e => this.changeBody(e, index, 'type')}>
|
||||
<Option value="file">File</Option>
|
||||
<Option value="text">Text</Option>
|
||||
</Select>
|
||||
<span>]</span>
|
||||
|
||||
{item.required == 1 ?
|
||||
<Checkbox checked={true} disabled >enable</Checkbox> :
|
||||
<Checkbox checked={item.enable} onChange={e => this.changeBody(e.target.checked, index, 'enable')}>enable</Checkbox>
|
||||
}
|
||||
|
||||
|
||||
<span className="eq-symbol">=</span>
|
||||
{item.type === 'file' ?
|
||||
<Input type="file" id={'file_' + index} onChange={e => this.changeBody(e, index, 'value')} multiple className="value" /> :
|
||||
@ -752,10 +768,11 @@ export default class Run extends Component {
|
||||
|
||||
<h2 className="interface-title">返回结果</h2>
|
||||
|
||||
<Spin spinning={this.state.loading}>
|
||||
<h2 style={{ display: this.state.resStatusCode !== null ? '' : 'none' }} className={'res-code ' + ((this.state.resStatusCode >= 200 && this.state.resStatusCode < 400 && !this.state.loading) ? 'success' : 'fail')}>{this.state.resStatusCode + ' ' + this.state.resStatusText}</h2>
|
||||
<Spin spinning={this.state.loading}>
|
||||
<h2 style={{ display: this.state.resStatusCode ? '' : 'none' }} className={'res-code ' + ((this.state.resStatusCode >= 200 && this.state.resStatusCode < 400 && !this.state.loading) ? 'success' : 'fail')}>
|
||||
{this.state.resStatusCode + ' ' + this.state.resStatusText}</h2>
|
||||
|
||||
<div style={{ display: this.state.res ? '' : 'none' }} className="container-header-body">
|
||||
<div style={{ display: this.state.res ? '' : 'none' }} className="container-header-body">
|
||||
<div className="header">
|
||||
<div className="container-title">
|
||||
<h4>Headers</h4>
|
||||
@ -780,7 +797,7 @@ export default class Run extends Component {
|
||||
</div>
|
||||
</Spin>
|
||||
|
||||
<p style={{ display: this.state.resStatusCode===null ? '' : 'none' }}>发送请求后在这里查看返回结果。</p>
|
||||
<p style={{ display: this.state.resStatusCode === null ? '' : 'none' }}>发送请求后在这里查看返回结果。</p>
|
||||
|
||||
<h2 className="interface-title">数据结构验证
|
||||
<Switch style={{ verticalAlign: 'text-bottom', marginLeft: '8px' }} checked={this.state.resMockTest} onChange={this.onTestSwitched} />
|
||||
|
@ -128,6 +128,7 @@ export default {
|
||||
{ name: 'id', mock: '@id' },
|
||||
{ name: 'guid', mock: '@guid' },
|
||||
{ name: '当前时间', mock: '@now' },
|
||||
{ name: '时间戳', mock: '@timestamp'},
|
||||
{ name: '日期', mock: '@date' },
|
||||
{ name: '时间', mock: '@time' },
|
||||
{ name: '日期时间', mock: '@datetime' },
|
||||
|
@ -273,7 +273,7 @@ class InterfaceColContent extends Component {
|
||||
arr = arr || [];
|
||||
const obj = {};
|
||||
arr.forEach(item => {
|
||||
if (item.name && item.type !== 'file') {
|
||||
if (item.name && item.enable && item.type !== 'file') {
|
||||
obj[item.name] = this.handleValue(item.value);
|
||||
}
|
||||
})
|
||||
@ -284,7 +284,7 @@ class InterfaceColContent extends Component {
|
||||
query = query || [];
|
||||
const queryObj = {};
|
||||
query.forEach(item => {
|
||||
if (item.name) {
|
||||
if (item.name && item.enable) {
|
||||
queryObj[item.name] = this.handleValue(item.value);
|
||||
}
|
||||
})
|
||||
|
@ -19,6 +19,7 @@ var langTools = ace.acequire("ace/ext/language_tools"),
|
||||
{ name: 'id', mock: '@id' },
|
||||
{ name: 'guid', mock: '@guid' },
|
||||
{ name: '当前时间', mock: '@now' },
|
||||
{ name: '时间戳', mock: '@timestamp'},
|
||||
{ name: '日期', mock: '@date' },
|
||||
{ name: '时间', mock: '@time' },
|
||||
{ name: '日期时间', mock: '@datetime' },
|
||||
|
@ -1,6 +1,13 @@
|
||||
var strRegex = /\${([a-zA-Z0-9_\.]+)\}/g;
|
||||
var varSplit = '.';
|
||||
var mockSplit = '|';
|
||||
var Mock = require('mockjs');
|
||||
Mock.Random.extend({
|
||||
timestamp: function(){
|
||||
var time = new Date().getTime() + '';
|
||||
return +time.substr(0, time.length - 3)
|
||||
}
|
||||
})
|
||||
|
||||
function mock(mockJSON, context) {
|
||||
context = context || {};
|
||||
|
@ -14,19 +14,19 @@ proxy_set_header Connection "upgrade";
|
||||
* mongodb(2.6+)
|
||||
|
||||
## 安装
|
||||
执行 yapi-cli server 启动可视化部署程序,输入相应的配置和点击开始部署,就能完成整个网站的部署。部署完成之后,可按照提示信息,执行 node/{网站路径/server/app.js} 启动服务器。在浏览器打开指定url, 点击登录输入您刚才设置的管理员邮箱,默认密码(ymfe.org) 登录系统(默认密码可在个人中心修改)。
|
||||
执行 yapi server 启动可视化部署程序,输入相应的配置和点击开始部署,就能完成整个网站的部署。部署完成之后,可按照提示信息,执行 node/{网站路径/server/app.js} 启动服务器。在浏览器打开指定url, 点击登录输入您刚才设置的管理员邮箱,默认密码(ymfe.org) 登录系统(默认密码可在个人中心修改)。
|
||||
```
|
||||
npm install -g yapi-cli --registry https://registry.npm.taobao.org
|
||||
yapi-cli server
|
||||
yapi server
|
||||
```
|
||||
|
||||
## 升级
|
||||
升级项目版本是非常容易的,并且不会影响已有的项目数据,只会同步 vendors 目录下的源码文件。
|
||||
|
||||
cd {项目目录}
|
||||
yapi-cli ls //查看版本号列表
|
||||
yapi-cli update //升级到最新版本
|
||||
yapi-cli update -v v1.1.0 //升级到指定版本
|
||||
yapi ls //查看版本号列表
|
||||
yapi update //升级到最新版本
|
||||
yapi update -v v1.1.0 //升级到指定版本
|
||||
|
||||
## 配置邮箱 (仅支持 SMTP)
|
||||
打开项目目录 config.json 文件,新增 mail 配置, 替换默认的邮箱配置
|
||||
|
@ -2,12 +2,12 @@
|
||||
假设插件名为:yapi-plugin-demo,安装方法如下:
|
||||
```
|
||||
cd {项目目录}
|
||||
yapi-cli plugin yapi-plugin-demo
|
||||
yapi plugin yapi-plugin-demo
|
||||
```
|
||||
|
||||
## 卸载插件
|
||||
假设插件名为:yapi-plugin-demo,卸载方法如下:
|
||||
```
|
||||
cd {项目目录}
|
||||
yapi-cli unplugin yapi-plugin-demo
|
||||
yapi unplugin yapi-plugin-demo
|
||||
```
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "yapi",
|
||||
"version": "1.1.1",
|
||||
"version": "1.1.2",
|
||||
"description": "YAPI",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
@ -20,9 +20,9 @@
|
||||
"axios": "^0.16.2",
|
||||
"chalk": "^2.0.1",
|
||||
"clipboard": "^1.7.1",
|
||||
"deref": "^0.7.0",
|
||||
"fs-extra": "^3.0.1",
|
||||
"happypack": "^4.0.0-beta.5",
|
||||
"json-schema-faker": "^0.5.0-rc11",
|
||||
"json-schema-ref-parser": "^4.0.0",
|
||||
"json5": "^0.5.1",
|
||||
"jsonwebtoken": "^7.4.1",
|
||||
"koa": "^2.0.0",
|
||||
@ -41,13 +41,16 @@
|
||||
"mongoose-auto-increment": "^5.0.1",
|
||||
"nodemailer": "^4.0.1",
|
||||
"ora": "^1.3.0",
|
||||
"randexp": "^0.4.6",
|
||||
"request": "^2.81.0",
|
||||
"sha1": "^1.1.1",
|
||||
"tslib": "^1.8.0",
|
||||
"underscore": "^1.8.3",
|
||||
"universal-cookie": "^2.0.8",
|
||||
"url": "^0.11.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"happypack": "^4.0.0-beta.5",
|
||||
"prop-types": "^15.5.10",
|
||||
"rc-queue-anim": "^1.2.0",
|
||||
"rc-scroll-anim": "^1.0.7",
|
||||
|
@ -4,6 +4,7 @@ const interfaceModel = require('../models/interface.js');
|
||||
const projectModel = require('../models/project.js');
|
||||
const baseController = require('./base.js');
|
||||
const yapi = require('../yapi.js');
|
||||
const _ = require('underscore');
|
||||
|
||||
class interfaceColController extends baseController{
|
||||
constructor(ctx) {
|
||||
@ -406,6 +407,11 @@ class interfaceColController extends baseController{
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {*} params 接口定义的参数
|
||||
* @param {*} val 接口case 定义的参数值
|
||||
*/
|
||||
handleParamsValue(params, val){
|
||||
let value = {};
|
||||
try{
|
||||
@ -419,7 +425,10 @@ class interfaceColController extends baseController{
|
||||
})
|
||||
params.forEach((item, index)=>{
|
||||
if(!value[item.name] || typeof value[item.name] !== 'object') return null;
|
||||
params[index].value = value[item.name].value;
|
||||
params[index].value = value[item.name].value;
|
||||
if(!_.isUndefined(value[item.name].enable)){
|
||||
params[index].enable = value[item.name].enable
|
||||
}
|
||||
})
|
||||
return params;
|
||||
}
|
||||
|
@ -725,72 +725,6 @@ class projectController extends baseController {
|
||||
|
||||
return ctx.body = yapi.commons.resReturn(queryList, 0, 'ok');
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载项目的 Mock 数据
|
||||
* @interface /project/download
|
||||
* @method GET
|
||||
* @category project
|
||||
* @foldnumber 10
|
||||
* @author wenbo.dong
|
||||
* @param {String} project_id
|
||||
*/
|
||||
async download(ctx) {
|
||||
const project_id = ctx.request.query.project_id;
|
||||
let interfaceInst = yapi.getInst(interfaceModel);
|
||||
// 根据 project_id 获取接口数据
|
||||
let count = await interfaceInst.list(project_id);
|
||||
|
||||
if (!project_id) {
|
||||
return ctx.body = yapi.commons.resReturn(null, 405, '项目id不能为空');
|
||||
} else if (!count) {
|
||||
return ctx.body = yapi.commons.resReturn(null, 401, '项目id不存在');
|
||||
}
|
||||
|
||||
const arr = JSON.stringify(count.map(function (item) {
|
||||
// 返回的json模板数据: item.res_body
|
||||
const mockData = Mock.mock(
|
||||
yapi.commons.json_parse(item.res_body)
|
||||
);
|
||||
return {
|
||||
path: item.path,
|
||||
mock: mockData
|
||||
}
|
||||
}));
|
||||
|
||||
const fileName = 'mock.js';
|
||||
ctx.attachment(fileName);
|
||||
await send(ctx, fileName, { root: __dirname + '/public' });
|
||||
|
||||
const res = `
|
||||
var Mock = require('mockjs');
|
||||
var xhook = require('xhook');
|
||||
var data = ${arr};
|
||||
function run() {
|
||||
xhook.before(function(request, callback) {
|
||||
setTimeout(function() {
|
||||
var res;
|
||||
data.forEach((item) => {
|
||||
// 请求的接口在 data 中存在
|
||||
if(request.url === item.path) {
|
||||
res = {
|
||||
status: 200,
|
||||
text: Mock.mock(item.mock)
|
||||
}
|
||||
}
|
||||
});
|
||||
if (res) {
|
||||
callback(res);
|
||||
}else {
|
||||
callback({ status: 405, text: '接口不存在' });
|
||||
}
|
||||
}, 500);
|
||||
});
|
||||
}
|
||||
module.exports = run;`
|
||||
.trim();
|
||||
return ctx.body = res;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = projectController;
|
||||
|
@ -23,11 +23,11 @@ class interfaceCase extends baseModel {
|
||||
name: String, value: String
|
||||
}],
|
||||
req_query: [{
|
||||
name: String, value: String
|
||||
name: String, value: String, enable: {type: Boolean, default: true}
|
||||
}],
|
||||
|
||||
req_body_form: [{
|
||||
name: String, value: String
|
||||
name: String, value: String, enable: {type: Boolean, default: true}
|
||||
}],
|
||||
req_body_other: String,
|
||||
test_res_body: String,
|
||||
|
@ -249,10 +249,6 @@
|
||||
<li >
|
||||
<a href="#-project-search">/project/search</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="#-project-download">/project/download</a>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
|
||||
@ -3219,68 +3215,6 @@
|
||||
<span class="token punctuation">}</span></code></pre>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<div class="con-list-item">
|
||||
<blockquote class="api">
|
||||
<h3 id="-project-download" class="page-header subject">
|
||||
/project/download
|
||||
|
||||
<span class="ui-badge">GET</span>
|
||||
|
||||
|
||||
<a class="hashlink" href="#-project-download">#</a>
|
||||
</h3>
|
||||
</blockquote>
|
||||
<p>
|
||||
<small class="text-muted">描述:</small>
|
||||
下载项目的 Mock 数据
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<small class="text-muted">源码位置:</small>
|
||||
<a href="./static/server/controllers/project.js.html#728" target="_blank">./server/controllers/project.js:728</a>
|
||||
</p>
|
||||
|
||||
|
||||
<p>
|
||||
<small class="text-muted">参数:</small>
|
||||
</p>
|
||||
<div class="docs-table">
|
||||
<table class="yo-table yo-table-border">
|
||||
<colgroup>
|
||||
<col class="c1">
|
||||
<col class="c2">
|
||||
<col class="c3">
|
||||
<col class="c4">
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr class="active">
|
||||
<th>参数名</th>
|
||||
<th>类型</th>
|
||||
<th>描述</th>
|
||||
<th>必选</th>
|
||||
<th>支持版本</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tr>
|
||||
<td>project_id</td>
|
||||
<td>String</td>
|
||||
<td></td>
|
||||
<td>
|
||||
|
||||
<i class="yo-ico glyphicon glyphicon-ok text-success"></i>
|
||||
|
||||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
@ -115,14 +115,14 @@ proxy_set_header Upgrade $http_upgrade<span class="token punctuation">;</span>
|
||||
proxy_set_header Connection <span class="token string">"upgrade"</span><span class="token punctuation">;</span>
|
||||
</code></pre><h2 class="subject" id="环境要求">环境要求 <a class="hashlink" href="#环境要求">#</a></h2><ul>
|
||||
<li>nodejs(7.6+)</li><li>mongodb(2.6+)</li></ul>
|
||||
<h2 class="subject" id="安装">安装 <a class="hashlink" href="#安装">#</a></h2><p>执行 yapi-cli server 启动可视化部署程序,输入相应的配置和点击开始部署,就能完成整个网站的部署。部署完成之后,可按照提示信息,执行 node/{网站路径/server/app.js} 启动服务器。在浏览器打开指定url, 点击登录输入您刚才设置的管理员邮箱,默认密码(ymfe.org) 登录系统(默认密码可在个人中心修改)。</p>
|
||||
<h2 class="subject" id="安装">安装 <a class="hashlink" href="#安装">#</a></h2><p>执行 yapi server 启动可视化部署程序,输入相应的配置和点击开始部署,就能完成整个网站的部署。部署完成之后,可按照提示信息,执行 node/{网站路径/server/app.js} 启动服务器。在浏览器打开指定url, 点击登录输入您刚才设置的管理员邮箱,默认密码(ymfe.org) 登录系统(默认密码可在个人中心修改)。</p>
|
||||
<pre><code>npm install -g yapi-cli --registry https<span class="token operator">:</span>//registry.npm.taobao.org
|
||||
yapi-cli server
|
||||
yapi server
|
||||
</code></pre><h2 class="subject" id="升级">升级 <a class="hashlink" href="#升级">#</a></h2><p>升级项目版本是非常容易的,并且不会影响已有的项目数据,只会同步 vendors 目录下的源码文件。</p>
|
||||
<pre><code>cd <span class="token punctuation">{</span>项目目录<span class="token punctuation">}</span>
|
||||
yapi-cli ls //查看版本号列表
|
||||
yapi-cli update //升级到最新版本
|
||||
yapi-cli update -v v1<span class="token number">.1</span>.<span class="token number">0</span> //升级到指定版本
|
||||
yapi ls //查看版本号列表
|
||||
yapi update //升级到最新版本
|
||||
yapi update -v v1<span class="token number">.1</span>.<span class="token number">0</span> //升级到指定版本
|
||||
</code></pre><h2 class="subject" id="配置邮箱__仅支持_SMTP_">配置邮箱 (仅支持 SMTP) <a class="hashlink" href="#配置邮箱__仅支持_SMTP_">#</a></h2><p>打开项目目录 config.json 文件,新增 mail 配置, 替换默认的邮箱配置</p>
|
||||
<pre><code><span class="token punctuation">{</span>
|
||||
<span class="token property">"port"</span><span class="token operator">:</span> <span class="token string">"*****"</span><span class="token punctuation">,</span>
|
||||
|
@ -130,10 +130,10 @@
|
||||
|
||||
<h2 class="subject" id="安装">安装 <a class="hashlink" href="#安装">#</a></h2><p>假设插件名为:yapi-plugin-demo,安装方法如下:</p>
|
||||
<pre><code>cd <span class="token punctuation">{</span>项目目录<span class="token punctuation">}</span>
|
||||
yapi-cli plugin yapi-plugin-demo
|
||||
yapi plugin yapi-plugin-demo
|
||||
</code></pre><h2 class="subject" id="卸载插件">卸载插件 <a class="hashlink" href="#卸载插件">#</a></h2><p>假设插件名为:yapi-plugin-demo,卸载方法如下:</p>
|
||||
<pre><code>cd <span class="token punctuation">{</span>项目目录<span class="token punctuation">}</span>
|
||||
yapi-cli unplugin yapi-plugin-demo
|
||||
yapi unplugin yapi-plugin-demo
|
||||
</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -118,10 +118,10 @@
|
||||
|
||||
<h2 class="subject" id="安装">安装 <a class="hashlink" href="#安装">#</a></h2><p>假设插件名为:yapi-plugin-demo,安装方法如下:</p>
|
||||
<pre><code>cd <span class="token punctuation">{</span>项目目录<span class="token punctuation">}</span>
|
||||
yapi-cli plugin yapi-plugin-demo
|
||||
yapi plugin yapi-plugin-demo
|
||||
</code></pre><h2 class="subject" id="卸载插件">卸载插件 <a class="hashlink" href="#卸载插件">#</a></h2><p>假设插件名为:yapi-plugin-demo,卸载方法如下:</p>
|
||||
<pre><code>cd <span class="token punctuation">{</span>项目目录<span class="token punctuation">}</span>
|
||||
yapi-cli unplugin yapi-plugin-demo
|
||||
yapi unplugin yapi-plugin-demo
|
||||
</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -132,7 +132,7 @@ class groupController extends baseController {
|
||||
result = yapi.commons.fieldSelect(result, ['_id', 'group_name', 'group_desc', 'uid', 'members','type']);
|
||||
let username = this.getUsername();
|
||||
yapi.commons.saveLog({
|
||||
content: `<a href="/user/profile/${this.getUid()}">${username}</a> 新增了分组 "${params.group_name}"`,
|
||||
content: `<a href="/user/profile/${this.getUid()}">${username}</a> 新增了分组 <a href="/group/${result._id}">${params.group_name}</a>`,
|
||||
type: 'group',
|
||||
uid: this.getUid(),
|
||||
username: username,
|
||||
|
@ -512,7 +512,7 @@ class interfaceController extends baseController {
|
||||
if (data.catid) {
|
||||
this.catModel.get(+data.catid).then((cate) => {
|
||||
yapi.commons.saveLog({
|
||||
content: `<a href="/user/profile/${this.getUid()}">${username}</a> 更新了分类 <a href="/project/${cate.project_id}/interface/api/cat_${data.catid}">${cate.name}</a> 下的接口 <a href="project/${cate.project_id}/interface/api/${id}">${interfaceData.title}</a>`,
|
||||
content: `<a href="/user/profile/${this.getUid()}">${username}</a> 更新了分类 <a href="/project/${cate.project_id}/interface/api/cat_${data.catid}">${cate.name}</a> 下的接口 <a href="/project/${cate.project_id}/interface/api/${id}">${interfaceData.title}</a>`,
|
||||
type: 'project',
|
||||
uid: this.getUid(),
|
||||
username: username,
|
||||
@ -524,7 +524,7 @@ class interfaceController extends baseController {
|
||||
let cateid = interfaceData.catid;
|
||||
this.catModel.get(cateid).then((cate) => {
|
||||
yapi.commons.saveLog({
|
||||
content: `<a href="/user/profile/${this.getUid()}">${username}</a> 更新了分类 <a href="/project/${cate.project_id}/interface/api/cat_${cateid}">${cate.name}</a> 下的接口 <a href="project/${cate.project_id}/interface/api/${id}>${interfaceData.title}</a>`,
|
||||
content: `<a href="/user/profile/${this.getUid()}">${username}</a> 更新了分类 <a href="/project/${cate.project_id}/interface/api/cat_${cateid}">${cate.name}</a> 下的接口 <a href="/project/${cate.project_id}/interface/api/${id}>${interfaceData.title}</a>`,
|
||||
type: 'project',
|
||||
uid: this.getUid(),
|
||||
username: username,
|
||||
@ -728,7 +728,7 @@ class interfaceController extends baseController {
|
||||
|
||||
let username = this.getUsername();
|
||||
yapi.commons.saveLog({
|
||||
content: `<a href="/user/profile/${this.getUid()}">${username}</a> 删除了分类 <a href="/project/${catData.project_id}/interface/api/cat_${id}">${catData.name}</a> 及该分类下的接口`,
|
||||
content: `<a href="/user/profile/${this.getUid()}">${username}</a> 删除了分类 "${catData.name}" 及该分类下的接口`,
|
||||
type: 'project',
|
||||
uid: this.getUid(),
|
||||
username: username,
|
||||
|
@ -554,7 +554,7 @@ class interfaceColController extends baseController{
|
||||
await this.caseModel.delByCol(id);
|
||||
let username = this.getUsername();
|
||||
yapi.commons.saveLog({
|
||||
content: `<a href="/user/profile/${this.getUid()}">${username}</a> 删除了接口集 <a href="/project/${colData.project_id}/interface/col/${id}">${colData.name}</a> 及其下面的接口`,
|
||||
content: `<a href="/user/profile/${this.getUid()}">${username}</a> 删除了接口集 ${colData.name} 及其下面的接口`,
|
||||
type: 'project',
|
||||
uid: this.getUid(),
|
||||
username: username,
|
||||
@ -591,7 +591,7 @@ class interfaceColController extends baseController{
|
||||
let username = this.getUsername();
|
||||
this.colModel.get(caseData.col_id).then((col)=>{
|
||||
yapi.commons.saveLog({
|
||||
content: `<a href="/user/profile/${this.getUid()}">${username}</a> 删除了接口集 <a href="/project/${caseData.project_id}/interface/col/${caseData.col_id}">${col.name}</a> 下的接口 <a href="/project/${caseData.project_id}/interface/case/${caseid}">${caseData.casename}</a>`,
|
||||
content: `<a href="/user/profile/${this.getUid()}">${username}</a> 删除了接口集 <a href="/project/${caseData.project_id}/interface/col/${caseData.col_id}">${col.name}</a> 下的接口 ${caseData.casename}`,
|
||||
type: 'project',
|
||||
uid: this.getUid(),
|
||||
username: username,
|
||||
|
@ -75,7 +75,7 @@ class logController extends baseController {
|
||||
projectLogList.forEach((item, index)=>{
|
||||
item = item.toObject();
|
||||
if(item.type === 'project'){
|
||||
item.content = `在 <a href="/group/${item.typeid}">${projectDatas[item.typeid].name}</a> 项目: ` + item.content;
|
||||
item.content = `在 <a href="/project/${item.typeid}">${projectDatas[item.typeid].name}</a> 项目: ` + item.content;
|
||||
}
|
||||
projectLogList[index] = item;
|
||||
})
|
||||
|
@ -752,72 +752,6 @@ class projectController extends baseController {
|
||||
|
||||
return ctx.body = yapi.commons.resReturn(queryList, 0, 'ok');
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载项目的 Mock 数据
|
||||
* @interface /project/download
|
||||
* @method GET
|
||||
* @category project
|
||||
* @foldnumber 10
|
||||
* @author wenbo.dong
|
||||
* @param {String} project_id
|
||||
*/
|
||||
async download(ctx) {
|
||||
const project_id = ctx.request.query.project_id;
|
||||
let interfaceInst = yapi.getInst(interfaceModel);
|
||||
// 根据 project_id 获取接口数据
|
||||
let count = await interfaceInst.list(project_id);
|
||||
|
||||
if (!project_id) {
|
||||
return ctx.body = yapi.commons.resReturn(null, 405, '项目id不能为空');
|
||||
} else if (!count) {
|
||||
return ctx.body = yapi.commons.resReturn(null, 401, '项目id不存在');
|
||||
}
|
||||
|
||||
const arr = JSON.stringify(count.map(function (item) {
|
||||
// 返回的json模板数据: item.res_body
|
||||
const mockData = Mock.mock(
|
||||
yapi.commons.json_parse(item.res_body)
|
||||
);
|
||||
return {
|
||||
path: item.path,
|
||||
mock: mockData
|
||||
}
|
||||
}));
|
||||
|
||||
const fileName = 'mock.js';
|
||||
ctx.attachment(fileName);
|
||||
await send(ctx, fileName, { root: __dirname + '/public' });
|
||||
|
||||
const res = `
|
||||
var Mock = require('mockjs');
|
||||
var xhook = require('xhook');
|
||||
var data = ${arr};
|
||||
function run() {
|
||||
xhook.before(function(request, callback) {
|
||||
setTimeout(function() {
|
||||
var res;
|
||||
data.forEach((item) => {
|
||||
// 请求的接口在 data 中存在
|
||||
if(request.url === item.path) {
|
||||
res = {
|
||||
status: 200,
|
||||
text: Mock.mock(item.mock)
|
||||
}
|
||||
}
|
||||
});
|
||||
if (res) {
|
||||
callback(res);
|
||||
}else {
|
||||
callback({ status: 405, text: '接口不存在' });
|
||||
}
|
||||
}, 500);
|
||||
});
|
||||
}
|
||||
module.exports = run;`
|
||||
.trim();
|
||||
return ctx.body = res;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = projectController;
|
||||
|
@ -1 +0,0 @@
|
||||
window.WEBPACK_ASSETS = {"index.js":{"js":"index@717f13477574c1d89f76.js","css":"index@717f13477574c1d89f76.css"},"lib":{"js":"lib@dd4c0752e32a8c051c7c.js"},"lib2":{"js":"lib2@fda61e2b7f61e65a452d.js"},"manifest":{"js":"manifest@b67af9f8b578904e66c5.js"}}
|
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
@ -1 +0,0 @@
|
||||
!function(e){function t(n){if(r[n])return r[n].exports;var i=r[n]={exports:{},id:n,loaded:!1};return e[n].call(i.exports,i,i.exports,t),i.loaded=!0,i.exports}var n=window.webpackJsonp;window.webpackJsonp=function(s,o){for(var u,f,l=0,c=[];l<s.length;l++)f=s[l],i[f]&&c.push.apply(c,i[f]),i[f]=0;for(u in o)e[u]=o[u];for(n&&n(s,o);c.length;)c.shift().call(null,t);if(o[0])return r[0]=0,t(0)};var r={},i={3:0};t.e=function(e,n){if(0===i[e])return n.call(null,t);if(void 0!==i[e])i[e].push(n);else{i[e]=[n];var r=document.getElementsByTagName("head")[0],s=document.createElement("script");s.type="text/javascript",s.charset="utf-8",s.async=!0,s.src=t.p+""+e+".chunk.min.js",r.appendChild(s)}},t.m=e,t.c=r,t.p=""}([])
|
Loading…
Reference in New Issue
Block a user