mirror of
https://github.com/YMFE/yapi.git
synced 2025-01-18 13:04:46 +08:00
feat: add project
This commit is contained in:
commit
d32742ac80
2
.gitignore
vendored
2
.gitignore
vendored
@ -37,3 +37,5 @@ node_modules/
|
||||
runtime/
|
||||
prd/
|
||||
dev/
|
||||
.tags
|
||||
.tags1
|
||||
|
@ -56,7 +56,7 @@ export default class App extends Component {
|
||||
<div className="router-main">
|
||||
<Header />
|
||||
<div className="router-container">
|
||||
<Route path="/" component={Home} exact />
|
||||
<Route exact path="/" component={Home} />
|
||||
<Route path="/group" component={requireAuthentication(Group)} />
|
||||
<Route path="/project/:id" component={requireAuthentication(Project)} />
|
||||
<Route path="/user" component={requireAuthentication(User)} />
|
||||
|
@ -10,18 +10,8 @@ import { withRouter } from 'react-router';
|
||||
import Srch from './Search/Search'
|
||||
const { Header } = Layout;
|
||||
|
||||
const headerStyle = {
|
||||
'height': '.56rem',
|
||||
'lineHeight': '.56rem',
|
||||
'padding': 0
|
||||
};
|
||||
|
||||
const MenuUser = (props) => (
|
||||
<Menu
|
||||
style={{
|
||||
"boxShadow":"0 1px 6px rgba(0, 0, 0, 0.3)"
|
||||
}}
|
||||
>
|
||||
<Menu className="user-menu" >
|
||||
<Menu.Item key="0">
|
||||
<Link to={`/user/profile/${props.uid}`} onClick={props.relieveLink}><Icon type="user"/>个人中心</Link>
|
||||
</Menu.Item>
|
||||
@ -171,7 +161,7 @@ export default class HeaderCom extends Component {
|
||||
render () {
|
||||
const { login, user, msg, uid } = this.props;
|
||||
return (
|
||||
<Header className="header-box" style={headerStyle}>
|
||||
<Header className="header-box m-header">
|
||||
<div className="content g-row">
|
||||
<div className="logo">
|
||||
<Link to="/" onClick={this.relieveLink} className="href">
|
||||
|
@ -13,6 +13,9 @@ $color-black-light : #404040;
|
||||
|
||||
/* .header-box.css */
|
||||
.header-box {
|
||||
height: .56rem;
|
||||
line-height: .56rem;
|
||||
padding: 0;
|
||||
.logo {
|
||||
position: relative;
|
||||
float: left;
|
||||
@ -46,6 +49,24 @@ $color-black-light : #404040;
|
||||
from { background-position: 0px; }
|
||||
to { background-position: -240px; }
|
||||
}
|
||||
&:before, &:after {
|
||||
content: '';
|
||||
display: block;
|
||||
width: 2px;
|
||||
height: .56rem;
|
||||
background-color: #222;
|
||||
border-left: 1px solid #575D67;
|
||||
position: relative;
|
||||
top: 0;
|
||||
}
|
||||
&:before {
|
||||
float: left;
|
||||
left: -.08rem;
|
||||
}
|
||||
&:after {
|
||||
float: right;
|
||||
right: -.27rem;
|
||||
}
|
||||
}
|
||||
|
||||
.nav-toolbar {
|
||||
|
@ -2,10 +2,8 @@ import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { connect } from 'react-redux';
|
||||
import { Button, Form, Input, Icon, Tooltip, Select, message, Row, Col, Radio } 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 { addProject } from '../../reducer/modules/project.js';
|
||||
import { fetchGroupList } from '../../reducer/modules/group.js'
|
||||
import { autobind } from 'core-decorators';
|
||||
const { TextArea } = Input;
|
||||
const FormItem = Form.Item;
|
||||
@ -30,77 +28,46 @@ const formItemLayout = {
|
||||
@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
|
||||
groupList: state.group.groupList
|
||||
}
|
||||
},
|
||||
{
|
||||
fetchProjectList,
|
||||
addProject,
|
||||
delProject,
|
||||
changeUpdateModal,
|
||||
changeTableLoading
|
||||
fetchGroupList,
|
||||
addProject
|
||||
}
|
||||
)
|
||||
|
||||
class ProjectList extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
visible: false,
|
||||
protocol: 'http:\/\/',
|
||||
projectData: []
|
||||
groupList: []
|
||||
}
|
||||
}
|
||||
static propTypes = {
|
||||
groupList: PropTypes.array,
|
||||
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
|
||||
fetchGroupList: PropTypes.func
|
||||
}
|
||||
|
||||
// 确认添加项目
|
||||
@autobind
|
||||
handleOk(e) {
|
||||
const { form, currGroup, changeTableLoading, addProject, fetchProjectList } = this.props;
|
||||
const that = this;
|
||||
const { form, addProject } = this.props;
|
||||
e.preventDefault();
|
||||
form.validateFields((err, values) => {
|
||||
// console.log(values);
|
||||
console.log(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);
|
||||
});
|
||||
}
|
||||
});
|
||||
@ -114,18 +81,9 @@ class ProjectList extends Component {
|
||||
})
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
// 切换项目列表
|
||||
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
|
||||
});
|
||||
}
|
||||
async componentWillMount() {
|
||||
await this.props.fetchGroupList();
|
||||
this.setState({groupList: this.props.groupList});
|
||||
}
|
||||
|
||||
render() {
|
||||
@ -157,8 +115,7 @@ class ProjectList extends Component {
|
||||
}]
|
||||
})(
|
||||
<Select>
|
||||
<Option value="china">China</Option>
|
||||
<Option value="use">U.S.A</Option>
|
||||
{this.state.groupList.map((item, index) => <Option value={item._id.toString()} key={index}>{item.group_name}</Option>)}
|
||||
</Select>
|
||||
)}
|
||||
</FormItem>
|
||||
@ -227,18 +184,18 @@ class ProjectList extends Component {
|
||||
{...formItemLayout}
|
||||
label="权限"
|
||||
>
|
||||
{getFieldDecorator('radio-group', {
|
||||
{getFieldDecorator('project_type', {
|
||||
rules: [{
|
||||
required: true
|
||||
}],
|
||||
initialValue: 1
|
||||
initialValue: 'private'
|
||||
})(
|
||||
<RadioGroup>
|
||||
<Radio value={1} className="radio">
|
||||
<Radio value="private" className="radio">
|
||||
<Icon type="lock" />私有<br /><span className="radio-desc">只有组长和项目开发者可以索引并查看项目信息</span>
|
||||
</Radio>
|
||||
<br />
|
||||
<Radio value={2} className="radio">
|
||||
<Radio value="public" className="radio">
|
||||
<Icon type="unlock" />公开<br /><span className="radio-desc">任何人都可以索引并查看项目信息</span>
|
||||
</Radio>
|
||||
</RadioGroup>
|
@ -1,4 +1,4 @@
|
||||
@import '../../../styles/common.scss';
|
||||
@import '../../styles/common.scss';
|
||||
|
||||
.m-container {
|
||||
margin: .24rem auto !important;
|
@ -2,6 +2,7 @@ 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 { Route, Switch, Redirect } from 'react-router-dom';
|
||||
import { Row, Col } from 'antd';
|
||||
|
||||
import './Group.scss'
|
||||
@ -12,6 +13,19 @@ export default class Group extends Component {
|
||||
}
|
||||
|
||||
render () {
|
||||
|
||||
const GroupContent = (
|
||||
<div className="g-row">
|
||||
<Row gutter={16}>
|
||||
<Col span={6}>
|
||||
<GroupList></GroupList>
|
||||
</Col>
|
||||
<Col span={18}>
|
||||
<ProjectList/>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
)
|
||||
return (
|
||||
<div>
|
||||
<Subnav
|
||||
@ -23,16 +37,10 @@ export default class Group extends Component {
|
||||
name: '我的关注',
|
||||
path: '/follow'
|
||||
}]}/>
|
||||
<div className="g-row">
|
||||
<Row gutter={16}>
|
||||
<Col span={6}>
|
||||
<GroupList></GroupList>
|
||||
</Col>
|
||||
<Col span={18}>
|
||||
<ProjectList/>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
<Switch>
|
||||
<Redirect exact from='/group' to='/group/0' />
|
||||
<Route path="/group/:groupId" render={() => GroupContent} />
|
||||
</Switch>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
0
client/containers/Project/Activity/Activity.js
Normal file
0
client/containers/Project/Activity/Activity.js
Normal file
@ -0,0 +1,4 @@
|
||||
import React from 'react'
|
||||
export default () => {
|
||||
return <h1>hello colContent</h1>
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
import React from 'react'
|
||||
export default () => {
|
||||
return <h1>hello colContent</h1>
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
import React from 'react'
|
||||
|
||||
export default () => {
|
||||
return <h1>接口Edit</h1>
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
import React from 'react'
|
||||
import { Tabs } from 'antd';
|
||||
import Edit from './Edit.js'
|
||||
import View from './View.js'
|
||||
import Run from './Run.js'
|
||||
|
||||
const TabPane = Tabs.TabPane;
|
||||
|
||||
const Content = () => {
|
||||
return <div className="interface-content">
|
||||
<Tabs defaultActiveKey="1" >
|
||||
<TabPane tab="预览" key="1">
|
||||
<View />
|
||||
</TabPane>
|
||||
<TabPane tab="编辑" key="2">
|
||||
<Edit />
|
||||
</TabPane>
|
||||
<TabPane tab="运行" key="3">
|
||||
<Run />
|
||||
</TabPane>
|
||||
</Tabs>
|
||||
</div>
|
||||
}
|
||||
|
||||
export default Content
|
@ -0,0 +1,17 @@
|
||||
import React from 'react'
|
||||
import { Menu, Button, Input, Icon, Tag } from 'antd';
|
||||
export default () => {
|
||||
return <div>
|
||||
<div className="interface-filter">
|
||||
<Input placeholder="Filter by name" style={{width:"70%"}} />
|
||||
<Tag color="#108ee9" style={{marginLeft:"15px"}} ><Icon type="plus" /></Tag>
|
||||
</div>
|
||||
<Menu className="interface-list">
|
||||
<Menu.Item><Button className="btn-http" type="primary">POST </Button>获取用过个人信息</Menu.Item>
|
||||
|
||||
<Menu.Item><Button className="btn-http btn-http-get" type="primary">GET</Button>获取用过个人信息</Menu.Item>
|
||||
|
||||
</Menu>
|
||||
</div>
|
||||
|
||||
}
|
5
client/containers/Project/Interface/InterfaceList/Run.js
Normal file
5
client/containers/Project/Interface/InterfaceList/Run.js
Normal file
@ -0,0 +1,5 @@
|
||||
import React from 'react'
|
||||
|
||||
export default () => {
|
||||
return <h1>接口Run</h1>
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
import React from 'react'
|
||||
|
||||
export default () => {
|
||||
return <h1>接口预览</h1>
|
||||
}
|
||||
|
70
client/containers/Project/Interface/interface.scss
Normal file
70
client/containers/Project/Interface/interface.scss
Normal file
@ -0,0 +1,70 @@
|
||||
.web-content{
|
||||
.left-menu{
|
||||
min-height: 5rem;
|
||||
box-shadow: 0 2px 4px 0 rgba(0,0,0,0.20);
|
||||
background: #FFF;
|
||||
border-radius:4px;
|
||||
margin: 3px;
|
||||
.ant-tabs-bar{
|
||||
border-bottom: none;
|
||||
margin-bottom: 0
|
||||
|
||||
}
|
||||
.ant-tabs-nav{
|
||||
width:100%;
|
||||
background-color: #ececec
|
||||
}
|
||||
.ant-tabs-tab{
|
||||
min-width: 50%;
|
||||
}
|
||||
.ant-tabs.ant-tabs-card > .ant-tabs-bar .ant-tabs-tab{
|
||||
background-color: #fff
|
||||
}
|
||||
.ant-tabs.ant-tabs-card > .ant-tabs-bar .ant-tabs-tab-active{
|
||||
background-color: #efefef
|
||||
}
|
||||
|
||||
.interface-filter{
|
||||
padding-left: 10px;
|
||||
height:45px;
|
||||
line-height: 32px;
|
||||
padding-top:7px;
|
||||
background-color: #efefef
|
||||
}
|
||||
.interface-list{
|
||||
|
||||
.btn-http{
|
||||
height: 23px;
|
||||
font-size: 10px;
|
||||
margin-right: 7px;
|
||||
padding: 0 5px;
|
||||
width: 40px;
|
||||
}
|
||||
|
||||
.btn-http-get{
|
||||
background-color: #00a854;
|
||||
border-color: #00a854
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.right-content{
|
||||
margin:3px;
|
||||
min-height: 5rem;
|
||||
box-shadow: 0 2px 4px 0 rgba(0,0,0,0.20);
|
||||
background: #FFF;
|
||||
border-radius:4px;
|
||||
.interface-content{
|
||||
.ant-tabs-nav{
|
||||
width:100%
|
||||
}
|
||||
.ant-tabs-nav-wrap{
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -3,8 +3,11 @@ import { connect } from 'react-redux';
|
||||
import PropTypes from 'prop-types'
|
||||
import { Route, Switch, Redirect } from 'react-router-dom';
|
||||
import { Subnav } from '../../components/index'
|
||||
import Interface from './Interface/Interface.js'
|
||||
import { getProject } from '../../reducer/modules/project';
|
||||
import { Interface } from './Interface/Interface.js'
|
||||
import { Activity } from './Activity/Activity.js'
|
||||
import { Setting } from './Setting/Setting.js'
|
||||
|
||||
|
||||
@connect(
|
||||
state => {
|
||||
@ -39,6 +42,7 @@ export default class Project extends Component {
|
||||
|
||||
render () {
|
||||
const { match } = this.props;
|
||||
console.log('project')
|
||||
return (
|
||||
<div>
|
||||
<Subnav
|
||||
@ -54,10 +58,10 @@ export default class Project extends Component {
|
||||
path: `/project/${match.params.id}/activity`
|
||||
}]}/>
|
||||
<Switch>
|
||||
<Redirect exact from='/project/:id' to={`/project/${match.params.id}/interface`} />
|
||||
<Route path="/project/:id/activity" component={null} />
|
||||
<Redirect exact from ="/project/:id" to={`/project/${match.params.id}/activity`}/>
|
||||
<Route path="/project/:id/activity" component={Activity} />
|
||||
<Route path="/project/:id/interface" component={Interface} />
|
||||
<Route path="/project/:id/setting" component={null} />
|
||||
<Route path="/project/:id/setting" component={Setting} />
|
||||
</Switch>
|
||||
</div>
|
||||
)
|
||||
|
0
client/containers/Project/Setting/Setting.js
Normal file
0
client/containers/Project/Setting/Setting.js
Normal file
@ -3,11 +3,23 @@ import { Row, Col, Input, Button, Select, message, Upload, Icon } from 'antd'
|
||||
import axios from 'axios';
|
||||
import {formatTime} from '../../common.js'
|
||||
import PropTypes from 'prop-types'
|
||||
import { connect } from 'react-redux'
|
||||
|
||||
@connect(state=>{
|
||||
return {
|
||||
curUid: state.user.uid,
|
||||
userType: state.user.type
|
||||
}
|
||||
},{
|
||||
|
||||
})
|
||||
|
||||
class Profile extends Component {
|
||||
|
||||
static propTypes = {
|
||||
match: PropTypes.object
|
||||
match: PropTypes.object,
|
||||
curUid: PropTypes.number,
|
||||
userType: PropTypes.string
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
@ -126,12 +138,21 @@ class Profile extends Component {
|
||||
const Option = Select.Option;
|
||||
let userinfo = this.state.userinfo;
|
||||
let _userinfo = this.state._userinfo;
|
||||
let roles = { admin: '管理员', member: '会员' }
|
||||
let roles = { admin: '管理员', member: '会员' };
|
||||
let userType = "";
|
||||
if(this.props.userType === "third"){
|
||||
userType = false;
|
||||
}else if(this.props.userType === "site"){
|
||||
userType = true;
|
||||
}else{
|
||||
userType = false;
|
||||
}
|
||||
|
||||
if (this.state.usernameEdit === false) {
|
||||
userNameEditHtml = <div >
|
||||
<span className="text">{userinfo.username}</span>
|
||||
{/*<span className="text-button" onClick={() => { this.handleEdit('usernameEdit', true) }}><Icon type="edit" />修改</span>*/}
|
||||
<Button icon="edit" onClick={() => { this.handleEdit('usernameEdit', true) }}>修改</Button>
|
||||
{userType?<Button icon="edit" onClick={() => { this.handleEdit('usernameEdit', true) }}>修改</Button>:""}
|
||||
</div>
|
||||
} else {
|
||||
userNameEditHtml = <div>
|
||||
@ -147,7 +168,7 @@ class Profile extends Component {
|
||||
emailEditHtml = <div >
|
||||
<span className="text">{userinfo.email}</span>
|
||||
{/*<span className="text-button" onClick={() => { this.handleEdit('emailEdit', true) }} ><Icon type="edit" />修改</span>*/}
|
||||
<Button icon="edit" onClick={() => { this.handleEdit('emailEdit', true) }}>修改</Button>
|
||||
{userType?<Button icon="edit" onClick={() => { this.handleEdit('emailEdit', true) }}>修改</Button>:""}
|
||||
</div>
|
||||
} else {
|
||||
emailEditHtml = <div>
|
||||
@ -163,7 +184,7 @@ class Profile extends Component {
|
||||
roleEditHtml = <div>
|
||||
<span className="text">{roles[userinfo.role]}</span>
|
||||
{/*<span className="text-button" onClick={() => { this.handleEdit('roleEdit', true) }} ><Icon type="edit" />修改</span>*/}
|
||||
<Button icon="edit" onClick={() => { this.handleEdit('roleEdit', true) }}>修改</Button>
|
||||
{userType?<Button icon="edit" onClick={() => { this.handleEdit('roleEdit', true) }}>修改</Button>:""}
|
||||
</div>
|
||||
} else {
|
||||
roleEditHtml = <Select defaultValue={_userinfo.role} onChange={ this.changeRole} style={{ width: 150 }} >
|
||||
@ -227,12 +248,12 @@ class Profile extends Component {
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<Row className="user-item" type="flex" justify="start">
|
||||
{userType?<Row className="user-item" type="flex" justify="start">
|
||||
<Col span={4}>密码</Col>
|
||||
<Col span={12}>
|
||||
{secureEditHtml}
|
||||
</Col>
|
||||
</Row>
|
||||
</Row>:""}
|
||||
</div>
|
||||
}
|
||||
}
|
||||
@ -243,15 +264,16 @@ class Avatar extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
imageUrl:""
|
||||
imageUrl: ""
|
||||
}
|
||||
}
|
||||
static propTypes = {
|
||||
uid: PropTypes.number
|
||||
}
|
||||
uploadAvatar(basecode){
|
||||
axios.post("/user/upload_avatar",{basecode: basecode}).then(()=>{
|
||||
this.setState({ imageUrl: basecode })
|
||||
axios.post("/api/user/upload_avatar",{basecode: basecode}).then(()=>{
|
||||
this.setState({ imageUrl: basecode });
|
||||
|
||||
}).catch((e)=>{
|
||||
console.log(e);
|
||||
})
|
||||
@ -264,18 +286,13 @@ class Avatar extends Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
let imageUrl = "";
|
||||
if(this.props.uid && !this.state.imageUrl){
|
||||
imageUrl = `/user/avatar?uid=${this.props.uid}`;
|
||||
}else{
|
||||
imageUrl = this.state.imageUrl;
|
||||
}
|
||||
let imageUrl = this.state.imageUrl?this.state.imageUrl:`/api/user/avatar?uid=${this.props.uid}`;
|
||||
return <div className="avatar-box">
|
||||
<Upload
|
||||
className="avatar-uploader"
|
||||
name="basecode"
|
||||
showUploadList={true}
|
||||
action="/user/upload_avatar"
|
||||
action="/api/user/upload_avatar"
|
||||
beforeUpload={beforeUpload}
|
||||
onChange={this.handleChange.bind(this)} >
|
||||
{
|
||||
@ -284,6 +301,7 @@ class Avatar extends Component {
|
||||
<Icon type="plus" className="avatar-uploader-trigger" />
|
||||
}
|
||||
</Upload>
|
||||
<span className="avatarChange">点击头像更换</span>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
@ -294,7 +312,7 @@ function beforeUpload(file) {
|
||||
if (!isJPG && !isPNG) {
|
||||
message.error('图片的格式只能为 jpg、png!');
|
||||
}
|
||||
const isLt2M = file.size / 1024 / 1024 < 2;
|
||||
const isLt2M = file.size / 1024 / 1024 < 0.2;
|
||||
if (!isLt2M) {
|
||||
message.error('图片必须小于 200kb!');
|
||||
}
|
||||
|
@ -8,10 +8,22 @@ import PropTypes from 'prop-types'
|
||||
import Profile from './Profile.js'
|
||||
import { Row } from 'antd';
|
||||
import Subnav from '../../components/Subnav/Subnav.js';
|
||||
@connect()
|
||||
@connect(state=>{
|
||||
console.log(state);
|
||||
return {
|
||||
curUid: state.user.uid,
|
||||
userType: state.user.type,
|
||||
role: state.user.role
|
||||
}
|
||||
},{
|
||||
|
||||
})
|
||||
class User extends Component {
|
||||
static propTypes = {
|
||||
match: PropTypes.object
|
||||
match: PropTypes.object,
|
||||
curUid: PropTypes.number,
|
||||
userType: PropTypes.string,
|
||||
role: PropTypes.string
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
@ -23,19 +35,22 @@ class User extends Component {
|
||||
}
|
||||
|
||||
render () {
|
||||
|
||||
let navData = [{
|
||||
name: '个人资料',
|
||||
path: `/user/profile/${this.props.curUid}`
|
||||
}];
|
||||
if(this.props.role === "admin"){
|
||||
navData.push({
|
||||
name: '成员管理',
|
||||
path: '/user/list'
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Subnav
|
||||
default={'我的关注'}
|
||||
data={[{
|
||||
name: '项目广场',
|
||||
path: '/group'
|
||||
}, {
|
||||
name: '我的关注',
|
||||
path: '/follow'
|
||||
}]}/>
|
||||
default={'个人资料'}
|
||||
data={navData}/>
|
||||
<div className="g-doc">
|
||||
<Row gutter={16} className="user-box">
|
||||
<Route path={this.props.match.path + '/list'} component={List} />
|
||||
|
@ -109,22 +109,23 @@
|
||||
border-bottom-left-radius: .04rem;
|
||||
border-bottom-right-radius: .04rem;
|
||||
}
|
||||
.avatar-uploader{
|
||||
border: none;
|
||||
}
|
||||
.avatar-uploader,
|
||||
.avatar-uploader-trigger,
|
||||
.avatar {
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
overflow: hidden;
|
||||
border-radius: 50px;
|
||||
|
||||
img{
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
.avatar-uploader {
|
||||
display: block;
|
||||
border: 1px dashed #d9d9d9;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.avatar-uploader {
|
||||
display: block;
|
||||
border: 1px dashed #d9d9d9;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.avatar-uploader-trigger {
|
||||
@ -133,4 +134,10 @@
|
||||
font-size: 28px;
|
||||
color: #999;
|
||||
}
|
||||
.avatarChange{
|
||||
display: block;
|
||||
width: 100px;
|
||||
text-align: center;
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ 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'
|
||||
import AddProject from './AddProject/AddProject.js'
|
||||
|
||||
export {
|
||||
Header,
|
||||
|
@ -65,3 +65,7 @@ em {
|
||||
margin: .24rem auto;
|
||||
padding: .24rem;
|
||||
}
|
||||
|
||||
.ant-dropdown .user-menu {
|
||||
box-shadow: 0 1px 6px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
@ -138,12 +138,20 @@
|
||||
<a href="#-user-update">/user/update</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="#-user-upload_avatar">/user/upload_avatar</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="#-user-avatar">/user/avatar</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="#-user-search">/user/search</a>
|
||||
</li>
|
||||
|
||||
<li >
|
||||
<a href="#-user-nav">/user/nav</a>
|
||||
<a href="#-user-project">/user/project</a>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
@ -1242,6 +1250,130 @@
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<div class="con-list-item">
|
||||
<blockquote class="api">
|
||||
<h3 id="-user-upload_avatar" class="page-header subject">
|
||||
/user/upload_avatar
|
||||
|
||||
<span class="ui-badge">POST</span>
|
||||
|
||||
|
||||
<a class="hashlink" href="#-user-upload_avatar">#</a>
|
||||
</h3>
|
||||
</blockquote>
|
||||
<p>
|
||||
<small class="text-muted">描述:</small>
|
||||
上传用户头像
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<small class="text-muted">源码位置:</small>
|
||||
<a href="./static/server/controllers/user.js.html#452" target="_blank">./server/controllers/user.js:452</a>
|
||||
</p>
|
||||
|
||||
|
||||
<p>
|
||||
<small class="text-muted">参数:</small>
|
||||
</p>
|
||||
<div class="docs-table">
|
||||
<table class="yo-table yo-table-border">
|
||||
<colgroup>
|
||||
<col class="c1">
|
||||
<col class="c2">
|
||||
<col class="c3">
|
||||
<col class="c4">
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr class="active">
|
||||
<th>参数名</th>
|
||||
<th>类型</th>
|
||||
<th>描述</th>
|
||||
<th>必选</th>
|
||||
<th>支持版本</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tr>
|
||||
<td>basecode</td>
|
||||
<td>*</td>
|
||||
<td>base64编码,通过h5 api传给后端</td>
|
||||
<td>
|
||||
|
||||
<i class="yo-ico glyphicon glyphicon-ok text-success"></i>
|
||||
|
||||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<div class="con-list-item">
|
||||
<blockquote class="api">
|
||||
<h3 id="-user-avatar" class="page-header subject">
|
||||
/user/avatar
|
||||
|
||||
<span class="ui-badge">GET</span>
|
||||
|
||||
|
||||
<a class="hashlink" href="#-user-avatar">#</a>
|
||||
</h3>
|
||||
</blockquote>
|
||||
<p>
|
||||
<small class="text-muted">描述:</small>
|
||||
根据用户uid头像
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<small class="text-muted">源码位置:</small>
|
||||
<a href="./static/server/controllers/user.js.html#495" target="_blank">./server/controllers/user.js:495</a>
|
||||
</p>
|
||||
|
||||
|
||||
<p>
|
||||
<small class="text-muted">参数:</small>
|
||||
</p>
|
||||
<div class="docs-table">
|
||||
<table class="yo-table yo-table-border">
|
||||
<colgroup>
|
||||
<col class="c1">
|
||||
<col class="c2">
|
||||
<col class="c3">
|
||||
<col class="c4">
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr class="active">
|
||||
<th>参数名</th>
|
||||
<th>类型</th>
|
||||
<th>描述</th>
|
||||
<th>必选</th>
|
||||
<th>支持版本</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tr>
|
||||
<td>uid</td>
|
||||
<td>*</td>
|
||||
<td></td>
|
||||
<td>
|
||||
|
||||
<i class="yo-ico glyphicon glyphicon-ok text-success"></i>
|
||||
|
||||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<div class="con-list-item">
|
||||
@ -1262,7 +1394,7 @@
|
||||
|
||||
<p>
|
||||
<small class="text-muted">源码位置:</small>
|
||||
<a href="./static/server/controllers/user.js.html#511" target="_blank">./server/controllers/user.js:511</a>
|
||||
<a href="./static/server/controllers/user.js.html#527" target="_blank">./server/controllers/user.js:527</a>
|
||||
</p>
|
||||
|
||||
|
||||
@ -1324,23 +1456,23 @@
|
||||
|
||||
<div class="con-list-item">
|
||||
<blockquote class="api">
|
||||
<h3 id="-user-nav" class="page-header subject">
|
||||
/user/nav
|
||||
<h3 id="-user-project" class="page-header subject">
|
||||
/user/project
|
||||
|
||||
<span class="ui-badge">GET</span>
|
||||
|
||||
|
||||
<a class="hashlink" href="#-user-nav">#</a>
|
||||
<a class="hashlink" href="#-user-project">#</a>
|
||||
</h3>
|
||||
</blockquote>
|
||||
<p>
|
||||
<small class="text-muted">描述:</small>
|
||||
根据路由id获取面包屑数据
|
||||
根据路由id初始化项目数据
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<small class="text-muted">源码位置:</small>
|
||||
<a href="./static/server/controllers/user.js.html#556" target="_blank">./server/controllers/user.js:556</a>
|
||||
<a href="./static/server/controllers/user.js.html#572" target="_blank">./server/controllers/user.js:572</a>
|
||||
</p>
|
||||
|
||||
|
||||
@ -1393,20 +1525,6 @@
|
||||
</div>
|
||||
|
||||
|
||||
<div>示例:</div>
|
||||
<pre class="ydoc-example" data-foldnumber=10><code class="js-code"><span class="token punctuation">{</span>
|
||||
<span class="token string">"errcode"</span><span class="token punctuation">:</span> <span class="token number">0</span><span class="token punctuation">,</span>
|
||||
<span class="token string">"errmsg"</span><span class="token punctuation">:</span> <span class="token string">"success"</span><span class="token punctuation">,</span>
|
||||
<span class="token string">"data"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span>
|
||||
<span class="token string">"interface_id"</span><span class="token punctuation">:</span> <span class="token number">2746</span><span class="token punctuation">,</span>
|
||||
<span class="token string">"interface_name"</span><span class="token punctuation">:</span> <span class="token string">"/a/c"</span><span class="token punctuation">,</span>
|
||||
<span class="token string">"project_id"</span><span class="token punctuation">:</span> <span class="token number">2481</span><span class="token punctuation">,</span>
|
||||
<span class="token string">"project_name"</span><span class="token punctuation">:</span> <span class="token string">"www.xxx.com/api"</span><span class="token punctuation">,</span>
|
||||
<span class="token string">"group_id"</span><span class="token punctuation">:</span> <span class="token number">181</span><span class="token punctuation">,</span>
|
||||
<span class="token string">"group_name"</span><span class="token punctuation">:</span> <span class="token string">"YMFE"</span>
|
||||
<span class="token punctuation">}</span>
|
||||
<span class="token punctuation">}</span></code></pre>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
@ -47,13 +47,13 @@ class baseController {
|
||||
async init(ctx) {
|
||||
this.$user = null;
|
||||
let ignoreRouter = [
|
||||
'/user/login_by_token',
|
||||
'/user/login',
|
||||
'/user/reg',
|
||||
'/user/status',
|
||||
'/user/logout'
|
||||
'/api/user/login_by_token',
|
||||
'/api/user/login',
|
||||
'/api/user/reg',
|
||||
'/api/user/status',
|
||||
'/api/user/logout'
|
||||
];
|
||||
if (ignoreRouter.indexOf(ctx.path) > -1) {
|
||||
if (ignoreRouter.indexOf(ctx.path) > -1) {
|
||||
this.$auth = true;
|
||||
} else {
|
||||
await this.checkLogin(ctx);
|
||||
@ -88,10 +88,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);
|
||||
}
|
||||
|
@ -603,7 +603,7 @@ class projectController extends baseController {
|
||||
}, 500);
|
||||
});
|
||||
}
|
||||
module.exports = run;`;
|
||||
module.exports = run;`
|
||||
.trim();
|
||||
return ctx.body = res;
|
||||
}
|
||||
|
@ -81,8 +81,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, '密码错误');
|
||||
@ -478,8 +478,13 @@ class userController extends baseController {
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* 上传用户头像
|
||||
* @interface /user/upload_avatar
|
||||
* @method POST
|
||||
* @param {*} basecode base64编码,通过h5 api传给后端
|
||||
* @category user
|
||||
* @returns {Object}
|
||||
* @example
|
||||
*/
|
||||
|
||||
async uploadAvatar(ctx) {
|
||||
@ -515,11 +520,22 @@ class userController extends baseController {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户uid头像
|
||||
* @interface /user/avatar
|
||||
* @method GET
|
||||
* @param {*} uid
|
||||
* @category user
|
||||
* @returns {Object}
|
||||
* @example
|
||||
*/
|
||||
|
||||
async avatar(ctx) {
|
||||
|
||||
try{
|
||||
let uid = ctx.query.uid ? ctx.query.uid: this.getUid();
|
||||
let avatarInst = yapi.getInst(avatarModel);
|
||||
let data = await avatarInst.get(this.getUid());
|
||||
let data = await avatarInst.get(uid);
|
||||
let dataBuffer, type;
|
||||
if(!data || !data.basecode){
|
||||
dataBuffer = yapi.fs.readFileSync(yapi.path.join(yapi.WEBROOT, 'static/image/avatar.png'));
|
||||
@ -582,26 +598,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;
|
||||
}
|
||||
@ -609,17 +623,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)
|
||||
|
@ -73,7 +73,7 @@
|
||||
"description": "高效、易用、功能强大、的api管理平台,旨在为开发、产品、测试人员提供更优雅的接口管理服务。"
|
||||
},
|
||||
"content": "./README/README-mock.md" // 内容(这里以markdown文件举例)
|
||||
|
||||
|
||||
},{
|
||||
"name": "api",
|
||||
"title": "",
|
||||
@ -85,8 +85,8 @@
|
||||
"options": {
|
||||
"type": "interface", // 类型,可选 component 和 lib,默认 component
|
||||
"source": true, // 是否生成源文件预览,默认 false
|
||||
"categories":["group","user","project", "interface"]
|
||||
|
||||
"categories":["group","user","project", "interface","follow"]
|
||||
|
||||
}
|
||||
}]
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user