fix: 利用ydoc生成文档

This commit is contained in:
qitmac000249 2017-07-28 23:31:35 +08:00
parent 89bbf17888
commit 4480a54834
29 changed files with 6583 additions and 21 deletions

6
README/README-home.md Normal file
View File

@ -0,0 +1,6 @@
<script>
window.onload = function(){
var aList = $('.ydoc-nav').find('a');
$(aList[aList.length-1]).css('display','none');
}
</script>

View File

@ -0,0 +1,44 @@
## 快速开始
### 1 接口管理架构
平台以**项目分组** -> **项目** -> **接口**的划分进行接口组织管理。
<img src="http://upload-images.jianshu.io/upload_images/842107-305ba49a60ee1ff5.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" width = "800" style="margin:0px auto;display:block;" alt="图片名称" align=center />
#### 1.1 项目分组
登录之后进到项目首页,左边侧边栏显示的即分组列表。
<img src="http://upload-images.jianshu.io/upload_images/842107-d90ca4b3242fa760.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" width = "200" style="margin-left:170px;display:block;" alt="图片名称" align=center />
管理员有权限添加或删除分组。
<img src="http://upload-images.jianshu.io/upload_images/842107-a0d4d9a98003896a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" width = "500" style="margin-left:170px;display:block;" alt="图片名称" align=center />
> 分组名称具有唯一性
#### 1.2 项目
选中不同的分组,右边会显示该分组下的项目列表。
<img src="http://upload-images.jianshu.io/upload_images/842107-137bcae58b84715e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" width = "800" style="margin:0px auto;display:block;" alt="图片名称" align=center />
创建项目需要填写项目名称,项目线上域名(添加完成后可配置项目其他环境域名),项目接口基本路径(接口路径前面相同的部分)以及项目描述。
<img src="http://upload-images.jianshu.io/upload_images/842107-360a50ddb746f73d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" width = "800" style="margin:0px auto;display:block;" alt="图片名称" align=center />
> 项目『线上域名 + 基本路径』具有唯一性
#### 1.3 接口
点击项目名称,进入该项目接口列表。
<img src="http://upload-images.jianshu.io/upload_images/842107-e858005f714f4889.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" width = "800" style="margin:0px auto;display:block;" alt="图片名称" align=center />
点击编辑,进入接口详情页(之后接口详情页和编辑也会分开),可以编辑接口或者请求测试真实接口。
<img src="http://upload-images.jianshu.io/upload_images/842107-78c0ea839619d068.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" width = "800" style="margin:0px auto;display:block;" alt="图片名称" align=center />
<img src="http://upload-images.jianshu.io/upload_images/842107-2ee7171d707e91ff.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" width = "800" style="margin:0px auto;display:block;" alt="图片名称" align=center />

36
README/README-mock.md Normal file
View File

@ -0,0 +1,36 @@
### Mock功能
<p style='text-indent:2em;line-height:1.8em'>yapi的Mock功能可以根据用户的输入接口信息如协议、URL、接口名、请求头、请求参数、mock规则生成Mock接口这些接口会自动生成模拟数据支持复杂的生成逻辑创建者可以自由构造需要的数据。而且与常见的Mock方式如将Mock写在代码里和JS拦截等相比yapi的Mock在使用场景和效率和复杂度上是相差甚远的正是由于yapi的Mock是一个第三方平台那么在 团队开发时任何人都可以权限许可下创建、修改接口信息等操作,这对于团队开发是很有好处的。</p>
#### 1 添加接口
通过点击页面上的"+添加接口"
<img src="http://note.youdao.com/yws/api/personal/file/WEB613bd4f29db038f2b41c03dcfceda2b6?method=download&shareKey=29bfc2b855f6f26ce0079baf567e54cc" width = "800" style="margin:0px auto;display:block;" alt="图片名称" align=center />
输入协议、URL、接口名、请求头、请求参数、mock规则等信息然后点击右上角的"Mock"按钮。
<img src="http://upload-images.jianshu.io/upload_images/842107-78c0ea839619d068.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" width = "800" style="margin:0px auto;display:block;" alt="图片名称" align=center />
#### 2 Mock
当点击"Mock"按钮之后就会在页面下方生成一个mock结果并产生一个API接口。点击"复制"按钮即可复制,用户拿到接口后就可以发请求了。
<img src="http://note.youdao.com/yws/api/personal/file/WEBf9b154cb88d21daa8206e8c4a3d76042?method=download&shareKey=1999f6c2cf197b5b6d775c312e34073d" width = "800" style="margin:0px auto;display:block;" alt="图片名称" align=center />
将请求的信息填写完善如请求方法post、get等、URL、请求头、请求的数据等。然后就点击"发送",然后在"返回结果"出可以看到接口返回的数据。
<img src="http://upload-images.jianshu.io/upload_images/842107-2ee7171d707e91ff.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" width = "800" style="margin:0px auto;display:block;" alt="图片名称" align=center />
#### 3 成员管理
你也可以通过点击"管理成员"来添加和删除项目的成员,便于团队管理。
<img src="http://note.youdao.com/yws/api/personal/file/WEB1b9defdf0cb884f46c2bd6c30ceb02fb?method=download&shareKey=218b9326659208ec564b9fff3ea8c6c3" width = "800" style="margin:0px auto;display:block;" alt="图片名称" align=center />
## 未来计划推出功能
1. 可视化JSON编辑器可定义JSON_Schema和mockjs
2. 支持HTTP和RPC协议
3. 自动化测试
4. 多人协作

3448
static/doc/api.html Normal file

File diff suppressed because it is too large Load Diff

197
static/doc/index.html Normal file
View File

@ -0,0 +1,197 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no" />
<meta name="format-detection" content="telephone=no,email=no" />
<meta http-equiv="X-UA-Compatible" content="ie=edge, chrome=1">
<meta name="description" content="description of your site">
<meta name="author" content="author of the site">
<title>YApi 首页</title>
<link rel="stylesheet" href="source/main.css" />
</head>
<body>
<div class="ydoc">
<header class="ydoc-header">
<div class="ydoc-header-area">
<a href="http://ued.qunar.com/ymfe/" class="navbar-brand">YMFE</a>
<button class="ydocIcon navbar-toggle">&#xf020;</button>
<nav class="ydoc-nav">
<ul class="navbar-left">
<li class="active">
<a href="index.html">首页</a>
</li>
<li class="">
<a href="interface.html">接口管理</a>
</li>
<li class="">
<a href="mock.html">Mock功能</a>
</li>
<li class="">
<a href="api.html"></a>
</li>
</ul>
</nav>
</div>
</header>
<!-- <header style="height:20px"></header> -->
<!-- Docs page layout -->
<div class="ydoc-banner-bg">
<div class="ydoc-banner ydoc-banner-home">
<div class="ydoc-banner-area">
<h1 class="home-title">YApi</h1>
<p class="desc home-desc">高效、易用、功能强大、的api管理平台旨在为开发、产品、测试人员提供更优雅的接口管理服务。</p>
<a class="ydoc-banner-button home-btn" href="./interface.html">开始</a>
<a class="ydoc-banner-button home-btn" href="https://github.com/YMFE/yapi">Github</a>
<p class="home-version">当前版本v1.0.0</p>
</div>
</div>
<div class="ydoc-container">
<div class="ydoc-container-content ydoc-container-home" id="readme">
<h1 class="home-page-title">为API开发者设计的管理平台</h1>
<p class="home-page-desc">YApi让接口开发更简单高效让接口的管理更具可读性、可维护性让团队协作更合理。</p>
<h1 class="home-page-title">功能</h1>
<div class="home-thumbnail">
<div class="home-item">
<div class="home-thumbnail-img">
<img class="home-thumbnail-src" src=http://ojk406wln.bkt.clouddn.com/intro_muti.png alt="">
</div>
<h3 class="home-thumbnail-name">项目接口管理</h3>
<p class="home-thumbnail-desc">提供基本的项目分组,项目管理,接口管理功能</p>
</div>
<div class="home-item">
<div class="home-thumbnail-img">
<img class="home-thumbnail-src" src=http://ojk406wln.bkt.clouddn.com/intro_md.png alt="">
</div>
<h3 class="home-thumbnail-name">mockServer服务</h3>
<p class="home-thumbnail-desc">用户只需在项目配置线上域名和接口基本路径通过将线上域名指到我们的YApi平台服务器就可使用mockServer服务</p>
</div>
<div class="home-item">
<div class="home-thumbnail-img">
<img class="home-thumbnail-src" src=http://ojk406wln.bkt.clouddn.com/intro_theme.png alt="">
</div>
<h3 class="home-thumbnail-name">用户管理</h3>
<p class="home-thumbnail-desc">提供基本的用户注册登录管理等功能集成了去哪儿QSSO登录</p>
</div>
</div>
<article class="markdown-body">
<script>
window.onload = function(){
var aList = $('.ydoc-nav').find('a');
$(aList[aList.length-1]).css('display','none');
}
</script>
</article>
</div>
</div>
</div>
<footer class="footer">
<div class="copyright">
&copy; 2016 <a href="http://ued.qunar.com/ymfe/">YMFE</a> Team. Build by <a href="http://ued.qunar.com/ydoc/">ydoc</a>.
</div>
</footer>
</div>
<script src="source/main.js"></script>
<script src="source/app.js"></script>
<script>
var lineHeight = 17.4;
var EXAMPLE_MAX_HEIGHT;
function fold() {
// 折叠code
$('.markdown-body pre').css({
"line-height": lineHeight + "px"
});
$('.markdown-body pre').map(function(i, item) {
var $item = $(item);
var foldnumber = $item.data('foldnumber');
EXAMPLE_MAX_HEIGHT = lineHeight * (foldnumber || 6);
if ($item.height() > EXAMPLE_MAX_HEIGHT) {
$item.css({
"padding-bottom": 30
});
$item.find('code').height(EXAMPLE_MAX_HEIGHT);
$item.append('<span class="extend">展开更多……</span>');
};
});
$('.ydoc-example').delegate('.extend', 'click', function() {
var $this = $(this);
$this.removeClass('extend').addClass('fold');
$this.html('折叠代码');
$this.prev().height('auto');
$this.prev().parent().height('auto');
});
$('.ydoc-example').delegate('.fold', 'click', function() {
var $this = $(this);
var foldnumber = $this.parent().data('foldnumber');
EXAMPLE_MAX_HEIGHT = lineHeight * (foldnumber || 6);
$this.removeClass('fold').addClass('extend');
$this.parent().height(EXAMPLE_MAX_HEIGHT); // pre
$this.prev().height(EXAMPLE_MAX_HEIGHT); // code
$this.html("展开更多……");
});
}
$(document).ready(fold);
</script>
</body>
</html>

156
static/doc/interface.html Normal file
View File

