diff --git a/.tags b/.tags
index 388b1988..ffb43780 100644
--- a/.tags
+++ b/.tags
@@ -61,48 +61,11 @@ fetchMoreNews /Users/qitmac000445/Desktop/YAPI/yapi/client/reducer/news/news.js
const.curUid /Users/qitmac000445/Desktop/YAPI/yapi/client/reducer/user/user.js /^const initialState = {$/;" property line:4
switch /Users/qitmac000445/Desktop/YAPI/yapi/client/reducer/user/user.js /^ switch (action.type) {$/;" function line:9
changeCurUid /Users/qitmac000445/Desktop/YAPI/yapi/client/reducer/user/user.js /^export function changeCurUid(curUid) {$/;" function line:23
-requireAuthentication /Users/qitmac000445/Desktop/YAPI/yapi/client/components/AuthenticatedComponent.js /^export function requireAuthentication(Component) {$/;" function line:16
-constructor /Users/qitmac000445/Desktop/YAPI/yapi/client/components/AuthenticatedComponent.js /^ constructor(props){$/;" function line:18
-static.isAuthenticated /Users/qitmac000445/Desktop/YAPI/yapi/client/components/AuthenticatedComponent.js /^ static propTypes ={$/;" property line:21
-componentWillMount /Users/qitmac000445/Desktop/YAPI/yapi/client/components/AuthenticatedComponent.js /^ componentWillMount() {$/;" function line:28
-componentWillReceiveProps /Users/qitmac000445/Desktop/YAPI/yapi/client/components/AuthenticatedComponent.js /^ componentWillReceiveProps() {$/;" function line:31
-checkAuth /Users/qitmac000445/Desktop/YAPI/yapi/client/components/AuthenticatedComponent.js /^ checkAuth() {$/;" function line:34
-render /Users/qitmac000445/Desktop/YAPI/yapi/client/components/AuthenticatedComponent.js /^ render() {$/;" function line:40
-MenuUser.propTypes.user /Users/qitmac000445/Desktop/YAPI/yapi/client/components/Header/Header.js /^MenuUser.propTypes={$/;" property line:27
-ToolUser.propTypes.user /Users/qitmac000445/Desktop/YAPI/yapi/client/components/Header/Header.js /^ToolUser.propTypes={$/;" property line:59
-constructor /Users/qitmac000445/Desktop/YAPI/yapi/client/components/Header/Header.js /^ constructor(props) {$/;" function line:89
-static.router /Users/qitmac000445/Desktop/YAPI/yapi/client/components/Header/Header.js /^ static propTypes ={$/;" property line:92
-render /Users/qitmac000445/Desktop/YAPI/yapi/client/components/Header/Header.js /^ render () {$/;" function line:149
constructor /Users/qitmac000445/Desktop/YAPI/yapi/client/components/Header/Search/Search.js /^ constructor(props){$/;" function line:24
state.dataSource /Users/qitmac000445/Desktop/YAPI/yapi/client/components/Header/Search/Search.js /^ this.state = {$/;" property line:26
static.groupList /Users/qitmac000445/Desktop/YAPI/yapi/client/components/Header/Search/Search.js /^ static propTypes = {$/;" property line:31
getDataSource /Users/qitmac000445/Desktop/YAPI/yapi/client/components/Header/Search/Search.js /^ getDataSource(groupList){$/;" function line:91
render /Users/qitmac000445/Desktop/YAPI/yapi/client/components/Header/Search/Search.js /^ render(){$/;" function line:99
-@connect.url /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/AddInterface/AddInterface.js /^ static propTypes = {$/;" property line:58
-constructor /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/AddInterface/AddInterface.js /^ constructor (props) {$/;" function line:75
-constructor.state.isLoading /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/AddInterface/AddInterface.js /^ this.state = {$/;" property line:77
-constructor.state.isSave /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/AddInterface/AddInterface.js /^ isLoading: '',$/;" property line:78
-constructor.state.mockJson /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/AddInterface/AddInterface.js /^ isSave: false,$/;" property line:79
-constructor.state.mockURL /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/AddInterface/AddInterface.js /^ mockJson: '',$/;" property line:80
-constructor.state.projectData /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/AddInterface/AddInterface.js /^ mockURL: '',$/;" property line:81
-componentDidMount /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/AddInterface/AddInterface.js /^ componentDidMount () {$/;" function line:88
-getInterfaceId /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/AddInterface/AddInterface.js /^ getInterfaceId () {$/;" function line:121
-modifyTagName /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/AddInterface/AddInterface.js /^ modifyTagName (tagName) {$/;" function line:134
-verificationURL /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/AddInterface/AddInterface.js /^ verificationURL () {$/;" function line:140
-getMockURL /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/AddInterface/AddInterface.js /^ getMockURL (project_id, result) {$/;" function line:148
-getMockURL.id /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/AddInterface/AddInterface.js /^ const params = {id: project_id}$/;" property line:149
-editState /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/AddInterface/AddInterface.js /^ editState (data) {$/;" function line:161
-initInterfaceData /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/AddInterface/AddInterface.js /^ initInterfaceData (interfaceId) {$/;" function line:177
-initInterfaceData.id /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/AddInterface/AddInterface.js /^ const params = { id: interfaceId }$/;" property line:178
-initInterfaceDataTwo /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/AddInterface/AddInterface.js /^ initInterfaceDataTwo (interfaceId) {$/;" function line:198
-initInterfaceDataTwo.id /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/AddInterface/AddInterface.js /^ const params = { id: interfaceId }$/;" property line:199
-setLoading /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/AddInterface/AddInterface.js /^ setLoading (boolean) {$/;" function line:211
-routerPage /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/AddInterface/AddInterface.js /^ routerPage () {$/;" function line:217
-changeState /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/AddInterface/AddInterface.js /^ changeState (ifTrue) {$/;" function line:223
-mockData /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/AddInterface/AddInterface.js /^ mockData () { \/\/ mock 数据$/;" function line:230
-jumpEditUrl /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/AddInterface/AddInterface.js /^ jumpEditUrl (_id) {$/;" function line:244
-saveForms /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/AddInterface/AddInterface.js /^ saveForms () {$/;" function line:255
-render /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/AddInterface/AddInterface.js /^ render () {$/;" function line:308
@connect.reqParams /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/AddInterface/InterfaceTest/InterfaceTest.js /^ static propTypes = {$/;" property line:33
state.res /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/AddInterface/InterfaceTest/InterfaceTest.js /^ state = {$/;" property line:43
state.method /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/AddInterface/InterfaceTest/InterfaceTest.js /^ res: '',$/;" property line:44
@@ -174,23 +137,6 @@ rhymeCompleter.identifierRegexps /Users/qitmac000445/Desktop/YAPI/yapi/client/co
getCompletions /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/AddInterface/ResParams/ResParams.js /^ getCompletions: function (editor, session, pos, prefix, callback) {$/;" function line:72
callback /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/AddInterface/ResParams/ResParams.js /^ callback(null, wordList.map(function (ea) {$/;" function line:94
render /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/AddInterface/ResParams/ResParams.js /^ render() {$/;" function line:113
-const.y /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Home/Home.js /^const oneAnim = { y: '+=30', opacity: 0, type: 'from', ease: 'easeOutQuad' };$/;" property line:15
-const.opacity /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Home/Home.js /^const oneAnim = { y: '+=30', opacity: 0, type: 'from', ease: 'easeOutQuad' };$/;" property line:15
-const.type /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Home/Home.js /^const oneAnim = { y: '+=30', opacity: 0, type: 'from', ease: 'easeOutQuad' };$/;" property line:15
-const.ease /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Home/Home.js /^const oneAnim = { y: '+=30', opacity: 0, type: 'from', ease: 'easeOutQuad' };$/;" property line:15
-const.y /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Home/Home.js /^const imgAnim = { y: '+=50', opacity: 0, type: 'from', ease: 'easeOutQuad', duration: '1500'};$/;" property line:16
-const.opacity /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Home/Home.js /^const imgAnim = { y: '+=50', opacity: 0, type: 'from', ease: 'easeOutQuad', duration: '1500'};$/;" property line:16
-const.type /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Home/Home.js /^const imgAnim = { y: '+=50', opacity: 0, type: 'from', ease: 'easeOutQuad', duration: '1500'};$/;" property line:16
-const.ease /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Home/Home.js /^const imgAnim = { y: '+=50', opacity: 0, type: 'from', ease: 'easeOutQuad', duration: '1500'};$/;" property line:16
-const.duration /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Home/Home.js /^const imgAnim = { y: '+=50', opacity: 0, type: 'from', ease: 'easeOutQuad', duration: '1500'};$/;" property line:16
-const.width /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Home/Home.js /^const style = {$/;" property line:17
-const.background /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Home/Home.js /^ 'width':'100%',$/;" property line:20
-const.backgroundSize /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Home/Home.js /^ 'background': 'url(.\/image\/bg-img.jpg) no-repeat',$/;" property line:21
-HomeGuest.propTypes.introList /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Home/Home.js /^HomeGuest.propTypes ={$/;" property line:125
-constructor /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Home/Home.js /^ constructor(props) {$/;" function line:139
-static.introList /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Home/Home.js /^ static propTypes = {$/;" property line:142
-render /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Home/Home.js /^ render () {$/;" function line:150
-Home.defaultProps.introList /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Home/Home.js /^Home.defaultProps={$/;" property line:174
from.fetchInterfaceData /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Interface/Interface.js /^ static propTypes = {$/;" property line:34
constructor /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Interface/Interface.js /^ constructor(props) {$/;" function line:43
componentWillMount /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Interface/Interface.js /^ componentWillMount () {$/;" function line:47
@@ -203,29 +149,6 @@ deleteInterfaceData /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Inte
deleteInterface /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Interface/InterfaceTable/InterfaceTable.js /^ deleteInterface (interfaceId) {$/;" function line:50
deleteInterface.id /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Interface/InterfaceTable/InterfaceTable.js /^ const params = {$/;" property line:51
render /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Interface/InterfaceTable/InterfaceTable.js /^ render () {$/;" function line:63
-import.marginBottom /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Login/Login.js /^const formItemStyle = {$/;" property line:9
-const.height /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Login/Login.js /^const changeHeight = {$/;" property line:13
-constructor /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Login/Login.js /^ constructor(props) {$/;" function line:29
-static.form /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Login/Login.js /^ static propTypes = {$/;" property line:33
-componentDidMount /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Login/Login.js /^ componentDidMount() {$/;" function line:56
-render /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Login/Login.js /^ render() {$/;" function line:61
-const.marginBottom /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Login/Reg.js /^const formItemStyle = {$/;" property line:8
-const.height /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Login/Reg.js /^const changeHeight = {$/;" property line:12
-constructor /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Login/Reg.js /^ constructor(props) {$/;" function line:28
-state.confirmDirty /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Login/Reg.js /^ this.state = {$/;" property line:30
-static.form /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Login/Reg.js /^ static propTypes = {$/;" property line:35
-render /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Login/Reg.js /^ render() {$/;" function line:80
-constructor /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/News/News.js /^ constructor(props) {$/;" function line:23
-from.state.loading /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/News/News.js /^ this.state = {$/;" property line:25
-static.newsData /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/News/News.js /^ static propTypes = {$/;" property line:29
-setLoading /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/News/News.js /^ setLoading(bool){$/;" function line:34
-componentWillMount /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/News/News.js /^ componentWillMount(){$/;" function line:39
-render /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/News/News.js /^ render () {$/;" function line:45
-@connect.fetchNewsData /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/News/NewsList/NewsList.js /^ static propTypes = {$/;" property line:34
-constructor /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/News/NewsList/NewsList.js /^ constructor(props) {$/;" function line:40
-constructor.state.selectedKeys /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/News/NewsList/NewsList.js /^ this.state = {$/;" property line:42
-getLogData /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/News/NewsList/NewsList.js /^ getLogData(e){$/;" function line:46
-render /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/News/NewsList/NewsList.js /^ render () {$/;" function line:59
from /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/News/NewsTimeline/NewsTimeline.js /^import { fetchMoreNews } from '..\/..\/..\/reducer\/modules\/news.js'$/;" function line:5
@connect.newsData /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/News/NewsTimeline/NewsTimeline.js /^ static propTypes = {$/;" property line:22
constructor /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/News/NewsTimeline/NewsTimeline.js /^ constructor(props) {$/;" function line:29
@@ -254,11 +177,6 @@ static.form /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/ProjectGroup
render /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/ProjectGroups/ProjectList/UpDateModal.js /^ render() {$/;" function line:152
validator /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/ProjectGroups/ProjectList/UpDateModal.js /^ validator(rule, value, callback) {$/;" function line:191
validator /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/ProjectGroups/ProjectList/UpDateModal.js /^ validator(rule, value, callback) {$/;" function line:224
-constructor /Users/qitmac000445/Desktop/YAPI/yapi/client/Application.js /^ constructor(props) {$/;" function line:27
-state.login /Users/qitmac000445/Desktop/YAPI/yapi/client/Application.js /^ this.state = {$/;" property line:29
-static.checkLoginState /Users/qitmac000445/Desktop/YAPI/yapi/client/Application.js /^ static propTypes = {$/;" property line:34
-componentDidMount /Users/qitmac000445/Desktop/YAPI/yapi/client/Application.js /^ componentDidMount() {$/;" function line:39
-render /Users/qitmac000445/Desktop/YAPI/yapi/client/Application.js /^ render() {$/;" function line:72
createStore /Users/qitmac000445/Desktop/YAPI/yapi/client/reducer/create.js /^export default function createStore(initialState = {}) {$/;" function line:8
module.exports.parser /Users/qitmac000445/Desktop/YAPI/yapi/client/.eslintrc.js /^module.exports = {$/;" property line:1
module.exports.extends /Users/qitmac000445/Desktop/YAPI/yapi/client/.eslintrc.js /^ parser: 'babel-eslint',$/;" property line:2
@@ -411,3 +329,135 @@ inputNewGroupDesc /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Projec
selectGroup /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/ProjectGroups/GroupList/GroupList.js /^ selectGroup(e) {$/;" function line:151
searchGroup /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/ProjectGroups/GroupList/GroupList.js /^ searchGroup(e, value) {$/;" function line:175
render /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/ProjectGroups/GroupList/GroupList.js /^ render () {$/;" function line:185
+constructor /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Group/Group.js /^ constructor(props) {$/;" function line:10
+render /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Group/Group.js /^ render () {$/;" function line:14
+const.isLogin /Users/qitmac000445/Desktop/YAPI/yapi/client/reducer/modules/user.js /^const initialState = {$/;" property line:15
+const.userName /Users/qitmac000445/Desktop/YAPI/yapi/client/reducer/modules/user.js /^ isLogin: false,$/;" property line:16
+const.uid /Users/qitmac000445/Desktop/YAPI/yapi/client/reducer/modules/user.js /^ userName: null,$/;" property line:17
+const.email /Users/qitmac000445/Desktop/YAPI/yapi/client/reducer/modules/user.js /^ uid: null,$/;" property line:18
+const.loginState /Users/qitmac000445/Desktop/YAPI/yapi/client/reducer/modules/user.js /^ email: '',$/;" property line:19
+const.loginWrapActiveKey /Users/qitmac000445/Desktop/YAPI/yapi/client/reducer/modules/user.js /^ loginState: LOADING_STATUS,$/;" property line:20
+switch /Users/qitmac000445/Desktop/YAPI/yapi/client/reducer/modules/user.js /^ switch (action.type) {$/;" function line:25
+checkLoginState /Users/qitmac000445/Desktop/YAPI/yapi/client/reducer/modules/user.js /^export function checkLoginState() {$/;" function line:82
+loginActions /Users/qitmac000445/Desktop/YAPI/yapi/client/reducer/modules/user.js /^export function loginActions(data) {$/;" function line:95
+regActions /Users/qitmac000445/Desktop/YAPI/yapi/client/reducer/modules/user.js /^export function regActions(data) {$/;" function line:102
+const.username /Users/qitmac000445/Desktop/YAPI/yapi/client/reducer/modules/user.js /^ password,$/;" property line:106
+logoutActions /Users/qitmac000445/Desktop/YAPI/yapi/client/reducer/modules/user.js /^export function logoutActions() {$/;" function line:115
+loginTypeAction /Users/qitmac000445/Desktop/YAPI/yapi/client/reducer/modules/user.js /^export function loginTypeAction(index) {$/;" function line:122
+constructor /Users/qitmac000445/Desktop/YAPI/yapi/client/Application.js /^ constructor(props) {$/;" function line:26
+state.login /Users/qitmac000445/Desktop/YAPI/yapi/client/Application.js /^ this.state = {$/;" property line:28
+static.checkLoginState /Users/qitmac000445/Desktop/YAPI/yapi/client/Application.js /^ static propTypes = {$/;" property line:33
+componentDidMount /Users/qitmac000445/Desktop/YAPI/yapi/client/Application.js /^ componentDidMount() {$/;" function line:45
+render /Users/qitmac000445/Desktop/YAPI/yapi/client/Application.js /^ render() {$/;" function line:78
+const.height /Users/qitmac000445/Desktop/YAPI/yapi/client/components/Header/Header.js /^const headerStyle = {$/;" property line:13
+const.lineHeight /Users/qitmac000445/Desktop/YAPI/yapi/client/components/Header/Header.js /^ 'height': '.56rem',$/;" property line:14
+const.padding /Users/qitmac000445/Desktop/YAPI/yapi/client/components/Header/Header.js /^ 'lineHeight': '.56rem',$/;" property line:15
+MenuUser.propTypes.user /Users/qitmac000445/Desktop/YAPI/yapi/client/components/Header/Header.js /^MenuUser.propTypes={$/;" property line:34
+ToolUser.propTypes.user /Users/qitmac000445/Desktop/YAPI/yapi/client/components/Header/Header.js /^ToolUser.propTypes={$/;" property line:78
+constructor /Users/qitmac000445/Desktop/YAPI/yapi/client/components/Header/Header.js /^ constructor(props) {$/;" function line:107
+static.router /Users/qitmac000445/Desktop/YAPI/yapi/client/components/Header/Header.js /^ static propTypes ={$/;" property line:110
+render /Users/qitmac000445/Desktop/YAPI/yapi/client/components/Header/Header.js /^ render () {$/;" function line:166
+import.marginBottom /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Login/Login.js /^const formItemStyle = {$/;" property line:9
+const.height /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Login/Login.js /^const changeHeight = {$/;" property line:13
+constructor /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Login/Login.js /^ constructor(props) {$/;" function line:29
+static.form /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Login/Login.js /^ static propTypes = {$/;" property line:33
+componentDidMount /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Login/Login.js /^ componentDidMount() {$/;" function line:56
+render /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Login/Login.js /^ render() {$/;" function line:61
+const.marginBottom /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Login/Reg.js /^const formItemStyle = {$/;" property line:8
+const.height /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Login/Reg.js /^const changeHeight = {$/;" property line:12
+constructor /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Login/Reg.js /^ constructor(props) {$/;" function line:28
+state.confirmDirty /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Login/Reg.js /^ this.state = {$/;" property line:30
+static.form /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Login/Reg.js /^ static propTypes = {$/;" property line:35
+render /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Login/Reg.js /^ render() {$/;" function line:80
+requireAuthentication /Users/qitmac000445/Desktop/YAPI/yapi/client/components/AuthenticatedComponent.js /^export function requireAuthentication(Component) {$/;" function line:16
+constructor /Users/qitmac000445/Desktop/YAPI/yapi/client/components/AuthenticatedComponent.js /^ constructor(props){$/;" function line:18
+static.isAuthenticated /Users/qitmac000445/Desktop/YAPI/yapi/client/components/AuthenticatedComponent.js /^ static propTypes ={$/;" property line:21
+componentWillMount /Users/qitmac000445/Desktop/YAPI/yapi/client/components/AuthenticatedComponent.js /^ componentWillMount() {$/;" function line:28
+componentWillReceiveProps /Users/qitmac000445/Desktop/YAPI/yapi/client/components/AuthenticatedComponent.js /^ componentWillReceiveProps() {$/;" function line:31
+checkAuth /Users/qitmac000445/Desktop/YAPI/yapi/client/components/AuthenticatedComponent.js /^ checkAuth() {$/;" function line:34
+render /Users/qitmac000445/Desktop/YAPI/yapi/client/components/AuthenticatedComponent.js /^ render() {$/;" function line:40
+const.y /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Home/Home.js /^const oneAnim = { y: '+=30', opacity: 0, type: 'from', ease: 'easeOutQuad' };$/;" property line:15
+const.opacity /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Home/Home.js /^const oneAnim = { y: '+=30', opacity: 0, type: 'from', ease: 'easeOutQuad' };$/;" property line:15
+const.type /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Home/Home.js /^const oneAnim = { y: '+=30', opacity: 0, type: 'from', ease: 'easeOutQuad' };$/;" property line:15
+const.ease /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Home/Home.js /^const oneAnim = { y: '+=30', opacity: 0, type: 'from', ease: 'easeOutQuad' };$/;" property line:15
+const.y /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Home/Home.js /^const imgAnim = { y: '+=50', opacity: 0, type: 'from', ease: 'easeOutQuad', duration: '1500'};$/;" property line:16
+const.opacity /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Home/Home.js /^const imgAnim = { y: '+=50', opacity: 0, type: 'from', ease: 'easeOutQuad', duration: '1500'};$/;" property line:16
+const.type /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Home/Home.js /^const imgAnim = { y: '+=50', opacity: 0, type: 'from', ease: 'easeOutQuad', duration: '1500'};$/;" property line:16
+const.ease /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Home/Home.js /^const imgAnim = { y: '+=50', opacity: 0, type: 'from', ease: 'easeOutQuad', duration: '1500'};$/;" property line:16
+const.duration /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Home/Home.js /^const imgAnim = { y: '+=50', opacity: 0, type: 'from', ease: 'easeOutQuad', duration: '1500'};$/;" property line:16
+const.width /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Home/Home.js /^const style = {$/;" property line:17
+const.background-color /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Home/Home.js /^ 'width':'100%',$/;" property line:18
+const.backgroundSize /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Home/Home.js /^ 'background-color': '#333',$/;" property line:20
+HomeGuest.propTypes.introList /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Home/Home.js /^HomeGuest.propTypes ={$/;" property line:124
+constructor /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Home/Home.js /^ constructor(props) {$/;" function line:138
+static.introList /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Home/Home.js /^ static propTypes = {$/;" property line:141
+render /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Home/Home.js /^ render () {$/;" function line:149
+Home.defaultProps.introList /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Home/Home.js /^Home.defaultProps={$/;" property line:173
+@connect.url /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/AddInterface/AddInterface.js /^ static propTypes = {$/;" property line:58
+constructor /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/AddInterface/AddInterface.js /^ constructor (props) {$/;" function line:75
+constructor.state.isLoading /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/AddInterface/AddInterface.js /^ this.state = {$/;" property line:77
+constructor.state.isSave /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/AddInterface/AddInterface.js /^ isLoading: '',$/;" property line:78
+constructor.state.mockJson /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/AddInterface/AddInterface.js /^ isSave: false,$/;" property line:79
+constructor.state.mockURL /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/AddInterface/AddInterface.js /^ mockJson: '',$/;" property line:80
+constructor.state.projectData /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/AddInterface/AddInterface.js /^ mockURL: '',$/;" property line:81
+componentDidMount /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/AddInterface/AddInterface.js /^ componentDidMount () {$/;" function line:88
+getInterfaceId /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/AddInterface/AddInterface.js /^ getInterfaceId () {$/;" function line:121
+modifyTagName /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/AddInterface/AddInterface.js /^ modifyTagName (tagName) {$/;" function line:134
+verificationURL /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/AddInterface/AddInterface.js /^ verificationURL () {$/;" function line:140
+getMockURL /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/AddInterface/AddInterface.js /^ getMockURL (project_id, result) {$/;" function line:148
+getMockURL.id /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/AddInterface/AddInterface.js /^ const params = {id: project_id}$/;" property line:149
+editState /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/AddInterface/AddInterface.js /^ editState (data) {$/;" function line:161
+initInterfaceData /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/AddInterface/AddInterface.js /^ initInterfaceData (interfaceId) {$/;" function line:177
+initInterfaceData.id /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/AddInterface/AddInterface.js /^ const params = { id: interfaceId }$/;" property line:178
+initInterfaceDataTwo /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/AddInterface/AddInterface.js /^ initInterfaceDataTwo (interfaceId) {$/;" function line:198
+initInterfaceDataTwo.id /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/AddInterface/AddInterface.js /^ const params = { id: interfaceId }$/;" property line:199
+setLoading /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/AddInterface/AddInterface.js /^ setLoading (boolean) {$/;" function line:211
+routerPage /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/AddInterface/AddInterface.js /^ routerPage () {$/;" function line:217
+changeState /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/AddInterface/AddInterface.js /^ changeState (ifTrue) {$/;" function line:223
+mockData /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/AddInterface/AddInterface.js /^ mockData () { \/\/ mock 数据$/;" function line:230
+jumpEditUrl /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/AddInterface/AddInterface.js /^ jumpEditUrl (_id) {$/;" function line:244
+saveForms /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/AddInterface/AddInterface.js /^ saveForms () {$/;" function line:255
+render /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/AddInterface/AddInterface.js /^ render () {$/;" function line:308
+from.groupList /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Group/GroupList/GroupList.js /^ static propTypes = {$/;" property line:35
+state.addGroupModalVisible /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Group/GroupList/GroupList.js /^ state = {$/;" property line:46
+state.editGroupModalVisible /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Group/GroupList/GroupList.js /^ addGroupModalVisible: false,$/;" property line:47
+state.newGroupName /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Group/GroupList/GroupList.js /^ editGroupModalVisible: false,$/;" property line:48
+state.newGroupDesc /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Group/GroupList/GroupList.js /^ newGroupName: '',$/;" property line:49
+state.currGroupName /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Group/GroupList/GroupList.js /^ newGroupDesc: '',$/;" property line:50
+state.currGroupDesc /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Group/GroupList/GroupList.js /^ currGroupName: '',$/;" property line:51
+state.groupList /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Group/GroupList/GroupList.js /^ currGroupDesc: '',$/;" property line:52
+constructor /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Group/GroupList/GroupList.js /^ constructor(props) {$/;" function line:56
+showModal /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Group/GroupList/GroupList.js /^ showModal(type) {$/;" function line:80
+hideModal /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Group/GroupList/GroupList.js /^ hideModal(type) {$/;" function line:95
+inputNewGroupName /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Group/GroupList/GroupList.js /^ inputNewGroupName(e, type) {$/;" function line:134
+inputNewGroupDesc /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Group/GroupList/GroupList.js /^ inputNewGroupDesc(e, type) {$/;" function line:142
+selectGroup /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Group/GroupList/GroupList.js /^ selectGroup(e) {$/;" function line:151
+searchGroup /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Group/GroupList/GroupList.js /^ searchGroup(e, value) {$/;" function line:175
+render /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Group/GroupList/GroupList.js /^ render () {$/;" function line:185
+constructor /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Login/LoginWrap.js /^ constructor(props){$/;" function line:16
+static.form /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Login/LoginWrap.js /^ static propTypes = {$/;" property line:20
+render /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Login/LoginWrap.js /^ render() {$/;" function line:25
+constructor /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/News/News.js /^ constructor(props) {$/;" function line:24
+state.mockURL /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/News/News.js /^ this.state = {$/;" property line:26
+static.uid /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/News/News.js /^ static propTypes = {$/;" property line:30
+componentWillMount /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/News/News.js /^ componentWillMount(){$/;" function line:34
+render /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/News/News.js /^ render () {$/;" function line:44
+@connect.fetchNewsData /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/News/NewsList/NewsList.js /^ static propTypes = {$/;" property line:34
+constructor /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/News/NewsList/NewsList.js /^ constructor(props) {$/;" function line:40
+constructor.state.selectedKeys /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/News/NewsList/NewsList.js /^ this.state = {$/;" property line:42
+getLogData /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/News/NewsList/NewsList.js /^ getLogData(e){$/;" function line:46
+render /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/News/NewsList/NewsList.js /^ render () {$/;" function line:59
+constructor /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/User/LeftMenu.js /^ constructor(props) {$/;" function line:21
+@connect.state.dataSource /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/User/LeftMenu.js /^ this.state = {$/;" property line:23
+static.curUid /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/User/LeftMenu.js /^ static propTypes = {$/;" property line:31
+render /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/User/LeftMenu.js /^ render() {$/;" function line:68
+constructor /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/User/List.js /^ constructor(props) {$/;" function line:24
+@connect.state.data /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/User/List.js /^ this.state = {$/;" property line:26
+static.curUserRole /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/User/List.js /^ static propTypes = {$/;" property line:32
+getUserList /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/User/List.js /^ getUserList() {$/;" function line:41
+componentDidMount /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/User/List.js /^ componentDidMount() {$/;" function line:60
+render /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/User/List.js /^ render() {$/;" function line:85
+from.children /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Project/Project.js /^ static propTypes = {$/;" property line:8
+constructor /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Project/Project.js /^ constructor(props) {$/;" function line:15
+componentWillMount /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Project/Project.js /^ componentWillMount() {$/;" function line:19
+render /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Project/Project.js /^ render () {$/;" function line:22
diff --git a/.tags1 b/.tags1
index 3a940a30..b1b2df20 100644
--- a/.tags1
+++ b/.tags1
@@ -4,19 +4,7 @@
!_TAG_PROGRAM_NAME Exuberant Ctags //
!_TAG_PROGRAM_URL http://ctags.sourceforge.net /official site/
!_TAG_PROGRAM_VERSION 5.8 //
-from.groupList /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/ProjectGroups/GroupList/GroupList.js /^ static propTypes = {$/;" property line:35
-state.addGroupModalVisible /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/ProjectGroups/GroupList/GroupList.js /^ state = {$/;" property line:46
-state.editGroupModalVisible /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/ProjectGroups/GroupList/GroupList.js /^ addGroupModalVisible: false,$/;" property line:47
-state.newGroupName /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/ProjectGroups/GroupList/GroupList.js /^ editGroupModalVisible: false,$/;" property line:48
-state.newGroupDesc /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/ProjectGroups/GroupList/GroupList.js /^ newGroupName: '',$/;" property line:49
-state.currGroupName /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/ProjectGroups/GroupList/GroupList.js /^ newGroupDesc: '',$/;" property line:50
-state.currGroupDesc /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/ProjectGroups/GroupList/GroupList.js /^ currGroupName: '',$/;" property line:51
-state.groupList /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/ProjectGroups/GroupList/GroupList.js /^ currGroupDesc: '',$/;" property line:52
-constructor /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/ProjectGroups/GroupList/GroupList.js /^ constructor(props) {$/;" function line:56
-showModal /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/ProjectGroups/GroupList/GroupList.js /^ showModal(type) {$/;" function line:80
-hideModal /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/ProjectGroups/GroupList/GroupList.js /^ hideModal(type) {$/;" function line:95
-inputNewGroupName /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/ProjectGroups/GroupList/GroupList.js /^ inputNewGroupName(e, type) {$/;" function line:134
-inputNewGroupDesc /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/ProjectGroups/GroupList/GroupList.js /^ inputNewGroupDesc(e, type) {$/;" function line:142
-selectGroup /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/ProjectGroups/GroupList/GroupList.js /^ selectGroup(e) {$/;" function line:151
-searchGroup /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/ProjectGroups/GroupList/GroupList.js /^ searchGroup(e, value) {$/;" function line:175
-render /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/ProjectGroups/GroupList/GroupList.js /^ render () {$/;" function line:185
+from.children /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Project/Project.js /^ static propTypes = {$/;" property line:8
+constructor /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Project/Project.js /^ constructor(props) {$/;" function line:15
+componentWillMount /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Project/Project.js /^ componentWillMount() {$/;" function line:19
+render /Users/qitmac000445/Desktop/YAPI/yapi/client/containers/Project/Project.js /^ render () {$/;" function line:22
diff --git a/README.md b/README.md
index b5e033a6..a77f9dc0 100644
--- a/README.md
+++ b/README.md
@@ -1,98 +1,17 @@
# YApi
-## 平台介绍
+## 一、平台介绍
-
YApi是高效、易用、功能强大、的api管理平台,旨在为开发、产品、测试人员提供更优雅的接口管理服务。可以帮助开发者轻松创建、发布、维护、监控和保护任意规模的 API,而且yapi为用户提供了优秀的交互体验,开发人员只需利用平台提供的接口数据写入工具以及简单的点击操作就可以实现接口的创建。
+YApi是高效、易用、功能强大、的api管理平台,旨在为开发、产品、测试人员提供更优雅的接口管理服务。可以帮助开发者轻松创建、发布、维护、监控和保护任意规模的 API,yapi还为用户提供了优秀的交互体验,开发人员只需利用平台提供的接口数据写入工具以及简单的点击操作就可以实现接口的管理。
-## 功能
-1. 项目接口管理
-
- 提供基本的项目分组,项目管理,接口管理功能
-
-2. mockServer服务
-
- 用户只需在项目配置线上域名和接口基本路径,通过将线上域名指到我们的yapi平台服务器,就可使用mockServer服务
-
-3. 用户管理
-
- 提供基本的用户注册登录管理等功能,集成了去哪儿QSSO登录
-
-## 快速开始
-### 1 接口管理架构
-平台以**项目分组** -> **项目** -> **接口**的划分进行接口组织管理。
-
-
-
-#### 1.1 项目分组
-
-登录之后进到项目首页,左边侧边栏显示的即分组列表。
-
-
-
-管理员有权限添加或删除分组。
-
-
-
-> 分组名称具有唯一性
-
-#### 1.2 项目
-
-选中不同的分组,右边会显示该分组下的项目列表。
-
-
-
-创建项目需要填写项目名称,项目线上域名(添加完成后可配置项目其他环境域名),项目接口基本路径(接口路径前面相同的部分)以及项目描述。
-
-
-
-> 项目『线上域名 + 基本路径』具有唯一性
-
-#### 1.3 接口
-
-点击项目名称,进入该项目接口列表。
-
-
-
-点击编辑,进入接口详情页(之后接口详情页和编辑也会分开),可以编辑接口或者请求测试真实接口。
-
-
-
-
+## 二、特性
+* 完善的项目接口管理功能
+* 易用的MockServer
+* 类gitlab的用户管理和权限管理功能
+* 强大的接口集功能
-### 2 Mock功能
- yapi的Mock功能可以根据用户的输入接口信息如协议、URL、接口名、请求头、请求参数、mock规则生成Mock接口,这些接口会自动生成模拟数据,支持复杂的生成逻辑,创建者可以自由构造需要的数据。而且与常见的Mock方式如将Mock写在代码里和JS拦截等相比yapi的Mock在使用场景和效率和复杂度上是相差甚远的,正是由于yapi的Mock是一个第三方平台那么在 团队开发时任何人都可以权限许可下创建、修改接口信息等操作,这对于团队开发是很有好处的。
-#### 2.1 添加接口
-通过点击页面上的"+添加接口"
-
-
- 输入协议、URL、接口名、请求头、请求参数、mock规则等信息,然后点击右上角的"Mock"按钮。
-
-
-
-#### 2.2 Mock
-
-当点击"Mock"按钮之后,就会在页面下方生成一个mock结果并产生一个API接口。点击"复制"按钮即可复制,用户拿到接口后就可以发请求了。
-
-
-
-将请求的信息填写完善如:请求方法(post、get等)、URL、请求头、请求的数据等。然后就点击"发送",然后在"返回结果"出可以看到接口返回的数据。
-
-
-
-#### 2.3 成员管理
-
-你也可以通过点击"管理成员"来添加和删除项目的成员,便于团队管理。
-
-
-
-## 未来计划推出功能
-
-1. 可视化JSON编辑器,可定义JSON_Schema和mockjs
-2. 支持HTTP和RPC协议
-3. 自动化测试
-4. 多人协作
diff --git a/client/Application.js b/client/Application.js
index 3fc1826a..24aafcd7 100644
--- a/client/Application.js
+++ b/client/Application.js
@@ -2,12 +2,12 @@ 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, Follows } from './containers/index';
+import { Home, Group, Project, News, AddInterface, Follows, AddProject } 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 './reducer/modules/login';
+import { checkLoginState } from './reducer/modules/user';
import { requireAuthentication } from './components/AuthenticatedComponent';
const LOADING_STATUS = 0;
@@ -15,7 +15,7 @@ const LOADING_STATUS = 0;
@connect(
state => {
return {
- loginState: state.login.loginState
+ loginState: state.user.loginState
};
},
{
@@ -35,6 +35,13 @@ export default class App extends Component {
loginState: PropTypes.number
};
+ // componentWillMount() {
+ // if( !this.props.isAuthenticated ){
+ // this.props.history.push('/');
+ // this.props.changeMenuItem('/');
+ // }
+ // }
+
componentDidMount() {
this.props.checkLoginState();
}
@@ -52,13 +59,14 @@ export default class App extends Component {
-
+
-
+
+
diff --git a/client/components/AuthenticatedComponent.js b/client/components/AuthenticatedComponent.js
index a7f69dca..940fcd29 100644
--- a/client/components/AuthenticatedComponent.js
+++ b/client/components/AuthenticatedComponent.js
@@ -6,7 +6,7 @@ import { changeMenuItem } from '../reducer/modules/menu'
@connect(
(state) => {
return{
- isAuthenticated: state.login.isLogin
+ isAuthenticated: state.user.isLogin
}
},
{
diff --git a/client/components/index.js b/client/components/index.js
new file mode 100644
index 00000000..4bfa756d
--- /dev/null
+++ b/client/components/index.js
@@ -0,0 +1,19 @@
+import Breadcrumb from './Breadcrumb/Breadcrumb.js'
+import Footer from './Footer/Footer.js'
+import Header from './Header/Header.js'
+import Intro from './Intro/Intro.js'
+import Loading from './Loading/Loading.js'
+import MockDoc from './MockDoc/MockDoc.js'
+import ProjectBox from './ProjectBox/ProjectBox.js'
+import Subnav from './Subnav/Subnav.js'
+
+export {
+ Breadcrumb,
+ Footer,
+ Header,
+ Intro,
+ Loading,
+ MockDoc,
+ ProjectBox,
+ Subnav
+}
diff --git a/client/containers/AddInterface/AddInterface.js b/client/containers/AddInterface/AddInterface.js
index bd360107..83cf978e 100644
--- a/client/containers/AddInterface/AddInterface.js
+++ b/client/containers/AddInterface/AddInterface.js
@@ -38,7 +38,7 @@ const success = (text, arg) => {
url: state.addInterface.url,
seqGroup: state.addInterface.seqGroup,
interfaceName: state.addInterface.interfaceName,
- server_ip: state.login.server_ip,
+ server_ip: state.user.server_ip,
clipboard: state.addInterface.clipboard
}
},
diff --git a/client/containers/Group/Group.js b/client/containers/Group/Group.js
new file mode 100644
index 00000000..0db97fb0
--- /dev/null
+++ b/client/containers/Group/Group.js
@@ -0,0 +1,39 @@
+import React, { Component } from 'react';
+import GroupList from './GroupList/GroupList.js';
+import ProjectList from './ProjectList/ProjectList.js';
+import Subnav from '../../components/Subnav/Subnav.js';
+import { Row, Col } from 'antd';
+
+import './Group.scss'
+
+export default class Group extends Component {
+ constructor(props) {
+ super(props)
+ }
+
+ render () {
+ return (
+
+ )
+ }
+}
diff --git a/client/containers/Group/Group.scss b/client/containers/Group/Group.scss
new file mode 100644
index 00000000..a6944eb2
--- /dev/null
+++ b/client/containers/Group/Group.scss
@@ -0,0 +1,6 @@
+@import '../../styles/mixin.scss';
+
+.g-doc {
+ @include row-width-limit;
+ margin: 0 auto .24rem;
+}
diff --git a/client/containers/Group/GroupList/GroupList.js b/client/containers/Group/GroupList/GroupList.js
new file mode 100644
index 00000000..fb193a32
--- /dev/null
+++ b/client/containers/Group/GroupList/GroupList.js
@@ -0,0 +1,276 @@
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
+import { connect } from 'react-redux'
+import { Button, Icon, Popconfirm, Modal, Input, message, Menu, Row, Col } from 'antd'
+import { autobind } from 'core-decorators';
+import axios from 'axios';
+import { withRouter } from 'react-router';
+const { TextArea } = Input;
+const Search = Input.Search;
+const TYPE_EDIT = 'edit';
+
+import {
+ fetchGroupList,
+ setCurrGroup,
+ setGroupList
+} from '../../../reducer/modules/group.js'
+
+import './GroupList.scss'
+
+@connect(
+ state => ({
+ groupList: state.group.groupList,
+ currGroup: state.group.currGroup,
+ curUserRole: state.user.role
+ }),
+ {
+ fetchGroupList,
+ setCurrGroup,
+ setGroupList
+ }
+)
+@withRouter
+export default class GroupList extends Component {
+
+ static propTypes = {
+ groupList: PropTypes.array,
+ currGroup: PropTypes.object,
+ fetchGroupList: PropTypes.func,
+ setCurrGroup: PropTypes.func,
+ setGroupList: PropTypes.func,
+ match: PropTypes.object,
+ history: PropTypes.object,
+ curUserRole: PropTypes.string
+ }
+
+ state = {
+ addGroupModalVisible: false,
+ editGroupModalVisible: false,
+ newGroupName: '',
+ newGroupDesc: '',
+ currGroupName: '',
+ currGroupDesc: '',
+ groupList: []
+ }
+
+ constructor(props) {
+ super(props)
+ }
+
+ async componentWillMount() {
+ const groupName = this.props.match.params.groupName;
+ await this.props.fetchGroupList();
+ let currGroup = this.props.groupList[0] || { group_name: '', group_desc: '' };
+ if(this.props.groupList.length && groupName){
+ for(let i = 0;i { return +group._id === +groupId });
+ this.props.setCurrGroup(currGroup);
+ this.props.history.replace(`${currGroup._id}`);
+ }
+
+ @autobind
+ async deleteGroup() {
+ const self = this;
+ const { currGroup } = self.props;
+ const res = await axios.post('/group/del', {id: currGroup._id})
+ if (res.data.errcode) {
+ message.error(res.data.errmsg);
+ } else {
+ message.success('删除成功');
+ await self.props.fetchGroupList()
+ const currGroup = self.props.groupList[0] || { group_name: '', group_desc: '' };
+ self.setState({groupList: self.props.groupList});
+ self.props.setCurrGroup(currGroup)
+ }
+ }
+
+ @autobind
+ searchGroup(e, value) {
+ const v = value || e.target.value;
+ const { groupList } = this.props;
+ if (v === '') {
+ this.setState({groupList})
+ } else {
+ this.setState({groupList: groupList.filter(group => new RegExp(v, 'i').test(group.group_name))})
+ }
+ }
+
+ render () {
+ const { currGroup } = this.props;
+ const delmark = this.showModal(TYPE_EDIT)}/>
+ const editmark = (
+
+ )
+
+
+ return (
+
+
+
+
+
{currGroup.group_name}
+ {
+ this.props.curUserRole === "admin"?(editmark):''
+ }
+ {
+ this.props.curUserRole === "admin"?(delmark):''
+ }
+
+
+
简介:{currGroup.group_desc}
+
+
+
+ this.searchGroup(null, v)}/>
+
+ {
+ this.props.curUserRole === "admin"?(
):''
+ }
+
+
+
+
+
+
+ 分组名:
+
+
+
+
+
+ 简介:
+
+
+
+
+
+
this.hideModal(TYPE_EDIT)}
+ className="add-group-modal"
+ >
+
+ 分组名:
+
+ this.inputNewGroupName(e, TYPE_EDIT)}>
+
+
+
+ 简介:
+
+
+
+
+
+
+ )
+ }
+}
diff --git a/client/containers/Group/GroupList/GroupList.scss b/client/containers/Group/GroupList/GroupList.scss
new file mode 100644
index 00000000..576d2d90
--- /dev/null
+++ b/client/containers/Group/GroupList/GroupList.scss
@@ -0,0 +1,92 @@
+.group-bar {
+ box-shadow: 0 2px 4px 0 rgba(0,0,0,0.20);
+ border-radius: 4px;
+ background-color: #fff;
+ min-height: 5rem;
+ .curr-group {
+ background: #34495E;
+ border-radius: 4px 4px 0 0;
+ padding: 32px 24px;
+ .curr-group-name {
+ .text {
+ display: inline-block;
+ overflow:hidden;
+ white-space:nowrap;
+ text-overflow:ellipsis;
+ max-width: 150px;
+ vertical-align: bottom;
+ }
+
+ color: #fff;
+ font-size: 24px;
+ }
+ .curr-group-desc {
+ color: #fff;
+ font-size: 12px;
+ max-height: 54px;
+ text-overflow:ellipsis;
+ overflow:hidden;
+ -webkit-line-clamp: 3;
+ -webkit-box-orient: vertical;
+ display: -webkit-box;
+ }
+ .delete-group, .edit-group {
+ font-size: 18px;
+ margin-left: 12px;
+ cursor: pointer;
+ }
+ .delete-group:hover, .edit-group:hover {
+ color: #ccc;
+ }
+ }
+ .group-operate {
+ height: 48px;
+ padding: 10px 6px;
+ background: #eee;
+ display: flex;
+ justify-content: space-around;
+ .search {
+ margin-right: 6px;
+ flex-grow: 1;
+ }
+
+ }
+ .group-list {
+ max-height: 650px;
+ overflow-y: scroll;
+ overflow-x: hidden;
+ border-bottom: 1px solid #e9e9e9;
+ padding-bottom: 24px;
+ border-radius: 0 0 4px 4px;
+ border: none;
+ .group-item {
+ // height: 48px;
+ // line-height: 48px;
+ // padding: 0 24px;
+ font-size: 14px;
+ }
+ .group-item:hover {
+ // background: #34495E;
+ // color: #fff;
+ }
+ .group-item.selected {
+ // background: #34495E;
+ }
+ .group-name {
+ float: left;
+ }
+ .group-edit {
+ float: right;
+ font-size: 18px;
+ }
+ }
+}
+.add-group-modal {
+ .modal-input {
+ margin: 24px;
+ }
+ .label {
+ text-align: right;
+ line-height: 28px;
+ }
+}
diff --git a/client/containers/Group/ProjectList/ProjectList.js b/client/containers/Group/ProjectList/ProjectList.js
new file mode 100644
index 00000000..f0c38eda
--- /dev/null
+++ b/client/containers/Group/ProjectList/ProjectList.js
@@ -0,0 +1,343 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import { connect } from 'react-redux';
+import { Table, Button, Modal, Form, Input, Icon, Tooltip, Select, Popconfirm, message } from 'antd';
+import { addProject, fetchProjectList, delProject, changeUpdateModal, changeTableLoading } from '../../../reducer/modules/project';
+import UpDateModal from './UpDateModal';
+import { Link } from 'react-router-dom'
+import variable from '../../../constants/variable';
+import common from '../../../common';
+import { autobind } from 'core-decorators';
+const { TextArea } = Input;
+const FormItem = Form.Item;
+const Option = Select.Option;
+
+import './ProjectList.scss'
+
+// 确认删除项目 handleDelete, currGroup._id, fetchProjectList
+const deleteConfirm = (id, props) => {
+ const { delProject, currGroup, fetchProjectList } = props;
+ const handle = () => {
+ delProject(id).then((res) => {
+ if (res.payload.data.errcode == 0) {
+ message.success('删除成功!')
+ fetchProjectList(currGroup._id).then(() => {
+ });
+ } else {
+ message.error(res.payload.data.errmsg);
+ }
+ });
+ }
+ return handle;
+};
+
+const getColumns = (data, props) => {
+ const { changeUpdateModal, userInfo } = props;
+ return [{
+ title: '项目名称',
+ dataIndex: 'name',
+ key: 'name',
+ render: (text, record) => {
+ return {text}
+ }
+ },{
+ title: 'Mock基本URL',
+ key: 'domain',
+ render: (item) => {
+ return 'http://'+ item.prd_host + item.basepath;
+ }
+
+ }, {
+ title: '创建人',
+ dataIndex: 'owner',
+ key: 'owner',
+ render: (text, record, index) => {
+ // data是projectList的列表值
+ // 根据序号找到对应项的uid,根据uid获取对应项目的创建人
+ return {userInfo[data[index].uid] ? userInfo[data[index].uid].username : ''};
+ }
+ }, {
+ title: '创建时间',
+ dataIndex: 'add_time',
+ key: 'add_time',
+ render: time => {common.formatTime(time)}
+ }, {
+ title: '操作',
+ key: 'action',
+ render: (text, record, index) => {
+ const id = record._id;
+ return (
+
+ changeUpdateModal(true, index)}>修改
+
+
+ 删除
+
+
+ )}
+ }];
+}
+
+const formItemLayout = {
+ labelCol: {
+ xs: { span: 24 },
+ sm: { span: 6 }
+ },
+ wrapperCol: {
+ xs: { span: 24 },
+ sm: { span: 14 }
+ }
+};
+
+@connect(
+ state => {
+ return {
+ projectList: state.project.projectList,
+ userInfo: state.project.userInfo,
+ tableLoading: state.project.tableLoading,
+ currGroup: state.group.currGroup,
+ total: state.project.total,
+ currPage: state.project.currPage
+ }
+ },
+ {
+ fetchProjectList,
+ addProject,
+ delProject,
+ changeUpdateModal,
+ changeTableLoading
+ }
+)
+class ProjectList extends Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ visible: false,
+ protocol: 'http:\/\/',
+ projectData: []
+ }
+ }
+ static propTypes = {
+ form: PropTypes.object,
+ fetchProjectList: PropTypes.func,
+ addProject: PropTypes.func,
+ delProject: PropTypes.func,
+ changeUpdateModal: PropTypes.func,
+ changeTableLoading: PropTypes.func,
+ projectList: PropTypes.array,
+ userInfo: PropTypes.object,
+ tableLoading: PropTypes.bool,
+ currGroup: PropTypes.object,
+ total: PropTypes.number,
+ currPage: PropTypes.number
+ }
+
+ // 显示模态框 - 创建项目
+ @autobind
+ showAddProjectModal() {
+ this.setState({
+ visible: true
+ });
+ }
+
+ // 确认添加项目
+ @autobind
+ handleOk(e) {
+ const { form, currGroup, changeTableLoading, addProject, fetchProjectList } = this.props;
+ const that = this;
+ e.preventDefault();
+ form.validateFields((err, values) => {
+ if (!err) {
+ values.protocol = this.state.protocol.split(':')[0];
+ // 获取当前分组id传入values
+ values.group_id = currGroup._id;
+
+ changeTableLoading(true);
+ addProject(values).then((res) => {
+ // 添加项目成功后再次请求列表
+ if (res.payload.data.errcode == 0) {
+ that.setState({
+ visible: false
+ });
+ form.resetFields();
+ message.success('创建成功! ');
+ fetchProjectList(currGroup._id, this.props.currPage).then(() => {
+ changeTableLoading(false);
+ });
+ } else {
+ changeTableLoading(false);
+ message.error(res.payload.data.errmsg);
+ }
+ }).catch(() => {
+ changeTableLoading(false);
+ });
+ }
+ });
+ }
+
+ // 取消修改
+ @autobind
+ handleCancel() {
+ this.props.form.resetFields();
+ this.setState({
+ visible: false
+ });
+ }
+
+ // 修改线上域名的协议类型 (http/https)
+ @autobind
+ protocolChange(value) {
+ this.setState({
+ protocol: value
+ })
+ }
+
+ // 分页逻辑
+ @autobind
+ paginationChange(pageNum) {
+ this.props.fetchProjectList(this.props.currGroup._id, pageNum).then((res) => {
+ if (res.payload.data.errcode) {
+ message.error(res.payload.data.errmsg);
+ } else {
+ this.props.changeTableLoading(false);
+ }
+ });
+ }
+
+ componentWillReceiveProps(nextProps) {
+ // 切换分组
+ if (this.props.currGroup !== nextProps.currGroup) {
+ 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);
+ }
+ }
+
+ // 切换项目列表
+ if (this.props.projectList !== nextProps.projectList) {
+ // console.log(nextProps.projectList);
+ const data = nextProps.projectList.map((item, index) => {
+ item.key = index;
+ return item;
+ });
+ this.setState({
+ projectData: data
+ });
+ }
+ }
+
+ render() {
+ const { getFieldDecorator } = this.props.form;
+ return (
+
+ );
+ }
+}
+
+export default Form.create()(ProjectList);
diff --git a/client/containers/Group/ProjectList/ProjectList.scss b/client/containers/Group/ProjectList/ProjectList.scss
new file mode 100644
index 00000000..d787db6b
--- /dev/null
+++ b/client/containers/Group/ProjectList/ProjectList.scss
@@ -0,0 +1,32 @@
+.m-container{
+ background-color: #fff;
+ padding: 24px;
+ box-shadow: 0 2px 4px 0 rgba(0,0,0,0.20);
+ border-radius: 4px;
+ min-height: 5rem;
+}
+
+.m-table {
+ text-align: left;
+ margin-top: .16rem;
+}
+
+.ant-input-group-wrapper {
+ width: 100%;
+}
+
+.dynamic-delete-button {
+ cursor: pointer;
+ position: relative;
+ top: 4px;
+ font-size: 24px;
+ color: #999;
+ transition: all .3s;
+}
+.dynamic-delete-button:hover {
+ color: #777;
+}
+.dynamic-delete-button[disabled] {
+ cursor: not-allowed;
+ opacity: 0.5;
+}
diff --git a/client/containers/Group/ProjectList/UpDateModal.js b/client/containers/Group/ProjectList/UpDateModal.js
new file mode 100644
index 00000000..c4ecfa96
--- /dev/null
+++ b/client/containers/Group/ProjectList/UpDateModal.js
@@ -0,0 +1,365 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import { connect } from 'react-redux';
+import { Modal, Form, Input, Icon, Tooltip, Select, message, Button, Row, Col } from 'antd';
+import { updateProject, fetchProjectList, delProject, changeUpdateModal, changeTableLoading } from '../../../reducer/modules/project';
+const { TextArea } = Input;
+const FormItem = Form.Item;
+const Option = Select.Option;
+
+import './ProjectList.scss'
+
+// layout
+const formItemLayout = {
+ labelCol: {
+ xs: { span: 24 },
+ sm: { span: 6 }
+ },
+ wrapperCol: {
+ xs: { span: 24 },
+ sm: { span: 14 }
+ }
+};
+const formItemLayoutWithOutLabel = {
+ wrapperCol: {
+ xs: { span: 24, offset: 0 },
+ sm: { span: 20, offset: 6 }
+ }
+};
+let uuid = 0;
+
+@connect(
+ state => {
+ return {
+ projectList: state.project.projectList,
+ isUpdateModalShow: state.project.isUpdateModalShow,
+ handleUpdateIndex: state.project.handleUpdateIndex,
+ tableLoading: state.project.tableLoading,
+ currGroup: state.group.currGroup
+ }
+ },
+ {
+ fetchProjectList,
+ updateProject,
+ delProject,
+ changeUpdateModal,
+ changeTableLoading
+ }
+)
+class UpDateModal extends Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ protocol: 'http:\/\/',
+ envProtocolChange: 'http:\/\/'
+ }
+ }
+ static propTypes = {
+ form: PropTypes.object,
+ fetchProjectList: PropTypes.func,
+ updateProject: PropTypes.func,
+ delProject: PropTypes.func,
+ changeUpdateModal: PropTypes.func,
+ changeTableLoading: PropTypes.func,
+ projectList: PropTypes.array,
+ currGroup: PropTypes.object,
+ isUpdateModalShow: PropTypes.bool,
+ handleUpdateIndex: PropTypes.number
+ }
+
+ // 修改线上域名的协议类型 (http/https)
+ protocolChange = (value) => {
+ this.setState({
+ protocol: value
+ })
+ }
+
+ handleCancel = () => {
+ this.props.form.resetFields();
+ this.props.changeUpdateModal(false, -1);
+ }
+
+ // 确认修改
+ handleOk = (e) => {
+ e.preventDefault();
+ const { form, updateProject, changeUpdateModal, currGroup, projectList, handleUpdateIndex, fetchProjectList, changeTableLoading } = this.props;
+ form.validateFields((err, values) => {
+ if (!err) {
+ // console.log(projectList[handleUpdateIndex]);
+ let assignValue = Object.assign(projectList[handleUpdateIndex], values);
+ values.protocol = this.state.protocol.split(':')[0];
+ assignValue.env = assignValue.envs.map((item, index) => {
+ return {
+ name: values['envs-name-' + index],
+ domain: values['envs-protocol-' + index] + values['envs-domain-' + index]
+ }
+ });
+ // console.log(assignValue);
+
+ changeTableLoading(true);
+ updateProject(assignValue).then((res) => {
+ if (res.payload.data.errcode == 0) {
+ changeUpdateModal(false, -1);
+ message.success('修改成功! ');
+ fetchProjectList(currGroup._id).then(() => {
+ changeTableLoading(false);
+ });
+ } else {
+ changeTableLoading(false);
+ message.error(res.payload.data.errmsg);
+ }
+ }).catch(() => {
+ changeTableLoading(false);
+ });
+ form.resetFields();
+ }
+ });
+ }
+
+ // 项目的修改操作 - 删除一项环境配置
+ remove = (id) => {
+ const { form } = this.props;
+ // can use data-binding to get
+ const envs = form.getFieldValue('envs');
+ // We need at least one passenger
+ if (envs.length === 0) {
+ return;
+ }
+
+ // can use data-binding to set
+ form.setFieldsValue({
+ envs: envs.filter(key => {
+ const realKey = key._id ? key._id : key
+ return realKey !== id;
+ })
+ });
+ }
+
+ // 项目的修改操作 - 添加一项环境配置
+ add = () => {
+ uuid++;
+ const { form } = this.props;
+ // can use data-binding to get
+ const envs = form.getFieldValue('envs');
+ const nextKeys = envs.concat(uuid);
+ // can use data-binding to set
+ // important! notify form to detect changes
+ form.setFieldsValue({
+ envs: nextKeys
+ });
+ }
+
+ render() {
+ const { getFieldDecorator, getFieldValue } = this.props.form;
+ // const that = this;
+ const { isUpdateModalShow, projectList, handleUpdateIndex } = this.props;
+ let initFormValues = {};
+ let envMessage = [];
+ // 如果列表存在且用户点击修改按钮时,设置表单默认值
+ if (projectList.length !== 0 && handleUpdateIndex !== -1) {
+ // console.log(projectList[handleUpdateIndex]);
+ const { name, basepath, desc, env } = projectList[handleUpdateIndex];
+ initFormValues = { name, basepath, desc, env };
+ if (env.length !== 0) {
+ envMessage = env;
+ }
+ initFormValues.prd_host = projectList[handleUpdateIndex].prd_host;
+ initFormValues.prd_protocol = projectList[handleUpdateIndex].protocol + '\:\/\/';
+
+ }
+
+ getFieldDecorator('envs', { initialValue: envMessage });
+ const envs = getFieldValue('envs');
+ const formItems = envs.map((k, index) => {
+ const secondIndex = 'next' + index; // 为保证key的唯一性
+ return (
+
+
+ 环境名称) : ''}
+ required={false}
+ key={index}
+ >
+ {getFieldDecorator(`envs-name-${index}`, {
+ validateTrigger: ['onChange', 'onBlur'],
+ initialValue: envMessage.length !== 0 ? k.name : '',
+ rules: [{
+ required: false,
+ whitespace: true,
+ validator(rule, value, callback) {
+ if (value) {
+ if (value.length === 0) {
+ callback('请输入环境域名');
+ } else if (!/\S/.test(value)) {
+ callback('请输入环境域名');
+ } else if (/prd/.test(value)) {
+ callback('环境域名不能是"prd"');
+ } else {
+ return callback();
+ }
+ } else {
+ callback('请输入环境域名');
+ }
+ }
+ }]
+ })(
+
+ )}
+
+
+
+ 环境域名) : ''}
+ required={false}
+ key={secondIndex}
+ >
+ {getFieldDecorator(`envs-domain-${index}`, {
+ validateTrigger: ['onChange', 'onBlur'],
+ initialValue: envMessage.length !== 0 && k.domain ? k.domain.split('\/\/')[1] : '',
+ rules: [{
+ required: false,
+ whitespace: true,
+ message: "请输入环境域名",
+ validator(rule, value, callback) {
+ if (value) {
+ if (value.length === 0) {
+ callback('请输入环境域名');
+ } else if (!/\S/.test(value)) {
+ callback('请输入环境域名');
+ } else {
+ return callback();
+ }
+ } else {
+ callback('请输入环境域名');
+ }
+ }
+ }]
+ })(
+
+
+
+
+ )} />
+ )}
+
+
+
+ {/* 新增的项中,只有最后一项有删除按钮 */}
+ {(envs.length > 0 && k._id) || (envs.length == index + 1) ? (
+ {
+ return this.remove(k._id ? k._id : k);
+ }}
+ />
+ ) : null}
+
+
+ );
+ });
+ return (
+
+
+
+ );
+ }
+}
+
+export default Form.create()(UpDateModal);
diff --git a/client/containers/Home/Home.js b/client/containers/Home/Home.js
index 1040da12..bc9e7d2e 100644
--- a/client/containers/Home/Home.js
+++ b/client/containers/Home/Home.js
@@ -127,7 +127,7 @@ HomeGuest.propTypes ={
@connect(
state => ({
- login: state.login.isLogin
+ login: state.user.isLogin
}),
{
changeMenuItem
diff --git a/client/containers/Login/Login.js b/client/containers/Login/Login.js
index fcee2b3e..764b5047 100644
--- a/client/containers/Login/Login.js
+++ b/client/containers/Login/Login.js
@@ -2,7 +2,7 @@ import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { Form, Button, Input, Icon, message } from 'antd';
-import { loginActions } from '../../reducer/modules/login';
+import { loginActions } from '../../reducer/modules/user';
const FormItem = Form.Item;
import './Login.scss'
@@ -17,7 +17,7 @@ const changeHeight = {
@connect(
state => {
return {
- loginData: state.login
+ loginData: state.user
}
},
{
diff --git a/client/containers/Login/LoginWrap.js b/client/containers/Login/LoginWrap.js
index 0c0947b6..7e9ded65 100644
--- a/client/containers/Login/LoginWrap.js
+++ b/client/containers/Login/LoginWrap.js
@@ -9,7 +9,7 @@ const TabPane = Tabs.TabPane;
@connect(
state =>({
- loginWrapActiveKey: state.login.loginWrapActiveKey
+ loginWrapActiveKey: state.user.loginWrapActiveKey
})
)
export default class LoginWrap extends Component {
diff --git a/client/containers/Login/Reg.js b/client/containers/Login/Reg.js
index 8f2ca2d0..94c52523 100644
--- a/client/containers/Login/Reg.js
+++ b/client/containers/Login/Reg.js
@@ -2,7 +2,7 @@ import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { Form, Button, Input, Icon, message } from 'antd';
-import { regActions } from '../../reducer/modules/login';
+import { regActions } from '../../reducer/modules/user';
const FormItem = Form.Item;
const formItemStyle = {
@@ -16,7 +16,7 @@ const changeHeight = {
@connect(
state => {
return {
- loginData: state.login
+ loginData: state.user
}
},
{
diff --git a/client/containers/News/News.js b/client/containers/News/News.js
index 153e5f8b..61f03249 100644
--- a/client/containers/News/News.js
+++ b/client/containers/News/News.js
@@ -12,7 +12,7 @@ import Subnav from '../../components/Subnav/Subnav.js';
state => {
console.log(state);
return {
- uid: state.login.uid + ''
+ uid: state.user.uid + ''
}
},
{
diff --git a/client/containers/News/NewsList/NewsList.js b/client/containers/News/NewsList/NewsList.js
index 45d9b49a..ea8a9ad0 100644
--- a/client/containers/News/NewsList/NewsList.js
+++ b/client/containers/News/NewsList/NewsList.js
@@ -20,7 +20,7 @@ const logList = [{
state => {
// console.log(state);
return {
- uid: state.login.uid + "",
+ uid: state.user.uid + "",
newsData: state.news.newsData
}
},
diff --git a/client/containers/Project/AddProject/AddProject.js b/client/containers/Project/AddProject/AddProject.js
new file mode 100644
index 00000000..19bc765b
--- /dev/null
+++ b/client/containers/Project/AddProject/AddProject.js
@@ -0,0 +1,274 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import { connect } from 'react-redux';
+import { Button, Form, Input, Icon, Tooltip, Select, message } from 'antd';
+import { addProject, fetchProjectList, delProject, changeUpdateModal, changeTableLoading } from '../../../reducer/modules/project';
+// import { Link } from 'react-router-dom'
+// import variable from '../../../constants/variable';
+// import common from '../../../common';
+import { autobind } from 'core-decorators';
+const { TextArea } = Input;
+const FormItem = Form.Item;
+const Option = Select.Option;
+import './Addproject.scss'
+
+// 确认删除项目 handleDelete, currGroup._id, fetchProjectList
+// const deleteConfirm = (id, props) => {
+// const { delProject, currGroup, fetchProjectList } = props;
+// const handle = () => {
+// delProject(id).then((res) => {
+// if (res.payload.data.errcode == 0) {
+// message.success('删除成功!')
+// fetchProjectList(currGroup._id).then(() => {
+// });
+// } else {
+// message.error(res.payload.data.errmsg);
+// }
+// });
+// }
+// return handle;
+// };
+
+
+const formItemLayout = {
+ labelCol: {
+ xs: { span: 24 },
+ sm: { span: 6 }
+ },
+ wrapperCol: {
+ xs: { span: 24 },
+ sm: { span: 14 }
+ }
+};
+
+@connect(
+ state => {
+ return {
+ projectList: state.project.projectList,
+ userInfo: state.project.userInfo,
+ tableLoading: state.project.tableLoading,
+ currGroup: state.group.currGroup,
+ total: state.project.total,
+ currPage: state.project.currPage
+ }
+ },
+ {
+ fetchProjectList,
+ addProject,
+ delProject,
+ changeUpdateModal,
+ changeTableLoading
+ }
+)
+class ProjectList extends Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ visible: false,
+ protocol: 'http:\/\/',
+ projectData: []
+ }
+ }
+ static propTypes = {
+ form: PropTypes.object,
+ fetchProjectList: PropTypes.func,
+ addProject: PropTypes.func,
+ delProject: PropTypes.func,
+ changeUpdateModal: PropTypes.func,
+ changeTableLoading: PropTypes.func,
+ projectList: PropTypes.array,
+ userInfo: PropTypes.object,
+ tableLoading: PropTypes.bool,
+ currGroup: PropTypes.object,
+ total: PropTypes.number,
+ currPage: PropTypes.number
+ }
+
+ // 显示模态框 - 创建项目
+ @autobind
+ showAddProjectModal() {
+ this.setState({
+ visible: true
+ });
+ }
+
+ // 确认添加项目
+ @autobind
+ handleOk(e) {
+ const { form, currGroup, changeTableLoading, addProject, fetchProjectList } = this.props;
+ const that = this;
+ e.preventDefault();
+ form.validateFields((err, values) => {
+ if (!err) {
+ values.protocol = this.state.protocol.split(':')[0];
+ // 获取当前分组id传入values
+ values.group_id = currGroup._id;
+
+ changeTableLoading(true);
+ addProject(values).then((res) => {
+ // 添加项目成功后再次请求列表
+ if (res.payload.data.errcode == 0) {
+ that.setState({
+ visible: false
+ });
+ form.resetFields();
+ message.success('创建成功! ');
+ fetchProjectList(currGroup._id, this.props.currPage).then(() => {
+ changeTableLoading(false);
+ });
+ } else {
+ changeTableLoading(false);
+ message.error(res.payload.data.errmsg);
+ }
+ }).catch(() => {
+ changeTableLoading(false);
+ });
+ }
+ });
+ }
+
+ // 取消修改
+ @autobind
+ handleCancel() {
+ this.props.form.resetFields();
+ this.setState({
+ visible: false
+ });
+ }
+
+ // 修改线上域名的协议类型 (http/https)
+ @autobind
+ protocolChange(value) {
+ this.setState({
+ protocol: value
+ })
+ }
+
+ // 分页逻辑
+ @autobind
+ paginationChange(pageNum) {
+ this.props.fetchProjectList(this.props.currGroup._id, pageNum).then((res) => {
+ if (res.payload.data.errcode) {
+ message.error(res.payload.data.errmsg);
+ } else {
+ this.props.changeTableLoading(false);
+ }
+ });
+ }
+
+ componentWillReceiveProps(nextProps) {
+ // 切换分组
+ if (this.props.currGroup !== nextProps.currGroup) {
+ 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);
+ }
+ }
+
+ // 切换项目列表
+ if (this.props.projectList !== nextProps.projectList) {
+ // console.log(nextProps.projectList);
+ const data = nextProps.projectList.map((item, index) => {
+ item.key = index;
+ return item;
+ });
+ this.setState({
+ projectData: data
+ });
+ }
+ }
+
+ render() {
+ const { getFieldDecorator } = this.props.form;
+ return (
+
+
+
+
+ );
+ }
+}
+
+export default Form.create()(ProjectList);
diff --git a/client/containers/Project/AddProject/Addproject.scss b/client/containers/Project/AddProject/Addproject.scss
new file mode 100644
index 00000000..b76d714a
--- /dev/null
+++ b/client/containers/Project/AddProject/Addproject.scss
@@ -0,0 +1,6 @@
+@import '../../../styles/common.scss';
+
+.m-container {
+ margin: .24rem auto !important;
+ padding: .24rem !important;
+}
diff --git a/client/containers/Project/Project.js b/client/containers/Project/Project.js
new file mode 100644
index 00000000..d419e832
--- /dev/null
+++ b/client/containers/Project/Project.js
@@ -0,0 +1,46 @@
+import React, { Component } from 'react'
+import PropTypes from 'prop-types'
+import { Route, Switch, Redirect } from 'react-router-dom';
+import { Subnav } from '../../components/index'
+
+export default class GroupList extends Component {
+
+ static propTypes = {
+ children: PropTypes.element
+ }
+
+ state = {
+ }
+
+ constructor(props) {
+ super(props)
+ }
+
+ componentWillMount() {
+ }
+
+ render () {
+ return (
+
+
+
+
+
+
+
+
+
+ )
+ }
+}
diff --git a/client/containers/User/LeftMenu.js b/client/containers/User/LeftMenu.js
index 0b1be35e..7a3529b6 100644
--- a/client/containers/User/LeftMenu.js
+++ b/client/containers/User/LeftMenu.js
@@ -11,9 +11,9 @@ const Option = AutoComplete.Option;
state => {
console.log(state);
return {
- curUid: state.login.uid + '',
- curUserName: state.login.userName,
- curUserRole: state.login.role
+ curUid: state.user.uid + '',
+ curUserName: state.user.userName,
+ curUserRole: state.user.role
}
}
)
diff --git a/client/containers/User/List.js b/client/containers/User/List.js
index 727a6662..9cac3a3f 100755
--- a/client/containers/User/List.js
+++ b/client/containers/User/List.js
@@ -15,7 +15,7 @@ const limit = 10;
@connect(
state => {
return {
- curUserRole: state.login.role
+ curUserRole: state.user.role
}
}
)
@@ -41,7 +41,7 @@ class List extends Component {
getUserList() {
axios.get('/user/list?page=' + this.state.current).then((res) => {
let result = res.data;
-
+
if (result.errcode === 0) {
let list = result.data.list;
let total = result.data.total * limit;
@@ -118,7 +118,7 @@ class List extends Component {
width:80,
render: (item) => {
return (
-
+
查看
{this.confirm(item._id)}} okText="确定" cancelText="取消">
diff --git a/client/containers/index.js b/client/containers/index.js
index e4a2fc29..1b9f7fe0 100644
--- a/client/containers/index.js
+++ b/client/containers/index.js
@@ -1,21 +1,25 @@
import Header from '../components/Header/Header.js'
import Home from './Home/Home.js'
import Login from './Login/LoginWrap.js'
-import ProjectGroups from './ProjectGroups/ProjectGroups.js'
+import Group from './Group/Group.js'
import Interface from './Interface/Interface.js'
+import Project from './Project/Project.js'
import News from './News/News.js'
import AddInterface from './AddInterface/AddInterface.js'
import DevTools from './DevTools/DevTools.js'
import Follows from './Follows/Follows.js'
+import AddProject from './Project/AddProject/AddProject.js'
export {
Header,
Home,
Login,
- ProjectGroups,
+ Group,
Interface,
+ Project,
AddInterface,
News,
DevTools,
- Follows
+ Follows,
+ AddProject
}
diff --git a/client/reducer/modules/project.js b/client/reducer/modules/project.js
index e23a7600..8fcd6b02 100644
--- a/client/reducer/modules/project.js
+++ b/client/reducer/modules/project.js
@@ -17,7 +17,8 @@ const initialState = {
userInfo: {},
tableLoading: true,
total: 0,
- currPage: 1
+ currPage: 1,
+ curProject: {}
};
export default (state = initialState, action) => {
@@ -94,7 +95,6 @@ export function addProject(data) {
};
return {
type: PROJECT_ADD,
- // payload 可以返回 Promise,异步请求使用 axios 即可
payload: axios.post('/project/add', param)
};
}
@@ -112,7 +112,6 @@ export function updateProject(data) {
};
return {
type: PROJECT_UPDATE,
- // payload 可以返回 Promise,异步请求使用 axios 即可
payload: axios.post('/project/up', param)
};
}
@@ -121,7 +120,6 @@ export function delProject(id) {
const param = { id };
return {
type: PROJECT_DEL,
- // payload 可以返回 Promise,异步请求使用 axios 即可
payload: axios.post('/project/del', param)
};
}
diff --git a/client/reducer/modules/reducer.js b/client/reducer/modules/reducer.js
index fa0fe382..885d640d 100644
--- a/client/reducer/modules/reducer.js
+++ b/client/reducer/modules/reducer.js
@@ -1,5 +1,5 @@
import { combineReducers } from 'redux';
-import login from './login.js'
+import user from './user.js'
import group from './group.js'
import project from './project.js'
import Interface from './interface.js'
@@ -9,7 +9,7 @@ import menu from './menu.js'
export default combineReducers({
group,
- login,
+ user,
Interface,
project,
news,
diff --git a/client/reducer/modules/user.js b/client/reducer/modules/user.js
new file mode 100644
index 00000000..716f0606
--- /dev/null
+++ b/client/reducer/modules/user.js
@@ -0,0 +1,127 @@
+import axios from 'axios';
+
+// Actions
+const LOGIN = 'yapi/user/LOGIN';
+const LOGIN_OUT = 'yapi/user/LOGIN_OUT';
+const LOGIN_TYPE = 'yapi/user/LOGIN_TYPE';
+const GET_LOGIN_STATE = 'yapi/user/GET_LOGIN_STATE';
+const REGISTER = 'yapi/user/REGISTER';
+
+// Reducer
+const LOADING_STATUS = 0;
+const GUEST_STATUS = 1;
+const MEMBER_STATUS = 2;
+// Reducer user
+const initialState = {
+ isLogin: false,
+ userName: null,
+ uid: null,
+ email: '',
+ loginState: LOADING_STATUS,
+ loginWrapActiveKey: "1"
+};
+
+export default (state = initialState, action) => {
+ switch (action.type) {
+ case GET_LOGIN_STATE: {
+ console.log(action.payload.data);
+ return {
+ ...state,
+ isLogin: (action.payload.data.errcode == 0),
+ role: action.payload.data.data ? action.payload.data.data.role:null,
+ loginState: (action.payload.data.errcode == 0)?MEMBER_STATUS:GUEST_STATUS,
+ userName: action.payload.data.data ? action.payload.data.data.username : null,
+ uid: action.payload.data.data ? action.payload.data.data._id : null,
+ server_ip: action.payload.data.data ? action.payload.data.data.server_ip:null
+ };
+ }
+ case LOGIN: {
+ if (action.payload.data.errcode === 0) {
+ return {
+ ...state,
+ isLogin: true,
+ loginState: MEMBER_STATUS,
+ uid: action.payload.data.data.uid,
+ userName: action.payload.data.data.username,
+ server_ip: action.payload.data.data.server_ip
+ };
+ } else {
+ return state;
+ }
+ }
+ case LOGIN_OUT: {
+ return{
+ ...state,
+ isLogin: false,
+ loginState: GUEST_STATUS,
+ userName: null,
+ uid: null
+ }
+ }
+ case LOGIN_TYPE: {
+ return {
+ ...state,
+ loginWrapActiveKey: action.index
+ };
+ }
+ case REGISTER: {
+ return {
+ ...state,
+ isLogin: true,
+ loginState: MEMBER_STATUS,
+ uid: action.payload.data.data.uid,
+ userName: action.payload.data.data.username
+ };
+ }
+ default:
+ return state;
+ }
+};
+
+// Action Creators
+export function checkLoginState() {
+ return(dispatch)=> {
+ axios.get('/user/status').then((res) => {
+ dispatch({
+ type: GET_LOGIN_STATE,
+ payload: res
+ });
+ }).catch((err) => {
+ console.log(err);
+ })
+ }
+}
+
+export function loginActions(data) {
+ return {
+ type: LOGIN,
+ payload: axios.post('/user/login', data)
+ };
+}
+
+export function regActions(data) {
+ const { email, password, userName } = data;
+ const param = {
+ email,
+ password,
+ username: userName
+ };
+ return {
+ type: REGISTER,
+ payload: axios.post('/user/reg', param)
+ };
+}
+
+export function logoutActions() {
+ return {
+ type: LOGIN_OUT,
+ payload: axios.get('./user/logout')
+ }
+}
+
+export function loginTypeAction(index) {
+ return{
+ type: LOGIN_TYPE,
+ index
+ }
+}
diff --git a/client/styles/common.scss b/client/styles/common.scss
index 1f81e740..b25b779f 100644
--- a/client/styles/common.scss
+++ b/client/styles/common.scss
@@ -61,6 +61,7 @@ em {
padding: 0 .24rem;
}
-.nav-tooltip {
- color: red;
+.m-container {
+ margin: .24rem auto;
+ padding: .24rem;
}
diff --git a/server/controllers/base.js b/server/controllers/base.js
index 3cbc4f86..668f1dea 100644
--- a/server/controllers/base.js
+++ b/server/controllers/base.js
@@ -19,6 +19,7 @@ class baseController {
async init(ctx) {
this.$user = null;
+ console.log(111111)
let ignoreRouter = [
'/user/login_by_token',
'/user/login',
@@ -26,7 +27,7 @@ class baseController {
'/user/status',
'/user/logout'
];
- if (ignoreRouter.indexOf(ctx.path) > -1) {
+ if (ignoreRouter.indexOf(ctx.path) > -1) {
this.$auth = true;
} else {
await this.checkLogin(ctx);
@@ -61,10 +62,14 @@ class baseController {
}
}
+ /**
+ *
+ * @param {*} ctx
+ */
async getLoginStatus(ctx) {
if (await this.checkLogin(ctx) === true) {
- let result = yapi.commons.fieldSelect(this.$user, ['_id', 'username', 'email', 'up_time', 'add_time', 'role']);
+ let result = yapi.commons.fieldSelect(this.$user, ['_id', 'username', 'email', 'up_time', 'add_time', 'role', 'type']);
result.server_ip = yapi.WEBCONFIG.server_ip;
return ctx.body = yapi.commons.resReturn(result);
}
diff --git a/server/controllers/project.js b/server/controllers/project.js
index 9840f2c1..d50f664a 100644
--- a/server/controllers/project.js
+++ b/server/controllers/project.js
@@ -525,30 +525,60 @@ class projectController extends baseController {
* @param {String} project_id
*/
async download(ctx) {
- const project_id = ctx.request.query.project_id;
- let interfaceInst = yapi.getInst(interfaceModel);
- let count = await interfaceInst.list(project_id);
- console.log(count);
- const arr = JSON.stringify(count.map(function(item) {
- // 返回的json模板数据: item.res_body
- const mockData = Mock.mock(
- yapi.commons.json_parse(item.res_body)
- );
- return {
- path: item.path,
- mock: mockData
+ const project_id = ctx.request.query.project_id;
+ let interfaceInst = yapi.getInst(interfaceModel);
+ // 根据 project_id 获取接口数据
+ let count = await interfaceInst.list(project_id);
+
+ if (!project_id) {
+ return ctx.body = yapi.commons.resReturn(null, 405, '项目id不能为空');
+ } else if (!count) {
+ return ctx.body = yapi.commons.resReturn(null, 401, '项目id不存在');
}
- }));
- // console.log(arr);
- const fileName = 'mock.js';
- ctx.attachment(fileName);
- await send(ctx, fileName, { root: __dirname + '/public' });
+ const arr = JSON.stringify(count.map(function(item) {
+ // 返回的json模板数据: item.res_body
+ const mockData = Mock.mock(
+ yapi.commons.json_parse(item.res_body)
+ );
+ return {
+ path: item.path,
+ mock: mockData
+ }
+ }));
- const res = `
- var data = ${arr}`
- .trim();
- return ctx.body = res;
+ const fileName = 'mock.js';
+ ctx.attachment(fileName);
+ await send(ctx, fileName, { root: __dirname + '/public' });
+
+ const res = `
+ var Mock = require('mockjs');
+ var xhook = require('xhook');
+ var data = ${arr};
+ function run() {
+ xhook.before(function(request, callback) {
+ setTimeout(function() {
+ var res;
+ data.forEach((item) => {
+ // 请求的接口在 data 中存在
+ if(request.url === item.path) {
+ res = {
+ status: 200,
+ text: Mock.mock(item.mock)
+ }
+ }
+ });
+ if (res) {
+ callback(res);
+ }else {
+ callback({ status: 405, text: '接口不存在' });
+ }
+ }, 500);
+ });
+ }
+ module.exports = run;`
+ .trim();
+ return ctx.body = res;
}
}
diff --git a/server/controllers/user.js b/server/controllers/user.js
index 83eb4eec..783ba9d8 100644
--- a/server/controllers/user.js
+++ b/server/controllers/user.js
@@ -54,8 +54,8 @@ class userController extends baseController {
email: result.email,
add_time: result.add_time,
up_time: result.up_time,
- server_ip: yapi.WEBCONFIG.server_ip
-
+ server_ip: yapi.WEBCONFIG.server_ip,
+ type: 'site'
}, 0, 'logout success...');
} else {
return ctx.body = yapi.commons.resReturn(null, 405, '密码错误');
@@ -555,26 +555,24 @@ class userController extends baseController {
}
/**
- * 根据路由id获取面包屑数据
- * @interface /user/nav
+ * 根据路由id初始化项目数据
+ * @interface /user/project
* @method GET
* @category user
* @foldnumber 10
* @param {String} type 可选group|interface|project
* @param {Number} id
* @return {Object}
- * @example ./api/user/nav.json
+ * @example
*/
- async nav(ctx) {
+ async project(ctx) {
let { id, type } = ctx.request.query;
let result = {};
try {
if (type === 'interface') {
let interfaceInst = yapi.getInst(interfaceModel);
let interfaceData = await interfaceInst.get(id)
- result["interface_id"] = interfaceData._id;
- result["interface_name"] = interfaceData.path;
-
+ result.interface = interfaceData;
type = 'project';
id = interfaceData.project_id;
}
@@ -582,17 +580,38 @@ class userController extends baseController {
if (type === 'project') {
let projectInst = yapi.getInst(projectModel);
let projectData = await projectInst.get(id);
- result["project_id"] = projectData._id;
- result["project_name"] = projectData.prd_host + projectData.basepath;
+ result.project = projectData.toObject();
+ let ownerAuth = await this.checkAuth(id, 'project', 'danger'), devAuth;
+ if(ownerAuth){
+ result.project.role = 'owner'
+ }else{
+ devAuth = await this.checkAuth(id, 'project', 'site');
+ if(devAuth){
+ result.project.role = 'dev'
+ }else{
+ result.project.role = 'member'
+ }
+ }
type = 'group';
- id = projectData.group_id
+ id = projectData.group_id;
}
if (type === 'group') {
let groupInst = yapi.getInst(groupModel);
let groupData = await groupInst.get(id);
- result["group_id"] = groupData._id;
- result["group_name"] = groupData.group_name;
+ result.group = groupData.toObject();
+ let ownerAuth = await this.checkAuth(id, 'group', 'danger'), devAuth;
+ if(ownerAuth){
+ result.group.role = 'owner'
+ }else{
+ devAuth = await this.checkAuth(id, 'group', 'site');
+ if(devAuth){
+ result.group.role = 'dev'
+ }else{
+ result.group.role = 'member'
+ }
+ }
+
}
return ctx.body = yapi.commons.resReturn(result)
diff --git a/server/models/interface.js b/server/models/interface.js
index dc65feae..a5a4f6e7 100644
--- a/server/models/interface.js
+++ b/server/models/interface.js
@@ -74,7 +74,6 @@ class interfaceModel extends baseModel {
}
list(project_id) {
- console.log(project_id);
return this.model.find({
project_id: project_id
})
diff --git a/server/router.js b/server/router.js
index 0aebdb98..82e57a97 100644
--- a/server/router.js
+++ b/server/router.js
@@ -145,8 +145,8 @@ const routerConfig = {
"method": "get"
},
{
- "action": "nav",
- "path": "nav",
+ "action": "project",
+ "path": "project",
"method": "get"
},{
"action": "avatar",
diff --git a/server_dist/controllers/base.js b/server_dist/controllers/base.js
index ac2000d4..d8e5cef2 100644
--- a/server_dist/controllers/base.js
+++ b/server_dist/controllers/base.js
@@ -66,22 +66,23 @@ var baseController = function () {
switch (_context.prev = _context.next) {
case 0:
this.$user = null;
+ console.log(111111);
ignoreRouter = ['/user/login_by_token', '/user/login', '/user/reg', '/user/status', '/user/logout'];
if (!(ignoreRouter.indexOf(ctx.path) > -1)) {
- _context.next = 6;
+ _context.next = 7;
break;
}
this.$auth = true;
- _context.next = 8;
+ _context.next = 9;
break;
- case 6:
- _context.next = 8;
+ case 7:
+ _context.next = 9;
return this.checkLogin(ctx);
- case 8:
+ case 9:
case 'end':
return _context.stop();
}
@@ -162,6 +163,11 @@ var baseController = function () {
return checkLogin;
}()
+ /**
+ *
+ * @param {*} ctx
+ */
+
}, {
key: 'getLoginStatus',
value: function () {
@@ -182,7 +188,7 @@ var baseController = function () {
break;
}
- result = _yapi2.default.commons.fieldSelect(this.$user, ['_id', 'username', 'email', 'up_time', 'add_time', 'role']);
+ result = _yapi2.default.commons.fieldSelect(this.$user, ['_id', 'username', 'email', 'up_time', 'add_time', 'role', 'type']);
result.server_ip = _yapi2.default.WEBCONFIG.server_ip;
return _context3.abrupt('return', ctx.body = _yapi2.default.commons.resReturn(result));
diff --git a/server_dist/controllers/project.js b/server_dist/controllers/project.js
index 5a575fc0..72adcd62 100644
--- a/server_dist/controllers/project.js
+++ b/server_dist/controllers/project.js
@@ -1192,13 +1192,30 @@ var projectController = function (_baseController) {
case 0:
project_id = ctx.request.query.project_id;
interfaceInst = _yapi2.default.getInst(_interface2.default);
+ // 根据 project_id 获取接口数据
+
_context12.next = 4;
return interfaceInst.list(project_id);
case 4:
count = _context12.sent;
- console.log(count);
+ if (project_id) {
+ _context12.next = 9;
+ break;
+ }
+
+ return _context12.abrupt('return', ctx.body = _yapi2.default.commons.resReturn(null, 405, '项目id不能为空'));
+
+ case 9:
+ if (count) {
+ _context12.next = 11;
+ break;
+ }
+
+ return _context12.abrupt('return', ctx.body = _yapi2.default.commons.resReturn(null, 401, '项目id不存在'));
+
+ case 11:
arr = (0, _stringify2.default)(count.map(function (item) {
// 返回的json模板数据: item.res_body
var mockData = _mockjs2.default.mock(_yapi2.default.commons.json_parse(item.res_body));
@@ -1207,19 +1224,17 @@ var projectController = function (_baseController) {
mock: mockData
};
}));
- // console.log(arr);
-
fileName = 'mock.js';
ctx.attachment(fileName);
- _context12.next = 11;
+ _context12.next = 16;
return send(ctx, fileName, { root: __dirname + '/public' });
- case 11:
- res = ('\n var data = ' + arr).trim();
+ case 16:
+ res = ('\n var Mock = require(\'mockjs\');\n var xhook = require(\'xhook\');\n var data = ' + arr + ';\n function run() {\n xhook.before(function(request, callback) {\n setTimeout(function() {\n var res;\n data.forEach((item) => {\n // \u8BF7\u6C42\u7684\u63A5\u53E3\u5728 data \u4E2D\u5B58\u5728\n if(request.url === item.path) {\n res = {\n status: 200,\n text: Mock.mock(item.mock)\n }\n }\n });\n if (res) {\n callback(res);\n }else {\n callback({ status: 405, text: \'\u63A5\u53E3\u4E0D\u5B58\u5728\' });\n }\n }, 500);\n });\n }\n module.exports = run;').trim();
return _context12.abrupt('return', ctx.body = res);
- case 13:
+ case 18:
case 'end':
return _context12.stop();
}
diff --git a/server_dist/controllers/user.js b/server_dist/controllers/user.js
index 34a5bb3a..29da82bc 100644
--- a/server_dist/controllers/user.js
+++ b/server_dist/controllers/user.js
@@ -155,8 +155,8 @@ var userController = function (_baseController) {
email: result.email,
add_time: result.add_time,
up_time: result.up_time,
- server_ip: _yapi2.default.WEBCONFIG.server_ip
-
+ server_ip: _yapi2.default.WEBCONFIG.server_ip,
+ type: 'site'
}, 0, 'logout success...'));
case 19:
@@ -1157,22 +1157,22 @@ var userController = function (_baseController) {
}()
/**
- * 根据路由id获取面包屑数据
- * @interface /user/nav
+ * 根据路由id初始化项目数据
+ * @interface /user/project
* @method GET
* @category user
* @foldnumber 10
* @param {String} type 可选group|interface|project
* @param {Number} id
* @return {Object}
- * @example ./api/user/nav.json
+ * @example
*/
}, {
- key: 'nav',
+ key: 'project',
value: function () {
var _ref14 = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee14(ctx) {
- var _ctx$request$query, id, type, result, interfaceInst, interfaceData, projectInst, projectData, groupInst, groupData;
+ var _ctx$request$query, id, type, result, interfaceInst, interfaceData, projectInst, projectData, ownerAuth, devAuth, groupInst, groupData, _ownerAuth, _devAuth;
return _regenerator2.default.wrap(function _callee14$(_context14) {
while (1) {
@@ -1183,7 +1183,7 @@ var userController = function (_baseController) {
_context14.prev = 2;
if (!(type === 'interface')) {
- _context14.next = 12;
+ _context14.next = 11;
break;
}
@@ -1194,67 +1194,121 @@ var userController = function (_baseController) {
case 7:
interfaceData = _context14.sent;
- result["interface_id"] = interfaceData._id;
- result["interface_name"] = interfaceData.path;
-
+ result.interface = interfaceData;
type = 'project';
id = interfaceData.project_id;
- case 12:
+ case 11:
if (!(type === 'project')) {
- _context14.next = 21;
+ _context14.next = 31;
break;
}
projectInst = _yapi2.default.getInst(_project2.default);
- _context14.next = 16;
+ _context14.next = 15;
return projectInst.get(id);
- case 16:
+ case 15:
projectData = _context14.sent;
- result["project_id"] = projectData._id;
- result["project_name"] = projectData.prd_host + projectData.basepath;
+ result.project = projectData.toObject();
+ _context14.next = 19;
+ return this.checkAuth(id, 'project', 'danger');
+
+ case 19:
+ ownerAuth = _context14.sent;
+ devAuth = void 0;
+
+ if (!ownerAuth) {
+ _context14.next = 25;
+ break;
+ }
+
+ result.project.role = 'owner';
+ _context14.next = 29;
+ break;
+
+ case 25:
+ _context14.next = 27;
+ return this.checkAuth(id, 'project', 'site');
+
+ case 27:
+ devAuth = _context14.sent;
+
+ if (devAuth) {
+ result.project.role = 'dev';
+ } else {
+ result.project.role = 'member';
+ }
+
+ case 29:
type = 'group';
id = projectData.group_id;
- case 21:
+ case 31:
if (!(type === 'group')) {
- _context14.next = 28;
+ _context14.next = 49;
break;
}
groupInst = _yapi2.default.getInst(_group2.default);
- _context14.next = 25;
+ _context14.next = 35;
return groupInst.get(id);
- case 25:
+ case 35:
groupData = _context14.sent;
- result["group_id"] = groupData._id;
- result["group_name"] = groupData.group_name;
+ result.group = groupData.toObject();
+ _context14.next = 39;
+ return this.checkAuth(id, 'group', 'danger');
- case 28:
+ case 39:
+ _ownerAuth = _context14.sent;
+ _devAuth = void 0;
+
+ if (!_ownerAuth) {
+ _context14.next = 45;
+ break;
+ }
+
+ result.group.role = 'owner';
+ _context14.next = 49;
+ break;
+
+ case 45:
+ _context14.next = 47;
+ return this.checkAuth(id, 'group', 'site');
+
+ case 47:
+ _devAuth = _context14.sent;
+
+ if (_devAuth) {
+ result.group.role = 'dev';
+ } else {
+ result.group.role = 'member';
+ }
+
+ case 49:
return _context14.abrupt('return', ctx.body = _yapi2.default.commons.resReturn(result));
- case 31:
- _context14.prev = 31;
+ case 52:
+ _context14.prev = 52;
_context14.t0 = _context14['catch'](2);
return _context14.abrupt('return', ctx.body = _yapi2.default.commons.resReturn(result, 422, _context14.t0.message));
- case 34:
+ case 55:
case 'end':
return _context14.stop();
}
}
- }, _callee14, this, [[2, 31]]);
+ }, _callee14, this, [[2, 52]]);
}));
- function nav(_x15) {
+ function project(_x15) {
return _ref14.apply(this, arguments);
}
- return nav;
+ return project;
}()
}]);
return userController;
diff --git a/server_dist/models/interface.js b/server_dist/models/interface.js
index 7caef0e3..d51903dd 100644
--- a/server_dist/models/interface.js
+++ b/server_dist/models/interface.js
@@ -117,7 +117,6 @@ var interfaceModel = function (_baseModel) {
}, {
key: 'list',
value: function list(project_id) {
- console.log(project_id);
return this.model.find({
project_id: project_id
}).sort({ _id: -1 }).exec();
diff --git a/server_dist/router.js b/server_dist/router.js
index 3d8a53e9..fcf42d42 100644
--- a/server_dist/router.js
+++ b/server_dist/router.js
@@ -162,8 +162,8 @@ var routerConfig = {
"path": "search",
"method": "get"
}, {
- "action": "nav",
- "path": "nav",
+ "action": "project",
+ "path": "project",
"method": "get"
}, {
"action": "avatar",
diff --git a/static/doc/api.html b/static/doc/api.html
index f587c9de..fb2d2110 100644
--- a/static/doc/api.html
+++ b/static/doc/api.html
@@ -191,6 +191,10 @@
/project/search
+
+
+ /project/download
+
@@ -227,13 +231,77 @@
- node
+ follow
+
+
+
+
+ col
+
+
+
+
+
+
+
+ log
+
+
+
@@ -266,7 +334,7 @@
源码位置:
- ./server/controllers/group.js:10
+ ./server/controllers/group.js:11
@@ -313,6 +381,18 @@
|
+
+ owner_uid |
+ String |
+ 组长uid |
+
+
+
+
+ |
+ |
+
+
@@ -349,7 +429,7 @@
源码位置:
- ./server/controllers/group.js:64
+ ./server/controllers/group.js:184
@@ -411,7 +491,7 @@
源码位置:
- ./server/controllers/group.js:83
+ ./server/controllers/group.js:203
@@ -483,7 +563,7 @@
源码位置:
- ./server/controllers/group.js:120
+ ./server/controllers/group.js:240
@@ -583,7 +663,7 @@
源码位置:
- ./server/controllers/user.js:17
+ ./server/controllers/user.js:18
@@ -670,7 +750,7 @@
源码位置:
- ./server/controllers/user.js:63
+ ./server/controllers/user.js:64
@@ -703,7 +783,7 @@
源码位置:
- ./server/controllers/user.js:160
+ ./server/controllers/user.js:162
@@ -799,7 +879,7 @@
源码位置:
- ./server/controllers/user.js:229
+ ./server/controllers/user.js:227
@@ -896,7 +976,7 @@
源码位置:
- ./server/controllers/user.js:301
+ ./server/controllers/user.js:300
@@ -966,7 +1046,7 @@
源码位置:
- ./server/controllers/user.js:329
+ ./server/controllers/user.js:328
@@ -1028,7 +1108,7 @@
源码位置:
- ./server/controllers/user.js:367
+ ./server/controllers/user.js:366
@@ -1090,7 +1170,7 @@
源码位置:
- ./server/controllers/user.js:398
+ ./server/controllers/user.js:397
@@ -1182,7 +1262,7 @@
源码位置:
- ./server/controllers/user.js:457
+ ./server/controllers/user.js:511
@@ -1260,7 +1340,7 @@
源码位置:
- ./server/controllers/user.js:503
+ ./server/controllers/user.js:556
@@ -1351,7 +1431,7 @@
源码位置:
- ./server/controllers/project.js:35
+ ./server/controllers/project.js:37
@@ -1492,7 +1572,7 @@
源码位置:
- ./server/controllers/project.js:116
+ ./server/controllers/project.js:126
@@ -1576,7 +1656,7 @@
源码位置:
- ./server/controllers/project.js:148
+ ./server/controllers/project.js:169
@@ -1660,7 +1740,7 @@
源码位置:
- ./server/controllers/project.js:181
+ ./server/controllers/project.js:222
@@ -1738,7 +1818,7 @@
源码位置:
- ./server/controllers/project.js:209
+ ./server/controllers/project.js:247
@@ -1821,7 +1901,7 @@
源码位置:
- ./server/controllers/project.js:233
+ ./server/controllers/project.js:271
@@ -1858,26 +1938,6 @@
|
-
- page |
- Number |
- 分页页码 |
-
-
- |
- |
-
-
-
- limit |
- Number |
- 每页数据条目,默认为10 |
-
-
- |
- |
-
-
@@ -2068,7 +2128,7 @@
源码位置:
- ./server/controllers/project.js:279
+ ./server/controllers/project.js:312
@@ -2140,7 +2200,7 @@
源码位置:
- ./server/controllers/project.js:312
+ ./server/controllers/project.js:372
@@ -2300,7 +2360,7 @@
源码位置:
- ./server/controllers/project.js:404
+ ./server/controllers/project.js:463
@@ -2375,6 +2435,68 @@
}
+
+
+
+
+
+
+
+ 描述:
+ 下载项目的 Mock 数据
+
+
+
+ 源码位置:
+ ./server/controllers/project.js:518
+
+
+
+
+ 参数:
+
+
+
+
+
+
+
+
+
+
+
+ 参数名 |
+ 类型 |
+ 描述 |
+ 必选 |
+ 支持版本 |
+
+
+
+
+ project_id |
+ String |
+ |
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
@@ -3127,27 +3249,27 @@
-
+
-
描述:
- 获取节点列表
+ 获取关注项目列表
源码位置:
- ./server/controllers/log.js:12
+ ./server/controllers/follow.js:24
@@ -3209,169 +3331,926 @@
示例:
-
{
- "errcode": 0,
- "errmsg": "success",
- "data": {
- "total": 2,
- "list": [
- {
- "_id": 529,
- "name": "yapi",
- "desc": "aaa",
- "prd_host": "http://www.yapi.com",
- "basepath": "/a/",
- "uid": 107,
- "group_id": 181,
- "add_time": 1500465369,
- "up_time": 1500522419,
- "__v": 0,
- "env": [],
- "members": [
- "107"
- ]
- },
- {
- "_id": 558,
- "name": "12",
- "desc": "21\n",
- "prd_host": "http://11/",
- "basepath": "12/",
- "uid": 107,
- "group_id": 181,
- "add_time": 1500466250,
- "up_time": 1500466250,
- "__v": 0,
- "env": [],
- "members": [
- "107"
- ]
- },
- {
- "_id": 626,
- "name": "1233",
- "desc": "123",
- "prd_host": "http://1234/",
- "basepath": "1234/",
- "uid": 107,
- "group_id": 181,
- "add_time": 1500471230,
- "up_time": 1500471230,
- "__v": 0,
- "env": [],
- "members": [
- "107"
- ]
- },
- {
- "_id": 665,
- "name": "222",
- "desc": "222",
- "prd_host": "http://222/",
- "basepath": "222/",
- "uid": 107,
- "group_id": 181,
- "add_time": 1500471668,
- "up_time": 1500471668,
- "__v": 0,
- "env": [],
- "members": [
- "107"
- ]
- },
- {
- "_id": 704,
- "name": "333",
- "desc": "222333",
- "prd_host": "http://333/",
- "basepath": "333/",
- "uid": 107,
- "group_id": 181,
- "add_time": 1500471674,
- "up_time": 1500471674,
- "__v": 0,
- "env": [],
- "members": [
- "107"
- ]
- },
- {
- "_id": 743,
- "name": "444",
- "desc": "444",
- "prd_host": "https://444/",
- "basepath": "444/",
- "uid": 107,
- "group_id": 181,
- "add_time": 1500471695,
- "up_time": 1500471695,
- "__v": 0,
- "env": [],
- "members": [
- "107"
- ]
- },
- {
- "_id": 763,
- "name": "122333",
- "desc": "3/",
- "prd_host": "http://33/",
- "basepath": "33/",
- "uid": 107,
- "group_id": 181,
- "add_time": 1500481743,
- "up_time": 1500481743,
- "__v": 0,
- "env": [],
- "members": [
- "107"
- ]
- },
- {
- "_id": 778,
- "name": "555",
- "desc": "555",
- "prd_host": "https://555/",
- "basepath": "555/",
- "uid": 107,
- "group_id": 181,
- "add_time": 1500519203,
- "up_time": 1500519203,
- "__v": 0,
- "env": [],
- "members": [
- "107"
- ]
- },
- {
- "_id": 823,
- "name": "5",
- "desc": "5",
- "prd_host": "http://5/",
- "basepath": "5/",
- "uid": 107,
- "group_id": 181,
- "add_time": 1500519769,
- "up_time": 1500519769,
- "__v": 0,
- "env": [],
- "members": [
- "107"
- ]
- }
- ],
- "userinfo": {
- "107": {
- "_id": 107,
- "username": "admin",
- "email": "admin@admin.com",
- "role": "admin",
- "add_time": 1500280333,
- "up_time": 1500373530
- }
- }
- }
-}
+
/follow/list
+
+
+
+
+
+
+
+
+
+ 描述:
+ 取消关注
+
+
+
+ 源码位置:
+ ./server/controllers/follow.js:60
+
+
+
+
+ 参数:
+
+
+
+
+
+
+
+
+
+
+
+ 参数名 |
+ 类型 |
+ 描述 |
+ 必选 |
+ 支持版本 |
+
+
+
+
+ id |
+ Number |
+ 关注id |
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
示例:
+
/follow/del
+
+
+
+
+
+
+
+
+
+ 描述:
+ 添加关注
+
+
+
+ 源码位置:
+ ./server/controllers/follow.js:86
+
+
+
+
+ 参数:
+
+
+
+
+
+
+
+
+
+
+
+ 参数名 |
+ 类型 |
+ 描述 |
+ 必选 |
+ 支持版本 |
+
+
+
+
+ uid |
+ Number |
+ 用户id |
+
+
+
+
+ |
+ |
+
+
+
+ projectid |
+ Number |
+ 项目id |
+
+
+
+
+ |
+ |
+
+
+
+ projectname |
+ String |
+ 项目名 |
+
+
+
+
+ |
+ |
+
+
+
+ icon |
+ String |
+ 项目icon |
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
示例:
+
/follow/add
+
+
+
+
+
+
+
+
+
+
+
+
+ 描述:
+ 获取所有接口集
+
+
+
+ 源码位置:
+ ./server/controllers/interfaceCol.js:12
+
+
+
+
+ 参数:
+
+
+
+
+
+
+
+
+
+
+
+ 参数名 |
+ 类型 |
+ 描述 |
+ 必选 |
+ 支持版本 |
+
+
+
+
+ project_id |
+ String |
+ email名称,不能为空 |
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 描述:
+ 增加接口集
+
+
+
+ 源码位置:
+ ./server/controllers/interfaceCol.js:33
+
+
+
+
+ 参数:
+
+
+
+
+
+
+
+
+
+
+
+ 参数名 |
+ 类型 |
+ 描述 |
+ 必选 |
+ 支持版本 |
+
+
+
+
+ project_id |
+ Number |
+ |
+
+
+
+
+ |
+ |
+
+
+
+ name |
+ String |
+ |
+
+
+
+
+ |
+ |
+
+
+
+ desc |
+ String |
+ |
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 描述:
+ 获取一个接口集下的所有的接口用例
+
+
+
+ 源码位置:
+ ./server/controllers/interfaceCol.js:77
+
+
+
+
+ 参数:
+
+
+
+
+
+
+
+
+
+
+
+ 参数名 |
+ 类型 |
+ 描述 |
+ 必选 |
+ 支持版本 |
+
+
+
+
+ col_id |
+ String |
+ 接口集id |
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 描述:
+ 增加一个接口用例
+
+
+
+ 源码位置:
+ ./server/controllers/interfaceCol.js:99
+
+
+
+
+ 参数:
+
+
+
+
+
+
+
+
+
+
+
+ 参数名 |
+ 类型 |
+ 描述 |
+ 必选 |
+ 支持版本 |
+
+
+
+
+ casename |
+ String |
+ |
+
+
+
+
+ |
+ |
+
+
+
+ col_id |
+ Number |
+ |
+
+
+
+
+ |
+ |
+
+
+
+ project_id |
+ Number |
+ |
+
+
+
+
+ |
+ |
+
+
+
+ env |
+ String |
+ |
+
+
+
+
+ |
+ |
+
+
+
+ domain |
+ String |
+ |
+
+
+
+
+ |
+ |
+
+
+
+ path |
+ String |
+ |
+
+
+
+
+ |
+ |
+
+
+
+ method |
+ String |
+ |
+
+
+
+
+ |
+ |
+
+
+
+ req_query |
+ Object |
+ |
+
+
+
+
+ |
+ |
+
+
+
+ req_headers |
+ Object |
+ |
+
+
+
+
+ |
+ |
+
+
+
+ req_body_type |
+ String |
+ |
+
+
+
+
+ |
+ |
+
+
+
+ req_body_form |
+ Array |
+ |
+
+
+
+
+ |
+ |
+
+
+
+ req_body_other |
+ String |
+ |
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 描述:
+ 获取一个接口用例详情
+
+
+
+ 源码位置:
+ ./server/controllers/interfaceCol.js:164
+
+
+
+
+ 参数:
+
+
+
+
+
+
+
+
+
+
+
+ 参数名 |
+ 类型 |
+ 描述 |
+ 必选 |
+ 支持版本 |
+
+
+
+
+ caseid |
+ String |
+ |
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 描述:
+ 更新一个接口集name或描述
+
+
+
+ 源码位置:
+ ./server/controllers/interfaceCol.js:185
+
+
+
+
+ 参数:
+
+
+
+
+
+
+
+
+
+
+
+ 参数名 |
+ 类型 |
+ 描述 |
+ 必选 |
+ 支持版本 |
+
+
+
+
+ name |
+ String |
+ |
+
+
+
+
+ |
+ |
+
+
+
+ desc |
+ String |
+ |
+
+
+
+
+ |
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 描述:
+ 更新多个接口case index
+
+
+
+ 源码位置:
+ ./server/controllers/interfaceCol.js:211
+
+
+
+
+ 参数:
+
+
+
+
+
+
+
+
+
+
+
+ 参数名 |
+ 类型 |
+ 描述 |
+ 必选 |
+ 支持版本 |
+
+
+
+
+ id, index |
+ Array |
+ |
+
+
+ |
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 描述:
+ 获取动态列表
+
+
+
+ 源码位置:
+ ./server/controllers/log.js:28
+
+
+
+
+ 参数:
+
+
+
+
+
+
+
+
+
+
+
+ 参数名 |
+ 类型 |
+ 描述 |
+ 必选 |
+ 支持版本 |
+
+
+
+
+ uid |
+ Number |
+ 用户id, 不能为空 |
+
+
+
+
+ |
+ |
+
+
+
+ page |
+ Number |
+ 分页页码 |
+
+
+ |
+ |
+
+
+
+ limit |
+ Number |
+ 分页大小 |
+
+
+ |
+ |
+
+
+
+
+
+
+
示例:
+
/log/list
diff --git a/static/doc/static/server/controllers/base.js.html b/static/doc/static/server/controllers/base.js.html
index 1ebf0223..e52fd60b 100644
--- a/static/doc/static/server/controllers/base.js.html
+++ b/static/doc/static/server/controllers/base.js.html
@@ -28,6 +28,10 @@
import yapi from '../yapi.js';
import projectModel from '../models/project.js';
import userModel from '../models/user.js';
+import interfaceModel from '../models/interface.js'
+import groupModel from '../models/group.js'
+
+import _ from 'underscore'
const jwt = require('jsonwebtoken');
class baseController {
@@ -87,7 +91,7 @@ class baseController {
async getLoginStatus(ctx) {
if (await this.checkLogin(ctx) === true) {
- let result = yapi.commons.fieldSelect(this.$user, ['_id', 'username', 'email', 'up_time', 'add_time','role']);
+ let result = yapi.commons.fieldSelect(this.$user, ['_id', 'username', 'email', 'up_time', 'add_time', 'role']);
result.server_ip = yapi.WEBCONFIG.server_ip;
return ctx.body = yapi.commons.resReturn(result);
}
@@ -98,44 +102,77 @@ class baseController {
return this.$user.role;
}
- async jungeProjectAuth(id) {
- let model = yapi.getInst(projectModel);
+ /**
+ *
+ * @param {*} id type对应的id
+ * @param {*} type enum[interface, project, group]
+ * @param {*} action enum[ danger , edit ] danger只有owner或管理员才能操作,edit只要是dev或以上就能执行
+ */
+ async checkAuth(id, type, action) {
+ let result = {};
+ try {
+ if (this.getRole() === 'admin') {
+ return true;
+ }
+ if (type === 'interface') {
+ let interfaceInst = yapi.getInst(interfaceModel);
+ let interfaceData = await interfaceInst.get(id)
+ result.interfaceData = interfaceData;
+ if (interfaceData.uid === this.getUid()) {
+ return true;
+ }
+ type = 'project';
+ id = interfaceData.project_id;
+ }
- if (this.getRole() === 'admin') {
- return true;
- }
+ if (type === 'project') {
+ let projectInst = yapi.getInst(projectModel);
+ let projectData = await projectInst.get(id);
+ if(projectData.uid === this.getUid()){
+ return true;
+ }
+ let memberData = _.find(projectData.members, (m) => {
+ if (m.uid === this.getUid()) {
+ return true;
+ }
+ })
+
+ if (memberData && memberData.role) {
+ if(action === 'danger' && memberData.role === 'owner'){
+ return true;
+ }
+ if(action === 'edit'){
+ return true;
+ }
+ }
+ type = 'group';
+ id = projectData.group_id
+ }
+
+ if (type === 'group') {
+ let groupInst = yapi.getInst(groupModel);
+ let groupData = await groupInst.get(id);
+ let groupMemberData = _.find(groupData.members, (m) => {
+ if (m.uid === this.getUid()) {
+ return true;
+ }
+ })
+ if (groupMemberData && groupMemberData.role) {
+ if(action === 'danger' && groupMemberData.role === 'owner'){
+ return true;
+ }
+ if(action === 'edit'){
+ return true;
+ }
+ }
+ }
- if (!id) {
return false;
}
-
- let result = await model.get(id);
-
- if (result.uid === this.getUid()) {
- return true;
- }
-
- return false;
- }
-
- async jungeMemberAuth(id, member_uid) {
- let model = yapi.getInst(projectModel);
-
- if (this.getRole() === 'admin') {
- return true;
- }
-
- if (!id || !member_uid) {
+ catch (e) {
+ yapi.commons.log(e.message, 'error')
return false;
}
-
- let result = await model.checkMemberRepeat(id, member_uid);
-
- if (result > 0) {
- return true;
- }
-
- return false;
}
}
diff --git a/static/doc/static/server/controllers/follow.js.html b/static/doc/static/server/controllers/follow.js.html
new file mode 100644
index 00000000..c3b2df1f
--- /dev/null
+++ b/static/doc/static/server/controllers/follow.js.html
@@ -0,0 +1,213 @@
+
+
+
+
+
+ YApi : ./server/controllers/follow.js
+
+
+
+
+
+
+
+
+
+
+
YApi : ./server/controllers/follow.js
+
源代码
+
+
+
+
+
+
+ import yapi from '../yapi.js';
+import baseController from './base.js';
+import followModel from '../models/follow';
+
+class followController extends baseController {
+ constructor(ctx) {
+ super(ctx);
+ this.Model = yapi.getInst(followModel);
+ // try{
+ // var res = this.Model.save({
+ // uid: 107,
+ // projectid: 221,
+ // projectname: 'Flight',
+ // icon: 'code'
+ // });
+ // // var res = this.Model.del(107);
+ // ctx.body = yapi.commons.resReturn(null, 200,res);
+ // }catch(err){
+ // ctx.body = yapi.commons.resReturn(null, 402, err.message);
+ // }
+
+
+ }
+
+ /**
+ * 获取关注项目列表
+ * @interface /follow/list
+ * @method GET
+ * @category follow
+ * @foldnumber 10
+ * @param {Number} uid 用户id, 不能为空
+ * @param {Number} [page] 分页页码
+ * @param {Number} [limit] 分页大小
+ * @returns {Object}
+ * @example /follow/list
+ */
+
+ async list(ctx) {
+ let uid = ctx.request.query.uid,
+ page = ctx.request.query.page || 1,
+ limit = ctx.request.query.limit || 10;
+
+ if (!uid) {
+ return ctx.body = yapi.commons.resReturn(null, 400, '用户id不能为空');
+ }
+
+ try {
+ let result = await this.Model.listWithPaging(uid, page, limit);
+ let count = await this.Model.listCount(uid);
+
+ ctx.body = yapi.commons.resReturn({
+ total: Math.ceil(count / limit),
+ list: result
+ });
+ } catch (err) {
+ ctx.body = yapi.commons.resReturn(null, 402, err.message);
+ }
+ }
+
+
+ /**
+ * 取消关注
+ * @interface /follow/list
+ * @method POST
+ * @category follow
+ * @foldnumber 10
+ * @param {Number} id 关注id
+ * @returns {Object}
+ * @example /follow/del
+ */
+
+ async del(ctx) {
+ let params = ctx.request.body;
+
+ if(params.followid){
+ return ctx.body = yapi.commons.resReturn(null, 400, '关注id不能为空');
+ }
+
+ try {
+ let result = await this.Model.del(params.id);
+ ctx.body = yapi.commons.resReturn(result);
+ } catch (e) {
+ ctx.body = yapi.commons.resReturn(null, 402, e.message);
+ }
+ }
+
+ /**
+ * 添加关注
+ * @interface /follow/list
+ * @method POST
+ * @category follow
+ * @foldnumber 10
+ * @param {Number} uid 用户id
+ * @param {Number} projectid 项目id
+ * @param {String} projectname 项目名
+ * @param {String} icon 项目icon
+ * @returns {Object}
+ * @example /follow/add
+ */
+
+ async add(ctx) {
+ let params = ctx.request.body;
+ params = yapi.commons.handleParams(params, {
+ uid: 'number',
+ projectid: 'number',
+ projectname: 'string',
+ icon: 'string'
+ });
+
+ if (!params.uid) {
+ return ctx.body = yapi.commons.resReturn(null, 400, '用户id不为空');
+ }
+
+ if (!params.projectid) {
+ return ctx.body = yapi.commons.resReturn(null, 400, '项目id不能为空');
+ }
+
+ let checkRepeat = await this.Model.checkProjectRepeat(params.uid,params.projectid);
+ if (checkRepeat) {
+ return ctx.body = yapi.commons.resReturn(null, 401, '项目已关注');
+ }
+
+ if (!params.projectname) {
+ return ctx.body = yapi.commons.resReturn(null, 400, '项目名不能为空');
+ }
+ if (!params.icon) {
+ return ctx.body = yapi.commons.resReturn(null, 400, '项目图标标志不能为空');
+ }
+
+ let data = {
+ uid: params.uid,
+ projectid: params.projectid,
+ projectname: params.projectname,
+ icon: params.icon
+ };
+
+ try {
+ let result = await this.Model.save(data);
+ result = yapi.commons.fieldSelect(result, ['_id', 'uid', 'projectid', 'projectname', 'icon']);
+ ctx.body = yapi.commons.resReturn(result);
+ } catch (e) {
+ ctx.body = yapi.commons.resReturn(null, 402, e.message);
+ }
+ }
+
+}
+
+module.exports = followController;
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/static/doc/static/server/controllers/group.js.html b/static/doc/static/server/controllers/group.js.html
index e283d75c..edda6bb4 100644
--- a/static/doc/static/server/controllers/group.js.html
+++ b/static/doc/static/server/controllers/group.js.html
@@ -29,6 +29,7 @@
import yapi from '../yapi.js';
import baseController from './base.js';
import projectModel from '../models/project.js';
+import userModel from '../models/user.js';
class groupController extends baseController {
constructor(ctx) {
@@ -42,7 +43,8 @@ class groupController extends baseController {
* @category group
* @foldnumber 10
* @param {String} group_name 项目分组名称,不能为空
- * @param {String} [group_desc] 项目分组描述
+ * @param {String} [group_desc] 项目分组描述
+ * @param {String} owner_uid 组长uid
* @returns {Object}
* @example ./api/group/add.json
*/
@@ -51,7 +53,8 @@ class groupController extends baseController {
params = yapi.commons.handleParams(params, {
group_name: 'string',
- group_desc: 'string'
+ group_desc: 'string',
+ owner_uid: 'number'
});
if (this.getRole() !== 'admin') {
@@ -62,6 +65,14 @@ class groupController extends baseController {
return ctx.body = yapi.commons.resReturn(null, 400, '项目分组名不能为空');
}
+ if(!params.owner_uid){
+ return ctx.body = yapi.commons.resReturn(null, 400, '项目分组必须添加一个组长');
+ }
+
+ let groupUserdata = await this.getUserdata(params.owner_uid, 'owner');
+ if(groupUserdata === null){
+ return ctx.body = yapi.commons.resReturn(null, 400, '组长uid不存在')
+ }
let groupInst = yapi.getInst(groupModel);
let checkRepeat = await groupInst.checkRepeat(params.group_name);
@@ -75,13 +86,14 @@ class groupController extends baseController {
group_desc: params.group_desc,
uid: this.getUid(),
add_time: yapi.commons.time(),
- up_time: yapi.commons.time()
+ up_time: yapi.commons.time(),
+ members: [groupUserdata]
};
try {
let result = await groupInst.save(data);
- result = yapi.commons.fieldSelect(result, ['_id', 'group_name', 'group_desc', 'uid']);
+ result = yapi.commons.fieldSelect(result, ['_id', 'group_name', 'group_desc', 'uid', 'members']);
ctx.body = yapi.commons.resReturn(result);
} catch (e) {
ctx.body = yapi.commons.resReturn(null, 402, e.message);
@@ -89,6 +101,114 @@ class groupController extends baseController {
}
+ async getUserdata(uid, role){
+ role = role || 'dev';
+ let userInst = yapi.getInst(userModel);
+ let userData = await userInst.findById(uid);
+ if(!userData){
+ return null;
+ }
+ return {
+ role: role,
+ uid: userData._id,
+ username: userData.username,
+ email: userData.email
+ }
+ }
+
+ async addMember(ctx){
+ let params = ctx.request.body;
+ let groupInst = yapi.getInst(groupModel);
+ if (!params.member_uid) {
+ return ctx.body = yapi.commons.resReturn(null, 400, '分组成员uid不能为空');
+ }
+ if (!params.id) {
+ return ctx.body = yapi.commons.resReturn(null, 400, '分组id不能为空');
+ }
+
+ var check = await groupInst.checkMemberRepeat(params.id, params.member_uid);
+ if (check > 0) {
+ return ctx.body = yapi.commons.resReturn(null, 400, '成员已存在');
+ }
+ let groupUserdata = await this.getUserdata(params.member_uid);
+ if(groupUserdata === null){
+ return ctx.body = yapi.commons.resReturn(null, 400, '组长uid不存在')
+ }
+ try {
+ let result = await groupInst.addMember(params.id, groupUserdata);
+ ctx.body = yapi.commons.resReturn(result);
+ } catch (e) {
+ ctx.body = yapi.commons.resReturn(null, 402, e.message);
+ }
+ }
+
+ async changeMemberRole(ctx){
+ let params = ctx.request.body;
+ let groupInst = yapi.getInst(groupModel);
+ if (!params.member_uid) {
+ return ctx.body = yapi.commons.resReturn(null, 400, '分组成员uid不能为空');
+ }
+ if (!params.id) {
+ return ctx.body = yapi.commons.resReturn(null, 400, '分组id不能为空');
+ }
+ var check = await groupInst.checkMemberRepeat(params.id, params.member_uid);
+ if (check === 0) {
+ return ctx.body = yapi.commons.resReturn(null, 400, '分组成员不存在');
+ }
+ if (await this.checkAuth(id, 'group', 'danger') !== true) {
+ return ctx.body = yapi.commons.resReturn(null, 405, '没有权限');
+ }
+
+ params.role = params.role === 'owner' ? 'owner' : 'dev';
+
+ try {
+ let result = await groupInst.changeMemberRole(params.id, params.member_uid, params.role);
+ ctx.body = yapi.commons.resReturn(result);
+ } catch (e) {
+ ctx.body = yapi.commons.resReturn(null, 402, e.message);
+ }
+ }
+
+ async getMemberList(ctx) {
+ let params = ctx.request.query;
+ if (!params.id) {
+ return ctx.body = yapi.commons.resReturn(null, 400, '项目id不能为空');
+ }
+
+ try {
+ let groupInst = yapi.getInst(groupModel);
+ let group = await groupInst.get(params.id);
+ ctx.body = yapi.commons.resReturn(group.members);
+ } catch (e) {
+ ctx.body = yapi.commons.resReturn(null, 402, e.message);
+ }
+ }
+
+ async delMember(ctx) {
+ let params = ctx.request.body;
+ let groupInst = yapi.getInst(groupModel);
+ if (!params.member_uid) {
+ return ctx.body = yapi.commons.resReturn(null, 400, '分组成员uid不能为空');
+ }
+ if (!params.id) {
+ return ctx.body = yapi.commons.resReturn(null, 400, '分组id不能为空');
+ }
+ var check = await groupInst.checkMemberRepeat(params.id, params.member_uid);
+ if (check === 0) {
+ return ctx.body = yapi.commons.resReturn(null, 400, '分组成员不存在');
+ }
+ if (await this.checkAuth(id, 'group', 'danger') !== true) {
+ return ctx.body = yapi.commons.resReturn(null, 405, '没有权限');
+ }
+
+ try {
+ let result = await groupInst.delMember(params.id, params.member_uid);
+ ctx.body = yapi.commons.resReturn(result);
+ } catch (e) {
+ ctx.body = yapi.commons.resReturn(null, 402, e.message);
+ }
+ }
+
/**
* 获取项目分组列表
* @interface /group/list
@@ -158,12 +278,10 @@ class groupController extends baseController {
* @example ./api/group/up.json
*/
async up(ctx) {
- if (this.getRole() !== 'admin') {
- return ctx.body = yapi.commons.resReturn(null, 401, '没有权限');
+ if (await this.checkAuth(id, 'group', 'danger') !== true) {
+ return ctx.body = yapi.commons.resReturn(null, 405, '没有权限');
}
-
try {
-
ctx.request.body = yapi.commons.handleParams(ctx.request.body, {
id: 'number',
group_name: 'string',
diff --git a/static/doc/static/server/controllers/interfaceCol.js.html b/static/doc/static/server/controllers/interfaceCol.js.html
new file mode 100644
index 00000000..87909f17
--- /dev/null
+++ b/static/doc/static/server/controllers/interfaceCol.js.html
@@ -0,0 +1,376 @@
+
+
+
+
+
+ YApi : ./server/controllers/interfaceCol.js
+
+
+
+
+
+
+
+
+
+
+
YApi : ./server/controllers/interfaceCol.js
+
源代码
+
+
+
+
+
+
+ import interfaceColModel from '../models/interfaceCol.js';
+import interfaceCaseModel from '../models/interfaceCase.js';
+import baseController from './base.js';
+import yapi from '../yapi.js';
+
+class interfaceColController extends baseController{
+ constructor(ctx) {
+ super(ctx);
+ this.colModel = yapi.getInst(interfaceColModel);
+ this.caseModel = yapi.getInst(interfaceCaseModel);
+ }
+
+ /**
+ * 获取所有接口集
+ * @interface /col/list
+ * @method GET
+ * @category col
+ * @foldnumber 10
+ * @param {String} project_id email名称,不能为空
+ * @returns {Object}
+ * @example
+ */
+ async list(ctx){
+ try {
+ let id = ctx.query.project_id;
+ let inst = this.colModel(interfaceColModel);
+ let result = await inst.list(id);
+ ctx.body = yapi.commons.resReturn(result);
+ } catch (e) {
+ ctx.body = yapi.commons.resReturn(null, 402, e.message);
+ }
+ }
+
+ /**
+ * 增加接口集
+ * @interface /col/add_col
+ * @method POST
+ * @category col
+ * @foldnumber 10
+ * @param {Number} project_id
+ * @param {String} name
+ * @param {String} desc
+ * @returns {Object}
+ * @example
+ */
+
+ async addCol(ctx){
+ try{
+ let params = ctx.request.body;
+ params = yapi.commons.handleParams(params, {
+ name: 'string',
+ project_id: 'number',
+ desc: 'string'
+ });
+
+ if (!params.project_id) {
+ return ctx.body = yapi.commons.resReturn(null, 400, '项目id不能为空');
+ }
+ if(!params.name){
+ return ctx.body = yapi.commons.resReturn(null, 400, '名称不能为空');
+ }
+
+ let result = await this.colModel.save({
+ name: params.name,
+ project_id: params.project_id,
+ desc: params.desc,
+ uid: this.getUid(),
+ add_time: yapi.commons.time(),
+ up_time: yapi.commons.time()
+ })
+ ctx.body = yapi.commons.resReturn(result);
+
+ }catch(e){
+ ctx.body = yapi.commons.resReturn(null, 402, e.message);
+ }
+ }
+
+ /**
+ * 获取一个接口集下的所有的接口用例
+ * @interface /col/case_list
+ * @method GET
+ * @category col
+ * @foldnumber 10
+ * @param {String} col_id 接口集id
+ * @returns {Object}
+ * @example
+ */
+
+ async getCaseList(ctx){
+ try {
+ let id = ctx.query.col_id;
+ let inst = yapi.getInst(interfaceCaseModel);
+ let result = await inst.list(id);
+ ctx.body = yapi.commons.resReturn(result);
+ } catch (e) {
+ ctx.body = yapi.commons.resReturn(null, 402, e.message);
+ }
+ }
+
+ /**
+ * 增加一个接口用例
+ * @interface /col/add_case
+ * @method POST
+ * @category col
+ * @foldnumber 10
+ * @param {String} casename
+ * @param {Number} col_id
+ * @param {Number} project_id
+ * @param {String} env
+ * @param {String} domain
+ * @param {String} path
+ * @param {String} method
+ * @param {Object} req_query
+ * @param {Object} req_headers
+ * @param {String} req_body_type
+ * @param {Array} req_body_form
+ * @param {String} req_body_other
+ * @returns {Object}
+ * @example
+ */
+
+ async addCase(ctx){
+ try{
+ let params = ctx.request.body;
+ params = yapi.commons.handleParams(params, {
+ casename: 'string',
+ project_id: 'number',
+ col_id: 'number',
+ env: 'string',
+ domain: 'string',
+ method: 'string'
+ });
+
+ if (!params.project_id) {
+ return ctx.body = yapi.commons.resReturn(null, 400, '项目id不能为空');
+ }
+ if (!params.col_id) {
+ return ctx.body = yapi.commons.resReturn(null, 400, '项目id不能为空');
+ }
+ if (!params.env) {
+ return ctx.body = yapi.commons.resReturn(null, 400, '缺少环境配置');
+ }
+ if (!params.path) {
+ return ctx.body = yapi.commons.resReturn(null, 400, 'path 不能为空');
+ }
+
+
+ if(!params.casename){
+ return ctx.body = yapi.commons.resReturn(null, 400, '用例名称不能为空');
+ }
+
+ params.uid = this.getUid();
+ params.index = 0;
+ params.add_time = yapi.commons.time();
+ params.up_time = yapi.commons.time();
+ let result = await this.caseModel.save(params);
+
+ ctx.body = yapi.commons.resReturn(result);
+
+ }catch(e){
+ ctx.body = yapi.commons.resReturn(null, 402, e.message);
+ }
+ }
+
+ /**
+ * 获取一个接口用例详情
+ * @interface /col/case
+ * @method GET
+ * @category col
+ * @foldnumber 10
+ * @param {String} caseid
+ * @returns {Object}
+ * @example
+ */
+
+ async getCase(ctx){
+ try{
+ let id = ctx.query.caseid;
+ let result = await this.caseModel.get(id);
+ ctx.body = yapi.commons.resReturn(result);
+ }catch(e){
+ ctx.body = yapi.commons.resReturn(null, 400, e.message)
+ }
+ }
+
+ /**
+ * 更新一个接口集name或描述
+ * @interface /col/up_col
+ * @method POST
+ * @category col
+ * @foldnumber 10
+ * @param {String} name
+ * @param {String} desc
+ * @returns {Object}
+ * @example
+ */
+
+ async upCol(ctx){
+ try{
+ let params = ctx.request.body;
+ let result = await this.caseModel.up(params.col_id, {
+ name: params.col_name,
+ desc: params.col_desc,
+ up_time: yapi.commons.time()
+ })
+ ctx.body = yapi.commons.resReturn(result)
+ }catch(e){
+ ctx.body = yapi.commons.resReturn(null, 400, e.message)
+ }
+ }
+
+ /**
+ * 更新多个接口case index
+ * @interface /col/up_col_index
+ * @method POST
+ * @category col
+ * @foldnumber 10
+ * @param {Array} [id, index]
+ * @returns {Object}
+ * @example
+ */
+
+ async upCaseIndex(ctx){
+ try{
+ let params = ctx.request.body;
+ if(!params || !Array.isArray(params)){
+ ctx.body = yapi.commons.resReturn(null, 400, "请求参数必须是数组")
+ }
+ params.forEach((item) => {
+ if(item.id && item.index){
+ this.caseModel.upCaseIndex(item.id, item.index).then((res) => {}, (err) => {
+ yapi.commons.log(err.message, 'error')
+ })
+ }
+
+ })
+
+ return ctx.body = yapi.commons.resReturn('success')
+ }catch(e){
+ ctx.body = yapi.commons.resReturn(null, 400, e.message)
+ }
+ }
+
+ /**
+ * 删除一个接口集
+ * @interface /col/del_col
+ * @method GET
+ * @category col
+ * @foldnumber 10
+ * @param {String}
+ * @returns {Object}
+ * @example
+ */
+
+ async delCol(ctx){
+ try{
+ let id = ctx.request.body.colid;
+ let colData = await this.colModel.get(id);
+ if(!colData){
+ ctx.body = yapi.commons.resReturn(null, 400, "不存在的id")
+ }
+
+ if(colData.uid !== this.getUid()){
+ let auth = await this.checkAuth(colData.project_id, 'project', 'danger')
+ if(!auth){
+ return ctx.body = yapi.commons.resReturn(null, 400, '没有权限');
+ }
+ }
+
+ let result = await this.colModel.del(caseid);
+ return ctx.body = yapi.commons.resReturn(result);
+
+
+ }catch(e){
+ yapi.commons.resReturn(null, 400, e.message)
+ }
+ }
+
+ /**
+ *
+ * @param {*} ctx
+ */
+
+ async delCase(ctx){
+ try{
+ let caseid = ctx.request.body.caseid;
+ let caseData = await this.caseModel.get(caseid);
+ if(!caseData){
+ ctx.body = yapi.commons.resReturn(null, 400, "不存在的caseid")
+ }
+
+ if(caseData.uid !== this.getUid()){
+ let auth = await this.checkAuth(caseData.project_id, 'project', 'danger')
+ if(!auth){
+ return ctx.body = yapi.commons.resReturn(null, 400, '没有权限');
+ }
+ }
+
+ let result = await this.caseModel.del(caseid);
+ return ctx.body = yapi.commons.resReturn(result);
+
+
+ }catch(e){
+ yapi.commons.resReturn(null, 400, e.message)
+ }
+ }
+
+
+}
+
+module.exports = interfaceColController
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/static/doc/static/server/controllers/log.js.html b/static/doc/static/server/controllers/log.js.html
index dcb5c7cb..688233b8 100644
--- a/static/doc/static/server/controllers/log.js.html
+++ b/static/doc/static/server/controllers/log.js.html
@@ -35,33 +35,49 @@ class logController extends baseController {
super(ctx);
this.Model = yapi.getInst(logModel);
this.groupModel = yapi.getInst(groupModel);
+ try{
+ // var res = this.Model.save({
+ // uid: 107,
+ // typeid: 21,
+ // type: 'project',
+ // username: '小明明宝宝',
+ // content: '小明应该修改了的项目宝宝',
+ // time: yapi.commons.time()
+ // });
+ // var res = this.Model.del(107);
+ // ctx.body = yapi.commons.resReturn(null, 200,res);
+ }catch(err){
+ // ctx.body = yapi.commons.resReturn(null, 402, err.message);
+ }
+
+
}
/**
- * 获取节点列表
- * @interface /node/list
+ * 获取动态列表
+ * @interface /log/list
* @method GET
- * @category node
+ * @category log
* @foldnumber 10
* @param {Number} uid 用户id, 不能为空
* @param {Number} [page] 分页页码
* @param {Number} [limit] 分页大小
* @returns {Object}
- * @example ./api/project/list.json
+ * @example /log/list
*/
-
+
async list(ctx) {
- let uid = ctx.request.query.uid,
+ let typeid = ctx.request.query.typeid,
page = ctx.request.query.page || 1,
limit = ctx.request.query.limit || 10;
- if (!uid) {
- return ctx.body = yapi.commons.resReturn(null, 400, '用户id不能为空');
+ if (!typeid) {
+ return ctx.body = yapi.commons.resReturn(null, 400, 'typeid不能为空');
}
try {
- let result = await this.Model.listWithPaging(uid, page, limit);
- let count = await this.Model.listCount(uid);
+ let result = await this.Model.listWithPaging(typeid, page, limit);
+ let count = await this.Model.listCount(typeid);
ctx.body = yapi.commons.resReturn({
total: Math.ceil(count / limit),
diff --git a/static/doc/static/server/controllers/project.js.html b/static/doc/static/server/controllers/project.js.html
index f5c06ccd..4f2559c2 100644
--- a/static/doc/static/server/controllers/project.js.html
+++ b/static/doc/static/server/controllers/project.js.html
@@ -32,6 +32,8 @@ import interfaceModel from '../models/interface.js';
import groupModel from '../models/group';
import commons from '../utils/commons.js';
import userModel from '../models/user.js';
+import Mock from 'mockjs';
+const send = require('koa-send');
class projectController extends baseController {
@@ -85,6 +87,11 @@ class projectController extends baseController {
group_id: 'number',
desc: 'string'
});
+
+ if (await this.checkAuth(params.group_id, 'group', 'edit') !== true) {
+ return ctx.body = yapi.commons.resReturn(null, 405, '没有权限');
+ }
+
if (!params.group_id) {
return ctx.body = yapi.commons.resReturn(null, 400, '项目分组id不能为空');
}
@@ -99,7 +106,7 @@ class projectController extends baseController {
return ctx.body = yapi.commons.resReturn(null, 401, '已存在的项目名');
}
-
+
if (!params.prd_host) {
return ctx.body = yapi.commons.resReturn(null, 400, '项目domain不能为空');
}
@@ -120,13 +127,16 @@ class projectController extends baseController {
return ctx.body = yapi.commons.resReturn(null, 401, '已存在domain和basepath');
}
+
+
let data = {
name: params.name,
desc: params.desc,
prd_host: params.prd_host,
basepath: params.basepath,
protocol: params.protocol || 'http',
- members: [this.getUid()],
+ members: [],
+ project_type: params.project_type || 'private',
uid: this.getUid(),
group_id: params.group_id,
add_time: yapi.commons.time(),
@@ -161,12 +171,23 @@ class projectController extends baseController {
return ctx.body = yapi.commons.resReturn(null, 400, '项目id不能为空');
}
+ if (await this.checkAuth(params.id, 'project', 'edit') !== true) {
+ return ctx.body = yapi.commons.resReturn(null, 405, '没有权限');
+ }
+
var check = await this.Model.checkMemberRepeat(params.id, params.member_uid);
if (check > 0) {
return ctx.body = yapi.commons.resReturn(null, 400, '项目成员已存在');
}
+
+ let userdata = await this.getUserdata(params.member_uid);
+ if(userdata === null){
+ return ctx.body = yapi.commons.resReturn(null, 400, '成员uid不存在')
+ }
+
+
try {
- let result = await this.Model.addMember(params.id, params.member_uid);
+ let result = await this.Model.addMember(params.id, userdata);
ctx.body = yapi.commons.resReturn(result);
} catch (e) {
ctx.body = yapi.commons.resReturn(null, 402, e.message);
@@ -198,6 +219,10 @@ class projectController extends baseController {
return ctx.body = yapi.commons.resReturn(null, 400, '项目成员不存在');
}
+ if (await this.checkAuth(params.id, 'project', 'danger') !== true) {
+ return ctx.body = yapi.commons.resReturn(null, 405, '没有权限');
+ }
+
try {
let result = await this.Model.delMember(params.id, params.member_uid);
ctx.body = yapi.commons.resReturn(result);
@@ -206,6 +231,22 @@ class projectController extends baseController {
}
}
+
+ async getUserdata(uid, role){
+ role = role || 'dev';
+ let userInst = yapi.getInst(userModel);
+ let userData = await userInst.findById(uid);
+ if(!userData){
+ return null;
+ }
+ return {
+ role: role,
+ uid: userData._id,
+ username: userData.username,
+ email: userData.email
+ }
+ }
+
/**
* 获取项目成员列表
* @interface /project/get_member_list
@@ -225,10 +266,7 @@ class projectController extends baseController {
try {
let project = await this.Model.get(params.id);
- let userInst = yapi.getInst(userModel);
- let result = await userInst.findByUids(project.members);
-
- ctx.body = yapi.commons.resReturn(result);
+ ctx.body = yapi.commons.resReturn(project.members);
} catch (e) {
ctx.body = yapi.commons.resReturn(null, 402, e.message);
}
@@ -265,24 +303,20 @@ class projectController extends baseController {
* @category project
* @foldnumber 10
* @param {Number} group_id 项目group_id,不能为空
- * @param {Number} [page] 分页页码
- * @param {Number} [limit] 每页数据条目,默认为10
* @returns {Object}
* @example ./api/project/list.json
*/
async list(ctx) {
- let group_id = ctx.request.query.group_id,
- page = ctx.request.query.page || 1,
- limit = ctx.request.query.limit || 10;
+ let group_id = ctx.request.query.group_id
if (!group_id) {
return ctx.body = yapi.commons.resReturn(null, 400, '项目分组id不能为空');
}
+ let auth =await this.checkAuth(group_id, 'group', 'edit')
try {
- let result = await this.Model.listWithPaging(group_id, page, limit);
- let count = await this.Model.listCount(group_id);
+ let result = await this.Model.list(group_id, auth);
let uids = [];
result.forEach((item) => {
if (uids.indexOf(item.uid) === -1) {
@@ -295,7 +329,6 @@ class projectController extends baseController {
_users[item._id] = item;
});
ctx.body = yapi.commons.resReturn({
- total: Math.ceil(count / limit),
list: result,
userinfo: _users
});
@@ -327,7 +360,7 @@ class projectController extends baseController {
return ctx.body = yapi.commons.resReturn(null, 400, '请先删除该项目下所有接口');
}
- if (await this.jungeProjectAuth(id) !== true) {
+ if (await this.checkAuth(id, 'project', 'danger') !== true) {
return ctx.body = yapi.commons.resReturn(null, 405, '没有权限');
}
let result = await this.Model.del(id);
@@ -337,6 +370,33 @@ class projectController extends baseController {
}
}
+ async changeMemberRole(ctx){
+ let params = ctx.request.body;
+ let groupInst = yapi.getInst(groupModel);
+ if (!params.member_uid) {
+ return ctx.body = yapi.commons.resReturn(null, 400, '分组成员uid不能为空');
+ }
+ if (!params.id) {
+ return ctx.body = yapi.commons.resReturn(null, 400, '分组id不能为空');
+ }
+ var check = await groupInst.checkMemberRepeat(params.id, params.member_uid);
+ if (check === 0) {
+ return ctx.body = yapi.commons.resReturn(null, 400, '分组成员不存在');
+ }
+ if (await this.checkAuth(id, 'group', 'danger') !== true) {
+ return ctx.body = yapi.commons.resReturn(null, 405, '没有权限');
+ }
+
+ params.role = params.role === 'owner' ? 'owner' : 'dev';
+
+ try {
+ let result = await groupInst.changeMemberRole(params.id, params.member_uid, params.role);
+ ctx.body = yapi.commons.resReturn(result);
+ } catch (e) {
+ ctx.body = yapi.commons.resReturn(null, 402, e.message);
+ }
+ }
+
/**
* 编辑项目
* @interface /project/up
@@ -372,7 +432,7 @@ class projectController extends baseController {
return ctx.body = yapi.commons.resReturn(null, 405, '项目id不能为空');
}
- if (await this.jungeMemberAuth(id, this.getUid()) !== true) {
+ if (await this.checkAuth(id, 'project', 'edit') !== true) {
return ctx.body = yapi.commons.resReturn(null, 405, '没有权限');
}
@@ -409,7 +469,6 @@ class projectController extends baseController {
}
let data = {
- uid: this.getUid(),
up_time: yapi.commons.time()
};
@@ -483,6 +542,71 @@ class projectController extends baseController {
return ctx.body = yapi.commons.resReturn(queryList, 0, 'ok');
}
+
+ /**
+ * 下载项目的 Mock 数据
+ * @interface /project/download
+ * @method GET
+ * @category project
+ * @foldnumber 10
+ * @param {String} project_id
+ */
+ async download(ctx) {
+ const project_id = ctx.request.query.project_id;
+ let interfaceInst = yapi.getInst(interfaceModel);
+ // 根据 project_id 获取接口数据
+ let count = await interfaceInst.list(project_id);
+
+ if (!project_id) {
+ return ctx.body = yapi.commons.resReturn(null, 405, '项目id不能为空');
+ } else if (!count) {
+ return ctx.body = yapi.commons.resReturn(null, 401, '项目id不存在');
+ }
+
+ const arr = JSON.stringify(count.map(function(item) {
+ // 返回的json模板数据: item.res_body
+ const mockData = Mock.mock(
+ yapi.commons.json_parse(item.res_body)
+ );
+ return {
+ path: item.path,
+ mock: mockData
+ }
+ }));
+
+ const fileName = 'mock.js';
+ ctx.attachment(fileName);
+ await send(ctx, fileName, { root: __dirname + '/public' });
+
+ const res = `
+ var Mock = require('mockjs');
+ var xhook = require('xhook');
+ var data = ${arr};
+ function run() {
+ xhook.before(function(request, callback) {
+ setTimeout(function() {
+ var res;
+ data.forEach((item) => {
+ // 请求的接口在 data 中存在
+ if(request.url === item.path) {
+ res = {
+ status: 200,
+ text: Mock.mock(item.mock)
+ }
+ }
+ });
+ if (res) {
+ callback(res);
+ }else {
+ callback({ status: 405, text: '接口不存在' });
+ }
+ }, 500);
+ });
+ }
+ module.exports = run;`;
+ .trim();
+ return ctx.body = res;
+ }
}
module.exports = projectController;
diff --git a/static/doc/static/server/controllers/user.js.html b/static/doc/static/server/controllers/user.js.html
index 1ae4e7ea..6c0fe69c 100644
--- a/static/doc/static/server/controllers/user.js.html
+++ b/static/doc/static/server/controllers/user.js.html
@@ -34,6 +34,7 @@ import common from '../utils/commons.js';
import interfaceModel from '../models/interface.js'
import groupModel from '../models/group.js'
import projectModel from '../models/project.js'
+import avatarModel from '../models/avatar.js'
const jwt = require('jsonwebtoken');
@@ -168,12 +169,13 @@ class userController extends baseController {
passsalt: passsalt,
role: 'member',
add_time: yapi.commons.time(),
- up_time: yapi.commons.time()
+ up_time: yapi.commons.time(),
+ type: 'third'
};
user = await userInst.save(data);
yapi.commons.sendMail({
to: email,
- contents: `亲爱的用户:
您好,感谢使用YApi,系统检测您是第一次用Qsso账号登录YApi服务,您的Email是: ${email} ,初始化密码为:${passsalt}
`
+ contents: `亲爱的用户:
您好,感谢使用YApi平台.
`
});
}
@@ -237,10 +239,6 @@ class userController extends baseController {
}
}
- async forgetPassword() { }
-
- async resetPassword() { }
-
setLoginCookie(uid, passsalt) {
let token = jwt.sign({ uid: uid }, passsalt, { expiresIn: '7 days' });
@@ -298,7 +296,8 @@ class userController extends baseController {
passsalt: passsalt,
role: 'member',
add_time: yapi.commons.time(),
- up_time: yapi.commons.time()
+ up_time: yapi.commons.time(),
+ type: "site"
};
if (!data.username) {
@@ -460,10 +459,6 @@ class userController extends baseController {
up_time: yapi.commons.time()
};
- if (this.getRole() === 'admin') {
- params.role && (data.role = params.role);
- }
-
params.username && (data.username = params.username);
params.email && (data.email = params.email);
@@ -482,6 +477,65 @@ class userController extends baseController {
}
}
+ /**
+ *
+ * @param {*} basecode base64编码,通过h5 api传给后端
+ */
+
+ async uploadAvatar(ctx) {
+ try {
+ let basecode = ctx.request.body.basecode;
+ if(!basecode){
+ return ctx.body = yapi.commons.resReturn(null, 400, 'basecode不能为空')
+ }
+ let pngPrefix = 'data:image/png;base64,';
+ let jpegPrefix = 'data:image/jpeg;base64,';
+ let type;
+ if(basecode.substr(0, pngPrefix.length ) === pngPrefix){
+ basecode = basecode.substr(pngPrefix.length);
+ type = 'image/png';
+ }else if(basecode.substr(0, jpegPrefix.length ) === jpegPrefix){
+ basecode = basecode.substr(jpegPrefix.length);
+ type = 'image/jpeg';
+ }else{
+ return ctx.body = yapi.commons.resReturn(null, 400, '仅支持jpeg和png格式的图片')
+ }
+ let strLength = basecode.length;
+ if(parseInt(strLength-(strLength/8)*2) > 200000){
+ return ctx.body = yapi.commons.resReturn(null, 400, '图片大小不能超过200kb');
+ }
+
+ let avatarInst = yapi.getInst(avatarModel);
+ let result = await avatarInst.up(this.getUid(), basecode, type)
+ ctx.body = yapi.commons.resReturn(result);
+
+ } catch (e) {
+ ctx.body = yapi.commons.resReturn(null, 401, e.message);
+ }
+
+ }
+
+ async avatar(ctx) {
+
+ try{
+ let avatarInst = yapi.getInst(avatarModel);
+ let data = await avatarInst.get(this.getUid());
+ let dataBuffer, type;
+ if(!data || !data.basecode){
+ dataBuffer = yapi.fs.readFileSync(yapi.path.join(yapi.WEBROOT, 'static/image/avatar.png'));
+ type = 'image/png'
+ }else{
+ type = data.type;
+ dataBuffer = new Buffer(data.basecode, 'base64');
+ }
+
+ ctx.set('Content-type', type);
+ ctx.body = dataBuffer;
+ }catch(err){
+ ctx.body = 'error:' + err.message
+ }
+ }
+
/**
* 模糊搜索用户名或者email
* @interface /user/search
@@ -523,7 +577,6 @@ class userController extends baseController {
];
let filteredRes = common.filterRes(queryList, rules);
- console.log(queryList); // eslint-disable-line
return ctx.body = yapi.commons.resReturn(filteredRes, 0, 'ok');
}
@@ -548,6 +601,7 @@ class userController extends baseController {
let interfaceData = await interfaceInst.get(id)
result["interface_id"] = interfaceData._id;
result["interface_name"] = interfaceData.path;
+
type = 'project';
id = interfaceData.project_id;
}
diff --git a/ykit.js b/ykit.js
index 7dacf0c1..7d3b2f98 100644
--- a/ykit.js
+++ b/ykit.js
@@ -6,6 +6,67 @@ var assetsPluginInstance = new AssetsPlugin({
return 'window.WEBPACK_ASSETS = ' + JSON.stringify(assets);
}
})
+
+function handleCommonsChunk(webpackConfig) {
+ var commonsChunk = {
+ //filename: 'scripts/[name]@[chunkhash][ext]',
+ vendors: {
+ lib: ['react', 'redux',
+ 'redux-thunk',
+ 'react-dom',
+ 'redux-promise',
+ 'react-router-dom',
+ 'prop-types'
+
+ ],
+ lib2: [
+ 'axios',
+ 'moment'
+ ]
+ }
+ },
+ chunks = [],
+ filenameTpl = webpackConfig.output[this.env],
+ vendors;
+
+
+
+ if (typeof commonsChunk === 'object' && commonsChunk !== undefined) {
+ if (typeof commonsChunk.name === 'string' && commonsChunk) {
+ chunks.push(commonsChunk.name);
+ }
+ vendors = commonsChunk.vendors;
+ if (typeof vendors === 'object' && vendors !== undefined) {
+ var i = 0;
+ for (var name in vendors) {
+ if (vendors.hasOwnProperty(name) && vendors[name]) {
+ i++;
+ chunks.push(name);
+ webpackConfig.entry[name] = Array.isArray(vendors[name]) ? vendors[name] : [vendors[name]];
+ }
+ }
+ if (i > 0) {
+ chunks.push('manifest');
+ }
+
+ }
+
+ if (chunks.length > 0) {
+ let chunkFilename = filenameTpl.filename
+ chunkFilename = chunkFilename.replace("[ext]", '.js')
+ webpackConfig.plugins.push(
+ new this.webpack.optimize.CommonsChunkPlugin({
+ name: chunks,
+ filename: chunkFilename,
+ minChunks: commonsChunk.minChunks ? commonsChunk.minChunks : 2
+ })
+ );
+
+ }
+ }
+}
+
+
module.exports = {
plugins: [{
name: 'antd',
@@ -28,45 +89,35 @@ module.exports = {
exports: [
'./index.js'
],
- commonsChunk: {
- //filename: 'scripts/[name]@[chunkhash][ext]',
- vendors: {
- lib: ['react', 'redux',
- 'redux-thunk',
- 'react-dom',
- 'redux-promise',
- 'react-router-dom',
- 'prop-types'
-
- ],
- lib2:[
- 'axios',
- 'moment'
- ]
- }
- },
modifyWebpackConfig: function (baseConfig) {
var ENV_PARAMS = {};
switch (this.env) {
case 'local':
- ENV_PARAMS = {development: true};
+ ENV_PARAMS = { development: true };
break;
case 'dev':
- ENV_PARAMS = {development: true};
+ ENV_PARAMS = { development: true };
break;
case 'prd':
- ENV_PARAMS = {development: false};
+ ENV_PARAMS = { development: false };
break;
default:
- }
+ }
+
baseConfig.plugins.push(new this.webpack.DefinePlugin({
- ENV_PARAMS: JSON.stringify(ENV_PARAMS)
+ ENV_PARAMS: JSON.stringify(ENV_PARAMS)
}))
+
+ //初始化配置
baseConfig.devtool = 'cheap-module-eval-source-map'
baseConfig.context = path.resolve(__dirname, "client");
baseConfig.output.prd.path = 'static/prd';
baseConfig.output.prd.publicPath = '';
baseConfig.output.prd.filename = '[name]@[chunkhash][ext]'
+
+ //commonsChunk
+ handleCommonsChunk.call(this, baseConfig)
+
baseConfig.module.loaders.push({
test: /\.(sass|scss)$/,
loader: ykit.ExtractTextPlugin.extract(