diff --git a/doc/build/api.html b/doc/build/api.html index 4a0ca4a8..3ef5327e 100644 --- a/doc/build/api.html +++ b/doc/build/api.html @@ -1131,8 +1131,28 @@ env + Array + 项目环境配置 + + + + + + + + env[].name String - JSON字符串,例如{"local": "http://www.api.com"} + 环境名称 + + + + + + + + env[].host + String + 环境域名 @@ -1144,7 +1164,19 @@
示例:
-
{
+    

+//请求示例
+{
+    "id": 8,
+    "env": [{
+        "name": "本地开发环境",
+        "domain": "http://api.quar.com"
+    }],
+    "desc": "yapi项目"
+}
+
+//返回示例
+{
     "errcode": 0,
     "errmsg": "success",
     "data": {
diff --git a/doc/build/static/server/controllers/project.js.html b/doc/build/static/server/controllers/project.js.html
index 9118bcb9..b34121c5 100644
--- a/doc/build/static/server/controllers/project.js.html
+++ b/doc/build/static/server/controllers/project.js.html
@@ -248,7 +248,9 @@ class projectController extends baseController {
      * @param {String} basepath 项目基本路径,不能为空
      * @param {String} prd_host 项目线上域名,不能为空。可通过配置的域名访问到mock数据
      * @param {String} [desc] 项目描述 
-     * @param {String} [env] JSON字符串,例如{"local": "http://www.api.com"}
+     * @param {Array} [env] 项目环境配置
+     * @param {String} [env[].name] 环境名称
+     * @param {String} [env[].host] 环境域名
      * @returns {Object} 
      * @example ./api/project/up.json
      */
diff --git a/exampleCode/api/project/up.json b/exampleCode/api/project/up.json
index de81d507..dd9f7cef 100644
--- a/exampleCode/api/project/up.json
+++ b/exampleCode/api/project/up.json
@@ -1,3 +1,15 @@
+
+//请求示例
+{
+    "id": 8,
+    "env": [{
+        "name": "本地开发环境",
+        "domain": "http://api.quar.com"
+    }],
+    "desc": "yapi项目"
+}
+
+//返回示例
 {
     "errcode": 0,
     "errmsg": "success",
diff --git a/package.json b/package.json
index 717cf7ea..5702abbb 100644
--- a/package.json
+++ b/package.json
@@ -25,6 +25,7 @@
     "koa-session-minimal": "^3.0.3",
     "koa-static": "^3.0.0",
     "koa-views": "^5.2.0",
+    "mockjs": "^1.0.1-beta3",
     "mongoose": "4.10.8",
     "mongoose-auto-increment": "^5.0.1"
   },
diff --git a/server/app.js b/server/app.js
index 37874085..eb9a780e 100644
--- a/server/app.js
+++ b/server/app.js
@@ -6,7 +6,7 @@ yapi.commons = commons;
 
 import dbModule from './utils/db.js';
 
-import userauth from './middleware/userauth.js'
+import mockServer from './middleware/mockServer.js'
 
 import Koa from 'koa'
 import convert from 'koa-convert'
@@ -17,7 +17,7 @@ import router from './router.js'
 yapi.connect = dbModule.connect()    
 
 const app = new Koa()
-app.use(userauth)
+app.use(mockServer)
 app.use(bodyParser())
 app.use(router.routes())
 app.use(router.allowedMethods())
diff --git a/server/config.dev.json b/server/config.dev.json
index 2969e202..45f1e2c6 100644
--- a/server/config.dev.json
+++ b/server/config.dev.json
@@ -1,5 +1,6 @@
 {
   "port": "3000",
+  "webhost": "127.0.0.1",
   "db": {
     "servername": "127.0.0.1",
     "DATABASE":  "yapi",
diff --git a/server/config.json b/server/config.json
index 32b4c4b5..a1627e6a 100644
--- a/server/config.json
+++ b/server/config.json
@@ -1,5 +1,6 @@
 {
   "port":"80",
+  "webhost": "127.0.0.1",
   "db": {
     "servername": "127.0.0.1",
     "DATABASE":  "yapi",
diff --git a/server/controllers/group.js b/server/controllers/group.js
index a6ce8664..9b1b5b1f 100644
--- a/server/controllers/group.js
+++ b/server/controllers/group.js
@@ -1,6 +1,7 @@
 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{
@@ -83,7 +84,16 @@ class groupController extends baseController{
     async del(ctx){   
         try{
             var groupInst = yapi.getInst(groupModel);
-            let id = ctx.request.body.id;
+            var projectInst = yapi.getInst(projectModel);
+            let id = ctx.request.body.id;            
+            if(!id){
+                return ctx.body = yapi.commons.resReturn(null, 402, 'id不能为空');
+            }
+            let count = 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){
diff --git a/server/controllers/project.js b/server/controllers/project.js
index e47096e4..7509f16a 100644
--- a/server/controllers/project.js
+++ b/server/controllers/project.js
@@ -1,6 +1,7 @@
 import  projectModel from '../models/project.js'
 import yapi from '../yapi.js'
 import baseController from './base.js'
+import interfaceModel from '../models/interface.js'
 
 class projectController extends baseController {
 
@@ -200,11 +201,17 @@ class projectController extends baseController {
             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)
+            ctx.body = yapi.commons.resReturn(result);
         }catch(err){
              ctx.body = yapi.commons.resReturn(null, 402, e.message)
         }
@@ -221,7 +228,9 @@ class projectController extends baseController {
      * @param {String} basepath 项目基本路径,不能为空
      * @param {String} prd_host 项目线上域名,不能为空。可通过配置的域名访问到mock数据
      * @param {String} [desc] 项目描述 
-     * @param {String} [env] JSON字符串,例如{"local": "http://www.api.com"}
+     * @param {Array} [env] 项目环境配置
+     * @param {String} [env[].name] 环境名称
+     * @param {String} [env[].host] 环境域名
      * @returns {Object} 
      * @example ./api/project/up.json
      */
diff --git a/server/middleware/mockServer.js b/server/middleware/mockServer.js
index 0008d654..9be8c849 100644
--- a/server/middleware/mockServer.js
+++ b/server/middleware/mockServer.js
@@ -1,7 +1,64 @@
+import yapi from '../yapi.js';
+import projectModel from '../models/project.js'
+import interfaceModel from '../models/interface.js'
+import Mock from 'mockjs'
+
 module.exports = async (ctx, next) => {
-    let hostname = ctx.hostname
+    yapi.commons.log('mock Server running...')
+    let hostname = ctx.protocol + "://" + ctx.hostname;
+    let config = yapi.WEBCONFIG;
+    if(hostname === config.webhost){
+        if(next) await next();
+        return true;
+    }
+    let projectInst = yapi.getInst(projectModel), projects;
+    try{
+        projects = await projectInst.getByDomain(hostname);
+    }catch(e){
+        return ctx.body = yapi.commons.resReturn(null, 403, e.message);
+    }
+    
+    let matchProject = [];
+    for(let i=0, l = projects.length; i< l; i++){
+        let project = projects[i];
+        if(ctx.path && ctx.path.indexOf(project.basepath) === 0 && project.basepath[project.basepath.length -1] === '/'){
+            matchProject.push(project);            
+        }
+    }
+
+
+    if(matchProject.length === 0){
+        return ctx.body = yapi.commons.resReturn(null, 400, '不存在的domain');
+    }
+
+    if(matchProject.length > 1){
+        return ctx.body = yapi.commons.resReturn(null, 401, '存在多个project,请检查数据库');
+    }
+
+    let project = matchProject[0], interfaceData;
+    let interfaceInst = yapi.getInst(interfaceModel);
+    try{
+        interfaceData = await  interfaceInst.getByPath(project._id, ctx.path.substr(project.basepath.length));
+
+        if(!interfaceData || interfaceData.length === 0){            
+            return ctx.body = yapi.commons.resReturn(null, 404, '不存在的api');
+        }
+
+        if(interfaceData.length > 1){
+            return ctx.body = yapi.commons.resReturn(null, 405, '存在多个api,请检查数据库');
+        }
+
+        interfaceData = interfaceData[0];
+        
+        if(interfaceData.res_body_type === 'json'){
+            return ctx.body = Mock.mock(
+                yapi.commons.json_parse(interfaceData.res_body)
+            );
+        }
+        return ctx.body = interfaceData.res_body;
+    }catch(e){
+        return ctx.body = yapi.commons.resReturn(null, 409, e.message);
+    }
     
 
-
-    if(next) await next();
 }
\ No newline at end of file
diff --git a/server/models/interface.js b/server/models/interface.js
index accb2ed7..37df4065 100644
--- a/server/models/interface.js
+++ b/server/models/interface.js
@@ -9,7 +9,12 @@ class interfaceModel extends baseModel{
     getSchema(){
         return {
             uid: {type: Number, required: true},
-            path: {type: String, required: true},
+            path: {type: String, required: true, validate: {
+                validator: (v) => {
+                    return v && v[0] !== '/';
+                },
+                message: '接口路径第一位不能是/'
+            }},
             method: {type: String, required: true},
             project_id: {type: Number, required: true},
             desc: String,
@@ -46,6 +51,13 @@ class interfaceModel extends baseModel{
         }).exec()
     }
 
+    getByPath(project_id, path){
+        return this.model.find({
+            project_id: project_id,
+            path: path
+        }).exec()
+    }
+
     checkRepeat(path, method){
         return this.model.count({
             path: path,
@@ -53,7 +65,11 @@ class interfaceModel extends baseModel{
         })
     }
 
-
+    countByProjectId(id){
+        return this.model.count({
+            project_id: id
+        })
+    }
 
     list (group_id){
         return this.model.find({
diff --git a/server/models/project.js b/server/models/project.js
index 6bc77cc4..00f4e19b 100644
--- a/server/models/project.js
+++ b/server/models/project.js
@@ -10,12 +10,19 @@ class projectModel extends baseModel{
         return {
             uid: {type: Number, required: true},
             name: {type: String, required: true},
-            basepath: {type: String, required: true},
+            basepath: {type: String, required: true, validate: {
+                validator: (v) => {
+                    return v && v[v.length - 1] === '/'
+                },
+                message: 'basepath字符串结尾必须是/'
+            }},
             desc: String,
             group_id: {type: Number, required: true},
             members: Array,
             prd_host: {type: String, required: true},
-            env: Object,
+            env: [
+                {name: String, domain: String}
+            ],
             add_time: Number,
             up_time: Number
         }
@@ -33,6 +40,12 @@ class projectModel extends baseModel{
         }).exec()
     }
 
+    getByDomain(domain){
+        return this.model.find({
+            prd_host: domain
+        }).exec()
+    }
+
     checkNameRepeat(name){
         return this.model.count({
             name: name
@@ -53,6 +66,12 @@ class projectModel extends baseModel{
         }).exec()
     }
 
+    countByGroupId(group_id){
+        return this.model.count({
+            group_id: group_id
+        })
+    }
+
     del(id){
         return this.model.deleteOne({
             _id: id
@@ -66,7 +85,6 @@ class projectModel extends baseModel{
     }
 
     addMember(id, uid){
-        console.log(id, uid)
         return this.model.update({
             _id: id
         }, {
diff --git a/server_dist/app.js b/server_dist/app.js
index 2e5d9a99..6a8139d6 100644
--- a/server_dist/app.js
+++ b/server_dist/app.js
@@ -12,9 +12,9 @@ var _db = require('./utils/db.js');
 
 var _db2 = _interopRequireDefault(_db);
 
-var _userauth = require('./middleware/userauth.js');
+var _mockServer = require('./middleware/mockServer.js');
 
-var _userauth2 = _interopRequireDefault(_userauth);
+var _mockServer2 = _interopRequireDefault(_mockServer);
 
 var _koa = require('koa');
 
@@ -43,7 +43,7 @@ _yapi2.default.commons = _commons2.default;
 _yapi2.default.connect = _db2.default.connect();
 
 var app = new _koa2.default();
-app.use(_userauth2.default);
+app.use(_mockServer2.default);
 app.use((0, _koaBodyparser2.default)());
 app.use(_router2.default.routes());
 app.use(_router2.default.allowedMethods());
diff --git a/server_dist/config.dev.json b/server_dist/config.dev.json
index 2969e202..45f1e2c6 100644
--- a/server_dist/config.dev.json
+++ b/server_dist/config.dev.json
@@ -1,5 +1,6 @@
 {
   "port": "3000",
+  "webhost": "127.0.0.1",
   "db": {
     "servername": "127.0.0.1",
     "DATABASE":  "yapi",
diff --git a/server_dist/config.json b/server_dist/config.json
index 32b4c4b5..a1627e6a 100644
--- a/server_dist/config.json
+++ b/server_dist/config.json
@@ -1,5 +1,6 @@
 {
   "port":"80",
+  "webhost": "127.0.0.1",
   "db": {
     "servername": "127.0.0.1",
     "DATABASE":  "yapi",
diff --git a/server_dist/controllers/group.js b/server_dist/controllers/group.js
index 40562b9c..2cca3589 100644
--- a/server_dist/controllers/group.js
+++ b/server_dist/controllers/group.js
@@ -44,6 +44,10 @@ var _base = require('./base.js');
 
 var _base2 = _interopRequireDefault(_base);
 
+var _project = require('../models/project.js');
+
+var _project2 = _interopRequireDefault(_project);
+
 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
 // 
@@ -213,36 +217,56 @@ var groupController = function (_baseController) {
         key: 'del',
         value: function () {
             var _ref3 = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee3(ctx) {
-                var groupInst, id, result;
+                var groupInst, projectInst, id, count, result;
                 return _regenerator2.default.wrap(function _callee3$(_context3) {
                     while (1) {
                         switch (_context3.prev = _context3.next) {
                             case 0:
                                 _context3.prev = 0;
                                 groupInst = _yapi2.default.getInst(_group2.default);
+                                projectInst = _yapi2.default.getInst(_project2.default);
                                 id = ctx.request.body.id;
-                                _context3.next = 5;
+
+                                if (id) {
+                                    _context3.next = 6;
+                                    break;
+                                }
+
+                                return _context3.abrupt('return', ctx.body = _yapi2.default.commons.resReturn(null, 402, 'id不能为空'));
+
+                            case 6:
+                                count = projectInst.countByGroupId(id);
+
+                                if (!(count > 0)) {
+                                    _context3.next = 9;
+                                    break;
+                                }
+
+                                return _context3.abrupt('return', ctx.body = _yapi2.default.commons.resReturn(null, 403, '请先删除该分组下的项目'));
+
+                            case 9:
+                                _context3.next = 11;
                                 return groupInst.del(id);
 
-                            case 5:
+                            case 11:
                                 result = _context3.sent;
 
                                 ctx.body = _yapi2.default.commons.resReturn(result);
-                                _context3.next = 12;
+                                _context3.next = 18;
                                 break;
 
-                            case 9:
-                                _context3.prev = 9;
+                            case 15:
+                                _context3.prev = 15;
                                 _context3.t0 = _context3['catch'](0);
 
                                 ctx.body = _yapi2.default.commons.resReturn(null, 402, e.message);
 
-                            case 12:
+                            case 18:
                             case 'end':
                                 return _context3.stop();
                         }
                     }
-                }, _callee3, this, [[0, 9]]);
+                }, _callee3, this, [[0, 15]]);
             }));
 
             function del(_x3) {
diff --git a/server_dist/controllers/project.js b/server_dist/controllers/project.js
index 9993e811..da0e462f 100644
--- a/server_dist/controllers/project.js
+++ b/server_dist/controllers/project.js
@@ -40,6 +40,10 @@ var _base = require('./base.js');
 
 var _base2 = _interopRequireDefault(_base);
 
+var _interface = require('../models/interface.js');
+
+var _interface2 = _interopRequireDefault(_interface);
+
 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
 var projectController = function (_baseController) {
@@ -490,7 +494,7 @@ var projectController = function (_baseController) {
         key: 'del',
         value: function () {
             var _ref6 = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee6(ctx) {
-                var id, result;
+                var id, interfaceInst, count, result;
                 return _regenerator2.default.wrap(function _callee6$(_context6) {
                     while (1) {
                         switch (_context6.prev = _context6.next) {
@@ -506,42 +510,57 @@ var projectController = function (_baseController) {
                                 return _context6.abrupt('return', ctx.body = _yapi2.default.commons.resReturn(null, 400, '项目id不能为空'));
 
                             case 4:
-                                _context6.next = 6;
+                                interfaceInst = _yapi2.default.getInst(_interface2.default);
+                                _context6.next = 7;
+                                return interfaceInst.countByProjectId(id);
+
+                            case 7:
+                                count = _context6.sent;
+
+                                if (!(count > 0)) {
+                                    _context6.next = 10;
+                                    break;
+                                }
+
+                                return _context6.abrupt('return', ctx.body = _yapi2.default.commons.resReturn(null, 400, '请先删除该项目下所有接口'));
+
+                            case 10:
+                                _context6.next = 12;
                                 return this.jungeProjectAuth(id);
 
-                            case 6:
+                            case 12:
                                 _context6.t0 = _context6.sent;
 
                                 if (!(_context6.t0 !== true)) {
-                                    _context6.next = 9;
+                                    _context6.next = 15;
                                     break;
                                 }
 
                                 return _context6.abrupt('return', ctx.body = _yapi2.default.commons.resReturn(null, 405, '没有权限'));
 
-                            case 9:
-                                _context6.next = 11;
+                            case 15:
+                                _context6.next = 17;
                                 return this.Model.del(id);
 
-                            case 11:
+                            case 17:
                                 result = _context6.sent;
 
                                 ctx.body = _yapi2.default.commons.resReturn(result);
-                                _context6.next = 18;
+                                _context6.next = 24;
                                 break;
 
-                            case 15:
-                                _context6.prev = 15;
+                            case 21:
+                                _context6.prev = 21;
                                 _context6.t1 = _context6['catch'](0);
 
                                 ctx.body = _yapi2.default.commons.resReturn(null, 402, e.message);
 
-                            case 18:
+                            case 24:
                             case 'end':
                                 return _context6.stop();
                         }
                     }
-                }, _callee6, this, [[0, 15]]);
+                }, _callee6, this, [[0, 21]]);
             }));
 
             function del(_x6) {
@@ -562,7 +581,9 @@ var projectController = function (_baseController) {
          * @param {String} basepath 项目基本路径,不能为空
          * @param {String} prd_host 项目线上域名,不能为空。可通过配置的域名访问到mock数据
          * @param {String} [desc] 项目描述 
-         * @param {String} [env] JSON字符串,例如{"local": "http://www.api.com"}
+         * @param {Array} [env] 项目环境配置
+         * @param {String} [env[].name] 环境名称
+         * @param {String} [env[].host] 环境域名
          * @returns {Object} 
          * @example ./api/project/up.json
          */
diff --git a/server_dist/middleware/mockServer.js b/server_dist/middleware/mockServer.js
index 34929e20..bbd05bfe 100644
--- a/server_dist/middleware/mockServer.js
+++ b/server_dist/middleware/mockServer.js
@@ -1,38 +1,151 @@
-"use strict";
+'use strict';
 
-var _regenerator = require("babel-runtime/regenerator");
+var _regenerator = require('babel-runtime/regenerator');
 
 var _regenerator2 = _interopRequireDefault(_regenerator);
 
-var _asyncToGenerator2 = require("babel-runtime/helpers/asyncToGenerator");
+var _asyncToGenerator2 = require('babel-runtime/helpers/asyncToGenerator');
 
 var _asyncToGenerator3 = _interopRequireDefault(_asyncToGenerator2);
 
+var _yapi = require('../yapi.js');
+
+var _yapi2 = _interopRequireDefault(_yapi);
+
+var _project2 = require('../models/project.js');
+
+var _project3 = _interopRequireDefault(_project2);
+
+var _interface = require('../models/interface.js');
+
+var _interface2 = _interopRequireDefault(_interface);
+
+var _mockjs = require('mockjs');
+
+var _mockjs2 = _interopRequireDefault(_mockjs);
+
 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
 module.exports = function () {
     var _ref = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee(ctx, next) {
-        var hostname;
+        var hostname, config, projectInst, projects, matchProject, i, l, _project, project, interfaceData, interfaceInst;
+
         return _regenerator2.default.wrap(function _callee$(_context) {
             while (1) {
                 switch (_context.prev = _context.next) {
                     case 0:
-                        hostname = ctx.hostname;
+                        _yapi2.default.commons.log('mock Server running...');
+                        hostname = ctx.protocol + "://" + ctx.hostname;
+                        config = _yapi2.default.WEBCONFIG;
 
-                        if (!next) {
-                            _context.next = 4;
+                        if (!(hostname === config.webhost)) {
+                            _context.next = 8;
                             break;
                         }
 
-                        _context.next = 4;
+                        if (!next) {
+                            _context.next = 7;
+                            break;
+                        }
+
+                        _context.next = 7;
                         return next();
 
-                    case 4:
-                    case "end":
+                    case 7:
+                        return _context.abrupt('return', true);
+
+                    case 8:
+                        projectInst = _yapi2.default.getInst(_project3.default), projects = void 0;
+                        _context.prev = 9;
+                        _context.next = 12;
+                        return projectInst.getByDomain(hostname);
+
+                    case 12:
+                        projects = _context.sent;
+                        _context.next = 18;
+                        break;
+
+                    case 15:
+                        _context.prev = 15;
+                        _context.t0 = _context['catch'](9);
+                        return _context.abrupt('return', ctx.body = _yapi2.default.commons.resReturn(null, 403, _context.t0.message));
+
+                    case 18:
+                        matchProject = [];
+
+                        for (i = 0, l = projects.length; i < l; i++) {
+                            _project = projects[i];
+
+                            if (ctx.path && ctx.path.indexOf(_project.basepath) === 0 && _project.basepath[_project.basepath.length - 1] === '/') {
+                                matchProject.push(_project);
+                            }
+                        }
+
+                        if (!(matchProject.length === 0)) {
+                            _context.next = 22;
+                            break;
+                        }
+
+                        return _context.abrupt('return', ctx.body = _yapi2.default.commons.resReturn(null, 400, '不存在的domain'));
+
+                    case 22:
+                        if (!(matchProject.length > 1)) {
+                            _context.next = 24;
+                            break;
+                        }
+
+                        return _context.abrupt('return', ctx.body = _yapi2.default.commons.resReturn(null, 401, '存在多个project,请检查数据库'));
+
+                    case 24:
+                        project = matchProject[0], interfaceData = void 0;
+                        interfaceInst = _yapi2.default.getInst(_interface2.default);
+                        _context.prev = 26;
+                        _context.next = 29;
+                        return interfaceInst.getByPath(project._id, ctx.path.substr(project.basepath.length));
+
+                    case 29:
+                        interfaceData = _context.sent;
+
+                        if (!(!interfaceData || interfaceData.length === 0)) {
+                            _context.next = 32;
+                            break;
+                        }
+
+                        return _context.abrupt('return', ctx.body = _yapi2.default.commons.resReturn(null, 404, '不存在的api'));
+
+                    case 32:
+                        if (!(interfaceData.length > 1)) {
+                            _context.next = 34;
+                            break;
+                        }
+
+                        return _context.abrupt('return', ctx.body = _yapi2.default.commons.resReturn(null, 405, '存在多个api,请检查数据库'));
+
+                    case 34:
+
+                        interfaceData = interfaceData[0];
+
+                        if (!(interfaceData.res_body_type === 'json')) {
+                            _context.next = 37;
+                            break;
+                        }
+
+                        return _context.abrupt('return', ctx.body = _mockjs2.default.mock(_yapi2.default.commons.json_parse(interfaceData.res_body)));
+
+                    case 37:
+                        return _context.abrupt('return', ctx.body = interfaceData.res_body);
+
+                    case 40:
+                        _context.prev = 40;
+                        _context.t1 = _context['catch'](26);
+                        return _context.abrupt('return', ctx.body = _yapi2.default.commons.resReturn(null, 409, _context.t1.message));
+
+                    case 43:
+                    case 'end':
                         return _context.stop();
                 }
             }
-        }, _callee, undefined);
+        }, _callee, undefined, [[9, 15], [26, 40]]);
     }));
 
     return function (_x, _x2) {
diff --git a/server_dist/models/interface.js b/server_dist/models/interface.js
index 3634eff8..90d8da3c 100644
--- a/server_dist/models/interface.js
+++ b/server_dist/models/interface.js
@@ -48,7 +48,12 @@ var interfaceModel = function (_baseModel) {
         value: function getSchema() {
             return {
                 uid: { type: Number, required: true },
-                path: { type: String, required: true },
+                path: { type: String, required: true, validate: {
+                        validator: function validator(v) {
+                            return v && v[0] !== '/';
+                        },
+                        message: '接口路径第一位不能是/'
+                    } },
                 method: { type: String, required: true },
                 project_id: { type: Number, required: true },
                 desc: String,
@@ -85,6 +90,14 @@ var interfaceModel = function (_baseModel) {
                 _id: id
             }).exec();
         }
+    }, {
+        key: 'getByPath',
+        value: function getByPath(project_id, path) {
+            return this.model.find({
+                project_id: project_id,
+                path: path
+            }).exec();
+        }
     }, {
         key: 'checkRepeat',
         value: function checkRepeat(path, method) {
@@ -93,6 +106,13 @@ var interfaceModel = function (_baseModel) {
                 method: method
             });
         }
+    }, {
+        key: 'countByProjectId',
+        value: function countByProjectId(id) {
+            return this.model.count({
+                project_id: id
+            });
+        }
     }, {
         key: 'list',
         value: function list(group_id) {
diff --git a/server_dist/models/project.js b/server_dist/models/project.js
index 8006f419..094fb158 100644
--- a/server_dist/models/project.js
+++ b/server_dist/models/project.js
@@ -49,12 +49,17 @@ var projectModel = function (_baseModel) {
             return {
                 uid: { type: Number, required: true },
                 name: { type: String, required: true },
-                basepath: { type: String, required: true },
+                basepath: { type: String, required: true, validate: {
+                        validator: function validator(v) {
+                            return v && v[v.length - 1] === '/';
+                        },
+                        message: 'basepath字符串结尾必须是/'
+                    } },
                 desc: String,
                 group_id: { type: Number, required: true },
                 members: Array,
                 prd_host: { type: String, required: true },
-                env: Object,
+                env: [{ name: String, domain: String }],
                 add_time: Number,
                 up_time: Number
             };
@@ -72,6 +77,13 @@ var projectModel = function (_baseModel) {
                 _id: id
             }).exec();
         }
+    }, {
+        key: 'getByDomain',
+        value: function getByDomain(domain) {
+            return this.model.find({
+                prd_host: domain
+            }).exec();
+        }
     }, {
         key: 'checkNameRepeat',
         value: function checkNameRepeat(name) {
@@ -94,6 +106,13 @@ var projectModel = function (_baseModel) {
                 group_id: group_id
             }).exec();
         }
+    }, {
+        key: 'countByGroupId',
+        value: function countByGroupId(group_id) {
+            return this.model.count({
+                group_id: group_id
+            });
+        }
     }, {
         key: 'del',
         value: function del(id) {
@@ -112,7 +131,6 @@ var projectModel = function (_baseModel) {
     }, {
         key: 'addMember',
         value: function addMember(id, uid) {
-            console.log(id, uid);
             return this.model.update({
                 _id: id
             }, {