@ -0,0 +1,156 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no" />
<meta name="format-detection" content="telephone=no,email=no" />
<meta http-equiv="X-UA-Compatible" content="ie=edge, chrome=1">
<meta name="description" content="description of your site">
<meta name="author" content="author of the site">
<title>YApi 接口管理</title>
<link rel="stylesheet" href="source/main.css" />
</head>
<body>
<div class="ydoc">
<header class="ydoc-header">
<div class="ydoc-header-area">
<a href="http://ued.qunar.com/ymfe/" class="navbar-brand">YMFE</a>
<button class="ydocIcon navbar-toggle">&#xf020;</button>
<nav class="ydoc-nav">
<ul class="navbar-left">
<li class="">
<a href="index.html">首页</a>
</li>
<li class="active">
<a href="interface.html">接口管理</a>
</li>
<li class="">
<a href="mock.html">Mock功能</a>
</li>
<li class="">
<a href="api.html"></a>
</li>
</ul>
</nav>
</div>
</header>
<!-- <header style="height:20px"></header> -->
<!-- Docs page layout -->
<div class="ydoc-banner-bg">
<div class="ydoc-banner ">
<div class="ydoc-banner-area">
<h1 >YApi</h1>
<p class="desc ">高效、易用、功能强大、的api管理平台旨在为开发、产品、测试人员提供更优雅的接口管理服务。</p>
</div>
</div>
<div class="ydoc-container">
<div class="ydoc-container-content " id="readme">
<article class="markdown-body">
<h2 class="subject" id="快速开始">快速开始 <a class="hashlink" href="#快速开始">#</a></h2><h3 class="subject" id="1_接口管理架构">1 接口管理架构 <a class="hashlink" href="#1_接口管理架构">#</a></h3><p>平台以<strong>项目分组</strong> -&gt; <strong>项目</strong> -&gt; <strong>接口</strong>的划分进行接口组织管理。</p>
<p><img src="http://upload-images.jianshu.io/upload_images/842107-305ba49a60ee1ff5.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" width = "800" style="margin:0px auto;display:block;" alt="图片名称" align=center /></p>
<h4 class="subject" id="1.1_项目分组">1.1 项目分组 <a class="hashlink" href="#1.1_项目分组">#</a></h4><p>登录之后进到项目首页,左边侧边栏显示的即分组列表。</p>
<p><img src="http://upload-images.jianshu.io/upload_images/842107-d90ca4b3242fa760.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" width = "200" style="margin-left:170px;display:block;" alt="图片名称" align=center /></p>
<p>管理员有权限添加或删除分组。</p>
<p><img src="http://upload-images.jianshu.io/upload_images/842107-a0d4d9a98003896a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" width = "500" style="margin-left:170px;display:block;" alt="图片名称" align=center /></p>
<blockquote>
<p>分组名称具有唯一性</p>
</blockquote>
<h4 class="subject" id="1.2_项目">1.2 项目 <a class="hashlink" href="#1.2_项目">#</a></h4><p>选中不同的分组,右边会显示该分组下的项目列表。</p>
<p><img src="http://upload-images.jianshu.io/upload_images/842107-137bcae58b84715e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" width = "800" style="margin:0px auto;display:block;" alt="图片名称" align=center /></p>
<p>创建项目需要填写项目名称,项目线上域名(添加完成后可配置项目其他环境域名),项目接口基本路径(接口路径前面相同的部分)以及项目描述。</p>
<p><img src="http://upload-images.jianshu.io/upload_images/842107-360a50ddb746f73d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" width = "800" style="margin:0px auto;display:block;" alt="图片名称" align=center /></p>
<blockquote>
<p>项目『线上域名 + 基本路径』具有唯一性</p>
</blockquote>
<h4 class="subject" id="1.3_接口">1.3 接口 <a class="hashlink" href="#1.3_接口">#</a></h4><p>点击项目名称,进入该项目接口列表。</p>
<p><img src="http://upload-images.jianshu.io/upload_images/842107-e858005f714f4889.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" width = "800" style="margin:0px auto;display:block;" alt="图片名称" align=center /></p>
<p>点击编辑,进入接口详情页(之后接口详情页和编辑也会分开),可以编辑接口或者请求测试真实接口。</p>
<p><img src="http://upload-images.jianshu.io/upload_images/842107-78c0ea839619d068.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" width = "800" style="margin:0px auto;display:block;" alt="图片名称" align=center /></p>
<p><img src="http://upload-images.jianshu.io/upload_images/842107-2ee7171d707e91ff.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" width = "800" style="margin:0px auto;display:block;" alt="图片名称" align=center /></p>
</article>
</div>
</div>
</div>
<footer class="footer">
<div class="copyright">
&copy; 2016 <a href="http://ued.qunar.com/ymfe/">YMFE</a> Team. Build by <a href="http://ued.qunar.com/ydoc/">ydoc</a>.
</div>
</footer>
</div>
<script src="source/main.js"></script>
<script src="source/app.js"></script>
<script>
var lineHeight = 17.4;
var EXAMPLE_MAX_HEIGHT;
function fold() {
// 折叠code
$('.markdown-body pre').css({
"line-height": lineHeight + "px"
});
$('.markdown-body pre').map(function(i, item) {
var $item = $(item);
var foldnumber = $item.data('foldnumber');
EXAMPLE_MAX_HEIGHT = lineHeight * (foldnumber || 6);
if ($item.height() > EXAMPLE_MAX_HEIGHT) {
$item.css({
"padding-bottom": 30
});
$item.find('code').height(EXAMPLE_MAX_HEIGHT);
$item.append('<span class="extend">展开更多……</span>');
};
});
$('.ydoc-example').delegate('.extend', 'click', function() {
var $this = $(this);
$this.removeClass('extend').addClass('fold');
$this.html('折叠代码');
$this.prev().height('auto');
$this.prev().parent().height('auto');
});
$('.ydoc-example').delegate('.fold', 'click', function() {
var $this = $(this);
var foldnumber = $this.parent().data('foldnumber');
EXAMPLE_MAX_HEIGHT = lineHeight * (foldnumber || 6);
$this.removeClass('fold').addClass('extend');
$this.parent().height(EXAMPLE_MAX_HEIGHT); // pre
$this.prev().height(EXAMPLE_MAX_HEIGHT); // code
$this.html("展开更多……");
});
}
$(document).ready(fold);
</script>
</body>
</html>

149
static/doc/mock.html Normal file
View File

@ -0,0 +1,149 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no" />
<meta name="format-detection" content="telephone=no,email=no" />
<meta http-equiv="X-UA-Compatible" content="ie=edge, chrome=1">
<meta name="description" content="description of your site">
<meta name="author" content="author of the site">
<title>YApi Mock功能</title>
<link rel="stylesheet" href="source/main.css" />
</head>
<body>
<div class="ydoc">
<header class="ydoc-header">
<div class="ydoc-header-area">
<a href="http://ued.qunar.com/ymfe/" class="navbar-brand">YMFE</a>
<button class="ydocIcon navbar-toggle">&#xf020;</button>
<nav class="ydoc-nav">
<ul class="navbar-left">
<li class="">
<a href="index.html">首页</a>
</li>
<li class="">
<a href="interface.html">接口管理</a>
</li>
<li class="active">
<a href="mock.html">Mock功能</a>
</li>
<li class="">
<a href="api.html"></a>
</li>
</ul>
</nav>
</div>
</header>
<!-- <header style="height:20px"></header> -->
<!-- Docs page layout -->
<div class="ydoc-banner-bg">
<div class="ydoc-banner ">
<div class="ydoc-banner-area">
<h1 >YApi</h1>
<p class="desc ">高效、易用、功能强大、的api管理平台旨在为开发、产品、测试人员提供更优雅的接口管理服务。</p>
</div>
</div>
<div class="ydoc-container">
<div class="ydoc-container-content " id="readme">
<article class="markdown-body">
<h3 class="subject" id="Mock功能">Mock功能 <a class="hashlink" href="#Mock功能">#</a></h3> <p style='text-indent:2em;line-height:1.8em'>yapi的Mock功能可以根据用户的输入接口信息如协议、URL、接口名、请求头、请求参数、mock规则生成Mock接口这些接口会自动生成模拟数据支持复杂的生成逻辑创建者可以自由构造需要的数据。而且与常见的Mock方式如将Mock写在代码里和JS拦截等相比yapi的Mock在使用场景和效率和复杂度上是相差甚远的正是由于yapi的Mock是一个第三方平台那么在 团队开发时任何人都可以权限许可下创建、修改接口信息等操作,这对于团队开发是很有好处的。</p>
<h4 class="subject" id="1_添加接口">1 添加接口 <a class="hashlink" href="#1_添加接口">#</a></h4><p>通过点击页面上的&quot;+添加接口&quot;</p>
<p><img src="http://note.youdao.com/yws/api/personal/file/WEB613bd4f29db038f2b41c03dcfceda2b6?method=download&shareKey=29bfc2b855f6f26ce0079baf567e54cc" width = "800" style="margin:0px auto;display:block;" alt="图片名称" align=center /></p>
<p> 输入协议、URL、接口名、请求头、请求参数、mock规则等信息然后点击右上角的&quot;Mock&quot;按钮。</p>
<p><img src="http://upload-images.jianshu.io/upload_images/842107-78c0ea839619d068.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" width = "800" style="margin:0px auto;display:block;" alt="图片名称" align=center /></p>
<h4 class="subject" id="2_Mock">2 Mock <a class="hashlink" href="#2_Mock">#</a></h4><p>当点击&quot;Mock&quot;按钮之后就会在页面下方生成一个mock结果并产生一个API接口。点击&quot;复制&quot;按钮即可复制,用户拿到接口后就可以发请求了。</p>
<p><img src="http://note.youdao.com/yws/api/personal/file/WEBf9b154cb88d21daa8206e8c4a3d76042?method=download&shareKey=1999f6c2cf197b5b6d775c312e34073d" width = "800" style="margin:0px auto;display:block;" alt="图片名称" align=center /></p>
<p>将请求的信息填写完善如请求方法post、get等、URL、请求头、请求的数据等。然后就点击&quot;发送&quot;,然后在&quot;返回结果&quot;出可以看到接口返回的数据。</p>
<p><img src="http://upload-images.jianshu.io/upload_images/842107-2ee7171d707e91ff.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" width = "800" style="margin:0px auto;display:block;" alt="图片名称" align=center /></p>
<h4 class="subject" id="3_成员管理">3 成员管理 <a class="hashlink" href="#3_成员管理">#</a></h4><p>你也可以通过点击&quot;管理成员&quot;来添加和删除项目的成员,便于团队管理。</p>
<p><img src="http://note.youdao.com/yws/api/personal/file/WEB1b9defdf0cb884f46c2bd6c30ceb02fb?method=download&shareKey=218b9326659208ec564b9fff3ea8c6c3" width = "800" style="margin:0px auto;display:block;" alt="图片名称" align=center /></p>
<h2 class="subject" id="未来计划推出功能">未来计划推出功能 <a class="hashlink" href="#未来计划推出功能">#</a></h2><ol>
<li>可视化JSON编辑器可定义JSON_Schema和mockjs</li><li>支持HTTP和RPC协议</li><li>自动化测试</li><li>多人协作</li></ol>
</article>
</div>
</div>
</div>
<footer class="footer">
<div class="copyright">
&copy; 2016 <a href="http://ued.qunar.com/ymfe/">YMFE</a> Team. Build by <a href="http://ued.qunar.com/ydoc/">ydoc</a>.
</div>
</footer>
</div>
<script src="source/main.js"></script>
<script src="source/app.js"></script>
<script>
var lineHeight = 17.4;
var EXAMPLE_MAX_HEIGHT;
function fold() {
// 折叠code
$('.markdown-body pre').css({
"line-height": lineHeight + "px"
});
$('.markdown-body pre').map(function(i, item) {
var $item = $(item);
var foldnumber = $item.data('foldnumber');
EXAMPLE_MAX_HEIGHT = lineHeight * (foldnumber || 6);
if ($item.height() > EXAMPLE_MAX_HEIGHT) {
$item.css({
"padding-bottom": 30
});
$item.find('code').height(EXAMPLE_MAX_HEIGHT);
$item.append('<span class="extend">展开更多……</span>');
};
});
$('.ydoc-example').delegate('.extend', 'click', function() {
var $this = $(this);
$this.removeClass('extend').addClass('fold');
$this.html('折叠代码');
$this.prev().height('auto');
$this.prev().parent().height('auto');
});
$('.ydoc-example').delegate('.fold', 'click', function() {
var $this = $(this);
var foldnumber = $this.parent().data('foldnumber');
EXAMPLE_MAX_HEIGHT = lineHeight * (foldnumber || 6);
$this.removeClass('fold').addClass('extend');
$this.parent().height(EXAMPLE_MAX_HEIGHT); // pre
$this.prev().height(EXAMPLE_MAX_HEIGHT); // code
$this.html("展开更多……");
});
}
$(document).ready(fold);
</script>
</body>
</html>

Binary file not shown.

230
static/doc/source/app.js Normal file
View File

