mirror of
https://github.com/YMFE/yapi.git
synced 2025-03-01 14:05:44 +08:00
feat: 添加项目逻辑
This commit is contained in:
commit
3eb65389e8
@ -1,6 +1,7 @@
|
||||
{
|
||||
"env": {
|
||||
"browser": true,
|
||||
"node": true,
|
||||
"commonjs": true
|
||||
},
|
||||
"extends": [],
|
||||
|
@ -3,11 +3,13 @@ import login from './reducer/Login/login.js'
|
||||
import group from './reducer/group/group.js'
|
||||
import project from './reducer/group/project.js'
|
||||
import Interface from './reducer/Interface/InterfaceReducer.js'
|
||||
import news from './reducer/news/news.js'
|
||||
|
||||
export default {
|
||||
group,
|
||||
login,
|
||||
LoginRedux,
|
||||
Interface,
|
||||
project
|
||||
project,
|
||||
news
|
||||
}
|
||||
|
@ -1,29 +1,20 @@
|
||||
import {
|
||||
FETCH_GROUP_LIST,
|
||||
FETCH_CURR_GROUP
|
||||
SET_CURR_GROUP
|
||||
} from '../constants/action-types';
|
||||
import axios from 'axios';
|
||||
|
||||
export function fetchGroupList() {
|
||||
return {
|
||||
type: FETCH_GROUP_LIST,
|
||||
// payload 可以返回 Promise,异步请求使用 axios 即可
|
||||
payload: axios.get('/group/list')
|
||||
// payload: new Promise((resolve) => {
|
||||
// resolve({
|
||||
// data: ['Hotel', 'Vacation', 'Flight', 'Pay'],
|
||||
// res: true
|
||||
// })
|
||||
// })
|
||||
}
|
||||
}
|
||||
|
||||
export function fetchCurrGroup() {
|
||||
export function setCurrGroup(group) {
|
||||
return {
|
||||
type: FETCH_CURR_GROUP,
|
||||
payload: {
|
||||
data: 'MFE'
|
||||
}
|
||||
type: SET_CURR_GROUP,
|
||||
payload: group
|
||||
}
|
||||
}
|
||||
|
||||
|
91
client/actions/news.js
Normal file
91
client/actions/news.js
Normal file
@ -0,0 +1,91 @@
|
||||
import {
|
||||
FETCH_NEWS_DATA,
|
||||
FETCH_MORE_NEWS
|
||||
} from '../constants/action-types.js';
|
||||
|
||||
export function fetchNewsData () {
|
||||
const data = [{
|
||||
name: 'John Brown',
|
||||
date: '2015-11-11 13:00:15',
|
||||
desc: '创建服务现场'
|
||||
}, {
|
||||
name: 'John Brown1',
|
||||
date: '2015-11-11 13:00:15',
|
||||
desc: '技术测试异常'
|
||||
}, {
|
||||
name: 'John Brown2',
|
||||
date: '2015-11-11 13:00:15',
|
||||
desc: '网络异常正在修复'
|
||||
}]
|
||||
|
||||
return {
|
||||
type: FETCH_NEWS_DATA,
|
||||
payload: data
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchViewedNews () {
|
||||
const data = [{
|
||||
name: 'John Brown21',
|
||||
date: '2015-11-11 13:00:15',
|
||||
desc: '创建服务现场'
|
||||
}, {
|
||||
name: 'John Brown12',
|
||||
date: '2015-11-11 13:00:15',
|
||||
desc: '技术测试异常'
|
||||
}, {
|
||||
name: 'John Brown22',
|
||||
date: '2015-11-11 13:00:15',
|
||||
desc: '网络异常正在修复'
|
||||
}]
|
||||
|
||||
return {
|
||||
type: FETCH_NEWS_DATA,
|
||||
payload: data
|
||||
}
|
||||
}
|
||||
|
||||
export function fetchNotVieweNews () {
|
||||
const data = [{
|
||||
name: 'John Brown22',
|
||||
date: '2015-11-11 13:00:15',
|
||||
desc: '创建服务现场'
|
||||
}, {
|
||||
name: 'John Brown12',
|
||||
date: '2015-11-11 13:00:15',
|
||||
desc: '技术测试异常'
|
||||
}, {
|
||||
name: 'John Brown22',
|
||||
date: '2015-11-11 13:00:15',
|
||||
desc: '网络异常正在修复'
|
||||
}]
|
||||
|
||||
return {
|
||||
type: FETCH_NEWS_DATA,
|
||||
payload: data
|
||||
}
|
||||
}
|
||||
|
||||
export function fetchMoreNews () {
|
||||
return (dispatch)=>{
|
||||
const data = [{
|
||||
name: 'John Brown2212',
|
||||
date: '2015-11-11 13:00:15',
|
||||
desc: '创建服务现场'
|
||||
}, {
|
||||
name: 'John Brown1132',
|
||||
date: '2015-11-11 13:00:15',
|
||||
desc: '技术测试异常'
|
||||
}, {
|
||||
name: 'John Brown23212',
|
||||
date: '2015-11-11 13:00:15',
|
||||
desc: '网络异常正在修复'
|
||||
}]
|
||||
|
||||
dispatch({
|
||||
type: FETCH_MORE_NEWS,
|
||||
payload: data
|
||||
})
|
||||
}
|
||||
|
||||
}
|
@ -3,13 +3,14 @@ import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { connect } from 'react-redux'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { Icon } from 'antd'
|
||||
import { Icon, Layout, Menu} from 'antd'
|
||||
import loginTypeAction from '../../actions/login';
|
||||
|
||||
const { Header } = Layout;
|
||||
const ToolUser = (props)=> (
|
||||
<ul>
|
||||
<li><Icon type="question-circle-o" />帮助</li>
|
||||
<li><Icon type="user" />{ props.user }</li>
|
||||
<li>消息{ props.msg.length }</li>
|
||||
<li>退出</li>
|
||||
</ul>
|
||||
);
|
||||
@ -29,7 +30,7 @@ ToolGuest.propTypes={
|
||||
onReg:PropTypes.func
|
||||
}
|
||||
|
||||
class Header extends Component {
|
||||
class HeaderCom extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
@ -45,31 +46,41 @@ class Header extends Component {
|
||||
const { login, user, msg } = this.props;
|
||||
return (
|
||||
<acticle className="header-box">
|
||||
<div className="content">
|
||||
<h1>
|
||||
<Link to={`/`}>YAPI</Link>
|
||||
</h1>
|
||||
<ul className="nav-toolbar">
|
||||
<li>
|
||||
<Link to={`/ProjectGroups`}>分组</Link>
|
||||
</li>
|
||||
<li>
|
||||
<a>我的项目</a>
|
||||
</li>
|
||||
<li>
|
||||
<a>文档</a>
|
||||
</li>
|
||||
</ul>
|
||||
<ul className="user-toolbar">
|
||||
{login?<ToolUser user={user} msg={msg}/>:''}
|
||||
</ul>
|
||||
</div>
|
||||
<Layout className="'layout">
|
||||
<Header>
|
||||
<div className="content">
|
||||
<div className="logo">
|
||||
YAPI
|
||||
</div>
|
||||
<Menu
|
||||
mode="horizontal"
|
||||
className="nav-toolbar"
|
||||
theme="dark"
|
||||
style={{ lineHeight : '.64rem'}}
|
||||
defaultSelectedKeys={['1']}
|
||||
>
|
||||
<Menu.Item key="1">
|
||||
<Link to={`/`}>首页</Link>
|
||||
</Menu.Item>
|
||||
<Menu.Item key="2">
|
||||
<Link to={`/ProjectGroups`}>分组</Link>
|
||||
</Menu.Item>
|
||||
<Menu.Item key="3">
|
||||
文档
|
||||
</Menu.Item>
|
||||
</Menu>
|
||||
<div className="user-toolbar">
|
||||
{login?<ToolUser user={user} msg={msg}/>:''}
|
||||
</div>
|
||||
</div>
|
||||
</Header>
|
||||
</Layout>
|
||||
</acticle>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Header.propTypes={
|
||||
HeaderCom.propTypes={
|
||||
user: PropTypes.string,
|
||||
msg: PropTypes.string,
|
||||
login:PropTypes.bool,
|
||||
@ -85,5 +96,5 @@ export default connect(
|
||||
}
|
||||
},
|
||||
{loginTypeAction}
|
||||
)(Header)
|
||||
)(HeaderCom)
|
||||
|
||||
|
@ -1,29 +1,35 @@
|
||||
@import '../../styles/common.scss';
|
||||
$color-white : #fff;
|
||||
$color-blue : #30a1f2;
|
||||
$color-blue : #108ee9;
|
||||
$color-blue-deeper: #34495E;
|
||||
$color-grey-deep : #929aac;
|
||||
$color-black-light : #404040;
|
||||
/* .header-box.css */
|
||||
.header-box {
|
||||
display: block;
|
||||
line-height: .64rem;
|
||||
background: #000c15;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
//line-height: .64rem;
|
||||
font-size: 0.14rem;
|
||||
color: $color-white;
|
||||
z-index: 9999;
|
||||
|
||||
// 内容宽度
|
||||
.content {
|
||||
max-width: 11rem;
|
||||
max-width: 10.3rem;
|
||||
margin: 0 auto;
|
||||
zoom: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: .25rem;
|
||||
.logo {
|
||||
font-size: .3rem;
|
||||
float: left;
|
||||
margin: 0 .2rem 0 0;
|
||||
color: $color-white;
|
||||
cursor: pointer;
|
||||
//cursor: pointer;
|
||||
a{
|
||||
color: $color-white;
|
||||
&:hover {
|
||||
@ -36,37 +42,30 @@ $color-grey-deep : #929aac;
|
||||
}
|
||||
|
||||
.nav-toolbar {
|
||||
font-size: .15rem;
|
||||
box-sizing: border-box;
|
||||
float: left;
|
||||
li {
|
||||
float: left;
|
||||
margin: 0 .2rem;
|
||||
a{
|
||||
color: $color-white;
|
||||
&:hover {
|
||||
color: $color-blue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.user-toolbar{
|
||||
float: right;
|
||||
line-height: .12rem;
|
||||
line-height: .14rem;
|
||||
li{
|
||||
float: left;
|
||||
height: .12rem;
|
||||
margin: .26rem 0;
|
||||
padding: 0 .1rem;
|
||||
font-size: .12rem;
|
||||
padding: 0 0 0 .12rem;
|
||||
font-size: .14rem;
|
||||
cursor: pointer;
|
||||
a{
|
||||
color: $color-white;
|
||||
&:hover{
|
||||
color: $color-blue;
|
||||
}
|
||||
}
|
||||
color: $color-white;
|
||||
&:not(:last-child){
|
||||
border-right: .01rem solid $color-white;
|
||||
padding: 0 .12rem;
|
||||
}
|
||||
&:hover{
|
||||
color: $color-blue;
|
||||
}
|
||||
i{
|
||||
margin-right: .09rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
72
client/components/Intro/Intro.js
Normal file
72
client/components/Intro/Intro.js
Normal file
@ -0,0 +1,72 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Row, Col, Icon } from 'antd'
|
||||
import "./Intro.scss"
|
||||
|
||||
const IntroPart = (props) =>(
|
||||
<Col span={12} className="switch-content">
|
||||
<div className="icon-switch">
|
||||
<Icon type="smile-o" />
|
||||
</div>
|
||||
<div>
|
||||
<p><b>{props.title}</b></p>
|
||||
<p>{props.des}</p>
|
||||
</div>
|
||||
</Col>
|
||||
)
|
||||
|
||||
IntroPart.propTypes = {
|
||||
title : PropTypes.string,
|
||||
des : PropTypes.string
|
||||
}
|
||||
|
||||
class Intro extends React.Component{
|
||||
constructor(props){
|
||||
super(props);
|
||||
}
|
||||
static propTypes={
|
||||
intro : PropTypes.shape({
|
||||
title:PropTypes.string,
|
||||
des:PropTypes.string,
|
||||
img:PropTypes.string,
|
||||
detail:PropTypes.arrayOf(PropTypes.shape({
|
||||
title:PropTypes.string,
|
||||
des:PropTypes.string
|
||||
}))
|
||||
})
|
||||
}
|
||||
render(){
|
||||
const { intro } = this.props;
|
||||
return(
|
||||
<div className="intro-container">
|
||||
<Row>
|
||||
<Col span={12}>
|
||||
<div>
|
||||
<div className="img-container">
|
||||
<img src={intro.img}/>
|
||||
</div>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span={12} className="des-container">
|
||||
<div>
|
||||
<div className="des-title">
|
||||
{intro.title}
|
||||
</div>
|
||||
<div className="des-detail">
|
||||
{intro.des}
|
||||
</div>
|
||||
</div>
|
||||
<div className="des-switch">
|
||||
{intro.detail.map(function(item,i){
|
||||
return(<IntroPart key={i} title={item.title} des={item.des}/>)
|
||||
})}
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default Intro;
|
||||
|
49
client/components/Intro/Intro.scss
Normal file
49
client/components/Intro/Intro.scss
Normal file
@ -0,0 +1,49 @@
|
||||
$imgUrl : "../../../static/image/";
|
||||
$color-grey : #E5E5E5;
|
||||
$color-blue : #108ee9;
|
||||
$color-white: #fff;
|
||||
|
||||
.intro-container{
|
||||
.des-container{
|
||||
padding-left: .15rem;
|
||||
.des-title{
|
||||
font-size: .24rem;
|
||||
margin-bottom: .1rem;
|
||||
}
|
||||
.des-detail{
|
||||
font-size: .15rem;
|
||||
margin-bottom: .2rem;
|
||||
}
|
||||
.des-switch{
|
||||
.switch-content{
|
||||
font-size: .14rem;
|
||||
margin-bottom: .15rem;
|
||||
div{
|
||||
float: left;
|
||||
}
|
||||
.icon-switch{
|
||||
height: .3rem;
|
||||
width: .3rem;
|
||||
border-radius: .02rem;
|
||||
background-color: $color-blue;
|
||||
margin-right: .1rem;
|
||||
color: $color-white;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.img-container{
|
||||
padding-right: .15rem;
|
||||
//background-image: url("#{$imgUrl}demo-img.png");
|
||||
img{
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
border: .01rem solid $color-grey;
|
||||
box-shadow : 0 0 3px 1px $color-grey;
|
||||
border-radius: .04rem;
|
||||
}
|
||||
}
|
||||
}
|
@ -5,7 +5,7 @@ export const PROJECT_MEMBER_INTERFACE = 'PROJECT_MEMBER_INTERFACE'
|
||||
|
||||
// group
|
||||
export const FETCH_GROUP_LIST = 'FETCH_GROUP_LIST'
|
||||
export const FETCH_CURR_GROUP = 'FETCH_CURR_GROUP'
|
||||
export const SET_CURR_GROUP = 'SET_CURR_GROUP'
|
||||
|
||||
// project
|
||||
export const PROJECT_ADD = 'PROJECT_ADD'
|
||||
@ -16,3 +16,8 @@ export const REGISTER = 'REGISTER';
|
||||
|
||||
//header
|
||||
export const LOGIN_TYPE = 'LOGIN_TYPE';
|
||||
|
||||
// News
|
||||
export const FETCH_NEWS_DATA = 'FETCH_NEWS_DATA';
|
||||
export const FETCH_MORE_NEWS = 'FETCH_MORE_NEWS';
|
||||
|
||||
|
@ -1,26 +1,77 @@
|
||||
import './Home.scss'
|
||||
import React, { Component } from 'react'
|
||||
import { Row, Col } from 'antd'
|
||||
import PropTypes from "prop-types"
|
||||
import Login from '../Login/login-wrap'
|
||||
import Intro from '../../components/Intro/Intro'
|
||||
|
||||
|
||||
class Home extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
introList:PropTypes.array
|
||||
}
|
||||
render () {
|
||||
return (
|
||||
<div className="home-main">
|
||||
<div className="main-one">
|
||||
<div className="home-des">
|
||||
<p className="title">YAPI</p>
|
||||
<div className="detail">一个高效,易用,功能强大的api管理系统</div>
|
||||
<div className="container">
|
||||
<Row>
|
||||
<Col span={24}>
|
||||
<div className="home-des">
|
||||
<p className="title">YAPI</p>
|
||||
<div className="detail">一个高效,易用,功能强大的api管理系统</div>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col span={8} className="main-one-left">
|
||||
<Login/>
|
||||
</Col>
|
||||
<Col span={16} className="main-one-right">
|
||||
<div className="img-container">
|
||||
<img src="./static/image/demo-img.png"/>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
<Login/>
|
||||
</div>
|
||||
{ this.props.introList.map(function(intro,i){
|
||||
return (
|
||||
<div className="main-part" key={i}>
|
||||
<div className="container">
|
||||
<Intro intro={intro}/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Home.defaultProps={
|
||||
introList:[{
|
||||
title:"接口管理",
|
||||
des:"yapi将满足你的所有接口管理需求。不再需要 为每个项目搭建独立的接口管理平台和编写离线的接口文档",
|
||||
detail:[
|
||||
{title:"接口管理",des:"强大的接口文档"},
|
||||
{title:"接口管理",des:"强大的接口文档"},
|
||||
{title:"接口管理",des:"强大的接口文档"}
|
||||
],
|
||||
img:"./static/image/demo-img.png"
|
||||
},{
|
||||
title:"接口管理",
|
||||
des:"yapi将满足你的所有接口管理需求。不再需要 为每个项目搭建独立的接口管理平台和编写离线的接口文档",
|
||||
detail:[
|
||||
{title:"接口管理",des:"强大的接口文档"},
|
||||
{title:"接口管理",des:"强大的接口文档"}
|
||||
],
|
||||
img:"./static/image/demo-img.png"
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
export default Home
|
||||
|
@ -1,27 +1,61 @@
|
||||
@import '../../styles/common.scss';
|
||||
/* .home-main.css */
|
||||
|
||||
$color-white : #fff;
|
||||
$color-blue-lighter : #f1f5ff;
|
||||
$color-grey-lighter : #F7F7F7;
|
||||
$color-blue-light: #5dade2;
|
||||
$color-black-lighter: #404040;
|
||||
|
||||
|
||||
.home-main {
|
||||
display: -webkit-box;
|
||||
max-width: 11rem;
|
||||
margin: 0 auto;
|
||||
margin-top: .64rem;
|
||||
-webkit-box-orient: vertical;
|
||||
background: $color-grey-lighter;
|
||||
.main-one{
|
||||
height:calc(100% - .64rem);
|
||||
padding: .5rem 0;
|
||||
padding: .5rem .5rem 0 .5rem;
|
||||
//background: radial-gradient(ellipse at center,#45484d 0%,#000 100%);
|
||||
.home-des{
|
||||
padding: .3rem 0;
|
||||
padding: 0 .3rem .3rem 0;
|
||||
.title{
|
||||
font-size: .6rem;
|
||||
}
|
||||
.detail{
|
||||
font-size: .23rem;
|
||||
font-size: .2rem;
|
||||
}
|
||||
}
|
||||
.login-form{
|
||||
|
||||
}
|
||||
.img-container{
|
||||
margin-bottom: -.2rem;
|
||||
img{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-shadow : 0 0 3px 0 $color-black-lighter;
|
||||
border-radius: .03rem;
|
||||
}
|
||||
}
|
||||
.main-one-left{
|
||||
padding-right: .15rem;
|
||||
}
|
||||
.main-one-right{
|
||||
padding-left: .15rem;
|
||||
}
|
||||
}
|
||||
|
||||
.main-part{
|
||||
padding: .9rem .5rem;
|
||||
&:nth-child(odd){
|
||||
background-color: $color-blue-lighter;
|
||||
}
|
||||
&:nth-child(even){
|
||||
background-color: $color-white;
|
||||
}
|
||||
}
|
||||
.container{
|
||||
max-width: 10.3rem;
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,6 +1,4 @@
|
||||
@import '../../styles/common.scss';
|
||||
|
||||
/* .login-main.css */
|
||||
.login-form {
|
||||
width: 4rem;
|
||||
}
|
||||
|
||||
|
43
client/containers/News/News.js
Normal file
43
client/containers/News/News.js
Normal file
@ -0,0 +1,43 @@
|
||||
import './News.scss'
|
||||
import React, { Component } from 'react'
|
||||
import NewsTimeline from './NewsTimeline/NewsTimeline'
|
||||
import { connect } from 'react-redux'
|
||||
import PropTypes from 'prop-types'
|
||||
import NewsList from './NewsList/NewsList.js'
|
||||
import { fetchNewsData } from '../../actions/news.js'
|
||||
|
||||
|
||||
@connect(
|
||||
state => {
|
||||
return {
|
||||
newsData: state.news.newsData?state.news.newsData:[]
|
||||
}
|
||||
},
|
||||
{
|
||||
fetchNewsData: fetchNewsData
|
||||
}
|
||||
)
|
||||
|
||||
class News extends Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
}
|
||||
static propTypes = {
|
||||
newsData: PropTypes.array,
|
||||
fetchNewsData: PropTypes.func
|
||||
}
|
||||
componentWillMount(){
|
||||
this.props.fetchNewsData()
|
||||
}
|
||||
render () {
|
||||
const data = this.props.newsData
|
||||
return (
|
||||
<section className="news-box">
|
||||
<NewsList />
|
||||
<NewsTimeline newsData = {data} />
|
||||
</section>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default News
|
81
client/containers/News/News.scss
Normal file
81
client/containers/News/News.scss
Normal file
@ -0,0 +1,81 @@
|
||||
/* .interface-box.css */
|
||||
.news-box {
|
||||
max-width: 11rem;
|
||||
display: -webkit-box;
|
||||
-webkit-box-flex: 1;
|
||||
margin: 15px auto 0 auto;
|
||||
font-size: 0.14rem;
|
||||
background: #FFF;
|
||||
|
||||
.news-list {
|
||||
width: 216px;
|
||||
line-height: 45px;
|
||||
background: #f9fafe;
|
||||
|
||||
li {
|
||||
padding: 0 0 0 30px;
|
||||
color: #344562;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover, &.active {
|
||||
background: #657289;
|
||||
color: #FFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.news-timeline{
|
||||
margin-left: 30px;
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
.ant-timeline-item-content{
|
||||
background-color: #ececec;
|
||||
margin-left: 30px;
|
||||
border-radius: 4px;
|
||||
border-left:4px solid #ececec;
|
||||
min-width: 350px;
|
||||
max-width: 450px;
|
||||
padding: 10px;
|
||||
|
||||
.timelineDate{
|
||||
display: block;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.timelineName{
|
||||
float: right;
|
||||
}
|
||||
|
||||
p{
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
div{
|
||||
overflow: hidden
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.ant-timeline-item-content:before{
|
||||
content:'';
|
||||
display: block;
|
||||
margin-left: -40px;
|
||||
width: 0px;
|
||||
height: 0px;
|
||||
float: left;
|
||||
border-width: 10px 13px;
|
||||
border-style: solid;
|
||||
border-color: transparent #ececec transparent transparent;
|
||||
}
|
||||
|
||||
.ant-timeline-item-tail{
|
||||
top: 16px;
|
||||
}
|
||||
|
||||
.ant-timeline-item-head{
|
||||
margin-top: 10px;
|
||||
}
|
77
client/containers/News/NewsList/NewsList.js
Normal file
77
client/containers/News/NewsList/NewsList.js
Normal file
@ -0,0 +1,77 @@
|
||||
import React, { Component } from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import PropTypes from 'prop-types'
|
||||
import {
|
||||
fetchNewsData,
|
||||
fetchViewedNews,
|
||||
fetchNotVieweNews } from '../../../actions/news.js'
|
||||
|
||||
|
||||
@connect(
|
||||
state => {
|
||||
return {
|
||||
newsData: state.news.newsData
|
||||
}
|
||||
},
|
||||
{
|
||||
fetchNewsData,
|
||||
fetchViewedNews,
|
||||
fetchNotVieweNews
|
||||
}
|
||||
)
|
||||
|
||||
class NewsList extends Component {
|
||||
|
||||
static propTypes = {
|
||||
fetchNewsData: PropTypes.func,
|
||||
fetchViewedNews: PropTypes.func,
|
||||
fetchNotVieweNews: PropTypes.func
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props)
|
||||
}
|
||||
|
||||
|
||||
|
||||
fetchData(e){
|
||||
const mark = e.target.className;
|
||||
if(mark.indexOf('allnews')>-1){
|
||||
this.props.fetchNewsData()
|
||||
this.switchColor(mark.indexOf('allnews'),e.target)
|
||||
}else if(mark.indexOf('viewednews')>-1){
|
||||
this.props.fetchViewedNews();
|
||||
this.switchColor(mark.indexOf('viewednews'),e.target)
|
||||
}else if(mark.indexOf('notview')>-1){
|
||||
this.props.fetchNotVieweNews();
|
||||
this.switchColor(mark.indexOf('notview'),e.target)
|
||||
}
|
||||
|
||||
}
|
||||
switchColor(index,e){
|
||||
let childNodes = e.parentNode.childNodes;
|
||||
if(e.className.indexOf('active')> -1) return;
|
||||
for(let j = 0;j<childNodes.length;j++){
|
||||
const i = childNodes[j].className.indexOf('active');
|
||||
if(i> -1){
|
||||
// console.log( childNodes[i].className.splice);
|
||||
let className = childNodes[j].className;
|
||||
className = className.split('');
|
||||
className.splice(i,6);
|
||||
childNodes[j].className = className.join('');
|
||||
}
|
||||
}
|
||||
e.className = e.className + ' active';
|
||||
}
|
||||
render () {
|
||||
return (
|
||||
<ul onClick = {this.fetchData.bind(this)} className="news-list">
|
||||
<li className="active allnews">全部消息</li>
|
||||
<li className='viewednews'>已读消息</li>
|
||||
<li className='notview'>未读消息</li>
|
||||
</ul>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default NewsList
|
48
client/containers/News/NewsTimeline/NewsTimeline.js
Normal file
48
client/containers/News/NewsTimeline/NewsTimeline.js
Normal file
@ -0,0 +1,48 @@
|
||||
import React, { Component } from 'react'
|
||||
import { Timeline } from 'antd'
|
||||
import PropTypes from 'prop-types'
|
||||
import { connect } from 'react-redux'
|
||||
import { fetchMoreNews } from '../../../actions/news.js'
|
||||
@connect(
|
||||
state=>{
|
||||
return state;
|
||||
},
|
||||
{
|
||||
fetchMoreNews: fetchMoreNews
|
||||
}
|
||||
)
|
||||
class NewsTimeline extends Component {
|
||||
static propTypes = {
|
||||
newsData: PropTypes.array,
|
||||
fetchMoreNews: PropTypes.func
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render () {
|
||||
const data = this.props.newsData;
|
||||
return (
|
||||
<section className="news-timeline">
|
||||
<Timeline pending={<a onClick = {this.props.fetchMoreNews}>See more</a>}>
|
||||
{
|
||||
data.map(function(item,i){
|
||||
return (
|
||||
<Timeline.Item color = 'green' key = {i} >
|
||||
<div>
|
||||
<span className='timelineDate'>{item.date}</span>
|
||||
<span className='timelineName'>{item.name}</span>
|
||||
</div>
|
||||
<p>{item.desc}</p>
|
||||
</Timeline.Item>
|
||||
)
|
||||
})
|
||||
}
|
||||
</Timeline>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default NewsTimeline
|
@ -6,7 +6,7 @@ import { autobind } from 'core-decorators';
|
||||
|
||||
import {
|
||||
fetchGroupList,
|
||||
fetchCurrGroup,
|
||||
setCurrGroup,
|
||||
addGroup
|
||||
} from '../../../actions/group.js'
|
||||
|
||||
@ -19,7 +19,7 @@ import './GroupList.scss'
|
||||
}),
|
||||
{
|
||||
fetchGroupList,
|
||||
fetchCurrGroup,
|
||||
setCurrGroup,
|
||||
addGroup
|
||||
}
|
||||
)
|
||||
@ -27,9 +27,10 @@ export default class GroupList extends Component {
|
||||
|
||||
static propTypes = {
|
||||
groupList: PropTypes.array,
|
||||
currGroup: PropTypes.string,
|
||||
currGroup: PropTypes.object,
|
||||
addGroup: PropTypes.func,
|
||||
fetchGroupList: PropTypes.func
|
||||
fetchGroupList: PropTypes.func,
|
||||
setCurrGroup: PropTypes.func
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
@ -37,7 +38,10 @@ export default class GroupList extends Component {
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
this.props.fetchGroupList();
|
||||
this.props.fetchGroupList().then(() => {
|
||||
const currGroup = this.props.groupList[0] || { group_name: '' };
|
||||
this.props.setCurrGroup(currGroup)
|
||||
});
|
||||
}
|
||||
|
||||
@autobind
|
||||
@ -51,7 +55,7 @@ export default class GroupList extends Component {
|
||||
return (
|
||||
<Card title="Groups">
|
||||
<Button type="primary" onClick={this.addGroup}>添加分组</Button>
|
||||
<div>{currGroup}</div>
|
||||
<div>{currGroup.group_name}</div>
|
||||
{
|
||||
groupList.map((group, index) => (
|
||||
<div key={index}>{group.group_name}</div>
|
||||
|
@ -13,21 +13,21 @@ class InterfaceTable extends Component {
|
||||
|
||||
render () {
|
||||
const columns = [{
|
||||
title: 'Uid',
|
||||
dataIndex: 'uid',
|
||||
key: 'uid'
|
||||
title: '接口名称',
|
||||
dataIndex: 'name',
|
||||
key: 'name'
|
||||
}, {
|
||||
title: '用户名',
|
||||
dataIndex: 'username',
|
||||
key: 'username'
|
||||
title: '接口URL',
|
||||
dataIndex: 'age',
|
||||
key: 'age'
|
||||
}, {
|
||||
title: 'email',
|
||||
dataIndex: 'email',
|
||||
key: 'email'
|
||||
title: '操作者',
|
||||
dataIndex: 'address',
|
||||
key: 'address'
|
||||
}, {
|
||||
title: '更新日期',
|
||||
dataIndex: 'up_time',
|
||||
key: 'up_time'
|
||||
dataIndex: 'date',
|
||||
key: 'date'
|
||||
}, {
|
||||
title: '功能',
|
||||
'key': 'action',
|
||||
@ -41,9 +41,7 @@ class InterfaceTable extends Component {
|
||||
}
|
||||
}]
|
||||
|
||||
const data = [
|
||||
{uid: 1, username: 'admin', email: 'admin@admin.com', up_time: '2017.07.01'}
|
||||
];
|
||||
const data = this.props.data;
|
||||
|
||||
return (
|
||||
<section className="interface-table">
|
62
client/containers/User/LeftMenu.js
Normal file
62
client/containers/User/LeftMenu.js
Normal file
@ -0,0 +1,62 @@
|
||||
import React, { Component } from 'react'
|
||||
import { Link } from 'react-router-dom'
|
||||
import {Input, Row, Col} from 'antd'
|
||||
|
||||
class LeftMenu extends Component {
|
||||
|
||||
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
curitem: 'profile'
|
||||
}
|
||||
console.log(this.props)
|
||||
}
|
||||
|
||||
handleCurItem(curitem) {
|
||||
return () => {
|
||||
this.setState({
|
||||
curitem: curitem
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const menus = [{
|
||||
title: '个人资料',
|
||||
path: '/user/profile'
|
||||
}, {
|
||||
title: '用户管理',
|
||||
path: '/user/list'
|
||||
}
|
||||
]
|
||||
|
||||
let content = menus.map((menu, index) => {
|
||||
return (
|
||||
<li key={index} className={location.hash === '#' + menu.path ? 'active' : ''}>
|
||||
<Link to={menu.path} >{menu.title}</Link>
|
||||
</li>
|
||||
)
|
||||
})
|
||||
|
||||
const Search = Input.Search;
|
||||
|
||||
return (<div>
|
||||
<Row type="flex" justify="start" className="search">
|
||||
<Col span="24">
|
||||
<Search
|
||||
placeholder="搜索用户"
|
||||
onSearch={value => console.log(value)}
|
||||
/>
|
||||
</Col>
|
||||
|
||||
</Row>
|
||||
<ul className="user-list">
|
||||
{content}
|
||||
</ul>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default LeftMenu
|
64
client/containers/User/List.js
Executable file
64
client/containers/User/List.js
Executable file
@ -0,0 +1,64 @@
|
||||
import React, { Component } from 'react'
|
||||
//import PropTypes from 'prop-types'
|
||||
import {
|
||||
Table,
|
||||
Button
|
||||
} from 'antd'
|
||||
|
||||
|
||||
|
||||
class List extends Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
const columns = [{
|
||||
title: 'UID',
|
||||
dataIndex: 'uid',
|
||||
key: 'uid'
|
||||
}, {
|
||||
title: '用户名',
|
||||
dataIndex: 'username',
|
||||
key: 'username'
|
||||
}, {
|
||||
title: 'email',
|
||||
dataIndex: 'email',
|
||||
key: 'email'
|
||||
}, {
|
||||
title: '更新日期',
|
||||
dataIndex: 'up_time',
|
||||
key: 'up_time'
|
||||
}, {
|
||||
title: '功能',
|
||||
key: 'action',
|
||||
render: () => {
|
||||
return (
|
||||
<span>
|
||||
<Button type="primary">编辑</Button>
|
||||
<Button type="danger">删除</Button>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
}]
|
||||
|
||||
|
||||
const data = [
|
||||
{ uid: 1, username: 'admin', email: 'admin@admin.com', up_time: '2017.07.01', key: 1 },
|
||||
{ uid: 2, username: 'admin2', email: 'admin21113qq3ß@admin311.com', up_time: '2017.07.21', key: 2 }
|
||||
];
|
||||
|
||||
return (
|
||||
<section className="user-table">
|
||||
|
||||
<Table columns={columns} dataSource={data} />
|
||||
|
||||
</section>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default List
|
123
client/containers/User/Profile.js
Normal file
123
client/containers/User/Profile.js
Normal file
@ -0,0 +1,123 @@
|
||||
import React, { Component } from 'react'
|
||||
import { Row, Col, Icon , Input, Button, Select} from 'antd'
|
||||
import axios from 'axios';
|
||||
|
||||
class Profile extends Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
usernameEdit: false,
|
||||
emailEdit: false,
|
||||
secureEdit: false,
|
||||
roleEdit: false
|
||||
}
|
||||
this.getUserInfo(101)
|
||||
}
|
||||
|
||||
handleEdit = (key, val) =>{
|
||||
var s = {};
|
||||
s[key] = val ;
|
||||
this.setState(s)
|
||||
}
|
||||
|
||||
getUserInfo = (id) => {
|
||||
axios.get('/user/find', {
|
||||
id: id
|
||||
}).then((res) =>{
|
||||
console.log(res)
|
||||
})
|
||||
}
|
||||
|
||||
render() {
|
||||
let ButtonGroup = Button.Group;
|
||||
let userNameEditHtml, emailEditHtml,secureEditHtml, roleEditHtml;
|
||||
const Option = Select.Option;
|
||||
if(this.state.usernameEdit === false){
|
||||
userNameEditHtml = <div >
|
||||
<span className="text">xiaoming</span>
|
||||
<span className="text-button" onClick={() => {this.handleEdit( 'usernameEdit', true)}}><Icon type="edit"/>修改</span>
|
||||
</div>
|
||||
}else{
|
||||
userNameEditHtml = <div>
|
||||
<Input placeholder="用户名" />
|
||||
<ButtonGroup className="edit-buttons" >
|
||||
<Button className="edit-button" onClick={() => {this.handleEdit( 'usernameEdit', false)}} >Cancel</Button>
|
||||
<Button className="edit-button" type="primary">OK</Button>
|
||||
</ButtonGroup>
|
||||
</div>
|
||||
}
|
||||
|
||||
if(this.state.emailEdit === false){
|
||||
emailEditHtml = <div >
|
||||
<span className="text">abc@qq.com</span>
|
||||
<span className="text-button" onClick={() => {this.handleEdit( 'emailEdit', true)}} ><Icon type="edit"/>修改</span>
|
||||
</div>
|
||||
}else{
|
||||
emailEditHtml = <div>
|
||||
<Input placeholder="Email" />
|
||||
<ButtonGroup className="edit-buttons" >
|
||||
<Button className="edit-button" onClick={() => {this.handleEdit( 'emailEdit', false)}} >Cancel</Button>
|
||||
<Button className="edit-button" type="primary">OK</Button>
|
||||
</ButtonGroup>
|
||||
</div>
|
||||
}
|
||||
|
||||
if(this.state.roleEdit === true){
|
||||
roleEditHtml = <div>
|
||||
<span className="text">管理员</span>
|
||||
<span className="text-button" onClick={() => {this.handleEdit( 'roleEdit', true)}} ><Icon type="edit"/>修改</span>
|
||||
</div>
|
||||
}else{
|
||||
roleEditHtml = <Select defaultValue="admin" style={{ width: 150 }} >
|
||||
<Option value="admin">管理员</Option>
|
||||
<Option value="member">会员</Option>
|
||||
|
||||
</Select>
|
||||
}
|
||||
|
||||
if(this.state.secureEdit === false){
|
||||
secureEditHtml = <Button type="primary" onClick={() => {this.handleEdit( 'secureEdit', true)}}>密码修改</Button>
|
||||
}else{
|
||||
secureEditHtml = <div>
|
||||
<Input placeholder="旧的密码" />
|
||||
<Input placeholder="新的密码" />
|
||||
<ButtonGroup className="edit-buttons" >
|
||||
<Button className="edit-button" onClick={() => {this.handleEdit( 'secureEdit', false)}}>Cancel</Button>
|
||||
<Button className="edit-button" type="primary">OK</Button>
|
||||
</ButtonGroup>
|
||||
</div>
|
||||
}
|
||||
|
||||
|
||||
return <div className="user-profile">
|
||||
<Row className="user-item" type="flex" justify="start">
|
||||
<Col span={4}>用户名</Col>
|
||||
<Col span={12}>
|
||||
{userNameEditHtml}
|
||||
</Col>
|
||||
|
||||
</Row>
|
||||
<Row className="user-item" type="flex" justify="start">
|
||||
<Col span={4}>Email</Col>
|
||||
<Col span={12}>
|
||||
{emailEditHtml}
|
||||
</Col>
|
||||
</Row>
|
||||
<Row className="user-item" type="flex" justify="start">
|
||||
<Col span={4}>角色</Col>
|
||||
<Col span={12}>
|
||||
{roleEditHtml}
|
||||
</Col>
|
||||
</Row>
|
||||
<Row className="user-item" type="flex" justify="start">
|
||||
<Col span={4}>安全</Col>
|
||||
<Col span={12}>
|
||||
{secureEditHtml}
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
export default Profile
|
41
client/containers/User/User.js
Executable file
41
client/containers/User/User.js
Executable file
@ -0,0 +1,41 @@
|
||||
import './index.scss'
|
||||
import React, { Component } from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import { Route} from 'react-router-dom'
|
||||
import LeftMenu from './LeftMenu.js'
|
||||
import List from './List.js'
|
||||
import PropTypes from 'prop-types'
|
||||
import Profile from './Profile.js'
|
||||
|
||||
@connect()
|
||||
class User extends Component {
|
||||
static propTypes = {
|
||||
match: PropTypes.object
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props)
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
console.log(this.props.match)
|
||||
}
|
||||
|
||||
render () {
|
||||
|
||||
|
||||
return (
|
||||
<div>
|
||||
<section className="user-box">
|
||||
|
||||
<LeftMenu />
|
||||
|
||||
<Route path={this.props.match.path + '/list/:uid'} component={List} />
|
||||
<Route path={this.props.match.path + '/profile'} component={Profile} />
|
||||
</section>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default User
|
@ -6,6 +6,30 @@
|
||||
margin: 15px auto 0 auto;
|
||||
font-size: 0.14rem;
|
||||
background: #FFF;
|
||||
min-height:500px;
|
||||
|
||||
.search{
|
||||
height: 40px;
|
||||
padding: 5px;
|
||||
background: #f9f9f9;
|
||||
|
||||
input{
|
||||
background: #f9f9f9;
|
||||
line-height: 40px;
|
||||
height: 40px;
|
||||
border: 0;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
input:focus{
|
||||
outline:0;
|
||||
border-color:0;
|
||||
box-shadow: none
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
.user-list {
|
||||
width: 216px;
|
||||
@ -14,13 +38,16 @@
|
||||
|
||||
li {
|
||||
padding: 0 0 0 30px;
|
||||
color: #344562;
|
||||
cursor: pointer;
|
||||
a{
|
||||
color: #344562;
|
||||
}
|
||||
|
||||
&:hover, &.active {
|
||||
&.active,&.active a {
|
||||
background: #657289;
|
||||
color: #FFF;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -36,4 +63,33 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.user-profile {
|
||||
-webkit-box-flex: 1;
|
||||
margin-top: 15px;
|
||||
margin-left: 15px;
|
||||
|
||||
.user-item {
|
||||
min-height:35px;
|
||||
line-height:35px;
|
||||
margin: 5px;
|
||||
margin-bottom:10px;
|
||||
|
||||
.text-button{
|
||||
font-size: 12px;
|
||||
color: #657289;
|
||||
cursor: pointer
|
||||
}
|
||||
|
||||
.edit-buttons{
|
||||
margin:10px;
|
||||
}
|
||||
|
||||
.edit-button{
|
||||
margin: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
class InterfaceList extends Component {
|
||||
static propTypes = {
|
||||
projectMember: PropTypes.func
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props)
|
||||
}
|
||||
|
||||
render () {
|
||||
const { projectMember } = this.props
|
||||
|
||||
return (
|
||||
<ul className="interface-list">
|
||||
<li className="active">个人资料</li>
|
||||
<li onClick={projectMember}>用户管理</li>
|
||||
</ul>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default InterfaceList
|
@ -2,10 +2,12 @@ import Home from './Home/Home.js'
|
||||
import Login from './Login/login-wrap.js'
|
||||
import ProjectGroups from './ProjectGroups/ProjectGroups.js'
|
||||
import Interface from './Interface/Interface.js'
|
||||
import News from './News/News.js'
|
||||
|
||||
export {
|
||||
Home,
|
||||
Login,
|
||||
ProjectGroups,
|
||||
Interface
|
||||
Interface,
|
||||
News
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
import {
|
||||
FETCH_GROUP_LIST,
|
||||
FETCH_CURR_GROUP
|
||||
SET_CURR_GROUP
|
||||
} from '../../constants/action-types';
|
||||
|
||||
const initialState = {
|
||||
groupList: [],
|
||||
currGroup: 'MFE'
|
||||
currGroup: { group_name: '' }
|
||||
};
|
||||
|
||||
export default (state = initialState, action) => {
|
||||
@ -19,14 +19,11 @@ export default (state = initialState, action) => {
|
||||
}
|
||||
return state;
|
||||
}
|
||||
case FETCH_CURR_GROUP: {
|
||||
if (action.payload.res) {
|
||||
return {
|
||||
...state,
|
||||
currGroup: action.payload.data
|
||||
};
|
||||
}
|
||||
return state;
|
||||
case SET_CURR_GROUP: {
|
||||
return {
|
||||
...state,
|
||||
currGroup: action.payload
|
||||
};
|
||||
}
|
||||
|
||||
default:
|
||||
|
29
client/reducer/news/news.js
Normal file
29
client/reducer/news/news.js
Normal file
@ -0,0 +1,29 @@
|
||||
import {
|
||||
FETCH_NEWS_DATA,
|
||||
FETCH_MORE_NEWS
|
||||
} from '../../constants/action-types.js'
|
||||
|
||||
const initialState = {
|
||||
newsData: []
|
||||
}
|
||||
|
||||
export default (state = initialState, action) => {
|
||||
switch (action.type) {
|
||||
case FETCH_NEWS_DATA: {
|
||||
|
||||
return {
|
||||
...state,
|
||||
newsData: action.payload
|
||||
};
|
||||
}
|
||||
case FETCH_MORE_NEWS: {
|
||||
state.newsData.push(...action.payload);
|
||||
return {
|
||||
...state
|
||||
}
|
||||
}
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,9 @@
|
||||
import React from 'react'
|
||||
|
||||
import { Route, HashRouter } from 'react-router-dom'
|
||||
import { Home, ProjectGroups, Interface } from './containers/index'
|
||||
import { Home, ProjectGroups, Interface, News } from './containers/index'
|
||||
import User from './containers/User/User.js'
|
||||
|
||||
import Header from './components/Header/Header'
|
||||
|
||||
export default () => {
|
||||
@ -11,7 +14,10 @@ export default () => {
|
||||
<Route path="/" component={ Home } exact />
|
||||
<Route path="/ProjectGroups" component={ ProjectGroups } />
|
||||
<Route path="/Interface" component={ Interface } />
|
||||
<Route path="/user" component={User} />
|
||||
<Route path="/News" component={ News } />
|
||||
</div>
|
||||
|
||||
</HashRouter>
|
||||
)
|
||||
}
|
||||
|
@ -26,6 +26,9 @@ ul {
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
&:active, &:hover, &:visited{
|
||||
text-decoration: none
|
||||
}
|
||||
}
|
||||
|
||||
a:hover {
|
||||
|
@ -3,9 +3,11 @@
|
||||
"webhost": "127.0.0.1",
|
||||
"adminAccount": "admin@admin.com",
|
||||
"db": {
|
||||
"servername": "192.168.237.71",
|
||||
"servername": "10.86.40.194",
|
||||
"DATABASE": "yapi",
|
||||
"port": 27017
|
||||
"port": 27017,
|
||||
"user": "test1",
|
||||
"pass": "test1"
|
||||
},
|
||||
"mail": {
|
||||
"host": "smtp.163.com",
|
||||
|
@ -22,6 +22,7 @@ function setupSql(){
|
||||
let userInst = yapi.getInst(userModel);
|
||||
let passsalt = yapi.commons.randStr();
|
||||
let result = userInst.save({
|
||||
username: yapi.WEBCONFIG.adminAccount.substr(0, yapi.WEBCONFIG.adminAccount.indexOf('@')),
|
||||
email: yapi.WEBCONFIG.adminAccount,
|
||||
password: yapi.commons.generatePassword('qunar.com', passsalt),
|
||||
passsalt: passsalt,
|
||||
|
@ -18,24 +18,23 @@ module.exports = async (ctx, next) => {
|
||||
return ctx.body = yapi.commons.resReturn(null, 403, e.message);
|
||||
}
|
||||
|
||||
let matchProject = [];
|
||||
let matchProject = false, maxBasepath = 0;
|
||||
for(let i=0, l = projects.length; i< l; i++){
|
||||
let project = projects[i];
|
||||
if(ctx.path && ctx.path.indexOf(project.basepath) === 0 && project.basepath[project.basepath.length -1] === '/'){
|
||||
matchProject.push(project);
|
||||
matchProject.push(project);
|
||||
if(project.basepath.length > maxBasepath){
|
||||
maxBasepath = project.basepath.length;
|
||||
matchProject = project;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(matchProject.length === 0){
|
||||
if(matchProject === false){
|
||||
return ctx.body = yapi.commons.resReturn(null, 400, '不存在的domain');
|
||||
}
|
||||
|
||||
if(matchProject.length > 1){
|
||||
return ctx.body = yapi.commons.resReturn(null, 401, '存在多个project,请检查数据库');
|
||||
}
|
||||
|
||||
let project = matchProject[0], interfaceData;
|
||||
let project = matchProject, interfaceData;
|
||||
let interfaceInst = yapi.getInst(interfaceModel);
|
||||
try{
|
||||
interfaceData = await interfaceInst.getByPath(project._id, ctx.path.substr(project.basepath.length));
|
||||
|
@ -38,7 +38,7 @@ createAction('group', 'del', 'post', 'del')
|
||||
createAction('user', 'login', 'post', 'login')
|
||||
createAction('user', 'reg', 'post', 'reg')
|
||||
createAction('user', 'list', 'get', 'list')
|
||||
createAction('user', 'find', 'post', 'findById')
|
||||
createAction('user', 'find', 'get', 'findById')
|
||||
createAction('user', 'update', 'post', 'update')
|
||||
createAction('user', 'del', 'post', 'del')
|
||||
createAction('user', 'status', 'get', 'getLoginStatus')
|
||||
|
@ -16,7 +16,10 @@ function connect(){
|
||||
mongoose.Promise = global.Promise;
|
||||
let config = yapi.WEBCONFIG;
|
||||
|
||||
let db = mongoose.connect(`mongodb://${config.db.servername}:${config.db.port}/${config.db.DATABASE}`);
|
||||
let db = mongoose.connect(`mongodb://${config.db.servername}:${config.db.port}/${config.db.DATABASE}`, {
|
||||
user: config.db.user,
|
||||
pass: config.db.pass
|
||||
});
|
||||
|
||||
db.then(function (res) {
|
||||
yapi.commons.log('mongodb load success...')
|
||||
|
@ -36,6 +36,7 @@ function setupSql() {
|
||||
var userInst = _yapi2.default.getInst(_user2.default);
|
||||
var passsalt = _yapi2.default.commons.randStr();
|
||||
var result = userInst.save({
|
||||
username: _yapi2.default.WEBCONFIG.adminAccount.substr(0, _yapi2.default.WEBCONFIG.adminAccount.indexOf('@')),
|
||||
email: _yapi2.default.WEBCONFIG.adminAccount,
|
||||
password: _yapi2.default.commons.generatePassword('qunar.com', passsalt),
|
||||
passsalt: passsalt,
|
||||
|
@ -28,7 +28,7 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
|
||||
|
||||
module.exports = function () {
|
||||
var _ref = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee(ctx, next) {
|
||||
var hostname, config, projectInst, projects, matchProject, i, l, _project, project, interfaceData, interfaceInst;
|
||||
var hostname, config, projectInst, projects, matchProject, maxBasepath, i, l, _project, project, interfaceData, interfaceInst;
|
||||
|
||||
return _regenerator2.default.wrap(function _callee$(_context) {
|
||||
while (1) {
|
||||
@ -71,17 +71,21 @@ module.exports = function () {
|
||||
return _context.abrupt('return', ctx.body = _yapi2.default.commons.resReturn(null, 403, _context.t0.message));
|
||||
|
||||
case 18:
|
||||
matchProject = [];
|
||||
matchProject = false, maxBasepath = 0;
|
||||
|
||||
for (i = 0, l = projects.length; i < l; i++) {
|
||||
_project = projects[i];
|
||||
|
||||
if (ctx.path && ctx.path.indexOf(_project.basepath) === 0 && _project.basepath[_project.basepath.length - 1] === '/') {
|
||||
matchProject.push(_project);
|
||||
if (_project.basepath.length > maxBasepath) {
|
||||
maxBasepath = _project.basepath.length;
|
||||
matchProject = _project;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!(matchProject.length === 0)) {
|
||||
if (!(matchProject === false)) {
|
||||
_context.next = 22;
|
||||
break;
|
||||
}
|
||||
@ -89,63 +93,55 @@ module.exports = function () {
|
||||
return _context.abrupt('return', ctx.body = _yapi2.default.commons.resReturn(null, 400, '不存在的domain'));
|
||||
|
||||
case 22:
|
||||
if (!(matchProject.length > 1)) {
|
||||
_context.next = 24;
|
||||
break;
|
||||
}
|
||||
|
||||
return _context.abrupt('return', ctx.body = _yapi2.default.commons.resReturn(null, 401, '存在多个project,请检查数据库'));
|
||||
|
||||
case 24:
|
||||
project = matchProject[0], interfaceData = void 0;
|
||||
project = matchProject, interfaceData = void 0;
|
||||
interfaceInst = _yapi2.default.getInst(_interface2.default);
|
||||
_context.prev = 26;
|
||||
_context.next = 29;
|
||||
_context.prev = 24;
|
||||
_context.next = 27;
|
||||
return interfaceInst.getByPath(project._id, ctx.path.substr(project.basepath.length));
|
||||
|
||||
case 29:
|
||||
case 27:
|
||||
interfaceData = _context.sent;
|
||||
|
||||
if (!(!interfaceData || interfaceData.length === 0)) {
|
||||
_context.next = 32;
|
||||
_context.next = 30;
|
||||
break;
|
||||
}
|
||||
|
||||
return _context.abrupt('return', ctx.body = _yapi2.default.commons.resReturn(null, 404, '不存在的api'));
|
||||
|
||||
case 32:
|
||||
case 30:
|
||||
if (!(interfaceData.length > 1)) {
|
||||
_context.next = 34;
|
||||
_context.next = 32;
|
||||
break;
|
||||
}
|
||||
|
||||
return _context.abrupt('return', ctx.body = _yapi2.default.commons.resReturn(null, 405, '存在多个api,请检查数据库'));
|
||||
|
||||
case 34:
|
||||
case 32:
|
||||
|
||||
interfaceData = interfaceData[0];
|
||||
|
||||
if (!(interfaceData.res_body_type === 'json')) {
|
||||
_context.next = 37;
|
||||
_context.next = 35;
|
||||
break;
|
||||
}
|
||||
|
||||
return _context.abrupt('return', ctx.body = _mockjs2.default.mock(_yapi2.default.commons.json_parse(interfaceData.res_body)));
|
||||
|
||||
case 37:
|
||||
case 35:
|
||||
return _context.abrupt('return', ctx.body = interfaceData.res_body);
|
||||
|
||||
case 40:
|
||||
_context.prev = 40;
|
||||
_context.t1 = _context['catch'](26);
|
||||
case 38:
|
||||
_context.prev = 38;
|
||||
_context.t1 = _context['catch'](24);
|
||||
return _context.abrupt('return', ctx.body = _yapi2.default.commons.resReturn(null, 409, _context.t1.message));
|
||||
|
||||
case 43:
|
||||
case 41:
|
||||
case 'end':
|
||||
return _context.stop();
|
||||
}
|
||||
}
|
||||
}, _callee, undefined, [[9, 15], [26, 40]]);
|
||||
}, _callee, undefined, [[9, 15], [24, 38]]);
|
||||
}));
|
||||
|
||||
return function (_x, _x2) {
|
||||
|
@ -65,7 +65,7 @@ createAction('group', 'del', 'post', 'del');
|
||||
createAction('user', 'login', 'post', 'login');
|
||||
createAction('user', 'reg', 'post', 'reg');
|
||||
createAction('user', 'list', 'get', 'list');
|
||||
createAction('user', 'find', 'post', 'findById');
|
||||
createAction('user', 'find', 'get', 'findById');
|
||||
createAction('user', 'update', 'post', 'update');
|
||||
createAction('user', 'del', 'post', 'del');
|
||||
createAction('user', 'status', 'get', 'getLoginStatus');
|
||||
|
@ -27,7 +27,10 @@ function connect() {
|
||||
_mongoose2.default.Promise = global.Promise;
|
||||
var config = _yapi2.default.WEBCONFIG;
|
||||
|
||||
var db = _mongoose2.default.connect('mongodb://' + config.db.servername + ':' + config.db.port + '/' + config.db.DATABASE);
|
||||
var db = _mongoose2.default.connect('mongodb://' + config.db.servername + ':' + config.db.port + '/' + config.db.DATABASE, {
|
||||
user: config.db.user,
|
||||
pass: config.db.pass
|
||||
});
|
||||
|
||||
db.then(function (res) {
|
||||
_yapi2.default.commons.log('mongodb load success...');
|
||||
|
BIN
static/image/demo-img.png
Normal file
BIN
static/image/demo-img.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 66 KiB |
Loading…
Reference in New Issue
Block a user