Merge branch 'dev' of gitlab.corp.qunar.com:mfe/yapi into dev

This commit is contained in:
zwjamnsss 2017-08-21 15:57:08 +08:00
commit 7ec9f122b7
22 changed files with 237 additions and 133 deletions

View File

@ -4,14 +4,8 @@
<p style='text-indent:2em;line-height:1.8em'>YApi是<strong>高效</strong><strong>易用</strong><strong>功能强大</strong>、的api管理平台旨在为开发、产品、测试人员提供更优雅的接口管理服务。可以帮助开发者轻松创建、发布、维护、监控和保护任意规模的 APIyapi还为用户提供了优秀的交互体验开发人员只需利用平台提供的接口数据写入工具以及简单的点击操作就可以实现接口的管理。</p>
## 二、特性
* 完善的项目接口管理功能
* 易用的MockServer
* 类gitlab的用户管理和权限管理功能
* 强大的接口集功能
## 二、功能
* REST API
* MockServer
* 扁平化的项目管理
* 用户管理集成了qsso登录

View File

@ -52,21 +52,23 @@ export default class App extends Component {
return <Loading visible />;
} else {
r = (
<Router>
<div className="router-main">
{this.props.loginState !== 1 ? <Header /> : null}
<div className="router-container">
<Route exact path="/" component={Home} />
<Route path="/group" component={requireAuthentication(Group)} />
<Route path="/project/:id" component={requireAuthentication(Project)} />
<Route path="/user" component={requireAuthentication(User)} />
<Route path="/follow" component={requireAuthentication(Follows)} />
<Route path="/add-project" component={requireAuthentication(AddProject)} />
<Route path="/login" component={Login} />
{
// <Route path="/news" component={requireAuthentication(News)} />
// <Route path="/add-interface" component={requireAuthentication(AddInterface)} />
}
<Router >
<div className="g-main">
<div className="router-main">
{this.props.loginState !== 1 ? <Header /> : null}
<div className="router-container">
<Route exact path="/" component={Home} />
<Route path="/group" component={requireAuthentication(Group)} />
<Route path="/project/:id" component={requireAuthentication(Project)} />
<Route path="/user" component={requireAuthentication(User)} />
<Route path="/follow" component={requireAuthentication(Follows)} />
<Route path="/add-project" component={requireAuthentication(AddProject)} />
<Route path="/login" component={Login} />
{
// <Route path="/news" component={requireAuthentication(News)} />
// <Route path="/add-interface" component={requireAuthentication(AddInterface)} />
}
</div>
</div>
<Footer />
</div>

View File

@ -1,6 +1,7 @@
import './Footer.scss'
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { Row, Col } from 'antd';
import { Icon } from 'antd'
class Footer extends Component {
constructor(props) {
@ -10,23 +11,17 @@ class Footer extends Component {
footList: PropTypes.array
}
render () {
const style = {
'background': 'url(/image/footer-bac.jpg)'
}
return (
<div className = 'footer-wrapper'>
<div className = 'footer' style = {style}>
<div className = 'footContent'>
{ this.props.footList.map(function(item,i){
return <FootItem key = { i } linkList = { item.linkList } title = { item.title } iconType = { item.iconType } ></FootItem>
}) }
<div className = 'copyRight'>
<h4>Copyright © 2017</h4>
YMFF出品 @ YMFF
</div>
<div className="footer-wrapper">
<Row>
{ this.props.footList.map(function(item,i){
return <FootItem key={ i } linkList={ item.linkList } title={ item.title } iconType={ item.iconType } ></FootItem>
}) }
<div className="copyRight">
<h4>Copyright © 2017</h4>
YMFF出品 @ YMFF
</div>
<div className='footerMask'></div>
</div>
</Row>
</div>
)
}
@ -43,12 +38,12 @@ class FootItem extends Component {
}
render () {
return (
<div className = 'footItem'>
<h4><Icon type= { this.props.iconType } style={{ fontSize: 16 }} />&nbsp;&nbsp; { this.props.title } </h4>
<Col span={6}>
<h4><Icon type={ this.props.iconType } style={{ fontSize: 16 }} />&nbsp;&nbsp; { this.props.title } </h4>
{ this.props.linkList.map(function(item,i){
return (<div key = {i}>&nbsp;&nbsp;<a href = { item.itemLink }><span>{ item.itemTitle }</span></a></div>);
return (<div key={i}>&nbsp;&nbsp;<a href={ item.itemLink }><span>{ item.itemTitle }</span></a></div>);
}) }
</div>
</Col>
);
}
}

View File

@ -2,39 +2,10 @@
@import '../../styles/mixin.scss';
.footer-wrapper{
height: 2rem;
width: 100%;
}
.footer{
@include wrap-width-limit;
margin: 0 auto;
clear: both;
font-size: 12px;
background: #000c15;
position: relative;
z-index: 1;
color: rgba(255,255,255,.65);
box-shadow: 0 1000px 0 1000px #fff;
// background-image: url('image/footer-bac.jpg');
background-repeat: no-repeat;
background-position: center center;
h4{
margin-bottom: 20px;
color: #FFF;
i{
margin-left: -20px;
}
}
}
.footerMask{
@include wrap-width-limit;
position: absolute;
top: 0;
height: 100%;
width: 100%;
background-color: #404040;
opacity: .65;
z-index: 1;
}
.footContent{
@include row-width-limit;
//width:90%;

View File

@ -107,18 +107,38 @@ const HomeGuest = () => (
<Row className="row-card">
<Col span={12} className="section-card">
<Card title="Mock 规则">
<p>通过学习一些简单的 Mock 模板规则即可轻松编写接口这将大大提高定义接口的效率并且无需为编写 Mock 数据烦恼: 所有的数据都可以实时随机生成</p>
<p>通过学习一些简单的 Mock 模板规则即可轻松编写接口这将大大提高定义接口的效率并且无需为编写 Mock 数据烦恼: 所有的数据都可以实时随机生成</p>
<p>通过学习一些简单的 Mock 模板规则即可轻松编写接口这将大大提高定义接口的效率并且无需为编写 Mock 数据烦恼: 所有的数据都可以实时随机生成</p>
<p className="mock-desc">通过学习一些简单的 Mock 模板规则即可轻松编写接口这将大大提高定义接口的效率并且无需为编写 Mock 数据烦恼: 所有的数据都可以实时随机生成</p>
<div className="code">
<ol start="1">
<li className="alt"><span className="orderNum orderNum-first">1</span><span><span>&#123;&ensp;&ensp;</span></span></li>
<li className=""><span className="orderNum">2</span><span>&ensp;&ensp;&ensp;&ensp;<span className="string">&quot;errcode|200-500&quot;</span><span>:&ensp;200,&ensp;&ensp;</span></span></li>
<li className="alt"><span className="orderNum">3</span><span>&ensp;&ensp;&ensp;&ensp;<span className="string">&quot;errmsg|4-8&quot;</span><span>:&ensp;</span><span className="string">&quot;@string&quot;</span><span>,&ensp;&ensp;</span></span></li>
<li className=""><span className="orderNum">4</span><span>&ensp;&ensp;&ensp;&ensp;<span className="string">&quot;data&quot;</span><span>:&ensp;&#123;&ensp;&ensp;</span></span></li>
<li className="alt"><span className="orderNum">5</span><span>&ensp;&ensp;&ensp;&ensp;&ensp;&ensp;&ensp;&ensp;<span className="string">&quot;boolean|1&quot;</span><span>:&ensp;</span><span className="keyword">true</span><span>,&ensp;&ensp;</span></span></li>
<li className=""><span className="orderNum">6</span><span>&ensp;&ensp;&ensp;&ensp;&ensp;&ensp;&ensp;&ensp;<span className="string">&quot;array|4&quot;</span><span>:&ensp;1,&ensp;&ensp;</span></span></li>
<li className="alt"><span className="orderNum">7</span><span>&ensp;&ensp;&ensp;&ensp;&ensp;&ensp;&ensp;&ensp;<span className="string">&quot;combine&quot;</span><span>:&ensp;</span><span className="string">&quot;@boolean&ensp;&amp;&ensp;@array&quot;</span><span>&ensp;&ensp;</span></span></li>
<li className=""><span className="orderNum">8</span><span>&ensp;&ensp;&ensp;&ensp;&#125;&ensp;&ensp;</span></li>
<li className="alt"><span className="orderNum orderNum-last">9</span><span>&#125;&ensp;&ensp;</span></li>
</ol>
</div>
</Card>
</Col>
<Col span={12} className="section-card mock-after">
<Card title="生成的 Mock 数据">
<p>生成的 Mock 数据可以在线使用(配置Hosts后直接访问接口)也可以下载到本地使用</p>
<p>生成的 Mock 数据可以在线使用(配置Hosts后直接访问接口)也可以下载到本地使用</p>
<p>生成的 Mock 数据可以在线使用(配置Hosts后直接访问接口)也可以下载到本地使用</p>
<p>生成的 Mock 数据可以在线使用(配置Hosts后直接访问接口)也可以下载到本地使用</p>
<p>生成的 Mock 数据可以在线使用(配置Hosts后直接访问接口)也可以下载到本地使用</p>
<p className="mock-desc">生成的 Mock 数据可以在线使用(配置Hosts后直接访问接口)也可以下载到本地使用</p>
<div className="code">
<ol start="1">
<li className="alt"><span className="orderNum orderNum-first">1</span><span><span>&#123;&ensp;&ensp;</span></span></li>
<li className=""><span className="orderNum">2</span><span>&ensp;&ensp;<span className="string">&quot;errcode&quot;</span><span>:&ensp;</span><span className="number">304</span><span>,&ensp;&ensp;</span></span></li>
<li className="alt"><span className="orderNum">3</span><span>&ensp;&ensp;<span className="string">&quot;errmsg&quot;</span><span>:&ensp;</span><span className="string">&quot;JtkMIoRu)N#ie^h%Z77[F)&quot;</span><span>,&ensp;&ensp;</span></span></li>
<li className=""><span className="orderNum">4</span><span>&ensp;&ensp;<span className="string">&quot;data&quot;</span><span>:&ensp;&#123;&ensp;&ensp;</span></span></li>
<li className="alt"><span className="orderNum">5</span><span>&ensp;&ensp;&ensp;&ensp;<span className="string">&quot;boolean&quot;</span><span>:&ensp;</span><span className="keyword">true</span><span>,&ensp;&ensp;</span></span></li>
<li className=""><span className="orderNum">6</span><span>&ensp;&ensp;&ensp;&ensp;<span className="string">&quot;array&quot;</span><span>:&ensp;</span><span className="number">4</span><span>,&ensp;&ensp;</span></span></li>
<li className="alt"><span className="orderNum">7</span><span>&ensp;&ensp;&ensp;&ensp;<span className="string">&quot;combine&quot;</span><span>:&ensp;</span><span className="string">&quot;true&ensp;&amp;&ensp;4&quot;</span><span>&ensp;&ensp;</span></span></li>
<li className=""><span className="orderNum">8</span><span>&ensp;&ensp;&#125;&ensp;&ensp;</span></li>
<li className="alt"><span className="orderNum orderNum-last">9</span><span>&#125;&ensp;&ensp;</span></li>
</ol>
</div>
</Card>
</Col>
</Row>
@ -206,8 +226,6 @@ class Home extends Component {
</div>
)
: <HomeGuest introList={this.props.introList}/>}
<div style={{height: '1000px'}}>
</div>
</div>
)
}

View File

@ -9,6 +9,7 @@ $color-blue-light: #5dade2;
$color-black-lighter: #404040;
$color-text-dark: #2e2e5a;
$color-text-light: #6d7c90;
$color-bg-lightblue: #c6e2ff;
.g-body {
position: relative;
}
@ -360,13 +361,37 @@ $color-text-light: #6d7c90;
}
.ant-card-body {
text-align: left;
padding: 0;
}
.mock-desc {
padding: .32rem;
min-height: 8em;
}
padding: .08rem;
}
.code {
color: $color-text-dark;
background-color: $color-blue-grey-lighter;
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
.orderNum {
background-color: $color-bg-lightblue;
display: inline-block;
text-align: center;
width: .4rem;
margin-right: .5em;
}
.orderNum-first {
padding-top: .5em;
}
.orderNum-last {
border-bottom-left-radius: 4px;
padding-bottom: .5em;
}
}
.mock-after {
.ant-card-head {
background-color: #c6e2ff;
background-color: $color-bg-lightblue;
}
.ant-card-head-title {
color: #4074af;

View File

@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { Form, Button, Input, Icon, message } from 'antd';
import { loginActions } from '../../reducer/modules/user';
import { withRouter } from 'react-router'
const FormItem = Form.Item;
import './Login.scss'
@ -24,7 +25,7 @@ const changeHeight = {
loginActions
}
)
@withRouter
class Login extends Component {
constructor(props) {
super(props)
@ -32,6 +33,7 @@ class Login extends Component {
static propTypes = {
form: PropTypes.object,
history: PropTypes.object,
loginActions: PropTypes.func
}
@ -42,6 +44,7 @@ class Login extends Component {
if (!err) {
this.props.loginActions(values).then((res) => {
if (res.payload.data.errcode == 0) {
this.props.history.push('/');
message.success('登录成功! ');
} else {
message.error(res.payload.data.errmsg);

View File

@ -24,7 +24,8 @@ class InterfaceEdit extends Component {
curdata: PropTypes.object,
currProject: PropTypes.object,
updateInterfaceData: PropTypes.func,
match: PropTypes.object
match: PropTypes.object,
switchToView: PropTypes.func
}
constructor(props) {
@ -43,6 +44,7 @@ class InterfaceEdit extends Component {
if (result.data.errcode === 0) {
this.props.updateInterfaceData(params);
message.success('保存成功');
this.props.switchToView()
} else {
message.success(result.data.errmsg)
}
@ -85,7 +87,7 @@ class InterfaceEdit extends Component {
render() {
return <div className="interface-edit">
{this.state.status === 1 ?
<InterfaceEditForm mockUrl={this.state.mockUrl} basepath={this.props.currProject.basepath} onSubmit={this.onSubmit} curdata={this.state.curdata} />
<InterfaceEditForm cat={this.props.currProject.cat} mockUrl={this.state.mockUrl} basepath={this.props.currProject.basepath} onSubmit={this.onSubmit} curdata={this.state.curdata} />
:
null}
{

View File

@ -59,6 +59,12 @@ class Content extends Component {
})
}
switchToView = ()=>{
this.setState({
curtab: 'view'
})
}
onChange = (key) => {
this.setState({
curtab: key
@ -81,7 +87,7 @@ class Content extends Component {
if (this.state.curtab === 'view') {
tabContent = <View />;
} else if (this.state.curtab === 'edit') {
tabContent = <Edit />
tabContent = <Edit switchToView={this.switchToView} />
} else if (this.state.curtab === 'run') {
tabContent = <Run />
}

View File

@ -26,7 +26,8 @@ class InterfaceEditForm extends Component {
curdata: PropTypes.object,
mockUrl: PropTypes.string,
onSubmit: PropTypes.func,
basepath: PropTypes.string
basepath: PropTypes.string,
cat: PropTypes.array
}
constructor(props) {
@ -102,9 +103,9 @@ class InterfaceEditForm extends Component {
})
}
}
values.req_headers = values.req_headers.filter((item)=> item.name !== '')
values.req_body_form = values.req_body_form.filter((item)=> item.name !== '')
values.req_params = values.req_params.filter(item=>item.name !== '')
values.req_headers = values.req_headers.filter((item) => item.name !== '')
values.req_body_form = values.req_body_form.filter((item) => item.name !== '')
values.req_params = values.req_params.filter(item => item.name !== '')
this.props.onSubmit(values)
}
});
@ -336,6 +337,24 @@ class InterfaceEditForm extends Component {
)}
</FormItem>
<FormItem
{...formItemLayout}
label="选择分类"
>
{getFieldDecorator('catid', {
initialValue: _.find(this.props.cat, item=> item._id === this.state.catid).name,
rules: [
{ required: true, message: '请选择一个分类' }
]
})(
<Select placeholder="请选择一个分类">
{this.props.cat.map(item => {
return <Option key={item._id} value={item._id + ""} >{item.name}</Option>
})}
</Select>
)}
</FormItem>
<FormItem
className="interface-edit-item"
{...formItemLayout}

View File

@ -1,10 +1,18 @@
import React, { Component } from 'react'
import { connect } from 'react-redux';
import PropTypes from 'prop-types'
import axios from 'axios'
import {
Table, Tag
} from 'antd';
import { formatTime } from '../../../../common.js'
@connect(
state => {
return {
curProject: state.project.currProject
}
})
class InterfaceList extends Component {
constructor(props) {
super(props)
@ -18,7 +26,8 @@ class InterfaceList extends Component {
}
static propTypes = {
match: PropTypes.object
match: PropTypes.object,
curProject: PropTypes.object
}
handleRequest = async (props) => {
@ -69,9 +78,12 @@ class InterfaceList extends Component {
},
sortOrder: sortedInfo.columnKey === 'title' && sortedInfo.order
}, {
title: '接口URL',
title: '接口路径',
dataIndex: 'path',
key: 'path'
key: 'path',
render: (item)=>{
return <span>{this.props.curProject.basepath + item}</span>
}
}, {
title: '请求方式',
dataIndex: 'method',
@ -97,8 +109,8 @@ class InterfaceList extends Component {
onFilter: (value, record) => record.status.indexOf(value) === 0
}, {
title: '更新日期',
dataIndex: 'add_time',
key: 'add_time',
dataIndex: 'up_time',
key: 'up_time',
render: (item) => {
return <span>{formatTime(item)}</span>
}

View File

@ -17,7 +17,7 @@ const TreeNode = Tree.TreeNode;
return {
list: state.inter.list,
inter: state.inter.curdata,
curProject: state.project.curProject
curProject: state.project.currProject
}
},
{

View File

@ -21,12 +21,24 @@
background-color: #fff
}
.ant-tabs.ant-tabs-card > .ant-tabs-bar .ant-tabs-tab-active{
background-color: #efefef
background-color: #efefef;
color:#021b2d;
font-weight: 500
}
.ant-tabs.ant-tabs-card > .ant-tabs-bar .ant-tabs-nav-container{
height: 40px;
}
.ant-tabs.ant-tabs-card > .ant-tabs-bar{
text-align: center;
line-height: 40px;
height:40px;
}
.ant-tabs-nav-wrap{
height: 40px;
line-height: 31px;
}
.interface-filter{

View File

@ -39,13 +39,20 @@ em {
font-style: normal;
}
[data-reactroot], .g-main, .router-main {
height: 100%;
}
// 页面最外层元素 样式
.router-main {
display: -webkit-box;
-webkit-box-orient: vertical;
padding-bottom: .24rem;
min-height: 100%;
height: auto !important;
height: 100%;
.router-container{
min-height:calc(100% - 2.47rem);
margin-bottom: -2rem;
&::after {
content: '';
display: block;
height: 2rem;
}
}

View File

@ -94,7 +94,7 @@ class interfaceColController extends baseController{
try {
let id = ctx.query.col_id;
let inst = yapi.getInst(interfaceCaseModel);
let result = await inst.list(id);
let result = await inst.list(id, 'all');
ctx.body = yapi.commons.resReturn(result);
} catch (e) {
ctx.body = yapi.commons.resReturn(null, 402, e.message);

View File

@ -4,6 +4,7 @@ import baseController from './base.js';
import interfaceModel from '../models/interface.js';
import interfaceColModel from '../models/interfaceCol.js';
import interfaceCaseModel from '../models/interfaceCase.js';
import interfaceCatModel from '../models/interfaceCat.js';
import groupModel from '../models/group';
import commons from '../utils/commons.js';
import userModel from '../models/user.js';
@ -287,12 +288,14 @@ class projectController extends baseController {
return ctx.body = yapi.commons.resReturn(null, 400, '项目id不能为空');
}
try {
let result = await this.Model.get(params.id);
let result = await this.Model.getBaseInfo(params.id);
if(!result){
return ctx.body = yapi.commons.resReturn(null, 400, '不存在的项目');
}
result = result.toObject();
delete result.members;
let catInst = yapi.getInst(interfaceCatModel);
let cat = await catInst.list(params.id);
result.cat = cat;
result.role = await this.getProjectRole(params.id, 'project');
ctx.body = yapi.commons.resReturn(result);
} catch (e) {

View File

@ -11,17 +11,17 @@ class interfaceCase extends baseModel {
casename: { type: String, required: true },
uid: { type: Number, required: true },
col_id: { type: Number, required: true },
index: {type: Number, default:0},
index: { type: Number, default: 0 },
project_id: { type: Number, required: true },
add_time: Number,
up_time: Number,
env: { type: String },
domain: {type: String },
domain: { type: String },
path: { type: String },
method: { type: String },
req_params: [{
name: String, value: String
}],
}],
req_query: [{
name: String, value: String
}],
@ -51,7 +51,13 @@ class interfaceCase extends baseModel {
}).exec();
}
list(col_id) {
list(col_id, select) {
select = select || 'casename uid col_id _id index'
if (select === 'all') {
return this.model.find({
col_id: col_id
}).exec();
}
return this.model.find({
col_id: col_id
}).select("casename uid col_id _id index").exec();
@ -63,13 +69,13 @@ class interfaceCase extends baseModel {
});
}
delByProjectId(id){
delByProjectId(id) {
return this.model.deleteMany({
project_id: id
})
}
delByCol(id){
delByCol(id) {
return this.model.deleteMany({
col_id: id
})
@ -83,12 +89,12 @@ class interfaceCase extends baseModel {
);
}
upCaseIndex(id, index){
upCaseIndex(id, index) {
return this.model.update({
_id: id
},{
index: index
})
}, {
index: index
})
}
}

View File

@ -33,11 +33,17 @@ class projectModel extends baseModel {
return m.save();
}
get(id) {
console.log(id)
get(id) {
return this.model.findOne({
_id: id
}).exec();
}
getBaseInfo(id){
return this.model.findOne({
_id: id
}).select('_id uid name basepath desc group_id group_name project_type env icon color add_time up_time')
.exec()
}
getByDomain(domain) {

View File

@ -243,7 +243,7 @@ var interfaceColController = function (_baseController) {
id = ctx.query.col_id;
inst = _yapi2.default.getInst(_interfaceCase2.default);
_context3.next = 5;
return inst.list(id);
return inst.list(id, 'all');
case 5:
result = _context3.sent;

View File

@ -56,6 +56,10 @@ var _interfaceCase = require('../models/interfaceCase.js');
var _interfaceCase2 = _interopRequireDefault(_interfaceCase);
var _interfaceCat = require('../models/interfaceCat.js');
var _interfaceCat2 = _interopRequireDefault(_interfaceCat);
var _group = require('../models/group');
var _group2 = _interopRequireDefault(_group);
@ -636,7 +640,7 @@ var projectController = function (_baseController) {
key: 'get',
value: function () {
var _ref6 = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee6(ctx) {
var params, result;
var params, result, catInst, cat;
return _regenerator2.default.wrap(function _callee6$(_context6) {
while (1) {
switch (_context6.prev = _context6.next) {
@ -653,7 +657,7 @@ var projectController = function (_baseController) {
case 3:
_context6.prev = 3;
_context6.next = 6;
return this.Model.get(params.id);
return this.Model.getBaseInfo(params.id);
case 6:
result = _context6.sent;
@ -667,29 +671,36 @@ var projectController = function (_baseController) {
case 9:
result = result.toObject();
delete result.members;
catInst = _yapi2.default.getInst(_interfaceCat2.default);
_context6.next = 13;
return this.getProjectRole(params.id, 'project');
return catInst.list(params.id);
case 13:
cat = _context6.sent;
result.cat = cat;
_context6.next = 17;
return this.getProjectRole(params.id, 'project');
case 17:
result.role = _context6.sent;
ctx.body = _yapi2.default.commons.resReturn(result);
_context6.next = 20;
_context6.next = 24;
break;
case 17:
_context6.prev = 17;
case 21:
_context6.prev = 21;
_context6.t0 = _context6['catch'](3);
ctx.body = _yapi2.default.commons.resReturn(null, 402, _context6.t0.message);
case 20:
case 24:
case 'end':
return _context6.stop();
}
}
}, _callee6, this, [[3, 17]]);
}, _callee6, this, [[3, 21]]);
}));
function get(_x7) {

View File

@ -93,7 +93,13 @@ var interfaceCase = function (_baseModel) {
}
}, {
key: 'list',
value: function list(col_id) {
value: function list(col_id, select) {
select = select || 'casename uid col_id _id index';
if (select === 'all') {
return this.model.find({
col_id: col_id
}).exec();
}
return this.model.find({
col_id: col_id
}).select("casename uid col_id _id index").exec();

View File

@ -71,11 +71,17 @@ var projectModel = function (_baseModel) {
}, {
key: 'get',
value: function get(id) {
console.log(id);
return this.model.findOne({
_id: id
}).exec();
}
}, {
key: 'getBaseInfo',
value: function getBaseInfo(id) {
return this.model.findOne({
_id: id
}).select('_id uid name basepath desc group_id group_name project_type env icon color add_time up_time').exec();
}
}, {
key: 'getByDomain',
value: function getByDomain(domain) {