@ -0,0 +1,230 @@
var EXAMPLE_MAX_HEIGHT = 98,
DEFAULT_SHOW_PARAMS = 5;
$(document).ready(function() {
// 移动端导航
var $openPanel = $('.open-panel');
var $contentLeft = $('.content-left');
var $contentLeftWidth = $contentLeft.width() - 1;
var $ydoc = $('.ydoc');
var $mask = $('.mask');
var $versionSelector = $('.version-selector');
var $versionMask = $('.m-version-mask');
var isPanelHide = true;
var winWidth = $(window).width();
var h2 = $('.content-right').find('h2');
var h3 = $('.content-right').find('h3');
var a = $('.content-left').find('a');
var lis = $contentLeft.find('li');
var titles = [];
var menus = [];
$ydoc.addClass('hidden');
if (isWechat() && $contentLeft[0]) {
$ydoc.addClass('off-webkit-scroll');
}
for (var i = 0; i < a.length; i++) {
menus.push({
name: $(a[i]).attr('href').split('#')[1],
offsetTop: $(a[i]).offset().top - 77,
parent: $(a[i]).parent()
})
}
for (var i = 0; i < h2.length; i++) {
titles.push({
name: h2[i].id,
jq: $(h2[i]),
offsetTop: $(h2[i]).offset().top
})
}
for (var i = 0; i < h3.length; i++) {
titles.push({
name: h3[i].id,
jq: $(h3[i]),
offsetTop: $(h3[i]).offset().top
})
}
titles.sort(sortAsOffset('offsetTop'));
$openPanel.on('click', function() {
if (isPanelHide) { // 点击弹出panel
isPanelHide = false;
$ydoc.addClass('hidden');
$mask.show();
setTimeout(function() {
$mask.addClass('show');
}, 50)
$openPanel.css({
'transform': 'translateX(-' + $contentLeftWidth + 'px)'
})
$contentLeft.css({
'transform': 'translateX(-' + $contentLeftWidth + 'px)'
})
} else { // 点击隐藏panel
isPanelHide = true;
$ydoc.removeClass('hidden');
$mask.removeClass('show');
setTimeout(function() {
$mask.hide();
}, 400)
$openPanel.css({
'transform': 'translateX(0px)'
})
$contentLeft.css({
'transform': 'translateX(0px)'
})
}
var scrollTop = $ydoc.scrollTop();
// 遍历主页面的标题,找到当前窗口顶部的标题
for (var i = 0; i < titles.length; i++) {
if (titles[i].offsetTop > scrollTop) {
// 遍历侧栏,找到对应的标题
for (var j in menus) {
if (menus[j].name == titles[i].name) {
lis.removeClass('active');
menus[j].parent.addClass('active');
$('.docs-sidenav').scrollTop(menus[j].offsetTop);
return;
}
}
return;
}
}
});
$ydoc.removeClass('hidden');
$ydoc.on('scroll', function() {
sessionStorage.setItem('offsetTop', $ydoc.scrollTop());
})
// 待元素获获取offsetTop值之后再设置ydoc的offsetTop
if (sessionStorage.offsetTop) {
$ydoc.scrollTop(sessionStorage.offsetTop);
}
// $openPanel.trigger('click');
$mask.on('click', function() {
if (!isPanelHide) {
$openPanel.click();
}
});
// PC端导航
$('.navbar-toggle').click(function() {
$(this).next(".ydoc-nav").toggle();
});
$('.docs-sidenav li').click(function(e) {
$('.docs-sidenav li').removeClass('active');
$(this).addClass('active');
if (!isPanelHide) {
$openPanel.trigger('click');
}
});
$ydoc.click(function(e) {
if ($(e.target).data('target') !== 'version') {
$versionMask.hide();
}
})
$versionSelector.click(function(e) {
$versionMask.show();
console.log('e');
});
$('.markdown-body pre').map(function(i, item) {
$(item).addClass('ydoc-example').append('<div class="ui-copy js-copy" data-clipboard-action="copy" data-clipboard-target=".js-code-' + i + '" data-copy-number="' + i + '">copy</div><div class="copy-tip copy-tip-' + i + '">已复制</div>');
$(item).children('code').addClass('js-code-'+i);
});
var winHeight = $(window).height() - 44,
sidebar = $('.docs-sidebar');
var docSideNav = $('.docs-sidenav');
if (winWidth > 767) {
docSideNav.width($contentLeftWidth);
}
if (sidebar.height() > winHeight) {
sidebar.css('max-height', winHeight + 'px');
$('.docs-sidenav').css('max-height', winHeight + 'px');
if (winWidth < 768) {
$('.docs-sidenav').css({
'overflow-x': 'hidden'
});
}
var activeMenu,
barScroll = false;
sidebar.on('mouseover', function() {
barScroll = true;
});
sidebar.on('mouseout', function() {
barScroll = false;
});
};
$(window).on('scroll', function(e) {
if ($(this).scrollTop() > ($('.footer').offset().top - $(window).height())) {
winHeight = $(window).height() - $('.footer').outerHeight() - 44;
sidebar.css('max-height', winHeight + 'px');
$('.docs-sidenav').css('max-height', winHeight + 'px');
} else {
winHeight = $(window).height() - 44;
sidebar.css('max-height', winHeight + 'px');
$('.docs-sidenav').css('max-height', winHeight + 'px');
}
if (!barScroll) {
var activeItem = $('.docs-sidebar li.active a');
if (activeItem.length) {
if (!activeMenu || (activeMenu.attr('href') != activeItem.attr('href'))) {
activeMenu = activeItem;
var top = activeMenu.offset().top - sidebar.offset().top;
if (top < 0) {
//sidebar.scrollTop(sidebar.scrollTop() + top);
$('.docs-sidenav').scrollTop($('.docs-sidenav').scrollTop() + top);
} else if (top > winHeight - 88) {
//sidebar.scrollTop(sidebar.scrollTop() + top - winHeight + 44);
$('.docs-sidenav').scrollTop($('.docs-sidenav').scrollTop() + top - winHeight + 88);
}
}
}
}
});
// 退出全屏浏览器窗口大小改变不触发resize
$(window).on('resize', function(e) {
$contentLeftWidth = $contentLeft.width() - 1;
});
function sortAsOffset(propertyName) {
return function(obj1, obj2) {
var val1 = obj1[propertyName];
var val2 = obj2[propertyName];
if (val1 < val2) {
return -1;
} else if (val1 > val2) {
return 1;
} else {
return 0;
}
}
}
function isWechat() {
var ua = navigator.userAgent.toLowerCase();
if (ua.match(/MicroMessenger/i) == "micromessenger") {
return true;
} else {
return false;
}
}
// 代码复制功能
var clipboard = new Clipboard('.js-copy');
clipboard.on('success', function(e) {
var copyNumber = $(e.trigger).attr('data-copy-number');
$('.copy-tip-'+copyNumber).show();
setTimeout(function() {
$('.copy-tip-'+copyNumber).hide();
}, 1000);
e.clearSelection();
});
});

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@ -0,0 +1,51 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
<svg xmlns="http://www.w3.org/2000/svg">
<defs>
<font id="ydoc" horiz-adv-x="1024">
<font-face
font-family="ydoc"
units-per-em="1024"
ascent="1024"
descent="0"
/>
<missing-glyph horiz-adv-x="0"/>
<glyph
glyph-name="qunar-bars"
unicode="&#xf020;"
horiz-adv-x="1024" d=" M192,576 L832,576 L832,448 L192,448 M192,320 L832,320 L832,192 L192,192 M192,832 L832,832 L832,704 L192,704" />
<glyph
glyph-name="qunar-loading_error_o"
unicode="&#xf077;"
horiz-adv-x="1024" d=" M824,245 L557,512 L823,778 Q832,788 832,800 Q832,812 822.5,821.5 Q813,831 800,831.5 Q787,832 778,824 L512,557 L246,824 Q237,832 224,831.5 Q211,831 201.5,821.5 Q192,812 192,800 Q192,788 201,778 L467,512 L200,245 Q192,236 192.5,223.5 Q193,211 202.5,201.5 Q212,192 224,192 Q236,192 245,200 L512,467 L779,200 Q788,192 800,192 Q812,192 821.5,201.5 Q831,211 831.5,223.5 Q832,236 824,245" />
<glyph
glyph-name="qunar-loading_done_o"
unicode="&#xf078;"
horiz-adv-x="1024" d=" M887,758 Q877,767 864.5,768 Q852,769 842,760 L416,331 L182,568 Q173,576 160,575.5 Q147,575 137.5,565.5 Q128,556 128,544 Q128,532 137,522 L395,264 Q404,255 416,255 Q428,255 437,264 L888,715 Q896,724 896,736 Q896,748 887,758" />
<glyph
glyph-name="qunar-back_line"
unicode="&#xf07d;"
horiz-adv-x="1024" d=" M335,511 L759,905 Q768,915 768,928 Q768,941 758.5,950.5 Q749,960 736,960 Q723,960 713,951 L265,533 Q256,523 256,510.5 Q256,498 265,488 L713,73 Q723,64 736,64 Q749,64 758.5,73.5 Q768,83 768,96 Q768,109 759,119" />
<glyph
glyph-name="qunar-next_line"
unicode="&#xf07f;"
horiz-adv-x="1024" d=" M689,511 L265,905 Q256,915 256,928 Q256,941 265.5,950.5 Q275,960 288,960 Q301,960 311,951 L759,533 Q768,523 768,510.5 Q768,498 759,488 L311,73 Q301,64 288,64 Q275,64 265.5,73.5 Q256,83 256,96 Q256,109 265,119" />
<glyph
glyph-name="qunar-dot_medium"
unicode="&#xf083;"
horiz-adv-x="1024" d=" M512,704 Q430,702 376,648 Q322,594 320,512 Q322,431 376,376.5 Q430,322 512,320 Q594,322 648,376.5 Q702,431 704,512 Q702,594 648,648 Q594,702 512,704" />
<glyph
glyph-name="mob-fangxingyigouxuan-o"
unicode="&#xf35e;"
horiz-adv-x="1024" d=" M752,896 L272,896 Q211,894 170.5,853.5 Q130,813 128,752 L128,272 Q130,211 170.5,170.5 Q211,130 272,128 L752,128 Q813,130 853.5,170.5 Q894,211 896,272 L896,752 Q894,813 853.5,853.5 Q813,894 752,896 M759,617 L471,329 Q461,320 448,320 Q435,320 425,329 L265,489 Q256,499 256,512 Q256,525 265.5,534.5 Q275,544 288,544 Q301,544 311,535 L448,397 L713,663 Q723,672 736,672 Q749,672 758.5,662.5 Q768,653 768,640 Q768,627 759,617" />
<glyph
glyph-name="mob-fangxingweigouxuan-f"
unicode="&#xf35f;"
horiz-adv-x="1024" d=" M752,896 L272,896 Q211,894 170.5,853.5 Q130,813 128,752 L128,272 Q130,211 170.5,170.5 Q211,130 272,128 L752,128 Q813,130 853.5,170.5 Q894,211 896,272 L896,752 Q894,813 853.5,853.5 Q813,894 752,896 M864,272 Q863,224 831.5,192.5 Q800,161 752,160 L272,160 Q224,161 192.5,192.5 Q161,224 160,272 L160,752 Q161,800 192.5,831.5 Q224,863 272,864 L752,864 Q800,863 831.5,831.5 Q863,800 864,752" />
<glyph
glyph-name="mob-sanjiaoxia-o"
unicode="&#xf3ff;"
horiz-adv-x="1024" d=" M768,640 L512,384 L256,640" />
</font>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 405 B

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

75
static/doc/source/shBrush-css.js vendored Normal file
View File

