diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 00000000..1c80996a --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,42 @@ +module.exports = { + "env": { + "browser": true, + "commonjs": true, + "es6": true, + "node": true + }, + "extends": "eslint:recommended", + "parser": "babel-eslint", + "parserOptions": { + "ecmaFeatures": { + "experimentalObjectRestSpread": true, + "jsx": true + }, + "sourceType": "module" + }, + "plugins": [ + "react" + ], + "rules": { + "indent": [ + "error", + 4, + { + "SwitchCase": 1 + } + ], + "linebreak-style": [ + "error", + "unix" + ], + "quotes": [ + "error", + "single" + ], + "semi": [ + "error", + "always" + ], + "strict": 0 + } +}; \ No newline at end of file diff --git a/client/Application.js b/client/Application.js index 8212403e..8e19d7ec 100644 --- a/client/Application.js +++ b/client/Application.js @@ -1,22 +1,22 @@ -import React, { Component } from 'react' -import { connect } from 'react-redux' -import PropTypes from 'prop-types' -import { Route, HashRouter, Redirect, Switch } from 'react-router-dom' -import { Home, ProjectGroups, Interface, News, AddInterface } from './containers/index' -import User from './containers/User/User.js' -import Header from './components/Header/Header' -import Footer from './components/Footer/Footer' -import Loading from './components/Loading/Loading' -import { checkLoginState } from './actions/login' +import React, { Component } from 'react'; +import { connect } from 'react-redux'; +import PropTypes from 'prop-types'; +import { Route, HashRouter, Redirect, Switch } from 'react-router-dom'; +import { Home, ProjectGroups, Interface, News, AddInterface } from './containers/index'; +import User from './containers/User/User.js'; +import Header from './components/Header/Header'; +import Footer from './components/Footer/Footer'; +import Loading from './components/Loading/Loading'; +import { checkLoginState } from './actions/login'; import { requireAuthentication } from './components/AuthenticatedComponent'; const LOADING_STATUS = 0; @connect( state => { - return{ - loginState:state.login.loginState - } + return { + loginState: state.login.loginState + }; }, { checkLoginState @@ -27,20 +27,22 @@ export default class App extends Component { super(props); this.state = { login: LOADING_STATUS - } + }; } + static propTypes = { - checkLoginState:PropTypes.func, - loginState:PropTypes.number - } + checkLoginState: PropTypes.func, + loginState: PropTypes.number + }; componentDidMount() { this.props.checkLoginState(); } + route = (status) => { let r; if (status === LOADING_STATUS) { - return <Loading visible/> + return <Loading visible />; } else { r = ( <HashRouter> @@ -50,20 +52,21 @@ export default class App extends Component { <Route path="/" component={Home} exact /> <Switch> <Redirect exact from='/group' to='/group/1' /> - <Route exact path="/group/:groupName" component={ requireAuthentication(ProjectGroups) } /> + <Route exact path="/group/:groupName" component={requireAuthentication(ProjectGroups)} /> </Switch> <Route path="/Interface" component={requireAuthentication(Interface)} /> <Route path="/user" component={requireAuthentication(User)} /> <Route path="/News" component={requireAuthentication(News)} /> - <Route path="/AddInterface" component={ requireAuthentication(AddInterface) } /> + <Route path="/AddInterface" component={requireAuthentication(AddInterface)} /> </div> - <Footer/> + <Footer /> </div> </HashRouter> ) } - return r + return r; } + render() { return this.route(this.props.loginState); } diff --git a/client/components/AuthenticatedComponent.js b/client/components/AuthenticatedComponent.js index 2932c6ca..fe82d842 100644 --- a/client/components/AuthenticatedComponent.js +++ b/client/components/AuthenticatedComponent.js @@ -3,9 +3,18 @@ import { connect } from 'react-redux'; import PropTypes from 'prop-types' import { changeMenuItem } from '../actions/menu' - +@connect( + (state) => { + return{ + isAuthenticated: state.login.isLogin + } + }, + { + changeMenuItem + } +) export function requireAuthentication(Component) { - class AuthenticatedComponent extends React.Component { + return class AuthenticatedComponent extends React.Component { constructor(props){ super(props); } @@ -37,19 +46,8 @@ export function requireAuthentication(Component) { } </div> ) - } } - return connect( - (state) => { - return{ - isAuthenticated: state.login.isLogin - } - }, - { - changeMenuItem - } - )(AuthenticatedComponent); } diff --git a/client/components/Footer/Footer.scss b/client/components/Footer/Footer.scss index ab4ed7fc..521e2e6d 100644 --- a/client/components/Footer/Footer.scss +++ b/client/components/Footer/Footer.scss @@ -1,4 +1,5 @@ @import '../../styles/common.scss'; +@import '../../styles/mixin.scss'; .footer{ // max-width: 12rem; @@ -31,7 +32,7 @@ z-index: 1; } .footContent{ - max-width: 11rem; + @include row-width-limit; width:90%; margin:0px auto; overflow: hidden; @@ -52,7 +53,7 @@ color: white; } } - + } .copyRight{ padding: 24px 2%; @@ -68,4 +69,4 @@ position: relative; text-indent: 0em; } -} \ No newline at end of file +} diff --git a/client/components/Header/Header.js b/client/components/Header/Header.js index e308d072..5f58aa3b 100644 --- a/client/components/Header/Header.js +++ b/client/components/Header/Header.js @@ -66,8 +66,26 @@ ToolUser.propTypes={ }; + +@connect( + (state) => { + return{ + user: state.login.userName, + uid: state.login.uid, + msg: null, + login:state.login.isLogin, + curKey: state.menu.curKey + } + }, + { + loginTypeAction, + logoutActions, + checkLoginState, + changeMenuItem + } +) @withRouter -class HeaderCom extends Component { +export default class HeaderCom extends Component { constructor(props) { super(props); } @@ -129,13 +147,13 @@ class HeaderCom extends Component { render () { const { login, user, msg, uid, curKey } = this.props; const headerStyle = { - 'background': 'url(./image/bg-img.jpg) no-repeat center', - 'backgroundSize':'cover' + 'background': 'url(./image/header-bg-img.jpg) no-repeat', + 'backgroundSize':'100% 100%' } return ( <acticle className={`header-box`} style={headerStyle}> <Header style={{ - background: "linear-gradient(to bottom,rgba(64,64,64,1),rgba(64,64,64,0.9))" + background: "linear-gradient(to bottom,rgba(0,0,0,0.6),rgba(0,0,0,0.5))" }}> <div className="content"> <div className="logo"> @@ -173,22 +191,4 @@ class HeaderCom extends Component { </acticle> ) } -} - -export default connect( - (state) => { - return{ - user: state.login.userName, - uid: state.login.uid, - msg: null, - login:state.login.isLogin, - curKey: state.menu.curKey - } - }, - { - loginTypeAction, - logoutActions, - checkLoginState, - changeMenuItem - } -)(HeaderCom) \ No newline at end of file +} \ No newline at end of file diff --git a/client/components/Header/Header.scss b/client/components/Header/Header.scss index df310905..0c478555 100644 --- a/client/components/Header/Header.scss +++ b/client/components/Header/Header.scss @@ -1,4 +1,6 @@ @import '../../styles/common.scss'; +@import '../../styles/mixin.scss'; + $color-white : #fff; $color-blue : #108ee9; $color-blue-deeper: #34495E; @@ -20,7 +22,7 @@ $color-black-light : #404040; z-index: 99; // 内容宽度 .content { - max-width: 11rem; + @include row-width-limit; margin: 0 auto; zoom: 1; overflow: hidden; @@ -85,4 +87,3 @@ $color-black-light : #404040; } } } - diff --git a/client/constants/variable.js b/client/constants/variable.js index a9265d45..e0ad6b4e 100644 --- a/client/constants/variable.js +++ b/client/constants/variable.js @@ -1,7 +1,3 @@ export default { - PAGE_LIMIT: 10, // 默认每页展示10条数据 - - // layout - ROW_MIN_WIDTH: '9.7rem', // 适应小屏幕分辨率 - ROW_MAX_WIDTH: '11.7rem' // 适应大屏幕分辨率 + PAGE_LIMIT: 10 // 默认每页展示10条数据 } diff --git a/client/containers/AddInterface/AddInterface.scss b/client/containers/AddInterface/AddInterface.scss index 2bee99f2..fb33b696 100644 --- a/client/containers/AddInterface/AddInterface.scss +++ b/client/containers/AddInterface/AddInterface.scss @@ -1,3 +1,5 @@ +@import '../../styles/mixin.scss'; + .add-interface-box { -webkit-box-flex: 1; font-size: .14rem; @@ -5,7 +7,7 @@ overflow-y: auto; .content { - max-width: 11rem; + @include row-width-limit; margin: 24px auto; border-radius: 4px; box-shadow: 0 2px 4px 0 rgba(0,0,0,0.20); @@ -169,7 +171,7 @@ color: #CCC; } } - + /* .mock-url-box.css */ .mock-url-box { clear: both; diff --git a/client/containers/AddInterface/InterfaceTest/InterfaceTest.js b/client/containers/AddInterface/InterfaceTest/InterfaceTest.js index b79fb77a..8a6f8df1 100644 --- a/client/containers/AddInterface/InterfaceTest/InterfaceTest.js +++ b/client/containers/AddInterface/InterfaceTest/InterfaceTest.js @@ -43,7 +43,15 @@ export default class InterfaceTest extends Component { state = { res: '', - header: {} + method: 'GET', + domains: [], + pathname: '', + query: {}, + params: {}, + paramsNotJson: false, + headers: {}, + search: '', + currDomain: '' } constructor(props) { @@ -51,21 +59,42 @@ export default class InterfaceTest extends Component { } componentWillMount() { + this.interfacePropsToState() + } + componentWillReceiveProps(nextProps) { + this.interfacePropsToState(nextProps) } @autobind - testInterface() { - const { method, url, seqGroup, interfaceProject } = this.props; - const { prd_host, basepath, protocol } = interfaceProject; - const reqParams = JSON.parse(this.props.reqParams); + interfacePropsToState(nextProps) { + const props = nextProps || this.props; + const { method, url, seqGroup, interfaceProject } = props; + const { prd_host, basepath, protocol, env } = interfaceProject; + const pathname = (basepath + url).replace(/\/+/g, '/'); + + const domains = {prd: protocol + '://' + prd_host}; + env.forEach(item => { + domains[item.name] = item.domain; + }) const query = {}; + let params = {}; + let reqParams = this.props.reqParams ? this.props.reqParams : '{}'; + let paramsNotJson = false; + try { + reqParams = JSON.parse(reqParams) + paramsNotJson = false; + } catch (e) { + paramsNotJson = true; + } if (method === 'GET') { Object.keys(reqParams).forEach(key => { - const value = typeof reqParams[key] === 'object' ? JSON.stringify(reqParams) : reqParams.toString(); + const value = typeof reqParams[key] === 'object' ? JSON.stringify(reqParams[key]) : reqParams[key].toString(); query[key] = value; }) + } else if (method === 'POST') { + params = reqParams; } const headers = {} @@ -75,10 +104,27 @@ export default class InterfaceTest extends Component { } }) + this.setState({ + domains, + pathname, + query, + params, + paramsNotJson, + headers, + currDomain: domains.prd + }); + } + + @autobind + testInterface() { + const { method } = this.props; + const { pathname, query, headers, params, currDomain } = this.state; + const urlObj = URL.parse(currDomain); + const href = URL.format({ - protocol: protocol || 'http', - host: prd_host, - pathname: (basepath + url).replace(/\/+/g, '/'), + protocol: urlObj.protocol || 'http', + host: urlObj.host, + pathname, query }); @@ -86,9 +132,7 @@ export default class InterfaceTest extends Component { url: href, method, headers, - data: { - a:1 - }, + data: params, success: (res, header) => { console.log(header) this.setState({res}) @@ -96,33 +140,38 @@ export default class InterfaceTest extends Component { }) } + @autobind + changeDomain(value) { + const domain = this.state.domains[value]; + this.setState({ currDomain: domain }); + } + + @autobind + changeHeader(e, key) { + const headers = JSON.parse(JSON.stringify(this.state.headers)); + headers[key] = e.target.value; + this.setState({ headers }); + } + + @autobind + changeQuery(e, key) { + const query = JSON.parse(JSON.stringify(this.state.query)); + query[key] = e.target.value; + this.setState({ query }); + } + + @autobind + changeParams(e, key) { + const params = JSON.parse(JSON.stringify(this.state.params)); + params[key] = e.target.value; + this.setState({ params }); + } + render () { - const { method, url, seqGroup, interfaceName, interfaceProject } = this.props; - const { prd_host, basepath, protocol, env } = interfaceProject; - const reqParams = this.props.reqParams ? JSON.parse(this.props.reqParams) : []; - const pathname = (basepath + url).replace(/\/+/g, '/'); - - const domains = [{name: 'prd', domain: protocol + '://' + prd_host}]; - env.forEach(item => { - domains.push({name: item.name, domain: item.domain}); - }) - - const query = {}; - if (method === 'GET') { - Object.keys(reqParams).forEach(key => { - const value = typeof reqParams[key] === 'object' ? JSON.stringify(reqParams[key]) : reqParams[key].toString(); - query[key] = value; - }) - } - - const headers = {} - seqGroup.forEach((headerItem) => { - if (headerItem.name) { - headers[headerItem.name] = headerItem.value; - } - }) + const { interfaceName, method } = this.props; + const { domains, pathname, query, headers, params, paramsNotJson } = this.state; const search = URL.format({ query }); @@ -135,40 +184,58 @@ export default class InterfaceTest extends Component { <div className="req-row href"> <InputGroup compact style={{display: 'inline-block', width: 680}}> <Input value={method} disabled style={{display: 'inline-block', width: 80}} /> - <Select defaultValue="prd" style={{display: 'inline-block', width: 300}}> + <Select defaultValue="prd" style={{display: 'inline-block', width: 300}} onChange={this.changeDomain}> { - domains.map((item, index) => (<Option value={item.name} key={index}>{item.domain}</Option>)) + Object.keys(domains).map((key, index) => (<Option value={key} key={index}>{domains[key]}</Option>)) } </Select> - <Input value={pathname+search} style={{display: 'inline-block', width: 300}} /> + <Input value={pathname+search} disabled style={{display: 'inline-block', width: 300}} /> </InputGroup> <Button onClick={this.testInterface} type="primary" style={{marginLeft: 10}}>发送</Button> </div> - <Card noHovering style={{marginTop: 10}} className={Object.keys(headers).length ? '' : 'hidden'}> + <Card title="HEADERS" noHovering style={{marginTop: 10}} className={Object.keys(headers).length ? '' : 'hidden'}> <div className="req-row headers"> - HEADERS: { Object.keys(headers).map((key, index) => { return ( <div key={index}> <Input disabled value={key} style={{display: 'inline-block', width: 200, margin: 10}} />{' = '} - <Input value={headers[key]} style={{display: 'inline-block', width: 200, margin: 10}} /> + <Input value={headers[key]} onChange={e => this.changeHeader(e, key)} style={{display: 'inline-block', width: 200, margin: 10}} /> </div> ) }) } </div> </Card> - <Card noHovering style={{marginTop: 10}} className={Object.keys(reqParams).length ? '' : 'hidden'}> - <div className="req-row params"> - 请求参数: + <Card title="Query" noHovering style={{marginTop: 10}} className={Object.keys(query).length ? '' : 'hidden'}> + <div className="req-row query"> { - Object.keys(reqParams).map((key, index) => { - const value = typeof reqParams[key] === 'object' ? JSON.stringify(reqParams[key]) : reqParams[key].toString(); + Object.keys(query).map((key, index) => { + const value = typeof query[key] === 'object' ? JSON.stringify(query[key]) : query[key].toString(); return ( <div key={index}> <Input disabled value={key} style={{display: 'inline-block', width: 200, margin: 10}} />{' = '} - <Input value={value} style={{display: 'inline-block', width: 200, margin: 10}} /> + <Input value={value} onChange={e => this.changeQuery(e, key)} style={{display: 'inline-block', width: 200, margin: 10}} /> + </div> + ) + }) + } + </div> + </Card> + <Card title="Body" noHovering style={{marginTop: 10}} className={Object.keys(params).length ? '' : 'hidden'}> + <div className="req-row params"> + { paramsNotJson ? + <TextArea + value={params} + style={{margin: 10}} + autosize={{ minRows: 2, maxRows: 6 }} + ></TextArea> : + Object.keys(params).map((key, index) => { + const value = typeof params[key] === 'object' ? JSON.stringify(params[key]) : params[key].toString(); + return ( + <div key={index}> + <Input disabled value={key} style={{display: 'inline-block', width: 200, margin: 10}} />{' = '} + <Input value={value} onChange={e => this.changeParams(e, key)} style={{display: 'inline-block', width: 200, margin: 10}} /> </div> ) }) @@ -176,9 +243,8 @@ export default class InterfaceTest extends Component { </div> </Card> </div> - <Card noHovering style={{marginTop: 10}}> + <Card title="返回结果" noHovering style={{marginTop: 10}}> <div className="res-part"> - 返回结果: <div> <TextArea value={this.state.res ? JSON.stringify(this.state.res, 2) : ''} diff --git a/client/containers/AddInterface/MockUrl/MockUrl.js b/client/containers/AddInterface/MockUrl/MockUrl.js index cfc8b81b..0dce9dac 100644 --- a/client/containers/AddInterface/MockUrl/MockUrl.js +++ b/client/containers/AddInterface/MockUrl/MockUrl.js @@ -24,7 +24,7 @@ class MockUrl extends Component { clipboard () { const btn = document.querySelector('#mock-clipboard') const txt = document.querySelector('#mock-p').innerHTML - console.log('txt', txt) + new Clipboard(btn, { text: () => txt, target () { diff --git a/client/containers/AddInterface/ReqHeader/ReqList.js b/client/containers/AddInterface/ReqHeader/ReqList.js index 21db94e1..4e3a6f83 100644 --- a/client/containers/AddInterface/ReqHeader/ReqList.js +++ b/client/containers/AddInterface/ReqHeader/ReqList.js @@ -6,7 +6,8 @@ import { autobind } from 'core-decorators' import { reqTagValue, reqHeaderValue, - deleteReqHeader + deleteReqHeader, + addReqHeader } from '../../../actions/addInterface.js' @connect( @@ -20,7 +21,8 @@ import { { reqTagValue, reqHeaderValue, - deleteReqHeader + deleteReqHeader, + addReqHeader } ) @@ -30,6 +32,7 @@ class ReqList extends Component { reqTagValue: PropTypes.func, reqHeaderValue: PropTypes.func, deleteReqHeader: PropTypes.func, + addReqHeader: PropTypes.func, _id: PropTypes.number, dataNum: PropTypes.number, value: PropTypes.object @@ -43,12 +46,32 @@ class ReqList extends Component { handleChange (value) { const dir = 'AddInterface/edit' const url = location.href + const newObject = [] + if (url.includes(dir)) { const { seqGroup, value: { id } } = this.props - seqGroup[id].name = value + seqGroup.forEach(v => { + if (id == v.id) { + v.name = value + } + }) + seqGroup.forEach(v => { + const {id, name, value} = v + newObject.push({id, name, value}) + }) + this.props.addReqHeader( newObject ) } else { const { seqGroup, dataNum } = this.props - seqGroup[dataNum].name = value + seqGroup.forEach(v => { + if (dataNum == v.id) { + v.name = value + } + }) + seqGroup.forEach(v => { + const {id, name, value} = v + newObject.push({id, name, value}) + }) + this.props.addReqHeader(newObject) } } @@ -56,7 +79,17 @@ class ReqList extends Component { handleBlur (e) { const value = e.target.value const { seqGroup, value: { id } } = this.props - seqGroup[id].value = value + const newObject = [] + seqGroup.forEach(v => { + if (id == v.id) { + v.value = value + } + }) + seqGroup.forEach(v => { + const {id, name, value} = v + newObject.push({id, name, value}) + }) + this.props.addReqHeader(newObject) } @autobind @@ -76,13 +109,13 @@ class ReqList extends Component { render () { const propsValue = this.props.value const Option = Select.Option - const value = propsValue.value + const value = propsValue.value || '' const name = propsValue.name || '' - + console.log(name) return ( <li> <em className="title">头部标签</em> - <Select defaultValue={name} style={{ width: 220 }} onChange={this.handleChange} size="large"> + <Select value={name} style={{ width: 220 }} onChange={this.handleChange} size="large"> <Option value="">选择请求头</Option> <Option value="Accept">Accept</Option> <Option value="Accept-Charset">Accept-Charset</Option> @@ -91,7 +124,7 @@ class ReqList extends Component { <Option value="Accept-Ranges">Accept-Ranges</Option> </Select> <em className="title">头部内容</em> - <Input defaultValue={value} placeholder="Basic usage" className="req-content" size="large" onBlur={this.handleBlur} /> + <Input value={value} placeholder="Basic usage" className="req-content" size="large" onInput={this.handleBlur} /> <Icon className="dynamic-delete-button" type="minus-circle-o" onClick={this.deleteReqHeader} /> </li> ) diff --git a/client/containers/AddInterface/ReqMethod/ReqMethod.js b/client/containers/AddInterface/ReqMethod/ReqMethod.js index 286120a8..2be444e2 100644 --- a/client/containers/AddInterface/ReqMethod/ReqMethod.js +++ b/client/containers/AddInterface/ReqMethod/ReqMethod.js @@ -58,6 +58,7 @@ class ReqMethod extends Component { render () { const { Option } = Select const { url, interfaceName, method } = this.props + return ( <table> <tbody> @@ -65,7 +66,7 @@ class ReqMethod extends Component { <th>协议 :</th> <td> <span className="h3">请求方式</span> - <Select defaultValue={method} style={{ width: 220 }} onChange={this.handleChange} size="large"> + <Select value={method} style={{ width: 220 }} onChange={this.handleChange} size="large"> <Option value="POST">POST</Option> <Option value="GET">GET</Option> <Option value="PUT">PUT</Option> diff --git a/client/containers/AddInterface/Result/Result.js b/client/containers/AddInterface/Result/Result.js index ee2ad149..25c2149b 100644 --- a/client/containers/AddInterface/Result/Result.js +++ b/client/containers/AddInterface/Result/Result.js @@ -27,7 +27,7 @@ class Result extends Component { render () { const TabPane = Tabs.TabPane const { mockJson } = this.props - console.log('mockJson', typeof mockJson, mockJson) + return ( <div className="result"> <Tabs defaultActiveKey="1"> diff --git a/client/containers/Home/Home.js b/client/containers/Home/Home.js index 478963de..e04d78a7 100644 --- a/client/containers/Home/Home.js +++ b/client/containers/Home/Home.js @@ -17,19 +17,19 @@ const imgAnim = { y: '+=50', opacity: 0, type: 'from', ease: 'easeOutQuad', dura const style = { 'height':'100%', 'width':'100%', - 'background': 'url(./image/bg-img.jpg) no-repeat center', - 'backgroundSize':'cover' + 'background': 'url(./image/bg-img.jpg) no-repeat', + 'backgroundSize':'100% 100%' } const HomeGuest = (props) => ( <div> <div className="main-one" style = {style}> - <div style={{ background: "linear-gradient(to bottom,rgba(64,64,64,0.9),rgba(64,64,64,0.5))"}}> + <div style={{ background: "linear-gradient(to bottom,rgba(0,0,0,0.5),rgba(0,0,0,0.2))"}}> <div className="container"> <Row> <Col span={24}> <div className="home-des"> <p className="title">YAPI</p> - <div className="detail">一个高效,易用,可部署的Api管理系统</div> + <div className="detail">高效、易用、可部署的API管理平台,旨在为开发、产品、测试人员提供更优雅的接口管理服务</div> </div> </Col> </Row> @@ -62,7 +62,7 @@ const HomeGuest = (props) => ( <TweenOne key="feat-motion-one" animation={oneAnim} - component="h3" + component="p" > <span>特性</span> </TweenOne> diff --git a/client/containers/Home/Home.scss b/client/containers/Home/Home.scss index 9e40753b..f62eb0f6 100644 --- a/client/containers/Home/Home.scss +++ b/client/containers/Home/Home.scss @@ -1,4 +1,5 @@ @import '../../styles/common.scss'; +@import '../../styles/mixin.scss'; $color-white : #fff; $color-blue-lighter : #f1f5ff; @@ -12,7 +13,7 @@ $color-black-lighter: #404040; -webkit-box-orient: vertical; .main-one{ .home-des{ - color: $color-white; + color: $color-blue-grey-lighter; padding: .5rem 0 0; .title{ font-size: .6rem; @@ -29,7 +30,8 @@ $color-black-lighter: #404040; img{ width: 100%; height: 100%; - box-shadow : 0 0 3px 0 $color-black-lighter; + //box-shadow : 0 0 3px 0 $color-black-lighter; + box-shadow : 0 30px 60px rgba(0,0,0,0.2); border-radius: .03rem; } } @@ -39,16 +41,17 @@ $color-black-lighter: #404040; } .main-one-right{ padding-left: .5rem; + padding-top: .3rem; } } .user-home{ display: flex; align-items: center; height: 100%; - max-width: 11rem; + @include row-width-limit; margin: 1rem auto 0; .user-des{ - max-width: 11rem; + @include row-width-limit; margin: 0 auto .5rem; text-align: center; .title{ @@ -82,13 +85,13 @@ $color-black-lighter: #404040; .feat-part{ padding: .9rem .5rem; background-color: $color-white; - h3{ + p{ display: flex; height: .3rem; align-items: center; padding: 0 .1rem; margin-bottom: .2rem; - color: #333; + //color: #333; &:before, &:after{ content: ""; display: inline-block; @@ -104,7 +107,7 @@ $color-black-lighter: #404040; } } .container{ - max-width: 11rem; + @include row-width-limit; margin: 0 auto; height:100%; position: relative; @@ -129,7 +132,6 @@ $color-black-lighter: #404040; .feat-title { font-size: .16rem; line-height: .3rem; - color: #333; } &:first-child { .feat-img { @@ -153,5 +155,3 @@ $color-black-lighter: #404040; } } } - - diff --git a/client/containers/Interface/Interface.js b/client/containers/Interface/Interface.js index 161c6063..6903506c 100644 --- a/client/containers/Interface/Interface.js +++ b/client/containers/Interface/Interface.js @@ -58,7 +58,7 @@ class Interface extends Component { .then(result => { result = result.data.data result.map(value => { - value.add_time = moment(value.add_time).format('YYYY-MM-DD HH:mm:ss') + value.add_time = moment(value.add_time*1000).format('YYYY-MM-DD HH:mm:ss') return value }) this.props.fetchInterfaceData(result) diff --git a/client/containers/Interface/Interface.scss b/client/containers/Interface/Interface.scss index 892a521d..4f47a523 100644 --- a/client/containers/Interface/Interface.scss +++ b/client/containers/Interface/Interface.scss @@ -1,6 +1,8 @@ +@import '../../styles/mixin.scss'; + /* .interface-box.css */ .interface-box { - max-width: 11rem; + @include row-width-limit; margin: 24px auto; border-radius: 4px; box-shadow: 0 2px 4px 0 rgba(0,0,0,0.20); diff --git a/client/containers/Interface/InterfaceTable/InterfaceTable.js b/client/containers/Interface/InterfaceTable/InterfaceTable.js index 8df22ee6..170514b0 100644 --- a/client/containers/Interface/InterfaceTable/InterfaceTable.js +++ b/client/containers/Interface/InterfaceTable/InterfaceTable.js @@ -81,14 +81,11 @@ class InterfaceTable extends Component { title: '功能', 'key': 'action', render: (data) => { - // const deleteInterface = this.deleteInterface.bind(this, data._id) const confirm = this.confirm.bind(this, data._id) return ( <span> <Link to={`/AddInterface/edit/${data._id}`}><span>编辑</span></Link> <span className="ant-divider" /> - <Link to={`/AddInterface/edit/${data._id}`}><span>测试</span></Link> - <span className="ant-divider" /> <Popconfirm title="是否删除接口!" onConfirm={confirm} okText="Yes" cancelText="No"> <a href="">删除</a> </Popconfirm> diff --git a/client/containers/Login/Login.scss b/client/containers/Login/Login.scss index 8c4420c7..3eb7cc3f 100644 --- a/client/containers/Login/Login.scss +++ b/client/containers/Login/Login.scss @@ -18,14 +18,14 @@ .qsso-breakline{ display: flex; align-items: center; - color: #999; + color: #f7fafc; margin: .2rem auto; &:before, &:after{ content: ""; display: inline-block; height: .02rem; flex: 1; - border-top: .01rem solid #bbb; + border-top: .01rem solid #f7fafc; } .qsso-breakword{ padding: 0 .1rem; diff --git a/client/containers/Login/LoginWrap.js b/client/containers/Login/LoginWrap.js index bd716d06..0c0947b6 100644 --- a/client/containers/Login/LoginWrap.js +++ b/client/containers/Login/LoginWrap.js @@ -7,8 +7,12 @@ import RegForm from './Reg'; import './Login.scss'; const TabPane = Tabs.TabPane; - -class LoginWrap extends Component { +@connect( + state =>({ + loginWrapActiveKey: state.login.loginWrapActiveKey + }) +) +export default class LoginWrap extends Component { constructor(props){ super(props); } @@ -32,9 +36,3 @@ class LoginWrap extends Component { ); } } - -export default connect( - state =>({ - loginWrapActiveKey: state.login.loginWrapActiveKey - }) -)(LoginWrap) diff --git a/client/containers/News/News.scss b/client/containers/News/News.scss index 8b605296..68b115c9 100644 --- a/client/containers/News/News.scss +++ b/client/containers/News/News.scss @@ -1,6 +1,8 @@ +@import '../../styles/mixin.scss'; + /* .interface-box.css */ .news-box { - max-width: 11rem; + @include row-width-limit; display: -webkit-box; -webkit-box-flex: 1; margin: .88rem auto 0 auto; diff --git a/client/containers/ProjectGroups/ProjectGroups.scss b/client/containers/ProjectGroups/ProjectGroups.scss index 53a31cf5..e57e92c8 100644 --- a/client/containers/ProjectGroups/ProjectGroups.scss +++ b/client/containers/ProjectGroups/ProjectGroups.scss @@ -1,4 +1,6 @@ +@import '../../styles/mixin.scss'; + .g-doc { - max-width: 11rem; + @include row-width-limit; margin: .24rem auto; } diff --git a/client/containers/ProjectGroups/ProjectList/ProjectList.js b/client/containers/ProjectGroups/ProjectList/ProjectList.js index a886e2c3..e53b8306 100644 --- a/client/containers/ProjectGroups/ProjectList/ProjectList.js +++ b/client/containers/ProjectGroups/ProjectList/ProjectList.js @@ -206,13 +206,18 @@ class ProjectList extends Component { componentWillReceiveProps(nextProps) { // 切换分组 if (this.props.currGroup !== nextProps.currGroup) { - this.props.fetchProjectList(nextProps.currGroup._id, this.props.currPage).then((res) => { - if (res.payload.data.errcode) { - message.error(res.payload.data.errmsg); - } else { - this.props.changeTableLoading(false); - } - }); + if (nextProps.currGroup._id) { + this.props.fetchProjectList(nextProps.currGroup._id, this.props.currPage).then((res) => { + if (res.payload.data.errcode) { + message.error(res.payload.data.errmsg); + } else { + this.props.changeTableLoading(false); + } + }); + } else { + // 无分组的时候停止loading状态 + this.props.changeTableLoading(false); + } } // 切换项目列表 @@ -306,7 +311,9 @@ class ProjectList extends Component { </Form> </Modal> <UpDateModal/> - <Button className="m-btn" icon="plus" type="primary" onClick={this.showAddProjectModal}>创建项目</Button> + <Button className="m-btn" icon="plus" type="primary" + onClick={this.showAddProjectModal} + disabled={this.props.currGroup._id ? false : true}>创建项目</Button> <Table className="m-table" bordered={true} diff --git a/client/containers/User/index.scss b/client/containers/User/index.scss index 374db48d..56dca065 100644 --- a/client/containers/User/index.scss +++ b/client/containers/User/index.scss @@ -1,16 +1,18 @@ +@import '../../styles/mixin.scss'; + /* .user-box.css */ .user-box { - max-width: 11rem; + @include row-width-limit; display: -webkit-box; -webkit-box-flex: 1; margin: .88rem auto 0 auto; // font-size: 0.14rem; - - + + margin-top: 40px; margin-bottom: 55px; - + .user-list { width: 216px; @@ -19,7 +21,7 @@ border-radius:5px; margin-top: 15px; .search{ - margin: 5px; + margin: 5px; } ul{border:none} } @@ -38,7 +40,7 @@ .user-table { -webkit-box-flex: 1; padding: 24px; - margin-left: 15px; + margin-left: 15px; border-radius:5px; box-shadow: 0 2px 4px 0 rgba(0,0,0,0.20); background: #FFF; @@ -96,4 +98,4 @@ } -} \ No newline at end of file +} diff --git a/client/styles/mixin.scss b/client/styles/mixin.scss new file mode 100644 index 00000000..0489cf44 --- /dev/null +++ b/client/styles/mixin.scss @@ -0,0 +1,4 @@ +@mixin row-width-limit { + max-width: 11.7rem; + min-width: 9.7rem; +} diff --git a/doc/api_doc.md b/doc/api_doc.md deleted file mode 100644 index e9765d3a..00000000 --- a/doc/api_doc.md +++ /dev/null @@ -1,35 +0,0 @@ -### 1.User -- /user/get //获取用户个人信息 -- /user/list //获取用户列表,需要提供分页功能 -- /user/del //删除用户 -- /user/up //更新用户个人信息 -- /uesr/login //登录 -- /user/reg //注册 -- /user/login/status //获取用户登录状态 - -### 2.Group -- /group/list //获取项目分组列表 -- /group/add //添加 -- /group/up //更新 -- /group/del //删除 - -### 3.Project -- /project/list/:group_id -- /project/add //添加项目 -- /project/up //编辑项目 -- /project/del //删除项目 -- /project/add_member //添加项目成员 -- /project/del_member //删除项目成员 -- /project/get //获取一个项目详细信息 - - - -### 4.interface -- /interface/list/:project_id -- /interface/add -- /interface/up -- /interface/del -- /interface/mock //执行用户定义的mock,返回mock结果 - -### 5. mock服务器 -用户修改host指到yapi服务器,yapi服务器收到请求后根据domain/basepath 找到相对应的项目,根据req信息,找到对应的接口,执行用户定义的mock数据,返回给用户相应的结果 diff --git a/doc/db_dict.md b/doc/db_dict.md deleted file mode 100644 index 9c3a747a..00000000 --- a/doc/db_dict.md +++ /dev/null @@ -1,93 +0,0 @@ -### 数据库字典 -### 数据库基于mongodb -#### 1.User数据表,表名:user -```json -{ - _id: (int) - username: (string) - password: (sha1) - passsalt: (string) - email : (string) - role : (string) - add_time: (int) - up_time: (int) -} -```` - -#### 2.Project 数据表,表名:project -```json -{ - _id: (int) - uid : (int) - name: (string) - basepath: (string) - desc: (string) - group_id: (int) - members: [ - ... //成员uid - ] - prd_host: (string)//网站上线的domain,可用来获取mock数据 - env:(object){ - 'local环境' : 'http://127.0.0.1' - } - add_time: (int) - up_time: (int) -} -```` - -#### 3.api 数据表,表名:interface -```json -{ - _id: (int) - uid: (int) //负责人uid - path: (string) - group_id: (int) - status: (int) - desc : (string) - add_time: (int) - up_time : (int) - req_headers:(Object){ - "header_name":(Object){ - default_value: (string), - desc: (string), - mock: (string) - } - } - req_params_type: (form|raw) - req_params: (Object){ - "key" : (Object){ - default_value: (string), - desc: (string), - mock: (string) - } - } - res_header: (Object){ - "header_name":(Object){ - default_value: (string), - desc: (string), - mock: (string) - } - } - res_body_type: (text|json), - res_body: (Object){ - "key":(Object){ - default_value: (string), - desc: (string), - mock: (string) - } - } -} - -``` - -#### 4.项目分组,表名: group -```json -{ - _id: (int), - uid: (int), - group_name: (string), - group_desc: (string), - add_time: (int), - up_time: (int) -} -``` diff --git a/gulpfile.js b/gulpfile.js index d29eb3cb..7f79ee0e 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -1,11 +1,12 @@ const fs = require('fs-extra'); const path = require('path'); const gulp = require('gulp'); +const watch = require('gulp-watch'); const babel = require('gulp-babel'); const ora = require('ora'); const chalk = require('chalk'); const { spawn } = require('child_process'); -let spinner = ora('请稍等...').start(); +let spinner = null; const DIST = 'server_dist/'; const SRC = 'server/**/*.js'; @@ -30,21 +31,18 @@ function generateBabel(status) { } function excuteCmd(cmd, args, opts) { - const command = spawn(cmd, args, opts); + const NAME = cmd === 'ykit' ? chalk.cyan('[ykit]') : chalk.blue('[dev-server]'); + let command = spawn(cmd, args, opts); command.stdout.on('data', data => { - output('log', `${cmd}: ${data.toString()}`, true); + output('log', `${NAME} ${data.toString()}`, true); }); command.stderr.on('data', data => { - output('log', `${cmd}: ${data.toString()}`, true); + output('log', `${NAME} ${data.toString()}`, true); }); - command.on('close', code => { - if (code !== 0) { - output('log', `${cmd}: ${data.toString()}`); - } - }); + return command; } function output(type, message, restart = false) { @@ -64,25 +62,29 @@ function output(type, message, restart = false) { } } +function waitingSpinner() { + spinner = ora({ + text: '等待文件变更...', + spinner: 'circleQuarters', + color: 'cyan' + }).start(); +} + gulp.task('removeDist', [], function () { return fs.removeSync(DIST) }); gulp.task('initialBuild', ['removeDist'], () => { - spinner.text = '初始编译...'; + spinner = ora('初始编译...').start(); return gulp.src(SRC) .pipe(generateBabel()) .pipe(gulp.dest(DIST)) .on('end', () => { output('success', '初始编译成功!'); - spinner = ora({ - text: '等待文件变更...', - spinner: 'pong', - color: 'green' - }).start(); + waitingSpinner(); - excuteCmd('node_modules/.bin/nodemon', ['-q', 'server_dist/app.js', 'dev'], { + excuteCmd('node_modules/.bin/nodemon', ['-q', 'server_dist/app.js'], { cwd: __dirname }); @@ -94,28 +96,41 @@ gulp.task('initialBuild', ['removeDist'], () => { gulp.task('default', ['initialBuild'], () => { gulp.watch(SRC, (event) => { + let originFilePath = path.relative(path.join(__dirname, 'server'), event.path) + let distPath = path.resolve(DIST, path.join(originFilePath)) spinner.text = `正在编译 ${event.path}...`; gulp.src(event.path).pipe(generateBabel()) - .pipe(gulp.dest(DIST)).on('end', () => { - output('success', `成功编译 ${event.path}`); - spinner = ora({ - text: 'waiting changes...', - spinner: 'pong', - color: 'green' - }); - spinner.start(); + .pipe(gulp.dest(path.parse(distPath).dir)).on('end', () => { + output('success', `成功编译 ${originFilePath}`); + output('success', '正在重启服务器...'); + waitingSpinner(); }); }); }); +gulp.task('buildNode', () => { + return gulp.src(SRC) + .pipe(generateBabel()) + .pipe(gulp.dest(DIST)); +}); + +gulp.task('watchNode', ['buildNode'], () => { + return watch(SRC, { + verbose: true, + ignoreInitial: false + }) + .pipe(generateBabel()) + .pipe(gulp.dest(DIST)); +}); + gulp.task('build', () => { let status = { count: 0 }; let ykitOutput = ''; - spinner.text = '正在编译...'; + spinner = ora('正在编译,请稍等...').start(); gulp.src(SRC) .pipe(generateBabel(status)) diff --git a/package.json b/package.json index 2ff7722a..89ca6c99 100644 --- a/package.json +++ b/package.json @@ -5,10 +5,11 @@ "main": "index.js", "scripts": { "build-server": "babel server -d server_dist", - "dev-server": "nodemon server_dist/app.js", - "install-server" : "node server_dist/install.js", + "dev-server": "nodemon server_dist/app.js -L", + "install-server": "node server_dist/install.js", "dev": "gulp --silent", - "build": "gulp build --silent" + "build": "gulp build --silent", + "only-watch": "gulp watchNode" }, "repository": { "type": "git", @@ -67,7 +68,7 @@ "babel": "^6.5.2", "babel-cli": "^6.24.1", "babel-core": "^6.8.0", - "babel-eslint": "^6.0.4", + "babel-eslint": "^7.2.3", "babel-loader": "^6.2.4", "babel-plugin-transform-decorators-legacy": "^1.3.4", "babel-plugin-transform-object-rest-spread": "^6.8.0", diff --git a/server/app.js b/server/app.js index fd7cdfa2..460a461f 100644 --- a/server/app.js +++ b/server/app.js @@ -2,35 +2,22 @@ import yapi from './yapi.js'; import commons from './utils/commons'; yapi.commons = commons; import dbModule from './utils/db.js'; -import mockServer from './middleware/mockServer.js' -import Koa from 'koa' -import convert from 'koa-convert' -import koaStatic from 'koa-static' -import bodyParser from 'koa-bodyparser' -import router from './router.js' +import mockServer from './middleware/mockServer.js'; +import Koa from 'koa'; +import convert from 'koa-convert'; +import koaStatic from 'koa-static'; +import bodyParser from 'koa-bodyparser'; +import router from './router.js'; -yapi.connect = dbModule.connect() -const app = new Koa() -app.use(mockServer) -app.use(bodyParser()) -app.use(router.routes()) -app.use(router.allowedMethods()) +yapi.connect = dbModule.connect(); +const app = new Koa(); + +app.use(mockServer); +app.use(bodyParser()); +app.use(router.routes()); +app.use(router.allowedMethods()); app.use(koaStatic( yapi.path.join(yapi.WEBROOT, 'static') -)) -app.listen(yapi.WEBCONFIG.port) -commons.log(`the server is start at port ${yapi.WEBCONFIG.port}`) - - - - - - - - - - - - - - +)); +app.listen(yapi.WEBCONFIG.port); +commons.log(`the server is start at port ${yapi.WEBCONFIG.port}`); \ No newline at end of file diff --git a/server/config.js b/server/config.js index fb1889bd..96623b87 100644 --- a/server/config.js +++ b/server/config.js @@ -1,10 +1,10 @@ module.exports = { - "port": "3000", + "port": 80, "webhost": "yapi.local.qunar.com", "adminAccount": "admin@admin.com", "db": { "servername": "127.0.0.1", - "DATABASE": "yapi", + "DATABASE": "yapi", "port": 27017 }, "mail": { @@ -12,8 +12,8 @@ module.exports = { "from": "****@mail.com", "port": 4652, "auth": { - "user": "****@mail.com", - "pass": "**********" + "user": "****@mail.com", + "pass": "**********" } } } \ No newline at end of file diff --git a/server/controllers/user.js b/server/controllers/user.js index b4c790c9..ed5a638f 100644 --- a/server/controllers/user.js +++ b/server/controllers/user.js @@ -98,7 +98,7 @@ class userController extends baseController { }) }) }, - tokenField: 'token', + tokenField: 'token' } } diff --git a/server/install.js b/server/install.js index 8935ef51..1ac097ce 100644 --- a/server/install.js +++ b/server/install.js @@ -1,27 +1,26 @@ -import fs from 'fs-extra' -import path from 'path' -import initConfig from './utils/initConfig.js' +import fs from 'fs-extra'; import yapi from './yapi.js'; import commons from './utils/commons'; - import dbModule from './utils/db.js'; -import userModel from './models/user.js' +import userModel from './models/user.js'; yapi.commons = commons; -yapi.connect = dbModule.connect() +yapi.connect = dbModule.connect(); -function install(){ - let exist = yapi.commons.fileExist(yapi.path.join(yapi.WEBROOT_RUNTIME, 'init.lock')) - if(exist){ - return yapi.commons.log('runtime/init.lock文件已存在,请确认您是否已安装。如果需要重新安装,请删掉runtime/init.lock文件'); - process.exit(1); +function install() { + let exist = yapi.commons.fileExist(yapi.path.join(yapi.WEBROOT_RUNTIME, 'init.lock')); + + if (exist) { + yapi.commons.log('runtime/init.lock文件已存在,请确认您是否已安装。如果需要重新安装,请删掉runtime/init.lock文件'); + process.exit(0); } + setupSql(); } -function setupSql(){ - let userInst = yapi.getInst(userModel); +function setupSql() { + let userInst = yapi.getInst(userModel); let passsalt = yapi.commons.randStr(); let result = userInst.save({ username: yapi.WEBCONFIG.adminAccount.substr(0, yapi.WEBCONFIG.adminAccount.indexOf('@')), @@ -31,15 +30,16 @@ function setupSql(){ role: 'admin', add_time: yapi.commons.time(), up_time: yapi.commons.time() - }) - result.then(function(success){ + }); + + result.then(function () { + fs.ensureFileSync(yapi.path.join(yapi.WEBROOT_RUNTIME, 'init.lock')); console.log(`初始化管理员账号 "${yapi.WEBCONFIG.adminAccount}" 成功`); - yapi.fs.ensureFileSync(yapi.path.join(yapi.WEBROOT_RUNTIME, 'init.lock')); - process.exit(1) - }, function(err){ + process.exit(0); + }, function (err) { console.log(`初始化管理员账号 "${yapi.WEBCONFIG.adminAccount}" 失败, ${err.message}`); - process.exit(1) - }) + process.exit(0); + }); } -install() \ No newline at end of file +install(); \ No newline at end of file diff --git a/server/models/base.js b/server/models/base.js index ef595022..83553958 100644 --- a/server/models/base.js +++ b/server/models/base.js @@ -1,24 +1,23 @@ -import yapi from '../yapi.js' -import mongoose from 'mongoose' -import autoIncrement from 'mongoose-auto-increment' - +import yapi from '../yapi.js'; +import mongoose from 'mongoose'; +import autoIncrement from 'mongoose-auto-increment'; /** * 所有的model都需要继承baseModel, 且需要 getSchema和getName方法,不然会报错 */ class baseModel{ - constructor(){ - this.schema = new mongoose.Schema(this.getSchema()) - this.name = this.getName() + this.schema = new mongoose.Schema(this.getSchema()); + this.name = this.getName(); + if(this.isNeedAutoIncrement() === true){ this.schema.plugin(autoIncrement.plugin, { model: this.name, field: this.getPrimaryKey(), startAt: 101, incrementBy: yapi.commons.rand(1, 100) - }) + }); } this.model = yapi.db(this.name, this.schema); @@ -32,22 +31,19 @@ class baseModel{ * 可通过覆盖此方法生成其他自增字段 */ getPrimaryKey(){ - return '_id' + return '_id'; } /** * 获取collection的schema结构 */ - getSchema(){ - yapi.commons.log('Model Class need getSchema function', 'error') + yapi.commons.log('Model Class need getSchema function', 'error'); } getName(){ - yapi.commons.log('Model Class need name', 'error') + yapi.commons.log('Model Class need name', 'error'); } - - } module.exports = baseModel; \ No newline at end of file diff --git a/server/models/group.js b/server/models/group.js index 059628a0..baaadc61 100644 --- a/server/models/group.js +++ b/server/models/group.js @@ -1,57 +1,61 @@ -import yapi from '../yapi.js' -import mongoose from 'mongoose' -import baseModel from './base.js' +import yapi from '../yapi.js'; +import mongoose from 'mongoose'; +import baseModel from './base.js'; -class groupModel extends baseModel{ - getName(){ - return 'group' +class groupModel extends baseModel { + getName() { + return 'group'; } - getSchema(){ + getSchema() { return { uid: Number, group_name: String, group_desc: String, add_time: Number, up_time: Number - } + }; } save(data) { let m = new this.model(data); return m.save(); } - checkRepeat(name) { + + checkRepeat(name) { return this.model.count({ group_name: name - }) + }); } - list(){ - return this.model.find().select("group_name _id group_desc add_time up_time").exec() + + list() { + return this.model.find().select("group_name _id group_desc add_time up_time").exec(); } - del (id) { + + del(id) { return this.model.deleteOne({ _id: id - }) + }); } - up (id, data) { - return this.model.update({ - _id: id, - }, { - group_name: data.group_name, - group_desc: data.group_desc, - up_time: yapi.commons.time() - }) + + up(id, data) { + return this.model.update( + { + _id: id + }, { + group_name: data.group_name, + group_desc: data.group_desc, + up_time: yapi.commons.time() + } + ); } search(keyword) { return this.model.find({ group_name: new RegExp(keyword, 'i') }) - .limit(10) + .limit(10); } - } - -module.exports= groupModel \ No newline at end of file +module.exports = groupModel; \ No newline at end of file diff --git a/server/models/interface.js b/server/models/interface.js index d0cb3f56..0f760aa0 100644 --- a/server/models/interface.js +++ b/server/models/interface.js @@ -1,38 +1,38 @@ -import yapi from '../yapi.js' -import baseModel from './base.js' +import yapi from '../yapi.js'; +import baseModel from './base.js'; -class interfaceModel extends baseModel{ - getName(){ - return 'interface' +class interfaceModel extends baseModel { + getName() { + return 'interface'; } - getSchema(){ + getSchema() { return { - title: {type: String, required: true}, - uid: {type: Number, required: true}, - path: {type: String, required: true}, - method: {type: String, required: true}, - project_id: {type: Number, required: true}, + title: { type: String, required: true }, + uid: { type: Number, required: true }, + path: { type: String, required: true }, + method: { type: String, required: true }, + project_id: { type: Number, required: true }, desc: String, add_time: Number, up_time: Number, req_headers: [{ - name: String, value: String, desc: String, required: Boolean + name: String, value: String, desc: String, required: Boolean }], req_params_type: { type: String, - enum: ["form", "json", "text", "xml"] + enum: ['form', 'json', 'text', 'xml'] }, req_params_form: [{ - name: String, value: String,value_type: {type: String, enum: ["text", "file"]}, desc: String, required: Boolean + name: String, value: String, value_type: { type: String, enum: ['text', 'file'] }, desc: String, required: Boolean }], req_params_other: String, res_body_type: { type: String, - enum: ["json", "text", "xml"] + enum: ['json', 'text', 'xml'] }, res_body: String - } + }; } save(data) { @@ -40,50 +40,53 @@ class interfaceModel extends baseModel{ return m.save(); } - - get(id){ + get(id) { return this.model.findOne({ _id: id - }).exec() + }) + .exec(); } - getByPath(project_id, path){ + getByPath(project_id, path) { return this.model.find({ project_id: project_id, path: path - }).exec() + }) + .exec(); } - checkRepeat(id, path, method){ + checkRepeat(id, path, method) { return this.model.count({ project_id: id, path: path, method: method - }) + }); } - countByProjectId(id){ + countByProjectId(id) { return this.model.count({ project_id: id - }) + }); } - list (project_id){ + list(project_id) { return this.model.find({ project_id: project_id - }).sort({_id: -1}).exec() + }) + .sort({ _id: -1 }) + .exec(); } - del(id){ + del(id) { return this.model.deleteOne({ _id: id - }) + }); } - up(id, data){ + up(id, data) { data.up_time = yapi.commons.time(); return this.model.update({ _id: id, - }, data, { runValidators: true }) + }, data, { runValidators: true }); } } diff --git a/server/models/log.js b/server/models/log.js index 064efd08..26141af1 100644 --- a/server/models/log.js +++ b/server/models/log.js @@ -9,13 +9,13 @@ class logModel extends baseModel { getSchema() { return { - uid: {type: Number, required: true}, - title: {type: String, required: true}, - type: {type: String, enum:['user', 'group', 'interface', 'project', 'other'], required: true}, - content: {type: String, required: true}, - username: {type: String, required: true}, + uid: { type: Number, required: true }, + title: { type: String, required: true }, + type: { type: String, enum: ['user', 'group', 'interface', 'project', 'other'], required: true }, + content: { type: String, required: true }, + username: { type: String, required: true }, add_time: Number - } + }; } /** @@ -36,21 +36,27 @@ class logModel extends baseModel { add_time: yapi.commons.time() }; let log = new this.model(saveData); + return log.save(); } - list (uid){ + list(uid) { return this.model.find({ uid: uid - }).exec() + }) + .exec(); } listWithPaging(uid, page, limit) { page = parseInt(page); limit = parseInt(limit); + return this.model.find({ uid: uid - }).skip((page - 1) * limit).limit(limit).exec(); + }) + .skip((page - 1) * limit) + .limit(limit) + .exec(); } listCount(uid) { diff --git a/server/models/project.js b/server/models/project.js index 1aa0742a..0c8851e1 100644 --- a/server/models/project.js +++ b/server/models/project.js @@ -1,33 +1,34 @@ -import yapi from '../yapi.js' -import baseModel from './base.js' +import yapi from '../yapi.js'; +import baseModel from './base.js'; -class projectModel extends baseModel{ - getName(){ - return 'project' +class projectModel extends baseModel { + getName() { + return 'project'; } - getSchema(){ + getSchema() { return { - uid: {type: Number, required: true}, - name: {type: String, required: true}, - basepath: {type: String, required: true, validate: { - validator: (v) => { - console.log('basepath: ', v) - return v && v[0] === '/' - }, - message: 'basepath必须是/开头' - }}, + uid: { type: Number, required: true }, + name: { type: String, required: true }, + basepath: { + type: String, required: true, validate: { + validator: (v) => { + return v && v[0] === '/'; + }, + message: 'basepath必须是/开头' + } + }, desc: String, - group_id: {type: Number, required: true}, - members: Array, - protocol: {type: String, required: true}, - prd_host: {type: String, required: true}, + group_id: { type: Number, required: true }, + members: Array, + protocol: { type: String, required: true }, + prd_host: { type: String, required: true }, env: [ - {name: String, domain: String} + { name: String, domain: String } ], add_time: Number, up_time: Number - } + }; } save(data) { @@ -35,37 +36,35 @@ class projectModel extends baseModel{ return m.save(); } - - get(id){ + get(id) { return this.model.findOne({ _id: id - }).exec() + }).exec(); } - getByDomain(domain){ + getByDomain(domain) { return this.model.find({ prd_host: domain - }).exec() + }).exec(); } - checkNameRepeat(name){ + checkNameRepeat(name) { return this.model.count({ name: name - }) + }); } - checkDomainRepeat(domain, basepath){ + checkDomainRepeat(domain, basepath) { return this.model.count({ prd_host: domain, basepath: basepath - }) + }); } - - list (group_id){ + list(group_id) { return this.model.find({ group_id: group_id - }).sort({_id: -1}).exec() + }).sort({ _id: -1 }).exec(); } listWithPaging(group_id, page, limit) { @@ -73,7 +72,7 @@ class projectModel extends baseModel{ limit = parseInt(limit); return this.model.find({ group_id: group_id - }).sort({_id: -1}).skip((page - 1) * limit).limit(limit).exec(); + }).sort({ _id: -1 }).skip((page - 1) * limit).limit(limit).exec(); } listCount(group_id) { @@ -82,54 +81,58 @@ class projectModel extends baseModel{ }); } - countByGroupId(group_id){ + countByGroupId(group_id) { return this.model.count({ group_id: group_id - }) + }); } - del(id){ + del(id) { return this.model.deleteOne({ _id: id - }) + }); } - up(id, data){ + + up(id, data) { data.up_time = yapi.commons.time(); return this.model.update({ _id: id, - }, data, { runValidators: true }) + }, data, { runValidators: true }); } - addMember(id, uid){ - return this.model.update({ - _id: id - }, { - $push: {members: uid} - }) + addMember(id, uid) { + return this.model.update( + { + _id: id + }, { + $push: { members: uid } + } + ); } - delMember(id, uid){ - return this.model.update({ - _id: id - }, { - $pull: {members: uid} - }) + delMember(id, uid) { + return this.model.update( + { + _id: id + }, { + $pull: { members: uid } + } + ); } - checkMemberRepeat(id, uid){ + checkMemberRepeat(id, uid) { return this.model.count({ _id: id, - members:[uid] - }) + members: [uid] + }); } search(keyword) { return this.model.find({ name: new RegExp(keyword, 'ig') }) - .limit(10) + .limit(10); } - } module.exports = projectModel; \ No newline at end of file diff --git a/server/models/user.js b/server/models/user.js index c15dfff6..b9366776 100644 --- a/server/models/user.js +++ b/server/models/user.js @@ -1,87 +1,95 @@ -import yapi from '../yapi.js' -import mongoose from 'mongoose' -import baseModel from './base.js' +import baseModel from './base.js'; -class userModel extends baseModel{ - getName(){ - return 'user' +class userModel extends baseModel { + getName() { + return 'user'; } - getSchema(){ - return{ - username: { + getSchema() { + return { + username: { type: String, - required: true - }, - password:{ - type:String, - required: true - }, - email: { - type: String, - required: true - }, - passsalt: String, - role: String, - add_time: Number, - up_time: Number - } + required: true + }, + password: { + type: String, + required: true + }, + email: { + type: String, + required: true + }, + passsalt: String, + role: String, + add_time: Number, + up_time: Number + }; } - save(data){ + + save(data) { let user = new this.model(data); return user.save(); } - checkRepeat(email){ + + checkRepeat(email) { return this.model.count({ email: email - }) + }); } - list(){ - return this.model.find().select("_id username email role add_time up_time").exec() //显示id name email role + + list() { + return this.model.find().select('_id username email role add_time up_time').exec(); //显示id name email role } - findByUids(uids){ + + findByUids(uids) { return this.model.find({ - _id: {$in: uids} - }).select("_id username email role add_time up_time").exec() + _id: { $in: uids } + }).select('_id username email role add_time up_time').exec(); } + listWithPaging(page, limit) { page = parseInt(page); limit = parseInt(limit); - return this.model.find().sort({_id: -1}).skip((page - 1) * limit).limit(limit).select("_id username email role add_time up_time").exec(); + return this.model.find().sort({ _id: -1 }).skip((page - 1) * limit).limit(limit).select('_id username email role add_time up_time').exec(); } + listCount() { return this.model.count(); } - findByEmail(email){ - return this.model.findOne({email: email}) + + findByEmail(email) { + return this.model.findOne({ email: email }); } - findById(id){ + + findById(id) { return this.model.findById({ _id: id - }) + }); } - del (id) { + + del(id) { return this.model.deleteOne({ - _id: id - }) + _id: id + }); } - update(id,data){ + + update(id, data) { return this.model.update({ _id: id - }, data) + }, data); } + search(keyword) { return this.model.find({ $or: [ { email: new RegExp(keyword, 'i') }, - { username: new RegExp(keyword, 'i')} + { username: new RegExp(keyword, 'i') } ] }, { passsalt: 0, password: 0 - }).limit(10) + }).limit(10); } - } -module.exports = userModel +module.exports = userModel; \ No newline at end of file diff --git a/server/router.js b/server/router.js index 719d71db..2846f3bf 100644 --- a/server/router.js +++ b/server/router.js @@ -1,12 +1,11 @@ -import koaRouter from 'koa-router' -import interfaceController from './controllers/interface.js' -import groupController from './controllers/group.js' -import userController from './controllers/user.js' - -import yapi from './yapi.js' -import projectController from './controllers/project.js' -import logController from './controllers/log.js' +import koaRouter from 'koa-router'; +import interfaceController from './controllers/interface.js'; +import groupController from './controllers/group.js'; +import userController from './controllers/user.js'; +import yapi from './yapi.js'; +import projectController from './controllers/project.js'; +import logController from './controllers/log.js'; const router = koaRouter(); @@ -34,47 +33,46 @@ const INTERFACE_CONFIG = { }; //group -createAction('group', 'list', 'get', 'list') -createAction('group', 'add', 'post', 'add') -createAction('group', 'up', 'post', 'up') -createAction('group', 'del', 'post', 'del') +createAction('group', 'list', 'get', 'list'); +createAction('group', 'add', 'post', 'add'); +createAction('group', 'up', 'post', 'up'); +createAction('group', 'del', 'post', 'del'); //user -createAction('user', 'login', 'post', 'login') -createAction('user', 'reg', 'post', 'reg') -createAction('user', 'list', 'get', 'list') -createAction('user', 'find', 'get', 'findById') -createAction('user', 'update', 'post', 'update') -createAction('user', 'del', 'post', 'del') -createAction('user', 'status', 'get', 'getLoginStatus') -createAction('user', 'logout', 'get', 'logout') -createAction('user', 'login_by_token', 'post', 'loginByToken') -createAction('user', 'change_password', 'post', 'changePassword') -createAction('user', 'search', 'get', 'search') +createAction('user', 'login', 'post', 'login'); +createAction('user', 'reg', 'post', 'reg'); +createAction('user', 'list', 'get', 'list'); +createAction('user', 'find', 'get', 'findById'); +createAction('user', 'update', 'post', 'update'); +createAction('user', 'del', 'post', 'del'); +createAction('user', 'status', 'get', 'getLoginStatus'); +createAction('user', 'logout', 'get', 'logout'); +createAction('user', 'login_by_token', 'post', 'loginByToken'); +createAction('user', 'change_password', 'post', 'changePassword'); +createAction('user', 'search', 'get', 'search'); //project -createAction('project', 'add', 'post', 'add') -createAction('project', 'list', 'get', 'list') -createAction('project', 'get', 'get', 'get') -createAction('project', 'up', 'post', 'up') -createAction('project', 'del', 'post', 'del') -createAction('project', 'add_member', 'post', 'addMember') -createAction('project', 'del_member', 'post', 'delMember') -createAction('project', 'get_member_list', 'get', 'getMemberList') -createAction('project', 'search', 'get', 'search') +createAction('project', 'add', 'post', 'add'); +createAction('project', 'list', 'get', 'list'); +createAction('project', 'get', 'get', 'get'); +createAction('project', 'up', 'post', 'up'); +createAction('project', 'del', 'post', 'del'); +createAction('project', 'add_member', 'post', 'addMember'); +createAction('project', 'del_member', 'post', 'delMember'); +createAction('project', 'get_member_list', 'get', 'getMemberList'); +createAction('project', 'search', 'get', 'search'); //interface -createAction('interface', 'add', 'post', 'add') -createAction('interface', 'list', 'get', 'list') -createAction('interface', 'get', 'get', 'get') -createAction('interface', 'up', 'post', 'up') -createAction('interface', 'del', 'post', 'del') +createAction('interface', 'add', 'post', 'add'); +createAction('interface', 'list', 'get', 'list'); +createAction('interface', 'get', 'get', 'get'); +createAction('interface', 'up', 'post', 'up'); +createAction('interface', 'del', 'post', 'del'); //node createAction('log', 'list', 'get', 'list'); - /** * * @param {*} controller controller_name @@ -82,18 +80,20 @@ createAction('log', 'list', 'get', 'list'); * @param {*} method request_method , post get put delete ... * @param {*} action controller_action_name */ -function createAction(controller, path, method, action){ +function createAction(controller, path, method, action) { router[method](INTERFACE_CONFIG[controller].prefix + path, async (ctx) => { let inst = new INTERFACE_CONFIG[controller].controller(ctx); + await inst.init(ctx); - if(inst.$auth === true){ + + if (inst.$auth === true) { await inst[action].call(inst, ctx); - }else{ + } else { ctx.body = yapi.commons.resReturn(null, 400, 'Without Permission.'); } - - }) + + }); } -module.exports = router +module.exports = router; \ No newline at end of file diff --git a/server/utils/commons.js b/server/utils/commons.js index 3ea8731e..c1a719b1 100644 --- a/server/utils/commons.js +++ b/server/utils/commons.js @@ -1,35 +1,36 @@ - -import fs from 'fs-extra' -import path from 'path' -import yapi from '../yapi.js' -import sha1 from 'sha1' +import fs from 'fs-extra'; +import path from 'path'; +import yapi from '../yapi.js'; +import sha1 from 'sha1'; exports.resReturn = (data, num, errmsg) => { num = num || 0; + return { errcode: num, errmsg: errmsg || 'success', data: data - } -} - -const MSGTYPE = { - 'log': 'Log', - 'warn': 'warning', - 'error': 'Error' -} + }; +}; exports.log = (msg, type) => { - if (!msg) return; + if (!msg) { + return; + } + type = type || 'log'; + let f; + switch (type) { case 'log': f = console.log; break; case 'warn': f = console.warn; break; case 'error': f = console.error; break; default: f = console.log; break; } + f(type + ':', msg); + let date = new Date(); let year = date.getFullYear(); let month = date.getMonth(); @@ -40,14 +41,13 @@ exports.log = (msg, type) => { if (msg instanceof Error) msg = msg.message; else msg = JSON.stringify(msg); } - let data = (new Date).toLocaleTimeString() + "\t|\t" + type + "\t|\t" + msg; + + let data = (new Date).toLocaleTimeString() + '\t|\t' + type + '\t|\t' + msg; + fs.writeFileSync(logfile, data, { flag: 'w+' }); - - -} - +}; exports.fileExist = (filePath) => { try { @@ -55,80 +55,88 @@ exports.fileExist = (filePath) => { } catch (err) { return false; } -} +}; exports.time = () => { return Date.parse(new Date()) / 1000; -} +}; exports.fieldSelect = (data, field) => { - if (!data || !field || !Array.isArray(field)) return null; + if (!data || !field || !Array.isArray(field)) { + return null; + } + var arr = {}; + field.forEach((f) => { data[f] && (arr[f] = data[f]); - }) + }); + return arr; -} +}; exports.rand = (min, max) => { return Math.floor(Math.random() * (max - min) + min); -} +}; exports.json_parse = (json) => { try { return JSON.parse(json); } catch (e) { - return json + return json; } -} +}; exports.randStr = () => { - return Math.random().toString(36).substr(2) -} + return Math.random().toString(36).substr(2); +}; exports.generatePassword = (password, passsalt) => { return sha1(password + sha1(passsalt)); -} +}; exports.expireDate = (day) => { let date = new Date(); date.setTime(date.getTime() + day * 86400000); return date; -} +}; exports.sendMail = (options, cb) => { if (!yapi.mail) return false; options.subject = options.subject ? options.subject + '-yapi平台' : 'ypai平台'; - cb = cb || function (err, info) { + + cb = cb || function (err) { if (err) { yapi.commons.log('send mail ' + options.to + ' error,' + err.message, 'error'); } else { yapi.commons.log('send mail ' + options.to + ' success'); } + }; - } try { yapi.mail.sendMail({ from: yapi.WEBCONFIG.mail.from, to: options.to, subject: 'yapi平台', html: options.contents - }, cb) + }, cb); } catch (e) { - console.error(e.message) + console.error(e.message); } -} +}; exports.validateSearchKeyword = keyword => { if (/^\*|\?|\+|\$|\^|\\|\.$/.test(keyword)) { return false; } + return true; -} +}; exports.filterRes = (list, rules) => { return list.map(item => { let filteredRes = {}; + rules.forEach(rule => { if (typeof rule == 'string') { filteredRes[rule] = item[rule]; @@ -136,38 +144,51 @@ exports.filterRes = (list, rules) => { filteredRes[rule.alias] = item[rule.key]; } }); + return filteredRes; - }) -} + }); +}; exports.verifyPath = (path) => { if (/^\/[a-zA-Z0-9\-\/_:\.]+$/.test(path)) { if (path[path.length - 1] === '/') { return false; } else { - return true + return true; } } else { return false; } -} +}; function trim(str) { - if (!str) return str; + if (!str) { + return str; + } + str = str + ''; - return str.replace(/(^\s*)|(\s*$)/g, ""); + + return str.replace(/(^\s*)|(\s*$)/g, ''); } function ltrim(str) { - if (!str) return str; + if (!str) { + return str; + } + str = str + ''; - return str.replace(/(^\s*)/g, ""); + + return str.replace(/(^\s*)/g, ''); } function rtrim(str) { - if (!str) return str; + if (!str) { + return str; + } + str = str + ''; - return str.replace(/(\s*$)/g, ""); + + return str.replace(/(\s*$)/g, ''); } exports.trim = trim; @@ -175,7 +196,10 @@ exports.ltrim = ltrim; exports.rtrim = rtrim; exports.handleParams = (params, keys) => { - if (!params || typeof params !== 'object' || !keys || typeof keys !== 'object') return false; + if (!params || typeof params !== 'object' || !keys || typeof keys !== 'object') { + return false; + } + for (var key in keys) { var filter = keys[key]; if (params[key]) { @@ -186,5 +210,6 @@ exports.handleParams = (params, keys) => { } } } + return params; -} \ No newline at end of file +}; \ No newline at end of file diff --git a/server/utils/db.js b/server/utils/db.js index 5adaee69..1a705e77 100644 --- a/server/utils/db.js +++ b/server/utils/db.js @@ -1,31 +1,35 @@ -import mongoose from 'mongoose' -import yapi from '../yapi.js' -import autoIncrement from 'mongoose-auto-increment' +import mongoose from 'mongoose'; +import yapi from '../yapi.js'; +import autoIncrement from 'mongoose-auto-increment'; function model(model, schema){ if(schema instanceof mongoose.Schema === false){ schema = new mongoose.Schema(schema); } + schema.set('autoIndex', false); - return yapi.connect.model(model, schema, model) + + return yapi.connect.model(model, schema, model); } function connect(){ mongoose.Promise = global.Promise; + let config = yapi.WEBCONFIG; let options = {}; + if(config.user){ options.user = config.db.user, - options.pass = config.db.pass + options.pass = config.db.pass; } let db = mongoose.connect(`mongodb://${config.db.servername}:${config.db.port}/${config.db.DATABASE}`, options); db.then(function (res) { - yapi.commons.log('mongodb load success...') + yapi.commons.log('mongodb load success...'); }, function (err) { yapi.commons.log(err, 'Mongo connect error'); - }) + }); autoIncrement.initialize(db); return db; @@ -33,12 +37,7 @@ function connect(){ yapi.db = model; - module.exports = { model: model, connect: connect -}; - - - - +}; \ No newline at end of file diff --git a/server/utils/initConfig.js b/server/utils/initConfig.js index 89f7d4fc..a52fa17e 100644 --- a/server/utils/initConfig.js +++ b/server/utils/initConfig.js @@ -1,11 +1,11 @@ -import path from 'path' -import fs from 'fs-extra' -import config from '../config.js' +import path from 'path'; +import fs from 'fs-extra'; +import config from '../config.js'; fs.ensureDirSync( path.join(path.resolve(__dirname, '../../'), 'runtime') ); let configPath = path.join(path.resolve(__dirname, '../../'), 'runtime', 'config.json') fs.writeFileSync(configPath, - JSON.stringify(config, null, "\t"), - {encoding: 'utf8'} -) \ No newline at end of file + JSON.stringify(config, null, '\t'), + { encoding: 'utf8' } +); \ No newline at end of file diff --git a/server/yapi.js b/server/yapi.js index d1059762..c7d3eb4a 100644 --- a/server/yapi.js +++ b/server/yapi.js @@ -1,24 +1,22 @@ -import path from 'path' -import fs from 'fs-extra' +import path from 'path'; +import fs from 'fs-extra'; import nodemailer from 'nodemailer'; -import config from '../runtime/config.json' +import config from '../runtime/config.json'; -var insts = new Map(); +let insts = new Map(); let mail; const WEBROOT = path.resolve(__dirname, '..'); //路径 const WEBROOT_SERVER = __dirname; const WEBROOT_RUNTIME = path.join(WEBROOT, 'runtime'); const WEBROOT_LOG = path.join(WEBROOT_RUNTIME, 'log'); -const WEBCONFIG = config; +const WEBCONFIG = config; fs.ensureDirSync(WEBROOT_RUNTIME); fs.ensureDirSync(WEBROOT_LOG); - - -if(WEBCONFIG.mail){ - mail = nodemailer.createTransport(WEBCONFIG.mail) +if (WEBCONFIG.mail) { + mail = nodemailer.createTransport(WEBCONFIG.mail); } /** @@ -27,18 +25,18 @@ if(WEBCONFIG.mail){ * @example * yapi.getInst(groupModel, arg1, arg2) */ -function getInst(m, ...args){ - if(!insts.get(m)){ - insts.set(m, new m(args)) +function getInst(m, ...args) { + if (!insts.get(m)) { + insts.set(m, new m(args)); } - return insts.get(m) + return insts.get(m); } -function delInst(m){ - try{ - insts.delete(m) - }catch(err){ - console.error(err) +function delInst(m) { + try { + insts.delete(m); + } catch (err) { + console.error(err); } } @@ -53,6 +51,6 @@ let r = { getInst: getInst, delInst: delInst, getInsts: insts -} -if(mail) r.mail = mail; +}; +if (mail) r.mail = mail; module.exports = r; \ No newline at end of file diff --git a/server_dist/app.js b/server_dist/app.js index d0ba09cd..4ca33334 100644 --- a/server_dist/app.js +++ b/server_dist/app.js @@ -43,6 +43,7 @@ _yapi2.default.commons = _commons2.default; _yapi2.default.connect = _db2.default.connect(); var app = new _koa2.default(); + app.use(_mockServer2.default); app.use((0, _koaBodyparser2.default)()); app.use(_router2.default.routes()); diff --git a/server_dist/config.js b/server_dist/config.js index c0502904..cbf2c2a6 100644 --- a/server_dist/config.js +++ b/server_dist/config.js @@ -1,7 +1,7 @@ "use strict"; module.exports = { - "port": "3000", + "port": 80, "webhost": "yapi.local.qunar.com", "adminAccount": "admin@admin.com", "db": { diff --git a/server_dist/install.js b/server_dist/install.js index 7399406e..c466f30c 100644 --- a/server_dist/install.js +++ b/server_dist/install.js @@ -4,14 +4,6 @@ var _fsExtra = require('fs-extra'); var _fsExtra2 = _interopRequireDefault(_fsExtra); -var _path = require('path'); - -var _path2 = _interopRequireDefault(_path); - -var _initConfig = require('./utils/initConfig.js'); - -var _initConfig2 = _interopRequireDefault(_initConfig); - var _yapi = require('./yapi.js'); var _yapi2 = _interopRequireDefault(_yapi); @@ -35,10 +27,12 @@ _yapi2.default.connect = _db2.default.connect(); function install() { var exist = _yapi2.default.commons.fileExist(_yapi2.default.path.join(_yapi2.default.WEBROOT_RUNTIME, 'init.lock')); + if (exist) { - return _yapi2.default.commons.log('runtime/init.lock文件已存在,请确认您是否已安装。如果需要重新安装,请删掉runtime/init.lock文件'); - process.exit(1); + _yapi2.default.commons.log('runtime/init.lock文件已存在,请确认您是否已安装。如果需要重新安装,请删掉runtime/init.lock文件'); + process.exit(0); } + setupSql(); } @@ -54,13 +48,14 @@ function setupSql() { add_time: _yapi2.default.commons.time(), up_time: _yapi2.default.commons.time() }); - result.then(function (success) { + + result.then(function () { + _fsExtra2.default.ensureFileSync(_yapi2.default.path.join(_yapi2.default.WEBROOT_RUNTIME, 'init.lock')); console.log('\u521D\u59CB\u5316\u7BA1\u7406\u5458\u8D26\u53F7 "' + _yapi2.default.WEBCONFIG.adminAccount + '" \u6210\u529F'); - _yapi2.default.fs.ensureFileSync(_yapi2.default.path.join(_yapi2.default.WEBROOT_RUNTIME, 'init.lock')); - process.exit(1); + process.exit(0); }, function (err) { console.log('\u521D\u59CB\u5316\u7BA1\u7406\u5458\u8D26\u53F7 "' + _yapi2.default.WEBCONFIG.adminAccount + '" \u5931\u8D25, ' + err.message); - process.exit(1); + process.exit(0); }); } diff --git a/server_dist/models/base.js b/server_dist/models/base.js index 39737624..62d976e5 100644 --- a/server_dist/models/base.js +++ b/server_dist/models/base.js @@ -32,6 +32,7 @@ var baseModel = function () { this.schema = new _mongoose2.default.Schema(this.getSchema()); this.name = this.getName(); + if (this.isNeedAutoIncrement() === true) { this.schema.plugin(_mongooseAutoIncrement2.default.plugin, { model: this.name, diff --git a/server_dist/models/interface.js b/server_dist/models/interface.js index 15242016..7e7b1ef6 100644 --- a/server_dist/models/interface.js +++ b/server_dist/models/interface.js @@ -60,15 +60,15 @@ var interfaceModel = function (_baseModel) { }], req_params_type: { type: String, - enum: ["form", "json", "text", "xml"] + enum: ['form', 'json', 'text', 'xml'] }, req_params_form: [{ - name: String, value: String, value_type: { type: String, enum: ["text", "file"] }, desc: String, required: Boolean + name: String, value: String, value_type: { type: String, enum: ['text', 'file'] }, desc: String, required: Boolean }], req_params_other: String, res_body_type: { type: String, - enum: ["json", "text", "xml"] + enum: ['json', 'text', 'xml'] }, res_body: String }; diff --git a/server_dist/models/log.js b/server_dist/models/log.js index 4dfe9cd4..fa2f4c2a 100644 --- a/server_dist/models/log.js +++ b/server_dist/models/log.js @@ -127,6 +127,7 @@ var logModel = function (_baseModel) { value: function listWithPaging(uid, page, limit) { page = parseInt(page); limit = parseInt(limit); + return this.model.find({ uid: uid }).skip((page - 1) * limit).limit(limit).exec(); diff --git a/server_dist/models/project.js b/server_dist/models/project.js index aa4110f1..e7801ee0 100644 --- a/server_dist/models/project.js +++ b/server_dist/models/project.js @@ -49,13 +49,14 @@ var projectModel = function (_baseModel) { return { uid: { type: Number, required: true }, name: { type: String, required: true }, - basepath: { type: String, required: true, validate: { + basepath: { + type: String, required: true, validate: { validator: function validator(v) { - console.log('basepath: ', v); return v && v[0] === '/'; }, message: 'basepath必须是/开头' - } }, + } + }, desc: String, group_id: { type: Number, required: true }, members: Array, diff --git a/server_dist/models/user.js b/server_dist/models/user.js index 991f2f21..5482ee14 100644 --- a/server_dist/models/user.js +++ b/server_dist/models/user.js @@ -20,14 +20,6 @@ var _inherits2 = require('babel-runtime/helpers/inherits'); var _inherits3 = _interopRequireDefault(_inherits2); -var _yapi = require('../yapi.js'); - -var _yapi2 = _interopRequireDefault(_yapi); - -var _mongoose = require('mongoose'); - -var _mongoose2 = _interopRequireDefault(_mongoose); - var _base = require('./base.js'); var _base2 = _interopRequireDefault(_base); @@ -85,21 +77,21 @@ var userModel = function (_baseModel) { }, { key: 'list', value: function list() { - return this.model.find().select("_id username email role add_time up_time").exec(); //显示id name email role + return this.model.find().select('_id username email role add_time up_time').exec(); //显示id name email role } }, { key: 'findByUids', value: function findByUids(uids) { return this.model.find({ _id: { $in: uids } - }).select("_id username email role add_time up_time").exec(); + }).select('_id username email role add_time up_time').exec(); } }, { key: 'listWithPaging', value: function listWithPaging(page, limit) { page = parseInt(page); limit = parseInt(limit); - return this.model.find().sort({ _id: -1 }).skip((page - 1) * limit).limit(limit).select("_id username email role add_time up_time").exec(); + return this.model.find().sort({ _id: -1 }).skip((page - 1) * limit).limit(limit).select('_id username email role add_time up_time').exec(); } }, { key: 'listCount', diff --git a/server_dist/utils/commons.js b/server_dist/utils/commons.js index 53156606..c43f49ee 100644 --- a/server_dist/utils/commons.js +++ b/server_dist/utils/commons.js @@ -28,6 +28,7 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de exports.resReturn = function (data, num, errmsg) { num = num || 0; + return { errcode: num, errmsg: errmsg || 'success', @@ -35,16 +36,15 @@ exports.resReturn = function (data, num, errmsg) { }; }; -var MSGTYPE = { - 'log': 'Log', - 'warn': 'warning', - 'error': 'Error' -}; - exports.log = function (msg, type) { - if (!msg) return; + if (!msg) { + return; + } + type = type || 'log'; + var f = void 0; + switch (type) { case 'log': f = console.log;break; @@ -55,7 +55,9 @@ exports.log = function (msg, type) { default: f = console.log;break; } + f(type + ':', msg); + var date = new Date(); var year = date.getFullYear(); var month = date.getMonth(); @@ -65,7 +67,9 @@ exports.log = function (msg, type) { if ((typeof msg === 'undefined' ? 'undefined' : (0, _typeof3.default)(msg)) === 'object') { if (msg instanceof Error) msg = msg.message;else msg = (0, _stringify2.default)(msg); } - var data = new Date().toLocaleTimeString() + "\t|\t" + type + "\t|\t" + msg; + + var data = new Date().toLocaleTimeString() + '\t|\t' + type + '\t|\t' + msg; + _fsExtra2.default.writeFileSync(logfile, data, { flag: 'w+' }); @@ -84,11 +88,16 @@ exports.time = function () { }; exports.fieldSelect = function (data, field) { - if (!data || !field || !Array.isArray(field)) return null; + if (!data || !field || !Array.isArray(field)) { + return null; + } + var arr = {}; + field.forEach(function (f) { data[f] && (arr[f] = data[f]); }); + return arr; }; @@ -121,13 +130,15 @@ exports.expireDate = function (day) { exports.sendMail = function (options, cb) { if (!_yapi2.default.mail) return false; options.subject = options.subject ? options.subject + '-yapi平台' : 'ypai平台'; - cb = cb || function (err, info) { + + cb = cb || function (err) { if (err) { _yapi2.default.commons.log('send mail ' + options.to + ' error,' + err.message, 'error'); } else { _yapi2.default.commons.log('send mail ' + options.to + ' success'); } }; + try { _yapi2.default.mail.sendMail({ from: _yapi2.default.WEBCONFIG.mail.from, @@ -144,12 +155,14 @@ exports.validateSearchKeyword = function (keyword) { if (/^\*|\?|\+|\$|\^|\\|\.$/.test(keyword)) { return false; } + return true; }; exports.filterRes = function (list, rules) { return list.map(function (item) { var filteredRes = {}; + rules.forEach(function (rule) { if (typeof rule == 'string') { filteredRes[rule] = item[rule]; @@ -157,6 +170,7 @@ exports.filterRes = function (list, rules) { filteredRes[rule.alias] = item[rule.key]; } }); + return filteredRes; }); }; @@ -174,21 +188,33 @@ exports.verifyPath = function (path) { }; function trim(str) { - if (!str) return str; + if (!str) { + return str; + } + str = str + ''; - return str.replace(/(^\s*)|(\s*$)/g, ""); + + return str.replace(/(^\s*)|(\s*$)/g, ''); } function ltrim(str) { - if (!str) return str; + if (!str) { + return str; + } + str = str + ''; - return str.replace(/(^\s*)/g, ""); + + return str.replace(/(^\s*)/g, ''); } function rtrim(str) { - if (!str) return str; + if (!str) { + return str; + } + str = str + ''; - return str.replace(/(\s*$)/g, ""); + + return str.replace(/(\s*$)/g, ''); } exports.trim = trim; @@ -196,7 +222,10 @@ exports.ltrim = ltrim; exports.rtrim = rtrim; exports.handleParams = function (params, keys) { - if (!params || (typeof params === 'undefined' ? 'undefined' : (0, _typeof3.default)(params)) !== 'object' || !keys || (typeof keys === 'undefined' ? 'undefined' : (0, _typeof3.default)(keys)) !== 'object') return false; + if (!params || (typeof params === 'undefined' ? 'undefined' : (0, _typeof3.default)(params)) !== 'object' || !keys || (typeof keys === 'undefined' ? 'undefined' : (0, _typeof3.default)(keys)) !== 'object') { + return false; + } + for (var key in keys) { var filter = keys[key]; if (params[key]) { @@ -210,5 +239,6 @@ exports.handleParams = function (params, keys) { } } } + return params; }; \ No newline at end of file diff --git a/server_dist/utils/db.js b/server_dist/utils/db.js index 35ac61e3..cb66a49a 100644 --- a/server_dist/utils/db.js +++ b/server_dist/utils/db.js @@ -18,14 +18,18 @@ function model(model, schema) { if (schema instanceof _mongoose2.default.Schema === false) { schema = new _mongoose2.default.Schema(schema); } + schema.set('autoIndex', false); + return _yapi2.default.connect.model(model, schema, model); } function connect() { _mongoose2.default.Promise = global.Promise; + var config = _yapi2.default.WEBCONFIG; var options = {}; + if (config.user) { options.user = config.db.user, options.pass = config.db.pass; } diff --git a/server_dist/utils/initConfig.js b/server_dist/utils/initConfig.js index 9db18b1f..f089425f 100644 --- a/server_dist/utils/initConfig.js +++ b/server_dist/utils/initConfig.js @@ -21,4 +21,4 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de _fsExtra2.default.ensureDirSync(_path2.default.join(_path2.default.resolve(__dirname, '../../'), 'runtime')); var configPath = _path2.default.join(_path2.default.resolve(__dirname, '../../'), 'runtime', 'config.json'); -_fsExtra2.default.writeFileSync(configPath, (0, _stringify2.default)(_config2.default, null, "\t"), { encoding: 'utf8' }); \ No newline at end of file +_fsExtra2.default.writeFileSync(configPath, (0, _stringify2.default)(_config2.default, null, '\t'), { encoding: 'utf8' }); \ No newline at end of file diff --git a/static/image/bg-img.jpg b/static/image/bg-img.jpg index f04905a2..a6a049e5 100644 Binary files a/static/image/bg-img.jpg and b/static/image/bg-img.jpg differ diff --git a/static/image/header-bg-img.jpg b/static/image/header-bg-img.jpg new file mode 100644 index 00000000..dcbb92d4 Binary files /dev/null and b/static/image/header-bg-img.jpg differ