@ -0,0 +1,75 @@
;(function()
{
// CommonJS
SyntaxHighlighter = SyntaxHighlighter || (typeof require !== 'undefined'? require('shCore').SyntaxHighlighter : null);
function Brush()
{
function getKeywordsCSS(str)
{
return '\\b([a-z_]|)' + str.replace(/ /g, '(?=:)\\b|\\b([a-z_\\*]|\\*|)') + '(?=:)\\b';
};
function getValuesCSS(str)
{
return '\\b' + str.replace(/ /g, '(?!-)(?!:)\\b|\\b()') + '\:\\b';
};
var keywords = 'ascent azimuth background-attachment background-color background-image background-position ' +
'background-repeat background baseline bbox border-collapse border-color border-spacing border-style border-top ' +
'border-right border-bottom border-left border-top-color border-right-color border-bottom-color border-left-color ' +
'border-top-style border-right-style border-bottom-style border-left-style border-top-width border-right-width ' +
'border-bottom-width border-left-width border-width border bottom cap-height caption-side centerline clear clip color ' +
'content counter-increment counter-reset cue-after cue-before cue cursor definition-src descent direction display ' +
'elevation empty-cells float font-size-adjust font-family font-size font-stretch font-style font-variant font-weight font ' +
'height left letter-spacing line-height list-style-image list-style-position list-style-type list-style margin-top ' +
'margin-right margin-bottom margin-left margin marker-offset marks mathline max-height max-width min-height min-width orphans ' +
'outline-color outline-style outline-width outline overflow padding-top padding-right padding-bottom padding-left padding page ' +
'page-break-after page-break-before page-break-inside pause pause-after pause-before pitch pitch-range play-during position ' +
'quotes right richness size slope src speak-header speak-numeral speak-punctuation speak speech-rate stemh stemv stress ' +
'table-layout text-align top text-decoration text-indent text-shadow text-transform unicode-bidi unicode-range units-per-em ' +
'vertical-align visibility voice-family volume white-space widows width widths word-spacing x-height z-index';
var values = 'above absolute all always aqua armenian attr aural auto avoid baseline behind below bidi-override black blink block blue bold bolder '+
'both bottom braille capitalize caption center center-left center-right circle close-quote code collapse compact condensed '+
'continuous counter counters crop cross crosshair cursive dashed decimal decimal-leading-zero default digits disc dotted double '+
'embed embossed e-resize expanded extra-condensed extra-expanded fantasy far-left far-right fast faster fixed format fuchsia '+
'gray green groove handheld hebrew help hidden hide high higher icon inline-table inline inset inside invert italic '+
'justify landscape large larger left-side left leftwards level lighter lime line-through list-item local loud lower-alpha '+
'lowercase lower-greek lower-latin lower-roman lower low ltr marker maroon medium message-box middle mix move narrower '+
'navy ne-resize no-close-quote none no-open-quote no-repeat normal nowrap n-resize nw-resize oblique olive once open-quote outset '+
'outside overline pointer portrait pre print projection purple red relative repeat repeat-x repeat-y rgb ridge right right-side '+
'rightwards rtl run-in screen scroll semi-condensed semi-expanded separate se-resize show silent silver slower slow '+
'small small-caps small-caption smaller soft solid speech spell-out square s-resize static status-bar sub super sw-resize '+
'table-caption table-cell table-column table-column-group table-footer-group table-header-group table-row table-row-group teal '+
'text-bottom text-top thick thin top transparent tty tv ultra-condensed ultra-expanded underline upper-alpha uppercase upper-latin '+
'upper-roman url visible wait white wider w-resize x-fast x-high x-large x-loud x-low x-slow x-small x-soft xx-large xx-small yellow';
var fonts = '[mM]onospace [tT]ahoma [vV]erdana [aA]rial [hH]elvetica [sS]ans-serif [sS]erif [cC]ourier mono sans serif';
this.regexList = [
{ regex: SyntaxHighlighter.regexLib.multiLineCComments, css: 'comments' }, // multiline comments
{ regex: SyntaxHighlighter.regexLib.doubleQuotedString, css: 'string' }, // double quoted strings
{ regex: SyntaxHighlighter.regexLib.singleQuotedString, css: 'string' }, // single quoted strings
{ regex: /\#[a-fA-F0-9]{3,6}/g, css: 'value' }, // html colors
{ regex: /(-?\d+)(\.\d+)?(px|em|pt|\:|\%|)/g, css: 'value' }, // sizes
{ regex: /!important/g, css: 'color3' }, // !important
{ regex: new RegExp(getKeywordsCSS(keywords), 'gm'), css: 'keyword' }, // keywords
{ regex: new RegExp(getValuesCSS(values), 'g'), css: 'value' }, // values
{ regex: new RegExp(this.getKeywords(fonts), 'g'), css: 'color1' } // fonts
];
this.forHtmlScript({
left: /(&lt;|<)\s*style.*?(&gt;|>)/gi,
right: /(&lt;|<)\/\s*style\s*(&gt;|>)/gi
});
};
Brush.prototype = new SyntaxHighlighter.Highlighter();
Brush.aliases = ['css'];
SyntaxHighlighter.brushes.CSS = Brush;
// CommonJS
typeof(exports) != 'undefined' ? exports.Brush = Brush : null;
})();

36
static/doc/source/shBrush-js.js vendored Normal file
View File

@ -0,0 +1,36 @@
;(function()
{
// CommonJS
SyntaxHighlighter = SyntaxHighlighter || (typeof require !== 'undefined'? require('shCore').SyntaxHighlighter : null);
function Brush()
{
var keywords = 'break case catch class continue ' +
'default delete do else enum export extends false ' +
'for function if implements import in instanceof ' +
'interface let new null package private protected ' +
'static return super switch ' +
'this throw true try typeof var while with yield';
var r = SyntaxHighlighter.regexLib;
this.regexList = [
{ regex: r.multiLineDoubleQuotedString, css: 'string' }, // double quoted strings
{ regex: r.multiLineSingleQuotedString, css: 'string' }, // single quoted strings
{ regex: r.singleLineCComments, css: 'comments' }, // one line comments
{ regex: r.multiLineCComments, css: 'comments' }, // multiline comments
{ regex: /\s*#.*/gm, css: 'preprocessor' }, // preprocessor tags like #region and #endregion
{ regex: new RegExp(this.getKeywords(keywords), 'gm'), css: 'keyword' } // keywords
];
this.forHtmlScript(r.scriptScriptTags);
};
Brush.prototype = new SyntaxHighlighter.Highlighter();
Brush.aliases = ['js', 'jscript', 'javascript', 'json'];
SyntaxHighlighter.brushes.JScript = Brush;
// CommonJS
typeof(exports) != 'undefined' ? exports.Brush = Brush : null;
})();

94
static/doc/source/shBrush-sass.js vendored Normal file
View File

@ -0,0 +1,94 @@
/**
* SyntaxHighlighter
* http://alexgorbatchev.com/SyntaxHighlighter
*
* SyntaxHighlighter is donationware. If you are using it, please donate.
* http://alexgorbatchev.com/SyntaxHighlighter/donate.html
*
* @version
* 3.0.83 (July 02 2010)
*
* @copyright
* Copyright (C) 2004-2010 Alex Gorbatchev.
*
* @license
* Dual licensed under the MIT and GPL licenses.
*/
;(function()
{
// CommonJS
typeof(require) != 'undefined' ? SyntaxHighlighter = require('shCore').SyntaxHighlighter : null;
function Brush()
{
function getKeywordsCSS(str)
{
return '\\b([a-z_]|)' + str.replace(/ /g, '(?=:)\\b|\\b([a-z_\\*]|\\*|)') + '(?=:)\\b';
};
function getValuesCSS(str)
{
return '\\b' + str.replace(/ /g, '(?!-)(?!:)\\b|\\b()') + '\:\\b';
};
var keywords = 'ascent azimuth background-attachment background-color background-image background-position ' +
'background-repeat background baseline bbox border-collapse border-color border-spacing border-style border-top ' +
'border-right border-bottom border-left border-top-color border-right-color border-bottom-color border-left-color ' +
'border-top-style border-right-style border-bottom-style border-left-style border-top-width border-right-width ' +
'border-bottom-width border-left-width border-width border bottom cap-height caption-side centerline clear clip color ' +
'content counter-increment counter-reset cue-after cue-before cue cursor definition-src descent direction display ' +
'elevation empty-cells float font-size-adjust font-family font-size font-stretch font-style font-variant font-weight font ' +
'height left letter-spacing line-height list-style-image list-style-position list-style-type list-style margin-top ' +
'margin-right margin-bottom margin-left margin marker-offset marks mathline max-height max-width min-height min-width orphans ' +
'outline-color outline-style outline-width outline overflow padding-top padding-right padding-bottom padding-left padding page ' +
'page-break-after page-break-before page-break-inside pause pause-after pause-before pitch pitch-range play-during position ' +
'quotes right richness size slope src speak-header speak-numeral speak-punctuation speak speech-rate stemh stemv stress ' +
'table-layout text-align top text-decoration text-indent text-shadow text-transform unicode-bidi unicode-range units-per-em ' +
'vertical-align visibility voice-family volume white-space widows width widths word-spacing x-height z-index';
var values = 'above absolute all always aqua armenian attr aural auto avoid baseline behind below bidi-override black blink block blue bold bolder '+
'both bottom braille capitalize caption center center-left center-right circle close-quote code collapse compact condensed '+
'continuous counter counters crop cross crosshair cursive dashed decimal decimal-leading-zero digits disc dotted double '+
'embed embossed e-resize expanded extra-condensed extra-expanded fantasy far-left far-right fast faster fixed format fuchsia '+
'gray green groove handheld hebrew help hidden hide high higher icon inline-table inline inset inside invert italic '+
'justify landscape large larger left-side left leftwards level lighter lime line-through list-item local loud lower-alpha '+
'lowercase lower-greek lower-latin lower-roman lower low ltr marker maroon medium message-box middle mix move narrower '+
'navy ne-resize no-close-quote none no-open-quote no-repeat normal nowrap n-resize nw-resize oblique olive once open-quote outset '+
'outside overline pointer portrait pre print projection purple red relative repeat repeat-x repeat-y rgb ridge right right-side '+
'rightwards rtl run-in screen scroll semi-condensed semi-expanded separate se-resize show silent silver slower slow '+
'small small-caps small-caption smaller soft solid speech spell-out square s-resize static status-bar sub super sw-resize '+
'table-caption table-cell table-column table-column-group table-footer-group table-header-group table-row table-row-group teal '+
'text-bottom text-top thick thin top transparent tty tv ultra-condensed ultra-expanded underline upper-alpha uppercase upper-latin '+
'upper-roman url visible wait white wider w-resize x-fast x-high x-large x-loud x-low x-slow x-small x-soft xx-large xx-small yellow';
var fonts = '[mM]onospace [tT]ahoma [vV]erdana [aA]rial [hH]elvetica [sS]ans-serif [sS]erif [cC]ourier mono sans serif';
var statements = '!important !default';
var preprocessor = '@import @extend @debug @warn @if @for @while @mixin @include';
var r = SyntaxHighlighter.regexLib;
this.regexList = [
{ regex: r.multiLineCComments, css: 'comments' }, // multiline comments
{ regex: r.singleLineCComments, css: 'comments' }, // singleline comments
{ regex: r.doubleQuotedString, css: 'string' }, // double quoted strings
{ regex: r.singleQuotedString, css: 'string' }, // single quoted strings
{ regex: /\#[a-fA-F0-9]{3,6}/g, css: 'value' }, // html colors
{ regex: /\b(-?\d+)(\.\d+)?(px|em|pt|\:|\%|)\b/g, css: 'value' }, // sizes
{ regex: /\$\w+/g, css: 'variable' }, // variables
{ regex: new RegExp(this.getKeywords(statements), 'g'), css: 'color3' }, // statements
{ regex: new RegExp(this.getKeywords(preprocessor), 'g'), css: 'preprocessor' }, // preprocessor
{ regex: new RegExp(getKeywordsCSS(keywords), 'gm'), css: 'keyword' }, // keywords
{ regex: new RegExp(getValuesCSS(values), 'g'), css: 'value' }, // values
{ regex: new RegExp(this.getKeywords(fonts), 'g'), css: 'color1' } // fonts
];
};
Brush.prototype = new SyntaxHighlighter.Highlighter();
Brush.aliases = ['sass', 'scss'];
SyntaxHighlighter.brushes.Sass = Brush;
// CommonJS
typeof(exports) != 'undefined' ? exports.Brush = Brush : null;
})();

17
static/doc/source/shCore.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,180 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no" />
<title>YApi : ./server/controllers/base.js</title>
<link type="text/css" rel="stylesheet" href="../../../source/code.css"/>
<script type="text/javascript" src="../../../source/shCore.js"></script>
<script type="text/javascript" src="../../../source/shBrush-js.js"></script>
<style>
.syntaxhighlighter .number1 .spaces,.syntaxhighlighter .toolbar{ display: none;}
.syntaxhighlighter table td.gutter .line.highlight { background-color: #6ce26c !important; color: white; }
</style>
</head>
<body>
<div class="ydoc">
<div class="ydoc-banner-bg">
<div class="ydoc-banner" id="content" tabindex="-1">
<div class="ydoc-banner-area">
<h1>YApi : ./server/controllers/base.js</h1>
<p>源代码</p>
</div>
</div>
<div class="ydoc-container">
<div class="ydoc-container-content">
<div class="static-code-content" role="main">
<pre class="brush: js;">
import yapi from '../yapi.js';
import projectModel from '../models/project.js';
import userModel from '../models/user.js';
const jwt = require('jsonwebtoken');
class baseController {
constructor(ctx) {
this.ctx = ctx;
//网站上线后role对象key是不能修改的value可以修改
this.roles = {
admin: 'Admin',
member: '网站会员'
};
}
async init(ctx) {
this.$user = null;
let ignoreRouter = [
'/user/login_by_token',
'/user/login',
'/user/reg',
'/user/status',
'/user/logout'
];
if (ignoreRouter.indexOf(ctx.path) > -1) {
this.$auth = true;
} else {
await this.checkLogin(ctx);
}
}
getUid() {
return parseInt(this.$uid, 10);
}
async checkLogin(ctx) {
let token = ctx.cookies.get('_yapi_token');
let uid = ctx.cookies.get('_yapi_uid');
try {
if (!token || !uid) return false;
let userInst = yapi.getInst(userModel); //创建user实体
let result = await userInst.findById(uid);
let decoded = jwt.verify(token, result.passsalt);
if (decoded.uid == uid) {
this.$uid = uid;
this.$auth = true;
this.$user = result;
return true;
}
return false;
} catch (e) {
return false;
}
}
async getLoginStatus(ctx) {
if (await this.checkLogin(ctx) === true) {
let result = yapi.commons.fieldSelect(this.$user, ['_id', 'username', 'email', 'up_time', 'add_time']);
result.server_ip = yapi.WEBCONFIG.server_ip;
return ctx.body = yapi.commons.resReturn(result);
}
return ctx.body = yapi.commons.resReturn(null, 300, 'Please login.');
}
getRole() {
return this.$user.role;
}
async jungeProjectAuth(id) {
let model = yapi.getInst(projectModel);
if (this.getRole() === 'admin') {
return true;
}
if (!id) {
return false;
}
let result = await model.get(id);
if (result.uid === this.getUid()) {
return true;
}
return false;
}
async jungeMemberAuth(id, member_uid) {
let model = yapi.getInst(projectModel);
if (this.getRole() === 'admin') {
return true;
}
if (!id || !member_uid) {
return false;
}
let result = await model.checkMemberRepeat(id, member_uid);
if (result > 0) {
return true;
}
return false;
}
}
module.exports = baseController;
</pre>
</div>
</div>
</div>
</div>
<!-- <div class="docs-header" id="content" tabindex="-1">
<div class="container">
<h1>YApi : ./server/controllers/base.js</h1>
<p>源代码</p>
</div>
</div> -->
<footer class="docs-footer" role="contentinfo">
<div class="container">
<p></p>
</div>
</footer>
</div>
<script type="text/javascript">
SyntaxHighlighter.all();
function getTop(node){
return node.offsetTop + (node.offsetParent ? getTop(node.offsetParent) : 0);
}
document.addEventListener('DOMContentLoaded', function() {
setTimeout(function() {
try {
var lineNum = (parseInt(location.hash.replace(/#/g, '')) - 1) || 0,
node = document.querySelectorAll('div.line')[lineNum];
document.body.scrollTop = getTop(node);
node.className += ' highlight';
} catch(e) {}
}, 500);
}, false);
</script>
</body>
</html>

View File

@ -0,0 +1,226 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no" />
<title>YApi : ./server/controllers/group.js</title>
<link type="text/css" rel="stylesheet" href="../../../source/code.css"/>
<script type="text/javascript" src="../../../source/shCore.js"></script>
<script type="text/javascript" src="../../../source/shBrush-js.js"></script>
<style>
.syntaxhighlighter .number1 .spaces,.syntaxhighlighter .toolbar{ display: none;}
.syntaxhighlighter table td.gutter .line.highlight { background-color: #6ce26c !important; color: white; }
</style>
</head>
<body>
<div class="ydoc">
<div class="ydoc-banner-bg">
<div class="ydoc-banner" id="content" tabindex="-1">
<div class="ydoc-banner-area">
<h1>YApi : ./server/controllers/group.js</h1>
<p>源代码</p>
</div>
</div>
<div class="ydoc-container">
<div class="ydoc-container-content">
<div class="static-code-content" role="main">
<pre class="brush: js;">
import groupModel from '../models/group.js';
import yapi from '../yapi.js';
import baseController from './base.js';
import projectModel from '../models/project.js';
class groupController extends baseController {
constructor(ctx) {
super(ctx);
}
/**
* 添加项目分组
* @interface /group/add
* @method POST
* @category group
* @foldnumber 10
* @param {String} group_name 项目分组名称,不能为空
* @param {String} [group_desc] 项目分组描述
* @returns {Object}
* @example ./api/group/add.json
*/
async add(ctx) {
let params = ctx.request.body;
params = yapi.commons.handleParams(params, {
group_name: 'string',
group_desc: 'string'
});
if (this.getRole() !== 'admin') {
return ctx.body = yapi.commons.resReturn(null, 401, '没有权限');
}
if (!params.group_name) {
return ctx.body = yapi.commons.resReturn(null, 400, '项目分组名不能为空');
}
let groupInst = yapi.getInst(groupModel);
let checkRepeat = await groupInst.checkRepeat(params.group_name);
if (checkRepeat > 0) {
return ctx.body = yapi.commons.resReturn(null, 401, '项目分组名已存在');
}
let data = {
group_name: params.group_name,
group_desc: params.group_desc,
uid: this.getUid(),
add_time: yapi.commons.time(),
up_time: yapi.commons.time()
};
try {
let result = await groupInst.save(data);
result = yapi.commons.fieldSelect(result, ['_id', 'group_name', 'group_desc', 'uid']);
ctx.body = yapi.commons.resReturn(result);
} catch (e) {
ctx.body = yapi.commons.resReturn(null, 402, e.message);
}
}
/**
* 获取项目分组列表
* @interface /group/list
* @method get
* @category group
* @foldnumber 10
* @returns {Object}
* @example ./api/group/list.json
*/
async list(ctx) {
try {
var groupInst = yapi.getInst(groupModel);
let result = await groupInst.list();
ctx.body = yapi.commons.resReturn(result);
} catch (e) {
ctx.body = yapi.commons.resReturn(null, 402, e.message);
}
}
/**
* 删除项目分组
* @interface /group/del
* @method post
* @param {String} id 项目分组id
* @category group
* @foldnumber 10
* @returns {Object}
* @example ./api/group/del.json
*/
async del(ctx) {
if (this.getRole() !== 'admin') {
return ctx.body = yapi.commons.resReturn(null, 401, '没有权限');
}
try {
let groupInst = yapi.getInst(groupModel);
let projectInst = yapi.getInst(projectModel);
let id = ctx.request.body.id;
if (!id) {
return ctx.body = yapi.commons.resReturn(null, 402, 'id不能为空');
}
let count = await projectInst.countByGroupId(id);
if (count > 0) {
return ctx.body = yapi.commons.resReturn(null, 403, '请先删除该分组下的项目');
}
let result = await groupInst.del(id);
ctx.body = yapi.commons.resReturn(result);
} catch (err) {
ctx.body = yapi.commons.resReturn(null, 402, err.message);
}
}
/**
* 更新项目分组
* @interface /group/up
* @method post
* @param {String} id 项目分组id
* @param {String} group_name 项目分组名称
* @param {String} group_desc 项目分组描述
* @category group
* @foldnumber 10
* @returns {Object}
* @example ./api/group/up.json
*/
async up(ctx) {
if (this.getRole() !== 'admin') {
return ctx.body = yapi.commons.resReturn(null, 401, '没有权限');
}
try {
ctx.request.body = yapi.commons.handleParams(ctx.request.body, {
id: 'number',
group_name: 'string',
group_desc: 'string'
});
let groupInst = yapi.getInst(groupModel);
let id = ctx.request.body.id;
let data = {};
ctx.request.body.group_name && (data.group_name = ctx.request.body.group_name);
ctx.request.body.group_desc && (data.group_desc = ctx.request.body.group_desc);
if (Object.keys(data).length === 0) {
ctx.body = yapi.commons.resReturn(null, 404, '分组名和分组描述不能为空');
}
let result = await groupInst.up(id, data);
ctx.body = yapi.commons.resReturn(result);
} catch (err) {
ctx.body = yapi.commons.resReturn(null, 402, err.message);
}
}
}
module.exports = groupController;
</pre>
</div>
</div>
</div>
</div>
<!-- <div class="docs-header" id="content" tabindex="-1">
<div class="container">
<h1>YApi : ./server/controllers/group.js</h1>
<p>源代码</p>
</div>
</div> -->
<footer class="docs-footer" role="contentinfo">
<div class="container">
<p></p>
</div>
</footer>
</div>
<script type="text/javascript">
SyntaxHighlighter.all();
function getTop(node){
return node.offsetTop + (node.offsetParent ? getTop(node.offsetParent) : 0);
}
document.addEventListener('DOMContentLoaded', function() {
setTimeout(function() {
try {
var lineNum = (parseInt(location.hash.replace(/#/g, '')) - 1) || 0,
node = document.querySelectorAll('div.line')[lineNum];
document.body.scrollTop = getTop(node);
node.className += ' highlight';
} catch(e) {}
}, 500);
}, false);
</script>
</body>
</html>

View File

@ -0,0 +1,352 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no" />
<title>YApi : ./server/controllers/interface.js</title>
<link type="text/css" rel="stylesheet" href="../../../source/code.css"/>
<script type="text/javascript" src="../../../source/shCore.js"></script>
<script type="text/javascript" src="../../../source/shBrush-js.js"></script>
<style>
.syntaxhighlighter .number1 .spaces,.syntaxhighlighter .toolbar{ display: none;}
.syntaxhighlighter table td.gutter .line.highlight { background-color: #6ce26c !important; color: white; }
</style>
</head>
<body>
<div class="ydoc">
<div class="ydoc-banner-bg">
<div class="ydoc-banner" id="content" tabindex="-1">
<div class="ydoc-banner-area">
<h1>YApi : ./server/controllers/interface.js</h1>
<p>源代码</p>
</div>
</div>
<div class="ydoc-container">
<div class="ydoc-container-content">
<div class="static-code-content" role="main">
<pre class="brush: js;">
import interfaceModel from '../models/interface.js';
import baseController from './base.js';
import yapi from '../yapi.js';
class interfaceController extends baseController {
constructor(ctx) {
super(ctx);
this.Model = yapi.getInst(interfaceModel);
}
/**
* 添加项目分组
* @interface /interface/add
* @method POST
* @category interface
* @foldnumber 10
* @param {Number} project_id 项目id不能为空
* @param {String} title 接口标题,不能为空
* @param {String} path 接口请求路径,不能为空
* @param {String} method 请求方式
* @param {Array} [req_headers] 请求的header信息
* @param {String} [req_headers[].name] 请求的header信息名
* @param {String} [req_headers[].value] 请求的header信息值
* @param {Boolean} [req_headers[].required] 是否是必须,默认为否
* @param {String} [req_headers[].desc] header描述
* @param {String} [req_params_type] 请求参数方式,有["form", "json", "text", "xml"]四种
* @param {Mixed} [req_params_form] 请求参数,如果请求方式是form参数是Array数组其他格式请求参数是字符串
* @param {String} [req_params_form[].name] 请求参数名
* @param {String} [req_params_form[].value] 请求参数值可填写生成规则mock。如@email随机生成一条email
* @param {String} [req_params_form[].type] 请求参数类型,有["text", "file"]两种
* @param {String} [req_params_other] 非form类型的请求参数可保存到此字段
* @param {String} [res_body_type] 相应信息的数据格式,有["json", "text", "xml"]三种
* @param {String} [res_body] 响应信息可填写任意字符串如果res_body_type是json,则会调用mock功能
* @param {String} [desc] 接口描述
* @returns {Object}
* @example ./api/interface/add.json
*/
async add(ctx) {
let params = ctx.request.body;
params = yapi.commons.handleParams(params, {
project_id: 'number',
title: 'string',
path: 'string',
method: 'string',
desc: 'string'
});
params.method = params.method || 'GET';
params.method = params.method.toUpperCase();
params.res_body_type = params.res_body_type ? params.res_body_type.toLowerCase() : 'json';
if (!params.project_id) {
return ctx.body = yapi.commons.resReturn(null, 400, '项目id不能为空');
}
if (!params.path) {
return ctx.body = yapi.commons.resReturn(null, 400, '接口请求路径不能为空');
}
if (!yapi.commons.verifyPath(params.path)) {
return ctx.body = yapi.commons.resReturn(null, 400, '接口path第一位必须是/,最后一位不能为/');
}
let checkRepeat = await this.Model.checkRepeat(params.project_id, params.path, params.method);
if (checkRepeat > 0) {
return ctx.body = yapi.commons.resReturn(null, 401, '已存在的接口:' + params.path + '[' + params.method + ']');
}
try {
let data = {
project_id: params.project_id,
title: params.title,
path: params.path,
desc: params.desc,
method: params.method,
req_headers: params.req_headers,
req_params_type: params.req_params_type,
res_body: params.res_body,
res_body_type: params.res_body_type,
uid: this.getUid(),
add_time: yapi.commons.time(),
up_time: yapi.commons.time()
};
if (params.req_params_form) {
data.req_params_form = params.req_params_form;
}
if (params.req_params_other) {
data.req_params_other = params.req_params_other;
}
let result = await this.Model.save(data);
ctx.body = yapi.commons.resReturn(result);
} catch (e) {
ctx.body = yapi.commons.resReturn(null, 402, e.message);
}
}
/**
* 添加项目分组
* @interface /interface/get
* @method GET
* @category interface
* @foldnumber 10
* @param {Number} id 接口id不能为空
* @returns {Object}
* @example ./api/interface/get.json
*/
async get(ctx) {
let params = ctx.request.query;
if (!params.id) {
return ctx.body = yapi.commons.resReturn(null, 400, '接口id不能为空');
}
try {
let result = await this.Model.get(params.id);
ctx.body = yapi.commons.resReturn(result);
} catch (e) {
ctx.body = yapi.commons.resReturn(null, 402, e.message);
}
}
/**
* 接口列表
* @interface /interface/list
* @method GET
* @category interface
* @foldnumber 10
* @param {Number} project_id 项目id不能为空
* @returns {Object}
* @example ./api/interface/list.json
*/
async list(ctx) {
let project_id = ctx.request.query.project_id;
if (!project_id) {
return ctx.body = yapi.commons.resReturn(null, 400, '项目id不能为空');
}
try {
let result = await this.Model.list(project_id);
ctx.body = yapi.commons.resReturn(result);
} catch (err) {
ctx.body = yapi.commons.resReturn(null, 402, err.message);
}
}
/**
* 编辑接口
* @interface /interface/up
* @method POST
* @category interface
* @foldnumber 10
* @param {Number} id 接口id不能为空
* @param {String} [path] 接口请求路径
* @param {String} [method] 请求方式
* @param {Array} [req_headers] 请求的header信息
* @param {String} [req_headers[].name] 请求的header信息名
* @param {String} [req_headers[].value] 请求的header信息值
* @param {Boolean} [req_headers[].required] 是否是必须,默认为否
* @param {String} [req_headers[].desc] header描述
* @param {String} [req_params_type] 请求参数方式,有["form", "json", "text", "xml"]四种
* @param {Mixed} [req_params_form] 请求参数,如果请求方式是form参数是Array数组其他格式请求参数是字符串
* @param {String} [req_params_form[].name] 请求参数名
* @param {String} [req_params_form[].value] 请求参数值可填写生成规则mock。如@email随机生成一条email
* @param {String} [req_params_form[].type] 请求参数类型,有["text", "file"]两种
* @param {String} [req_params_other] 非form类型的请求参数可保存到此字段
* @param {String} [res_body_type] 相应信息的数据格式,有["json", "text", "xml"]三种
* @param {String} [res_body] 响应信息可填写任意字符串如果res_body_type是json,则会调用mock功能
* @param {String} [desc] 接口描述
* @returns {Object}
* @example ./api/interface/up.json
*/
async up(ctx) {
let params = ctx.request.body;
params = yapi.commons.handleParams(params, {
title: 'string',
path: 'string',
method: 'string',
desc: 'string'
});
params.method = params.method || 'GET';
params.method = params.method.toUpperCase();
let id = ctx.request.body.id;
if (!id) {
return ctx.body = yapi.commons.resReturn(null, 400, '接口id不能为空');
}
let interfaceData = await this.Model.get(id);
if (params.path && !yapi.commons.verifyPath(params.path)) {
return ctx.body = yapi.commons.resReturn(null, 400, '接口path第一位必须是/,最后一位不能为/');
}
if (params.path && params.path !== interfaceData.path && params.method !== interfaceData.method) {
let checkRepeat = await this.Model.checkRepeat(interfaceData.project_id, params.path, params.method);
if (checkRepeat > 0) {
return ctx.body = yapi.commons.resReturn(null, 401, '已存在的接口:' + params.path + '[' + params.method + ']');
}
}
let data = {
up_time: yapi.commons.time()
};
if (params.path) {
data.path = params.path;
}
if (params.title) {
data.title = params.title;
}
if (params.desc) {
data.desc = params.desc;
}
if (params.method) {
data.method = params.method;
}
if (params.req_headers) {
data.req_headers = params.req_headers;
}
if (params.req_params_form) {
data.req_params_form = params.req_params_form;
}
if (params.req_params_other) {
data.req_params_other = params.req_params_other;
}
if (params.res_body_type) {
data.res_body_type = params.res_body_type;
}
if (params.res_body) {
data.res_body = params.res_body;
}
try {
let result = await this.Model.up(id, data);
ctx.body = yapi.commons.resReturn(result);
} catch (e) {
ctx.body = yapi.commons.resReturn(null, 402, e.message);
}
}
/**
* 删除接口
* @interface /interface/del
* @method GET
* @category interface
* @foldnumber 10
* @param {Number} id 接口id不能为空
* @returns {Object}
* @example ./api/interface/del.json
*/
async del(ctx) {
try {
let id = ctx.request.body.id;
if (!id) {
return ctx.body = yapi.commons.resReturn(null, 400, '接口id不能为空');
}
let data = await this.Model.get(ctx.request.body.id);
if (data.uid != this.getUid()) {
if (await this.jungeProjectAuth(data.project_id) !== true) {
return ctx.body = yapi.commons.resReturn(null, 405, '没有权限');
}
}
let result = await this.Model.del(id);
ctx.body = yapi.commons.resReturn(result);
} catch (err) {
ctx.body = yapi.commons.resReturn(null, 402, err.message);
}
}
}
module.exports = interfaceController;
</pre>
</div>
</div>
</div>
</div>
<!-- <div class="docs-header" id="content" tabindex="-1">
<div class="container">
<h1>YApi : ./server/controllers/interface.js</h1>
<p>源代码</p>
</div>
</div> -->
<footer class="docs-footer" role="contentinfo">
<div class="container">
<p></p>
</div>
</footer>
</div>
<script type="text/javascript">
SyntaxHighlighter.all();
function getTop(node){
return node.offsetTop + (node.offsetParent ? getTop(node.offsetParent) : 0);
}
document.addEventListener('DOMContentLoaded', function() {
setTimeout(function() {
try {
var lineNum = (parseInt(location.hash.replace(/#/g, '')) - 1) || 0,
node = document.querySelectorAll('div.line')[lineNum];
document.body.scrollTop = getTop(node);
node.className += ' highlight';
} catch(e) {}
}, 500);
}, false);
</script>
</body>
</html>

View File

@ -0,0 +1,115 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no" />
<title>YApi : ./server/controllers/log.js</title>
<link type="text/css" rel="stylesheet" href="../../../source/code.css"/>
<script type="text/javascript" src="../../../source/shCore.js"></script>
<script type="text/javascript" src="../../../source/shBrush-js.js"></script>
<style>
.syntaxhighlighter .number1 .spaces,.syntaxhighlighter .toolbar{ display: none;}
.syntaxhighlighter table td.gutter .line.highlight { background-color: #6ce26c !important; color: white; }
</style>
</head>
<body>
<div class="ydoc">
<div class="ydoc-banner-bg">
<div class="ydoc-banner" id="content" tabindex="-1">
<div class="ydoc-banner-area">
<h1>YApi : ./server/controllers/log.js</h1>
<p>源代码</p>
</div>
</div>
<div class="ydoc-container">
<div class="ydoc-container-content">
<div class="static-code-content" role="main">
<pre class="brush: js;">
import logModel from '../models/log.js';
import yapi from '../yapi.js';
import baseController from './base.js';
import groupModel from '../models/group';
class logController extends baseController {
constructor(ctx) {
super(ctx);
this.Model = yapi.getInst(logModel);
this.groupModel = yapi.getInst(groupModel);
}
/**
* 获取节点列表
* @interface /node/list
* @method GET
* @category node
* @foldnumber 10
* @param {Number} uid 用户id 不能为空
* @param {Number} [page] 分页页码
* @param {Number} [limit] 分页大小
* @returns {Object}
* @example ./api/project/list.json
*/
async list(ctx) {
let uid = ctx.request.query.uid,
page = ctx.request.query.page || 1,
limit = ctx.request.query.limit || 10;
if (!uid) {
return ctx.body = yapi.commons.resReturn(null, 400, '用户id不能为空');
}
try {
let result = await this.Model.listWithPaging(uid, page, limit);
let count = await this.Model.listCount(uid);
ctx.body = yapi.commons.resReturn({
total: Math.ceil(count / limit),
list: result
});
} catch (err) {
ctx.body = yapi.commons.resReturn(null, 402, err.message);
}
}
}
module.exports = logController;
</pre>
</div>
</div>
</div>
</div>
<!-- <div class="docs-header" id="content" tabindex="-1">
<div class="container">
<h1>YApi : ./server/controllers/log.js</h1>
<p>源代码</p>
</div>
</div> -->
<footer class="docs-footer" role="contentinfo">
<div class="container">
<p></p>
</div>
</footer>
</div>
<script type="text/javascript">
SyntaxHighlighter.all();
function getTop(node){
return node.offsetTop + (node.offsetParent ? getTop(node.offsetParent) : 0);
}
document.addEventListener('DOMContentLoaded', function() {
setTimeout(function() {
try {
var lineNum = (parseInt(location.hash.replace(/#/g, '')) - 1) || 0,
node = document.querySelectorAll('div.line')[lineNum];
document.body.scrollTop = getTop(node);
node.className += ' highlight';
} catch(e) {}
}, 500);
}, false);
</script>
</body>
</html>

View File

@ -0,0 +1,525 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no" />
<title>YApi : ./server/controllers/project.js</title>
<link type="text/css" rel="stylesheet" href="../../../source/code.css"/>
<script type="text/javascript" src="../../../source/shCore.js"></script>
<script type="text/javascript" src="../../../source/shBrush-js.js"></script>
<style>
.syntaxhighlighter .number1 .spaces,.syntaxhighlighter .toolbar{ display: none;}
.syntaxhighlighter table td.gutter .line.highlight { background-color: #6ce26c !important; color: white; }
</style>
</head>
<body>
<div class="ydoc">
<div class="ydoc-banner-bg">
<div class="ydoc-banner" id="content" tabindex="-1">
<div class="ydoc-banner-area">
<h1>YApi : ./server/controllers/project.js</h1>
<p>源代码</p>
</div>
</div>
<div class="ydoc-container">
<div class="ydoc-container-content">
<div class="static-code-content" role="main">
<pre class="brush: js;">
import projectModel from '../models/project.js';
import yapi from '../yapi.js';
import baseController from './base.js';
import interfaceModel from '../models/interface.js';
import groupModel from '../models/group';
import commons from '../utils/commons.js';
import userModel from '../models/user.js';
class projectController extends baseController {
constructor(ctx) {
super(ctx);
this.Model = yapi.getInst(projectModel);
this.groupModel = yapi.getInst(groupModel);
}
handleBasepath(basepath) {
if (!basepath) return false;
if (basepath[0] !== '/') basepath = '/' + basepath;
if (basepath[basepath.length - 1] === '/') basepath = basepath.substr(0, basepath.length - 1);
if (!yapi.commons.verifyPath(basepath)) {
return false;
}
return basepath;
}
verifyDomain(domain) {
if (!domain) return false;
if (/^[a-zA-Z0-9\-_\.]+?\.[a-zA-Z0-9\-_\.]*?[a-zA-Z]{2,6}$/.test(domain)) {
return true;
}
return false;
}
/**
* 添加项目分组
* @interface /project/add
* @method POST
* @category project
* @foldnumber 10
* @param {String} name 项目名称,不能为空
* @param {String} basepath 项目基本路径,不能为空
* @param {String} prd_host 项目线上域名不能为空。可通过配置的域名访问到mock数据
* @param {String} protocol 线上域名协议,不能为空
* @param {Number} group_id 项目分组id不能为空
* @param {String} [desc] 项目描述
* @returns {Object}
* @example ./api/project/add.json
*/
async add(ctx) {
let params = ctx.request.body;
params = yapi.commons.handleParams(params, {
name: 'string',
basepath: 'string',
prd_host: 'string',
protocol: 'string',
group_id: 'number',
desc: 'string'
});
if (!params.group_id) {
return ctx.body = yapi.commons.resReturn(null, 400, '项目分组id不能为空');
}
if (!params.name) {
return ctx.body = yapi.commons.resReturn(null, 400, '项目名不能为空');
}
let checkRepeat = await this.Model.checkNameRepeat(params.name);
if (checkRepeat > 0) {
return ctx.body = yapi.commons.resReturn(null, 401, '已存在的项目名');
}
if (!params.basepath) {
return ctx.body = yapi.commons.resReturn(null, 400, '项目basepath不能为空');
}
if (!params.prd_host) {
return ctx.body = yapi.commons.resReturn(null, 400, '项目domain不能为空');
}
if ((params.basepath = this.handleBasepath(params.basepath)) === false) {
return ctx.body = yapi.commons.resReturn(null, 401, 'basepath格式有误');
}
if (!this.verifyDomain(params.prd_host)) {
return ctx.body = yapi.commons.resReturn(null, 401, '线上域名格式有误');
}
let checkRepeatDomain = await this.Model.checkDomainRepeat(params.prd_host, params.basepath);
if (checkRepeatDomain > 0) {
return ctx.body = yapi.commons.resReturn(null, 401, '已存在domain和basepath');
}
let data = {
name: params.name,
desc: params.desc,
prd_host: params.prd_host,
basepath: params.basepath,
protocol: params.protocol || 'http',
members: [this.getUid()],
uid: this.getUid(),
group_id: params.group_id,
add_time: yapi.commons.time(),
up_time: yapi.commons.time()
};
try {
let result = await this.Model.save(data);
ctx.body = yapi.commons.resReturn(result);
} catch (e) {
ctx.body = yapi.commons.resReturn(null, 402, e.message);
}
}
/**
* 添加项目
* @interface /project/add_member
* @method POST
* @category project
* @foldnumber 10
* @param {Number} id 项目id不能为空
* @param {String} member_uid 项目成员uid,不能为空
* @returns {Object}
* @example ./api/project/add_member.json
*/
async addMember(ctx) {
let params = ctx.request.body;
if (!params.member_uid) {
return ctx.body = yapi.commons.resReturn(null, 400, '项目成员uid不能为空');
}
if (!params.id) {
return ctx.body = yapi.commons.resReturn(null, 400, '项目id不能为空');
}
var check = await this.Model.checkMemberRepeat(params.id, params.member_uid);
if (check > 0) {
return ctx.body = yapi.commons.resReturn(null, 400, '项目成员已存在');
}
try {
let result = await this.Model.addMember(params.id, params.member_uid);
ctx.body = yapi.commons.resReturn(result);
} catch (e) {
ctx.body = yapi.commons.resReturn(null, 402, e.message);
}
}
/**
* 添加项目
* @interface /project/del_member
* @method POST
* @category project
* @foldnumber 10
* @param {Number} id 项目id不能为空
* @param {member_uid} uid 项目成员uid,不能为空
* @returns {Object}
* @example ./api/project/del_member.json
*/
async delMember(ctx) {
let params = ctx.request.body;
if (!params.member_uid) {
return ctx.body = yapi.commons.resReturn(null, 400, '项目成员uid不能为空');
}
if (!params.id) {
return ctx.body = yapi.commons.resReturn(null, 400, '项目id不能为空');
}
var check = await this.Model.checkMemberRepeat(params.id, params.member_uid);
if (check === 0) {
return ctx.body = yapi.commons.resReturn(null, 400, '项目成员不存在');
}
try {
let result = await this.Model.delMember(params.id, params.member_uid);
ctx.body = yapi.commons.resReturn(result);
} catch (e) {
ctx.body = yapi.commons.resReturn(null, 402, e.message);
}
}
/**
* 获取项目成员列表
* @interface /project/get_member_list
* @method GET
* @category project
* @foldnumber 10
* @param {Number} id 项目id不能为空
* @return {Object}
* @example ./api/project/get_member_list.json
*/
async getMemberList(ctx) {
let params = ctx.request.query;
if (!params.id) {
return ctx.body = yapi.commons.resReturn(null, 400, '项目id不能为空');
}
try {
let project = await this.Model.get(params.id);
let userInst = yapi.getInst(userModel);
let result = await userInst.findByUids(project.members);
ctx.body = yapi.commons.resReturn(result);
} catch (e) {
ctx.body = yapi.commons.resReturn(null, 402, e.message);
}
}
/**
* 添加项目
* @interface /project/get
* @method GET
* @category project
* @foldnumber 10
* @param {Number} id 项目id不能为空
* @returns {Object}
* @example ./api/project/get.json
*/
async get(ctx) {
let params = ctx.request.query;
if (!params.id) {
return ctx.body = yapi.commons.resReturn(null, 400, '项目id不能为空');
}
try {
let result = await this.Model.get(params.id);
ctx.body = yapi.commons.resReturn(result);
} catch (e) {
ctx.body = yapi.commons.resReturn(null, 402, e.message);
}
}
/**
* 获取项目列表
* @interface /project/list
* @method GET
* @category project
* @foldnumber 10
* @param {Number} group_id 项目group_id不能为空
* @param {Number} [page] 分页页码
* @param {Number} [limit] 每页数据条目默认为10
* @returns {Object}
* @example ./api/project/list.json
*/
async list(ctx) {
let group_id = ctx.request.query.group_id,
page = ctx.request.query.page || 1,
limit = ctx.request.query.limit || 10;
if (!group_id) {
return ctx.body = yapi.commons.resReturn(null, 400, '项目分组id不能为空');
}
try {
let result = await this.Model.listWithPaging(group_id, page, limit);
let count = await this.Model.listCount(group_id);
let uids = [];
result.forEach((item) => {
if (uids.indexOf(item.uid) === -1) {
uids.push(item.uid);
}
});
let _users = {}, users = await yapi.getInst(userModel).findByUids(uids);
users.forEach((item) => {
_users[item._id] = item;
});
ctx.body = yapi.commons.resReturn({
total: Math.ceil(count / limit),
list: result,
userinfo: _users
});
} catch (e) {
ctx.body = yapi.commons.resReturn(null, 402, e.message);
}
}
/**
* 删除项目
* @interface /project/del
* @method POST
* @category project
* @foldnumber 10
* @param {Number} id 项目id不能为空
* @returns {Object}
* @example ./api/project/del.json
*/
async del(ctx) {
try {
let id = ctx.request.body.id;
if (!id) {
return ctx.body = yapi.commons.resReturn(null, 400, '项目id不能为空');
}
let interfaceInst = yapi.getInst(interfaceModel);
let count = await interfaceInst.countByProjectId(id);
if (count > 0) {
return ctx.body = yapi.commons.resReturn(null, 400, '请先删除该项目下所有接口');
}
if (await this.jungeProjectAuth(id) !== true) {
return ctx.body = yapi.commons.resReturn(null, 405, '没有权限');
}
let result = await this.Model.del(id);
ctx.body = yapi.commons.resReturn(result);
} catch (err) {
ctx.body = yapi.commons.resReturn(null, 402, err.message);
}
}
/**
* 编辑项目
* @interface /project/up
* @method POST
* @category project
* @foldnumber 10
* @param {Number} id 项目id不能为空
* @param {String} name 项目名称,不能为空
* @param {String} basepath 项目基本路径,不能为空
* @param {String} prd_host 项目线上域名不能为空。可通过配置的域名访问到mock数据
* @param {String} [desc] 项目描述
* @param {Array} [env] 项目环境配置
* @param {String} [env[].name] 环境名称
* @param {String} [env[].domain] 环境域名
* @returns {Object}
* @example ./api/project/up.json
*/
async up(ctx) {
try {
let id = ctx.request.body.id;
let params = ctx.request.body;
params = yapi.commons.handleParams(params, {
name: 'string',
basepath: 'string',
prd_host: 'string',
protocol: 'string',
group_id: 'number',
desc: 'string'
});
if (!id) {
return ctx.body = yapi.commons.resReturn(null, 405, '项目id不能为空');
}
if (await this.jungeMemberAuth(id, this.getUid()) !== true) {
return ctx.body = yapi.commons.resReturn(null, 405, '没有权限');
}
let projectData = await this.Model.get(id);
if ((params.basepath = this.handleBasepath(params.basepath)) === false) {
return ctx.body = yapi.commons.resReturn(null, 401, 'basepath格式有误');
}
if (!this.verifyDomain(params.prd_host)) {
return ctx.body = yapi.commons.resReturn(null, 401, '线上域名格式有误');
}
if (projectData.name === params.name) {
delete params.name;
}
if (projectData.basepath === params.basepath && projectData.prd_host === params.prd_host) {
delete params.basepath;
delete params.prd_host;
}
if (params.name) {
let checkRepeat = await this.Model.checkNameRepeat(params.name);
if (checkRepeat > 0) {
return ctx.body = yapi.commons.resReturn(null, 401, '已存在的项目名');
}
}
if (params.basepath && params.prd_host) {
let checkRepeatDomain = await this.Model.checkDomainRepeat(params.prd_host, params.basepath);
if (checkRepeatDomain > 0) {
return ctx.body = yapi.commons.resReturn(null, 401, '已存在domain和basepath');
}
}
let data = {
uid: this.getUid(),
up_time: yapi.commons.time()
};
if (params.name) data.name = params.name;
if (params.desc) data.desc = params.desc;
if (params.prd_host && params.basepath) {
data.prd_host = params.prd_host;
data.basepath = params.basepath;
}
if (params.protocol) data.protocol = params.protocol;
if (params.env) data.env = params.env;
let result = await this.Model.up(id, data);
ctx.body = yapi.commons.resReturn(result);
} catch (e) {
ctx.body = yapi.commons.resReturn(null, 402, e.message);
}
}
/**
* 模糊搜索项目名称或者组名称
* @interface /project/search
* @method GET
* @category project
* @foldnumber 10
* @param {String} q
* @return {Object}
* @example ./api/project/search.json
*/
async search(ctx) {
const { q } = ctx.request.query;
if (!q) {
return ctx.body = yapi.commons.resReturn(void 0, 400, 'No keyword.');
}
if (!yapi.commons.validateSearchKeyword(q)) {
return ctx.body = yapi.commons.resReturn(void 0, 400, 'Bad query.');
}
let projectList = await this.Model.search(q);
let groupList = await this.groupModel.search(q);
let projectRules = [
'_id',
'name',
'basepath',
'uid',
'env',
'members',
{ key: 'group_id', alias: 'groupId' },
{ key: 'up_time', alias: 'upTime' },
{ key: 'prd_host', alias: 'prdHost' },
{ key: 'add_time', alias: 'addTime' }
];
let groupRules = [
'_id',
'uid',
{ key: 'group_name', alias: 'groupName' },
{ key: 'group_desc', alias: 'groupDesc' },
{ key: 'add_time', alias: 'addTime' },
{ key: 'up_time', alias: 'upTime' }
];
projectList = commons.filterRes(projectList, projectRules);
groupList = commons.filterRes(groupList, groupRules);
let queryList = {
project: projectList,
group: groupList
};
return ctx.body = yapi.commons.resReturn(queryList, 0, 'ok');
}
}
module.exports = projectController;
</pre>
</div>
</div>
</div>
</div>
<!-- <div class="docs-header" id="content" tabindex="-1">
<div class="container">
<h1>YApi : ./server/controllers/project.js</h1>
<p>源代码</p>
</div>
</div> -->
<footer class="docs-footer" role="contentinfo">
<div class="container">
<p></p>
</div>
</footer>
</div>
<script type="text/javascript">
SyntaxHighlighter.all();
function getTop(node){
return node.offsetTop + (node.offsetParent ? getTop(node.offsetParent) : 0);
}
document.addEventListener('DOMContentLoaded', function() {
setTimeout(function() {
try {
var lineNum = (parseInt(location.hash.replace(/#/g, '')) - 1) || 0,
node = document.querySelectorAll('div.line')[lineNum];
document.body.scrollTop = getTop(node);
node.className += ' highlight';
} catch(e) {}
}, 500);
}, false);
</script>
</body>
</html>

View File

@ -0,0 +1,617 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no" />
<title>YApi : ./server/controllers/user.js</title>
<link type="text/css" rel="stylesheet" href="../../../source/code.css"/>
<script type="text/javascript" src="../../../source/shCore.js"></script>
<script type="text/javascript" src="../../../source/shBrush-js.js"></script>
<style>
.syntaxhighlighter .number1 .spaces,.syntaxhighlighter .toolbar{ display: none;}
.syntaxhighlighter table td.gutter .line.highlight { background-color: #6ce26c !important; color: white; }
</style>
</head>
<body>
<div class="ydoc">
<div class="ydoc-banner-bg">
<div class="ydoc-banner" id="content" tabindex="-1">
<div class="ydoc-banner-area">
<h1>YApi : ./server/controllers/user.js</h1>
<p>源代码</p>
</div>
</div>
<div class="ydoc-container">
<div class="ydoc-container-content">
<div class="static-code-content" role="main">
<pre class="brush: js;">
import userModel from '../models/user.js';
import yapi from '../yapi.js';
import baseController from './base.js';
import request from 'request';
import common from '../utils/commons.js';
import interfaceModel from '../models/interface.js'
import groupModel from '../models/group.js'
import projectModel from '../models/project.js'
const jwt = require('jsonwebtoken');
class userController extends baseController {
constructor(ctx) {
super(ctx);
this.Model = yapi.getInst(userModel);
}
/**
* 用户登录接口
* @interface /user/login
* @method POST
* @category user
* @foldnumber 10
* @param {String} email email名称不能为空
* @param {String} password 密码,不能为空
* @returns {Object}
* @example ./api/user/login.json
*/
async login(ctx) { //登录
let userInst = yapi.getInst(userModel); //创建user实体
let email = ctx.request.body.email;
let password = ctx.request.body.password;
if (!email) {
return ctx.body = yapi.commons.resReturn(null, 400, 'email不能为空');
}
if (!password) {
return ctx.body = yapi.commons.resReturn(null, 400, '密码不能为空');
}
let result = await userInst.findByEmail(email);
if (!result) {
return ctx.body = yapi.commons.resReturn(null, 404, '该用户不存在');
} else if (yapi.commons.generatePassword(password, result.passsalt) === result.password) {
this.setLoginCookie(result._id, result.passsalt);
return ctx.body = yapi.commons.resReturn({
username: result.username,
uid: result._id,
email: result.email,
add_time: result.add_time,
up_time: result.up_time,
server_ip: yapi.WEBCONFIG.server_ip
}, 0, 'logout success...');
} else {
return ctx.body = yapi.commons.resReturn(null, 405, '密码错误');
}
}
/**
* 退出登录接口
* @interface /user/logout
* @method GET
* @category user
* @foldnumber 10
* @returns {Object}
* @example ./api/user/logout.json
*/
async logout(ctx) {
ctx.cookies.set('_yapi_token', null);
ctx.cookies.set('_yapi_uid', null);
ctx.body = yapi.commons.resReturn('ok');
}
/**
* 第三方登录需要提供一个request方法和 token字段暂时只支持qunar第三方
* @return {email: String, username: String}
*/
thirdQunarLogin() {
return {
request: (token) => {
return new Promise((resolve, reject) => {
request('http://qsso.corp.qunar.com/api/verifytoken.php?token=' + token, function (error, response, body) {
if (!error && response.statusCode == 200) {
let result = JSON.parse(body);
if (result && result.ret === true) {
let ret = {
email: result.userId + '@qunar.com',
username: result.data.userInfo.name
};
resolve(ret);
} else {
reject(result);
}
}
reject(error);
});
});
},
tokenField: 'token'
};
}
async loginByToken(ctx) {
let config = this.thirdQunarLogin();
let token = ctx.request.body[config.tokenField] || ctx.request.query[config.tokenField];
try {
let ret = await config.request(token);
let login = await this.handleThirdLogin(ret.email, ret.username);
if (login === true) {
yapi.commons.log('login success');
ctx.redirect('/');
}
} catch (e) {
yapi.commons.log(e.message, 'error');
ctx.redirect('/');
}
}
async handleThirdLogin(email, username) {
let user, data, passsalt;
let userInst = yapi.getInst(userModel);
try {
user = await userInst.findByEmail(email);
if (!user || !user._id) {
passsalt = yapi.commons.randStr();
data = {
username: username,
password: yapi.commons.generatePassword(passsalt, passsalt),
email: email,
passsalt: passsalt,
role: 'member',
add_time: yapi.commons.time(),
up_time: yapi.commons.time()
};
user = await userInst.save(data);
yapi.commons.sendMail({
to: email,
contents: `<h3>亲爱的用户:</h3><p>您好感谢使用YApi,系统检测您是第一次用Qsso账号登录YApi服务,您的Email是 ${email} ,初始化密码为:${passsalt}</p>`
});
}
this.setLoginCookie(user._id, user.passsalt);
return true;
} catch (e) {
console.error('third_login:', e.message); // eslint-disable-line
return false;
}
}
/**
* 修改用户密码
* @interface /user/change_password
* @method POST
* @category user
* @param {Number} uid 用户ID
* @param {Number} [old_password] 旧密码, 非admin用户必须传
* @param {Number} password 新密码
* @return {Object}
* @example ./api/user/change_password.json
*/
async changePassword(ctx) {
let params = ctx.request.body;
let userInst = yapi.getInst(userModel);
if (!params.uid) {
return ctx.body = yapi.commons.resReturn(null, 400, 'uid不能为空');
}
if (!params.password) {
return ctx.body = yapi.commons.resReturn(null, 400, '密码不能为空');
}
if (this.getRole() !== 'admin' && params.uid != this.getUid()) {
return ctx.body = yapi.commons.resReturn(null, 402, '没有权限');
}
if (this.getRole() !== 'admin') {
if (!params.old_password) {
return ctx.body = yapi.commons.resReturn(null, 400, '旧密码不能为空');
}
let user = await userInst.findById(params.uid);
if (yapi.commons.generatePassword(params.old_password, user.passsalt) !== user.password) {
return ctx.body = yapi.commons.resReturn(null, 402, '旧密码错误');
}
}
let passsalt = yapi.commons.randStr();
let data = {
up_time: yapi.commons.time(),
password: yapi.commons.generatePassword(params.password, passsalt),
passsalt: passsalt
};
try {
let result = await userInst.update(params.uid, data);
ctx.body = yapi.commons.resReturn(result);
} catch (e) {
ctx.body = yapi.commons.resReturn(null, 401, e.message);
}
}
async forgetPassword() { }
async resetPassword() { }
setLoginCookie(uid, passsalt) {
let token = jwt.sign({ uid: uid }, passsalt, { expiresIn: '7 days' });
this.ctx.cookies.set('_yapi_token', token, {
expires: yapi.commons.expireDate(7),
httpOnly: true
});
this.ctx.cookies.set('_yapi_uid', uid, {
expires: yapi.commons.expireDate(7),
httpOnly: true
});
}
/**
* 用户注册接口
* @interface /user/reg
* @method POST
* @category user
* @foldnumber 10
* @param {String} email email名称不能为空
* @param {String} password 密码,不能为空
* @param {String} [username] 用户名
* @returns {Object}
* @example ./api/user/login.json
*/
async reg(ctx) { //注册
let userInst = yapi.getInst(userModel);
let params = ctx.request.body; //获取请求的参数,检查是否存在用户名和密码
params = yapi.commons.handleParams(params, {
username: 'string',
password: 'string',
email: 'string'
});
if (!params.email) {
return ctx.body = yapi.commons.resReturn(null, 400, '邮箱不能为空');
}
if (!params.password) {
return ctx.body = yapi.commons.resReturn(null, 400, '密码不能为空');
}
let checkRepeat = await userInst.checkRepeat(params.email);//然后检查是否已经存在该用户
if (checkRepeat > 0) {
return ctx.body = yapi.commons.resReturn(null, 401, '该email已经注册');
}
let passsalt = yapi.commons.randStr();
let data = {
username: params.username,
password: yapi.commons.generatePassword(params.password, passsalt),//加密
email: params.email,
passsalt: passsalt,
role: 'member',
add_time: yapi.commons.time(),
up_time: yapi.commons.time()
};
if (!data.username) {
data.username = data.email.substr(0, data.email.indexOf('@'));
}
try {
let user = await userInst.save(data);
this.setLoginCookie(user._id, user.passsalt);
ctx.body = yapi.commons.resReturn({
uid: user._id,
email: user.email,
username: user.username,
add_time: user.add_time,
up_time: user.up_time,
role: 'member'
});
yapi.commons.sendMail({
to: user.email,
contents: `<h3>亲爱的用户:</h3><p>您好感谢使用YApi,您的账号 ${params.email} 已经注册成功</p>`
});
} catch (e) {
ctx.body = yapi.commons.resReturn(null, 401, e.message);
}
}
/**
* 获取用户列表
* @interface /user/list
* @method GET
* @category user
* @foldnumber 10
* @param {Number} [page] 分页页码
* @param {Number} [limit] 分页大小,默认为10条
* @returns {Object}
* @example
*/
async list(ctx) {
let page = ctx.request.query.page || 1,
limit = ctx.request.query.limit || 10;
const userInst = yapi.getInst(userModel);
try {
let user = await userInst.listWithPaging(page, limit);
let count = await userInst.listCount();
return ctx.body = yapi.commons.resReturn({
total: Math.ceil(count / limit),
list: user
});
} catch (e) {
return ctx.body = yapi.commons.resReturn(null, 402, e.message);
}
}
/**
* 获取用户个人信息
* @interface /user/find
* @method GET
* @param id 用户uid
* @category user
* @foldnumber 10
* @returns {Object}
* @example
*/
async findById(ctx) { //根据id获取用户信息
try {
let userInst = yapi.getInst(userModel);
let id = ctx.request.query.id;
if (!id) {
return ctx.body = yapi.commons.resReturn(null, 400, 'uid不能为空');
}
let result = await userInst.findById(id);
if (!result) {
return ctx.body = yapi.commons.resReturn(null, 402, '不存在的用户');
}
return ctx.body = yapi.commons.resReturn({
uid: result._id,
username: result.username,
email: result.email,
role: result.role,
add_time: result.add_time,
up_time: result.up_time
});
} catch (e) {
return ctx.body = yapi.commons.resReturn(null, 402, e.message);
}
}
/**
* 删除用户,只有admin用户才有此权限
* @interface /user/del
* @method POST
* @param id 用户uid
* @category user
* @foldnumber 10
* @returns {Object}
* @example
*/
async del(ctx) { //根据id删除一个用户
try {
if (this.getRole() !== 'admin') {
return ctx.body = yapi.commons.resReturn(null, 402, 'Without permission.');
}
let userInst = yapi.getInst(userModel);
let id = ctx.request.body.id;
if (!id) {
return ctx.body = yapi.commons.resReturn(null, 400, 'uid不能为空');
}
let result = await userInst.del(id);
ctx.body = yapi.commons.resReturn(result);
} catch (e) {
ctx.body = yapi.commons.resReturn(null, 402, e.message);
}
}
/**
* 更新用户个人信息
* @interface /user/update
* @method POST
* @param uid 用户uid
* @param [role] 用户角色,只有管理员有权限修改
* @param [username] String
* @param [email] String
* @category user
* @foldnumber 10
* @returns {Object}
* @example
*/
async update(ctx) { //更新用户信息
try {
let params = ctx.request.body;
params = yapi.commons.handleParams(params, {
username: 'string',
email: 'string'
});
if (this.getRole() !== 'admin' && params.uid != this.getUid()) {
return ctx.body = yapi.commons.resReturn(null, 401, '没有权限');
}
let userInst = yapi.getInst(userModel);
let id = params.uid;
if (!id) {
return ctx.body = yapi.commons.resReturn(null, 400, 'uid不能为空');
}
let data = {
up_time: yapi.commons.time()
};
if (this.getRole() === 'admin') {
params.role && (data.role = params.role);
}
params.username && (data.username = params.username);
params.email && (data.email = params.email);
if (data.email) {
var checkRepeat = await userInst.checkRepeat(data.email);//然后检查是否已经存在该用户
if (checkRepeat > 0) {
return ctx.body = yapi.commons.resReturn(null, 401, '该email已经注册');
}
}
let result = await userInst.update(id, data);
ctx.body = yapi.commons.resReturn(result);
} catch (e) {
ctx.body = yapi.commons.resReturn(null, 402, e.message);
}
}
/**
* 模糊搜索用户名或者email
* @interface /user/search
* @method GET
* @category user
* @foldnumber 10
* @param {String} q
* @return {Object}
* @example ./api/user/search.json
*/
async search(ctx) {
const { q } = ctx.request.query;
if (!q) {
return ctx.body = yapi.commons.resReturn(void 0, 400, 'No keyword.');
}
if (!yapi.commons.validateSearchKeyword(q)) {
return ctx.body = yapi.commons.resReturn(void 0, 400, 'Bad query.');
}
let queryList = await this.Model.search(q);
let rules = [
{
key: '_id',
alias: 'uid'
},
'username',
'email',
'role',
{
key: 'add_time',
alias: 'addTime'
},
{
key: 'up_time',
alias: 'upTime'
}
];
let filteredRes = common.filterRes(queryList, rules);
console.log(queryList); // eslint-disable-line
return ctx.body = yapi.commons.resReturn(filteredRes, 0, 'ok');
}
/**
* 根据路由id获取面包屑数据
* @interface /user/nav
* @method GET
* @category user
* @foldnumber 10
* @param {String} type 可选group|interface|project
* @param {Number} id
* @return {Object}
* @example ./api/user/nav.json
*/
async nav(ctx) {
let { id, type } = ctx.request.query;
let result = {};
try {
if (type === 'interface') {
let interfaceInst = yapi.getInst(interfaceModel);
let interfaceData = await interfaceInst.get(id)
result["interface_id"] = interfaceData._id;
result["interface_name"] = interfaceData.path;
type = 'project';
id = interfaceData.project_id;
}
if (type === 'project') {
let projectInst = yapi.getInst(projectModel);
let projectData = await projectInst.get(id);
result["project_id"] = projectData._id;
result["project_name"] = projectData.prd_host + projectData.basepath;
type = 'group';
id = projectData.group_id
}
if (type === 'group') {
let groupInst = yapi.getInst(groupModel);
let groupData = await groupInst.get(id);
result["group_id"] = groupData._id;
result["group_name"] = groupData.group_name;
}
return ctx.body = yapi.commons.resReturn(result)
}
catch (e) {
return ctx.body = yapi.commons.resReturn(result, 422, e.message)
}
}
}
module.exports = userController;
</pre>
</div>
</div>
</div>
</div>
<!-- <div class="docs-header" id="content" tabindex="-1">
<div class="container">
<h1>YApi : ./server/controllers/user.js</h1>
<p>源代码</p>
</div>
</div> -->
<footer class="docs-footer" role="contentinfo">
<div class="container">
<p></p>
</div>
</footer>
</div>
<script type="text/javascript">
SyntaxHighlighter.all();
function getTop(node){
return node.offsetTop + (node.offsetParent ? getTop(node.offsetParent) : 0);
}
document.addEventListener('DOMContentLoaded', function() {
setTimeout(function() {
try {
var lineNum = (parseInt(location.hash.replace(/#/g, '')) - 1) || 0,
node = document.querySelectorAll('div.line')[lineNum];
document.body.scrollTop = getTop(node);
node.className += ' highlight';
} catch(e) {}
}, 500);
}, false);
</script>
</body>
</html>

View File

@ -1,12 +1,12 @@
{
"name": "yapi",
"name": "YApi",
"dest": "static/doc",
"examplePath": "./exampleCode",
"defaultGrammar": "json",
"instructionsInfoPath": "", //使 (JS-Component@instructions使)
"instructionsUrlPath": "", //使demo (JS-Component@instructions使)
"common": { //
"title": "yapi", //page title
"title": "YApi", //page title
"footer": "&copy; 2016 <a href=\"http://ued.qunar.com/ymfe/\">YMFE</a> Team. Build by <a href=\"http://ued.qunar.com/ydoc/\">ydoc</a>.", //
"home": "YMFE", // logo
"homeUrl": "http://ued.qunar.com/ymfe/" // logourl
@ -18,61 +18,61 @@
"name": "index", // Page Name html : index.html
"title": "首页", // Page Title
"homepage": { //
"version": "v3.0.0", // banner
"version": "v1.0.0", // banner
"button": [{ // banner
"name": "开始",
"href": "./start.html"
"href": "./interface.html"
},{
"name": "Github",
"href": "https://github.com/YMFE/ydoc"
"href": "https://github.com/YMFE/yapi"
}],
"intro": [{ // 使
"title": "为前端开发者设计的文档生成工具", //
"desc": "YDoc让文档开发更简单高效让开发者专注于程序本身让项目代码更具可读性、可维护性。" //
"title": "为API开发者设计的管理平台", //
"desc": "YApi让接口开发更简单高效让接口的管理更具可读性、可维护性让团队协作更合理。" //
},{
"title": "特性",
"title": "功能",
"detail": {
"type": "thumbnail", //
"content": [{ // keykey
"name": "丰富、可扩展的API", //
"name": "项目接口管理", //
"src": "http://ojk406wln.bkt.clouddn.com/intro_muti.png", //
"desc": "YDoc提供了非常详尽的API扩展性较强如果你希望添加某些功能可以在<a href=\"https://github.com/YMFE/ydoc\" target=\"_blank\"> Github </a>上面提Issue。" //
"desc": "提供基本的项目分组,项目管理,接口管理功能" //
},{
"name": "基于注释/markdown",
"name": "mockServer服务",
"src": "http://ojk406wln.bkt.clouddn.com/intro_md.png",
"desc": "基于项目代码注释与markdown快速构建文档二者亦可在同一页面中使用。"
"desc": "用户只需在项目配置线上域名和接口基本路径通过将线上域名指到我们的YApi平台服务器就可使用mockServer服务"
},{
"name": "可配置主题",
"name": "用户管理",
"src": "http://ojk406wln.bkt.clouddn.com/intro_theme.png",
"desc": "官方提供多套主题,并且支持用户自定义开发主题。"
"desc": "提供基本的用户注册登录管理等功能集成了去哪儿QSSO登录"
}]
}
}]
},
"banner": { // Banner
"title": "Yapi",
"title": "YApi",
"description": "高效、易用、功能强大、的api管理平台旨在为开发、产品、测试人员提供更优雅的接口管理服务。"
},
"content": "./README.md" // (markdown)
"content": "./README/README-home.md" // (markdown)
},{
"name": "interface", // Page Name html : index.html
"title": "接口管理", // Page Title
"banner": { // Banner
"title": "Yapi",
"title": "YApi",
"description": "高效、易用、功能强大、的api管理平台旨在为开发、产品、测试人员提供更优雅的接口管理服务。"
},
"content": "./README.md" // (markdown)
"content": "./README/README-interface.md" // (markdown)
},{
"name": "mock", // Page Name html : index.html
"title": "Mock功能", // Page Title
"banner": { // Banner
"title": "Yapi",
"title": "YApi",
"description": "高效、易用、功能强大、的api管理平台旨在为开发、产品、测试人员提供更优雅的接口管理服务。"
},
"content": "./README.md" // (markdown)
"content": "./README/README-mock.md" // (markdown)
},{
"name": "api",
"title": " ",
"title": "",
"banner": {
"title": "api",
"description": "api文档"