mirror of
https://github.com/YMFE/yapi.git
synced 2025-03-07 14:16:52 +08:00
Merge branch 'dev' of http://gitlab.corp.qunar.com/mfe/yapi into dev
This commit is contained in:
commit
b77811280b
@ -29,14 +29,7 @@ module.exports = {
|
||||
"error",
|
||||
"unix"
|
||||
],
|
||||
"quotes": [
|
||||
"error",
|
||||
"single"
|
||||
],
|
||||
"semi": [
|
||||
"error",
|
||||
"always"
|
||||
],
|
||||
|
||||
"strict": 0,
|
||||
"comma-dangle": ["error", "never"],
|
||||
"no-console": ["off"]
|
||||
|
@ -238,7 +238,7 @@ export default class GroupList extends Component {
|
||||
this.props.curUserRole === "admin" ? (editmark) : ''
|
||||
}
|
||||
{
|
||||
this.props.curUserRole === "admin" ? (delmark) : ''
|
||||
this.props.curUserRole === "admin" || currGroup.role ==='owner' ? (delmark) : ''
|
||||
}
|
||||
{
|
||||
this.props.curUserRole === 'admin' ? (addmark) : ''
|
||||
|
@ -14,6 +14,9 @@
|
||||
.ant-select-selection__rendered{
|
||||
line-height: 34px;
|
||||
}
|
||||
.interace-edit-desc{
|
||||
height: 250px;
|
||||
}
|
||||
}
|
||||
|
||||
.table-interfacelist {
|
||||
|
@ -5,7 +5,7 @@ import constants from '../../../../constants/variable.js'
|
||||
import { handlePath, nameLengthLimit } from '../../../../common.js'
|
||||
import json5 from 'json5'
|
||||
import { message, Tabs } from 'antd'
|
||||
import Editor from 'wangeditor'
|
||||
import Editor from 'wangeditor'
|
||||
const TabPane = Tabs.TabPane;
|
||||
|
||||
const validJson = (json) => {
|
||||
@ -100,7 +100,7 @@ class InterfaceEditForm extends Component {
|
||||
handleSubmit = (e) => {
|
||||
e.preventDefault();
|
||||
this.props.form.validateFields((err, values) => {
|
||||
if (!err) {
|
||||
if (!err) {
|
||||
values.desc = this.editor.txt.html();
|
||||
if (values.res_body_type === 'json') {
|
||||
if (this.state.res_body && validJson(this.state.res_body) === false) {
|
||||
@ -118,7 +118,7 @@ class InterfaceEditForm extends Component {
|
||||
values.method = this.state.method;
|
||||
values.req_params = values.req_params || [];
|
||||
let isfile = false, isHavaContentType = false;
|
||||
if (values.req_body_type === 'form') {
|
||||
if (values.req_body_type === 'form') {
|
||||
values.req_body_form.forEach((item) => {
|
||||
if (item.type === 'file') {
|
||||
isfile = true;
|
||||
@ -218,7 +218,7 @@ class InterfaceEditForm extends Component {
|
||||
this.setState(newValue)
|
||||
}
|
||||
|
||||
handleJsonType = (key)=>{
|
||||
handleJsonType = (key) => {
|
||||
key = key || 'tpl';
|
||||
this.setState({
|
||||
jsonType: key
|
||||
@ -260,14 +260,14 @@ class InterfaceEditForm extends Component {
|
||||
|
||||
const queryTpl = (data, index) => {
|
||||
return <Row key={index} className="interface-edit-item-content">
|
||||
<Col span="4">
|
||||
<Col span="6">
|
||||
{getFieldDecorator('req_query[' + index + '].name', {
|
||||
initialValue: data.name
|
||||
})(
|
||||
<Input placeholder="参数名称" />
|
||||
)}
|
||||
</Col>
|
||||
<Col span="4" >
|
||||
<Col span="3" >
|
||||
{getFieldDecorator('req_query[' + index + '].required', {
|
||||
initialValue: data.required
|
||||
})(
|
||||
@ -277,14 +277,14 @@ class InterfaceEditForm extends Component {
|
||||
</Select>
|
||||
)}
|
||||
</Col>
|
||||
<Col span="8" >
|
||||
<Col span="14" >
|
||||
{getFieldDecorator('req_query[' + index + '].desc', {
|
||||
initialValue: data.desc
|
||||
})(
|
||||
<Input placeholder="备注" />
|
||||
)}
|
||||
</Col>
|
||||
<Col span="2" >
|
||||
<Col span="1" >
|
||||
<Icon type="delete" className="interface-edit-del-icon" onClick={() => this.delParams(index, 'req_query')} />
|
||||
</Col>
|
||||
|
||||
@ -311,7 +311,7 @@ class InterfaceEditForm extends Component {
|
||||
<Input placeholder="参数值" />
|
||||
)}
|
||||
</Col>
|
||||
<Col span="8" >
|
||||
<Col span="10" >
|
||||
{getFieldDecorator('req_headers[' + index + '].desc', {
|
||||
initialValue: data.desc
|
||||
})(
|
||||
@ -334,7 +334,7 @@ class InterfaceEditForm extends Component {
|
||||
<Input placeholder="name" />
|
||||
)}
|
||||
</Col>
|
||||
<Col span="4" >
|
||||
<Col span="3" >
|
||||
{getFieldDecorator('req_body_form[' + index + '].type', {
|
||||
initialValue: data.type
|
||||
})(
|
||||
@ -344,7 +344,7 @@ class InterfaceEditForm extends Component {
|
||||
</Select>
|
||||
)}
|
||||
</Col>
|
||||
<Col span="4" >
|
||||
<Col span="3" >
|
||||
{getFieldDecorator('req_body_form[' + index + '].required', {
|
||||
initialValue: data.required
|
||||
})(
|
||||
@ -354,14 +354,14 @@ class InterfaceEditForm extends Component {
|
||||
</Select>
|
||||
)}
|
||||
</Col>
|
||||
<Col span="8">
|
||||
<Col span="11">
|
||||
{getFieldDecorator('req_body_form[' + index + '].desc', {
|
||||
initialValue: data.desc
|
||||
})(
|
||||
<Input placeholder="备注" />
|
||||
)}
|
||||
</Col>
|
||||
<Col span="2" >
|
||||
<Col span="1" >
|
||||
<Icon type="delete" className="interface-edit-del-icon" onClick={() => this.delParams(index, 'req_body_form')} />
|
||||
</Col>
|
||||
</Row>
|
||||
@ -376,7 +376,7 @@ class InterfaceEditForm extends Component {
|
||||
<Input disabled placeholder="参数名称" />
|
||||
)}
|
||||
</Col>
|
||||
<Col span="8" >
|
||||
<Col span="14" >
|
||||
{getFieldDecorator('req_params[' + index + '].desc', {
|
||||
initialValue: data.desc
|
||||
})(
|
||||
@ -540,24 +540,23 @@ class InterfaceEditForm extends Component {
|
||||
)}
|
||||
|
||||
</FormItem>
|
||||
{this.props.form.getFieldValue('req_body_type') === 'form' ?
|
||||
<Row className="interface-edit-item">
|
||||
<Col span={18} offset={4} style={{ minHeight: "50px" }}>
|
||||
<Row>
|
||||
<Col span="24" className="interface-edit-item">
|
||||
|
||||
<Button size="small" type="primary" onClick={() => this.addParams('req_body_form')}>添加form参数</Button>
|
||||
<Row className="interface-edit-item" style={{ display: this.props.form.getFieldValue('req_body_type') === 'form' ? 'block' : 'none' }}>
|
||||
<Col span={18} offset={4} style={{ minHeight: "50px" }}>
|
||||
<Row>
|
||||
<Col span="24" className="interface-edit-item">
|
||||
|
||||
</Col>
|
||||
<Button size="small" type="primary" onClick={() => this.addParams('req_body_form')}>添加form参数</Button>
|
||||
|
||||
</Col>
|
||||
|
||||
</Row>
|
||||
{requestBodyList}
|
||||
</Col>
|
||||
|
||||
</Row>
|
||||
|
||||
</Row>
|
||||
{requestBodyList}
|
||||
</Col>
|
||||
|
||||
</Row>
|
||||
:
|
||||
null
|
||||
}
|
||||
</div>
|
||||
: null}
|
||||
|
||||
@ -621,9 +620,9 @@ class InterfaceEditForm extends Component {
|
||||
|
||||
</Tabs>
|
||||
<div>
|
||||
<h3 style={{padding: '10px 0'}}>基于mockjs和json5,可直接写mock模板和注释,具体使用方法请查看文档</h3>
|
||||
<div id="res_body_json" style={{ minHeight: "300px", display: this.state.jsonType === 'tpl'? 'block': 'none' }} ></div>
|
||||
<div id="mock-preview" style={{ backgroundColor: "#eee", lineHeight: "20px", minHeight: "300px", display: this.state.jsonType === 'preview'? 'block': 'none' }}></div>
|
||||
<h3 style={{ padding: '10px 0' }}>基于mockjs和json5,可直接写mock模板和注释,具体使用方法请查看文档</h3>
|
||||
<div id="res_body_json" style={{ minHeight: "300px", display: this.state.jsonType === 'tpl' ? 'block' : 'none' }} ></div>
|
||||
<div id="mock-preview" style={{ backgroundColor: "#eee", lineHeight: "20px", minHeight: "300px", display: this.state.jsonType === 'preview' ? 'block' : 'none' }}></div>
|
||||
</div>
|
||||
|
||||
</Col>
|
||||
@ -639,21 +638,16 @@ class InterfaceEditForm extends Component {
|
||||
|
||||
</Row>
|
||||
|
||||
|
||||
<FormItem
|
||||
className="interface-edit-item"
|
||||
{...formItemLayout}
|
||||
label="备注"
|
||||
>
|
||||
<div id="desc" ></div>
|
||||
{/* {getFieldDecorator('desc', { initialValue: this.state.desc })(
|
||||
<Input.TextArea style={{minHeight: '200px'}} placeholder="接口备注信息" />
|
||||
)} */}
|
||||
<div >
|
||||
<div id="desc" ></div>
|
||||
</div>
|
||||
</FormItem>
|
||||
|
||||
|
||||
|
||||
|
||||
<FormItem
|
||||
className="interface-edit-item"
|
||||
{...formItemLayout}
|
||||
|
@ -9,7 +9,8 @@ import { getProject } from '../../reducer/modules/project';
|
||||
import Interface from './Interface/Interface.js'
|
||||
import Activity from './Activity/Activity.js'
|
||||
import Setting from './Setting/Setting.js'
|
||||
|
||||
import ProjectMember from './Setting/ProjectMember/ProjectMember.js';
|
||||
import ProjectData from './Setting/ProjectData/ProjectData.js';
|
||||
|
||||
@connect(
|
||||
state => {
|
||||
@ -55,7 +56,9 @@ export default class Project extends Component {
|
||||
const routers = {
|
||||
activity: { name: '动态', path: "/project/:id/activity" },
|
||||
interface: { name: '接口', path: "/project/:id/interface/:action" },
|
||||
setting: { name: '设置', path: "/project/:id/setting" }
|
||||
setting: { name: '设置', path: "/project/:id/setting" },
|
||||
members: { name: '成员管理', path: "/project/:id/members" },
|
||||
data: { name: '数据管理', path: "/project/:id/data" }
|
||||
}
|
||||
|
||||
let key, defaultName;
|
||||
@ -81,12 +84,20 @@ export default class Project extends Component {
|
||||
}, {
|
||||
name: routers.activity.name,
|
||||
path: `/project/${match.params.id}/activity`
|
||||
}, {
|
||||
name: routers.members.name,
|
||||
path: `/project/${match.params.id}/members`
|
||||
}, {
|
||||
name: routers.data.name,
|
||||
path: `/project/${match.params.id}/data`
|
||||
}]} />
|
||||
<Switch>
|
||||
<Redirect exact from="/project/:id" to={`/project/${match.params.id}/interface/api`} />
|
||||
<Route path={routers.activity.path} component={Activity} />
|
||||
<Route path={routers.interface.path} component={Interface} />
|
||||
<Route path={routers.setting.path} component={Setting} />
|
||||
<Route path={routers.members.path} component={ProjectMember} />
|
||||
<Route path={routers.data.path} component={ProjectData} />
|
||||
</Switch>
|
||||
</div>
|
||||
)
|
||||
|
@ -7,6 +7,10 @@ import axios from 'axios';
|
||||
const Dragger = Upload.Dragger;
|
||||
const Option = Select.Option;
|
||||
|
||||
const plugin = require('client/plugin.js');
|
||||
|
||||
let importDataModule = {};
|
||||
|
||||
@connect(
|
||||
state=>{
|
||||
// console.log(state);
|
||||
@ -24,23 +28,24 @@ class ProjectData extends Component {
|
||||
super(props);
|
||||
this.state = {
|
||||
selectCatid:"",
|
||||
menuList:[]
|
||||
menuList:[],
|
||||
curImportType: null
|
||||
}
|
||||
}
|
||||
static propTypes = {
|
||||
match: PropTypes.object,
|
||||
projectId: PropTypes.number,
|
||||
curCatid: PropTypes.number,
|
||||
basePath: PropTypes.string
|
||||
}
|
||||
|
||||
componentWillMount(){
|
||||
axios.get(`/api/interface/getCatMenu?project_id=${this.props.projectId}`).then((data)=>{
|
||||
axios.get(`/api/interface/getCatMenu?project_id=${this.props.match.params.id}`).then((data)=>{
|
||||
let menuList = data.data.data;
|
||||
this.setState({
|
||||
menuList: menuList
|
||||
})
|
||||
});
|
||||
plugin.emitHook('import_data', importDataModule, this.props);
|
||||
}
|
||||
selectChange(value){
|
||||
this.setState({
|
||||
@ -48,149 +53,7 @@ class ProjectData extends Component {
|
||||
})
|
||||
}
|
||||
|
||||
parseUrl(url){
|
||||
let parser = document.createElement('a');
|
||||
parser.href = url;
|
||||
return {
|
||||
protocol: parser.protocol,
|
||||
hostname: parser.hostname,
|
||||
port: parser.port,
|
||||
pathname: parser.pathname,
|
||||
search: parser.search,
|
||||
host: parser.host
|
||||
}
|
||||
}
|
||||
|
||||
checkInterRepeat(interData){
|
||||
let obj = {};
|
||||
let arr = [];
|
||||
for(let item in interData){
|
||||
// console.log(interData[item].url + "-" + interData[item].method);
|
||||
if(!obj[interData[item].url + "-" + interData[item].method+ "-"+interData[item].method]){
|
||||
arr.push(interData[item]);
|
||||
obj[interData[item].url + "-" + interData[item].method+ "-"+interData[item].method] = true;
|
||||
}
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
handleReq_query(query){
|
||||
let res = [];
|
||||
if(query&&query.length){
|
||||
for(let item in query){
|
||||
res.push({
|
||||
name: query[item].key,
|
||||
desc: query[item].description,
|
||||
required: query[item].enable
|
||||
});
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
handleReq_headers(headers){
|
||||
let res = [];
|
||||
if(headers&&headers.length){
|
||||
for(let item in headers){
|
||||
res.push({
|
||||
name: headers[item].key,
|
||||
desc: headers[item].description,
|
||||
value: headers[item].value,
|
||||
required: headers[item].enable
|
||||
});
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
handleReq_body_form(body_form){
|
||||
let res = [];
|
||||
if(body_form&&body_form.length){
|
||||
for(let item in body_form){
|
||||
res.push({
|
||||
name: body_form[item].key,
|
||||
value: body_form[item].value,
|
||||
type: body_form[item].type
|
||||
});
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
handlePath(path){
|
||||
path = path.replace(/{{(\w*)}}/,"");
|
||||
path = this.parseUrl(path).pathname;
|
||||
if(path.indexOf(this.props.basePath)>-1){
|
||||
path = path.substr(this.props.basePath.length);
|
||||
}
|
||||
if(path.charAt(0) != "/"){
|
||||
path = "/" + path;
|
||||
}
|
||||
if(path.charAt(path.length-1) === "/"){
|
||||
path = path.substr(0,path.length-1);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
importPostman(data,key){
|
||||
let reflect = {//数据字段映射关系
|
||||
title: "name",
|
||||
path: "url",
|
||||
method: "method",
|
||||
desc: "description",
|
||||
req_query: "queryParams",
|
||||
req_headers: "headerData",
|
||||
req_params: "",
|
||||
req_body_type: "dataMode",
|
||||
req_body_form: "data",
|
||||
req_body_other: "rawModeData"
|
||||
};
|
||||
let allKey = ["title","path","method","desc","req_query","req_headers","req_body_type","req_body_form","req_body_other"];
|
||||
key = key || allKey;
|
||||
let res = {};
|
||||
for(let item in key){
|
||||
item = key[item];
|
||||
if(item === "req_query"){
|
||||
res[item] = this.handleReq_query.bind(this)(data[reflect[item]]);
|
||||
}else if(item === "req_headers"){
|
||||
res[item] = this.handleReq_headers.bind(this)(data[reflect[item]]);
|
||||
}else if(item === "req_body_form"){
|
||||
res[item] = this.handleReq_body_form.bind(this)(data[reflect[item]]);
|
||||
}else if(item === "req_body_type"){
|
||||
if(data.headers.indexOf('application/json')>-1){
|
||||
res[item] = "json";
|
||||
}else{
|
||||
res[item] = "raw";
|
||||
}
|
||||
}else if(item === "path"){
|
||||
res[item] = this.handlePath.bind(this)(data[reflect[item]]);
|
||||
if(res[item] && res[item].indexOf("/:") > -1){
|
||||
let params = res[item].substr(res[item].indexOf("/:")+2).split("/:");
|
||||
// res[item] = res[item].substr(0,res[item].indexOf("/:"));
|
||||
let arr = [];
|
||||
for(let i in params){
|
||||
arr.push({
|
||||
name: params[i],
|
||||
desc: ""
|
||||
});
|
||||
}
|
||||
res["req_params"] = arr;
|
||||
}
|
||||
}else if(item === "title"){
|
||||
let path = this.handlePath.bind(this)(data[reflect["path"]]);
|
||||
if(data[reflect[item]].indexOf(path) > -1){
|
||||
res[item] = path;
|
||||
if(res[item] && res[item].indexOf("/:") > -1){
|
||||
res[item] = res[item].substr(0,res[item].indexOf("/:"));
|
||||
}
|
||||
}else{
|
||||
res[item] = data[reflect[item]];
|
||||
}
|
||||
}else{
|
||||
res[item] = data[reflect[item]];
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
uploadChnange(info){
|
||||
const status = info.file.status;
|
||||
@ -206,53 +69,46 @@ class ProjectData extends Component {
|
||||
|
||||
handleAddInterface(info){
|
||||
if(this.state.selectCatid){
|
||||
let filename = info.file.name;
|
||||
let filetype = filename.substr(filename.lastIndexOf(".")).toLowerCase();
|
||||
// let filename = info.file.name;
|
||||
// let filetype = filename.substr(filename.lastIndexOf(".")).toLowerCase();
|
||||
// console.log(filename,filetype);
|
||||
if(filetype != ".json") return message.error("文件格式只能为json");
|
||||
//if(filetype != ".json") return message.error("文件格式只能为json");
|
||||
let reader = new FileReader();
|
||||
reader.readAsText(info.file);
|
||||
reader.onload = (res)=>{
|
||||
|
||||
res = res.target.result;
|
||||
try{
|
||||
res = JSON.parse(res);
|
||||
let interData = res.requests;
|
||||
interData = this.checkInterRepeat.bind(this)(interData);
|
||||
|
||||
if(interData && interData.length){
|
||||
let len = interData.length;
|
||||
let count = 0;
|
||||
let successNum = len;
|
||||
for(let item in interData){
|
||||
let data = this.importPostman.bind(this)(interData[item]);
|
||||
data = {
|
||||
...data,
|
||||
project_id: this.props.projectId,
|
||||
catid: this.state.selectCatid
|
||||
}
|
||||
axios.post('/api/interface/add',data).then((res)=>{
|
||||
count++;
|
||||
if(res.data.errcode){
|
||||
successNum--;
|
||||
}
|
||||
if(count === len){
|
||||
message.success(`成功导入接口 ${successNum} 个`);
|
||||
}
|
||||
});
|
||||
}
|
||||
res = importDataModule[this.state.curImportType].run(res.target.result);
|
||||
res = res.apis;
|
||||
let len = res.length;
|
||||
let count = 0;
|
||||
let successNum = len;
|
||||
res.forEach(async (item)=>{
|
||||
let data = {
|
||||
...item,
|
||||
project_id: this.props.match.params.id,
|
||||
catid: this.state.selectCatid
|
||||
}
|
||||
|
||||
}catch(e){
|
||||
message.error("文件格式必须为JSON");
|
||||
}
|
||||
|
||||
let result = await axios.post('/api/interface/add',data);
|
||||
count++;
|
||||
if(result.data.errcode){
|
||||
successNum--;
|
||||
}
|
||||
if(count === len){
|
||||
message.success(`成功导入接口 ${successNum} 个`);
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
}else{
|
||||
message.error("请选择上传的分类");
|
||||
}
|
||||
}
|
||||
|
||||
handleImportType=(val) =>{
|
||||
this.setState({
|
||||
curImportType: val
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
@ -269,11 +125,19 @@ class ProjectData extends Component {
|
||||
onChange: this.uploadChnange.bind(this)
|
||||
}
|
||||
return (
|
||||
<div className="m-panel">
|
||||
<div className="m-panel g-row" style={{paddingTop: '15px'}}>
|
||||
<div className="postman-dataImport">
|
||||
|
||||
<h2>数据导入</h2>
|
||||
<div className="dataImportCon">
|
||||
<h3 className="dataImportTile">Postman 数据导入</h3>
|
||||
<div className="dataImportTile">
|
||||
<Select placeholder="请选择导入数据的方式" onChange={this.handleImportType}>
|
||||
{Object.keys(importDataModule).map((name)=>{
|
||||
return <Option key={name} value={name}>{importDataModule[name].name}</Option>
|
||||
})}
|
||||
|
||||
|
||||
</Select>
|
||||
</div>
|
||||
<div className="catidSelect">
|
||||
<Select
|
||||
showSearch
|
||||
@ -295,7 +159,7 @@ class ProjectData extends Component {
|
||||
<Icon type="inbox" />
|
||||
</p>
|
||||
<p className="ant-upload-text">点击或者拖拽文件到上传区域</p>
|
||||
<p className="ant-upload-hint">注意:只支持json格式数据</p>
|
||||
<p className="ant-upload-hint">{this.state.curImportType?importDataModule[this.state.curImportType].desc: null}</p>
|
||||
</Dragger>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -11,5 +11,9 @@
|
||||
color: #2395f1;
|
||||
padding: 16px 0px;
|
||||
font-weight: 500;
|
||||
width: 100%;
|
||||
.ant-select{
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ import { fetchGroupMsg } from '../../../../reducer/modules/group';
|
||||
import { connect } from 'react-redux';
|
||||
import ErrMsg from '../../../../components/ErrMsg/ErrMsg.js';
|
||||
import { fetchGroupMemberList } from '../../../../reducer/modules/group.js';
|
||||
import { getProjectMsg, getProjectMemberList, addMember, delMember, changeMemberRole } from '../../../../reducer/modules/project.js';
|
||||
import { getProjectMsg, getProjectMemberList,getProject, addMember, delMember, changeMemberRole } from '../../../../reducer/modules/project.js';
|
||||
import UsernameAutoComplete from '../../../../components/UsernameAutoComplete/UsernameAutoComplete.js';
|
||||
import '../Setting.scss';
|
||||
|
||||
@ -24,7 +24,7 @@ const arrayAddKey = (arr) => {
|
||||
@connect(
|
||||
state => {
|
||||
return {
|
||||
projectMsg: state.project.projectMsg,
|
||||
projectMsg: state.project.currProject,
|
||||
uid: state.user.uid
|
||||
}
|
||||
},
|
||||
@ -35,7 +35,8 @@ const arrayAddKey = (arr) => {
|
||||
addMember,
|
||||
delMember,
|
||||
fetchGroupMsg,
|
||||
changeMemberRole
|
||||
changeMemberRole,
|
||||
getProject
|
||||
}
|
||||
)
|
||||
class ProjectMember extends Component {
|
||||
@ -49,16 +50,18 @@ class ProjectMember extends Component {
|
||||
visible: false,
|
||||
dataSource: [],
|
||||
inputUid: 0,
|
||||
inputRole: 'dev'
|
||||
inputRole: 'dev'
|
||||
}
|
||||
}
|
||||
static propTypes = {
|
||||
match: PropTypes.object,
|
||||
projectId: PropTypes.number,
|
||||
projectMsg: PropTypes.object,
|
||||
uid: PropTypes.number,
|
||||
addMember: PropTypes.func,
|
||||
delMember: PropTypes.func,
|
||||
changeMemberRole: PropTypes.func,
|
||||
getProject: PropTypes.func,
|
||||
fetchGroupMemberList: PropTypes.func,
|
||||
getProjectMsg: PropTypes.func,
|
||||
fetchGroupMsg: PropTypes.func,
|
||||
@ -74,7 +77,7 @@ class ProjectMember extends Component {
|
||||
// 重新获取列表
|
||||
@autobind
|
||||
reFetchList() {
|
||||
this.props.getProjectMemberList(this.props.projectId).then((res) => {
|
||||
this.props.getProjectMemberList(this.props.match.params.id).then((res) => {
|
||||
this.setState({
|
||||
projectMemberList: arrayAddKey(res.payload.data.data),
|
||||
visible: false
|
||||
@ -86,7 +89,7 @@ class ProjectMember extends Component {
|
||||
@autobind
|
||||
handleOk() {
|
||||
this.props.addMember({
|
||||
id: this.props.projectId,
|
||||
id: this.props.match.params.id,
|
||||
member_uid: this.state.inputUid,
|
||||
role: this.state.inputRole
|
||||
}).then((res) => {
|
||||
@ -108,7 +111,7 @@ class ProjectMember extends Component {
|
||||
@autobind
|
||||
deleteConfirm(member_uid) {
|
||||
return () => {
|
||||
const id = this.props.projectId;
|
||||
const id = this.props.match.params.id;
|
||||
this.props.delMember({ id, member_uid }).then((res) => {
|
||||
if (!res.payload.data.errcode) {
|
||||
message.success(res.payload.data.errmsg);
|
||||
@ -121,7 +124,7 @@ class ProjectMember extends Component {
|
||||
// 改 - 修改成员权限
|
||||
@autobind
|
||||
changeUserRole(e) {
|
||||
const id = this.props.projectId;
|
||||
const id = this.props.match.params.id;
|
||||
const role = e.split('-')[0];
|
||||
const member_uid = e.split('-')[1];
|
||||
this.props.changeMemberRole({ id, member_uid, role }).then((res) => {
|
||||
@ -147,11 +150,12 @@ class ProjectMember extends Component {
|
||||
})
|
||||
}
|
||||
|
||||
async componentWillMount() {
|
||||
async componentWillMount() {
|
||||
await this.props.getProject(this.props.match.params.id)
|
||||
const groupMemberList = await this.props.fetchGroupMemberList(this.props.projectMsg.group_id);
|
||||
const groupMsg = await this.props.fetchGroupMsg(this.props.projectMsg.group_id);
|
||||
const rojectMsg = await this.props.getProjectMsg(this.props.projectId);
|
||||
const projectMemberList = await this.props.getProjectMemberList(this.props.projectId);
|
||||
const rojectMsg = await this.props.getProjectMsg(this.props.match.params.id);
|
||||
const projectMemberList = await this.props.getProjectMemberList(this.props.match.params.id);
|
||||
this.setState({
|
||||
groupMemberList: groupMemberList.payload.data.data,
|
||||
groupName: groupMsg.payload.data.data.group_name,
|
||||
@ -201,7 +205,7 @@ class ProjectMember extends Component {
|
||||
}
|
||||
}];
|
||||
return (
|
||||
<div className="m-panel">
|
||||
<div className="m-panel g-row" style={{paddingTop: '15px'}}>
|
||||
<Modal
|
||||
title="添加成员"
|
||||
visible={this.state.visible}
|
||||
|
@ -3,8 +3,7 @@ import { Tabs } from 'antd';
|
||||
import PropTypes from 'prop-types';
|
||||
const TabPane = Tabs.TabPane;
|
||||
import ProjectMessage from './ProjectMessage/ProjectMessage.js';
|
||||
import ProjectMember from './ProjectMember/ProjectMember.js';
|
||||
import ProjectData from './ProjectData/ProjectData.js';
|
||||
|
||||
import './Setting.scss';
|
||||
|
||||
class Setting extends Component {
|
||||
@ -17,8 +16,7 @@ class Setting extends Component {
|
||||
<div className="g-row">
|
||||
<Tabs type="card" className="m-tab">
|
||||
<TabPane tab="项目信息" key="1"><ProjectMessage projectId={+id}/></TabPane>
|
||||
<TabPane tab="成员列表" key="2"><ProjectMember projectId={+id}/></TabPane>
|
||||
<TabPane tab="数据管理" key="3"><ProjectData projectId={+id}/></TabPane>
|
||||
|
||||
</Tabs>
|
||||
</div>
|
||||
)
|
||||
|
@ -1,28 +1,47 @@
|
||||
const config = process.env.config;
|
||||
let hooks, pluginModule, systemPlugins;
|
||||
|
||||
/**
|
||||
* type single 只绑定一个监听函数,会返回处理结果
|
||||
* mulit 绑定多个监听函数
|
||||
* type component 组件
|
||||
* listener 监听函数
|
||||
* mulit 是否绑定多个监听函数
|
||||
*
|
||||
*/
|
||||
|
||||
var hooks = {
|
||||
hooks = {
|
||||
'third_login': {
|
||||
type: 'single',
|
||||
type: 'component',
|
||||
mulit: false,
|
||||
listener: null
|
||||
},
|
||||
'add_interface': {
|
||||
type: 'mulit',
|
||||
type: 'listener',
|
||||
mulit: true,
|
||||
listener: []
|
||||
},
|
||||
import_data: {
|
||||
type: 'listener',
|
||||
mulit: true,
|
||||
listener: []
|
||||
}
|
||||
};
|
||||
|
||||
pluginModule = {
|
||||
hooks: hooks,
|
||||
bindHook: bindHook,
|
||||
emitHook: emitHook
|
||||
}
|
||||
|
||||
systemPlugins = ['postman']
|
||||
|
||||
config.plugins = config.plugins && Array.isArray(config.plugins) ? config.plugins: [];
|
||||
|
||||
function bindHook(name, listener) {
|
||||
if (!name) throw new Error('缺少hookname');
|
||||
if (name in hooks === false) {
|
||||
throw new Error('不存在的hookname');
|
||||
}
|
||||
if (hooks[name].type === 'multi') {
|
||||
if (hooks[name].mulit === true) {
|
||||
hooks[name].listener.push(listener);
|
||||
} else {
|
||||
hooks[name].listener = listener;
|
||||
@ -30,16 +49,39 @@ function bindHook(name, listener) {
|
||||
|
||||
}
|
||||
|
||||
var yapi = {
|
||||
hooks: hooks,
|
||||
bindHook: bindHook
|
||||
function emitHook(name, ...args){
|
||||
if(!hooks[name]) throw new Error('不存在的hook name');
|
||||
let hook = hooks[name];
|
||||
if(hook.mulit === true && hook.type === 'listener'){
|
||||
if(Array.isArray(hook.listener)){
|
||||
hook.listener.forEach(item=>{
|
||||
if(typeof item === 'function'){
|
||||
item.call(pluginModule, ...args)
|
||||
}
|
||||
})
|
||||
}
|
||||
}else if(hook.mulit === false && hook.type === 'listener'){
|
||||
if(typeof hook.listener === 'function'){
|
||||
hook.listener.call(pluginModule, ...args);
|
||||
}
|
||||
}else if( hook.type === 'component'){
|
||||
return hook.listener;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (config.plugins && Array.isArray(config.plugins)) {
|
||||
config.plugins.forEach(plugin => {
|
||||
let pluginModule = require(`plugins/yapi-plugin-${plugin}/client.js`);
|
||||
pluginModule.call(yapi) ;
|
||||
let p = require(`plugins/yapi-plugin-${plugin}/client.js`);
|
||||
p.call(pluginModule) ;
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = hooks;
|
||||
systemPlugins.forEach(plugin => {
|
||||
let p = require(`exts/yapi-plugin-${plugin}/client.js`);
|
||||
p.call(pluginModule) ;
|
||||
})
|
||||
|
||||
module.exports = pluginModule;
|
185
exts/yapi-plugin-postman/client.js
Normal file
185
exts/yapi-plugin-postman/client.js
Normal file
@ -0,0 +1,185 @@
|
||||
|
||||
import {message} from 'antd'
|
||||
|
||||
function postman(obj){
|
||||
|
||||
function parseUrl(url){
|
||||
let parser = document.createElement('a');
|
||||
parser.href = url;
|
||||
return {
|
||||
protocol: parser.protocol,
|
||||
hostname: parser.hostname,
|
||||
port: parser.port,
|
||||
pathname: parser.pathname,
|
||||
search: parser.search,
|
||||
host: parser.host
|
||||
}
|
||||
}
|
||||
|
||||
function checkInterRepeat(interData){
|
||||
let obj = {};
|
||||
let arr = [];
|
||||
for(let item in interData){
|
||||
// console.log(interData[item].url + "-" + interData[item].method);
|
||||
if(!obj[interData[item].url + "-" + interData[item].method+ "-"+interData[item].method]){
|
||||
arr.push(interData[item]);
|
||||
obj[interData[item].url + "-" + interData[item].method+ "-"+interData[item].method] = true;
|
||||
}
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
function handleReq_query(query){
|
||||
let res = [];
|
||||
if(query&&query.length){
|
||||
for(let item in query){
|
||||
res.push({
|
||||
name: query[item].key,
|
||||
desc: query[item].description,
|
||||
required: query[item].enable
|
||||
});
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
function handleReq_headers(headers){
|
||||
let res = [];
|
||||
if(headers&&headers.length){
|
||||
for(let item in headers){
|
||||
res.push({
|
||||
name: headers[item].key,
|
||||
desc: headers[item].description,
|
||||
value: headers[item].value,
|
||||
required: headers[item].enable
|
||||
});
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
function handleReq_body_form(body_form){
|
||||
let res = [];
|
||||
if(body_form&&body_form.length){
|
||||
for(let item in body_form){
|
||||
res.push({
|
||||
name: body_form[item].key,
|
||||
value: body_form[item].value,
|
||||
type: body_form[item].type
|
||||
});
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
function handlePath(path){
|
||||
path = path.replace(/{{(\w*)}}/,"");
|
||||
path = parseUrl(path).pathname;
|
||||
if(path.charAt(0) != "/"){
|
||||
path = "/" + path;
|
||||
}
|
||||
if(path.charAt(path.length-1) === "/"){
|
||||
path = path.substr(0,path.length-1);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
function run(res){
|
||||
try{
|
||||
res = JSON.parse(res);
|
||||
let interData = res.requests;
|
||||
let interfaceData = {apis: []};
|
||||
interData = checkInterRepeat.bind(this)(interData);
|
||||
if(interData && interData.length){
|
||||
for(let item in interData){
|
||||
let data = importPostman.bind(this)(interData[item]);
|
||||
interfaceData.apis.push(data);
|
||||
}
|
||||
}
|
||||
return interfaceData;
|
||||
|
||||
}catch(e){
|
||||
message.error("文件格式必须为JSON");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function importPostman(data,key){
|
||||
let reflect = {//数据字段映射关系
|
||||
title: "name",
|
||||
path: "url",
|
||||
method: "method",
|
||||
desc: "description",
|
||||
req_query: "queryParams",
|
||||
req_headers: "headerData",
|
||||
req_params: "",
|
||||
req_body_type: "dataMode",
|
||||
req_body_form: "data",
|
||||
req_body_other: "rawModeData"
|
||||
};
|
||||
let allKey = ["title","path","method","desc","req_query","req_headers","req_body_type","req_body_form","req_body_other"];
|
||||
key = key || allKey;
|
||||
let res = {};
|
||||
for(let item in key){
|
||||
item = key[item];
|
||||
if(item === "req_query"){
|
||||
res[item] = handleReq_query.bind(this)(data[reflect[item]]);
|
||||
}else if(item === "req_headers"){
|
||||
res[item] = handleReq_headers.bind(this)(data[reflect[item]]);
|
||||
}else if(item === "req_body_form"){
|
||||
res[item] = handleReq_body_form.bind(this)(data[reflect[item]]);
|
||||
}else if(item === "req_body_type"){
|
||||
if(data.headers.indexOf('application/json')>-1){
|
||||
res[item] = "json";
|
||||
}else{
|
||||
res[item] = "raw";
|
||||
}
|
||||
}else if(item === "path"){
|
||||
res[item] = handlePath.bind(this)(data[reflect[item]]);
|
||||
if(res[item] && res[item].indexOf("/:") > -1){
|
||||
let params = res[item].substr(res[item].indexOf("/:")+2).split("/:");
|
||||
// res[item] = res[item].substr(0,res[item].indexOf("/:"));
|
||||
let arr = [];
|
||||
for(let i in params){
|
||||
arr.push({
|
||||
name: params[i],
|
||||
desc: ""
|
||||
});
|
||||
}
|
||||
res["req_params"] = arr;
|
||||
}
|
||||
}else if(item === "title"){
|
||||
let path = handlePath.bind(this)(data[reflect["path"]]);
|
||||
if(data[reflect[item]].indexOf(path) > -1){
|
||||
res[item] = path;
|
||||
if(res[item] && res[item].indexOf("/:") > -1){
|
||||
res[item] = res[item].substr(0,res[item].indexOf("/:"));
|
||||
}
|
||||
}else{
|
||||
res[item] = data[reflect[item]];
|
||||
}
|
||||
}else{
|
||||
res[item] = data[reflect[item]];
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
if(!obj || typeof obj !== 'object'){
|
||||
console.error('obj参数必需是一个对象');
|
||||
return null;
|
||||
}
|
||||
|
||||
obj.postman = {
|
||||
name: 'Postman',
|
||||
run: run,
|
||||
desc: '注意:只支持json格式数据'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
module.exports = function(){
|
||||
|
||||
|
||||
this.bindHook('import_data', postman)
|
||||
}
|
@ -286,8 +286,8 @@ class groupController extends baseController {
|
||||
if(result && result.length > 0){
|
||||
for(let i=0; i< result.length; i++){
|
||||
result[i] = result[i].toObject();
|
||||
result[i].role = await this.checkAuth(result[i]._id, 'group', 'edit');
|
||||
if(result[i].role){
|
||||
result[i].role = await this.getProjectRole(result[i]._id, 'group');
|
||||
if(result[i].role !== 'member'){
|
||||
newResult.unshift(result[i]);
|
||||
}else{
|
||||
newResult.push(result[i]);
|
||||
|
@ -59,6 +59,14 @@ class interfaceController extends baseController {
|
||||
catid: 'number'
|
||||
});
|
||||
|
||||
if (!params.project_id) {
|
||||
return ctx.body = yapi.commons.resReturn(null, 400, '项目id不能为空');
|
||||
}
|
||||
|
||||
if (!params.path) {
|
||||
return ctx.body = yapi.commons.resReturn(null, 400, '接口请求路径不能为空');
|
||||
}
|
||||
|
||||
let auth = await this.checkAuth(params.project_id, 'project', 'edit')
|
||||
if (!auth) {
|
||||
return ctx.body = yapi.commons.resReturn(null, 400, '没有权限');
|
||||
@ -68,13 +76,7 @@ class interfaceController extends baseController {
|
||||
params.req_params = params.req_params || [];
|
||||
params.res_body_type = params.res_body_type ? params.res_body_type.toLowerCase() : 'json';
|
||||
|
||||
if (!params.project_id) {
|
||||
return ctx.body = yapi.commons.resReturn(null, 400, '项目id不能为空');
|
||||
}
|
||||
|
||||
if (!params.path) {
|
||||
return ctx.body = yapi.commons.resReturn(null, 400, '接口请求路径不能为空');
|
||||
}
|
||||
|
||||
|
||||
let http_path = url.parse(params.path, true);
|
||||
params.path = http_path.pathname;
|
||||
@ -654,28 +656,30 @@ class interfaceController extends baseController {
|
||||
|
||||
|
||||
/**
|
||||
* 获取分类列表
|
||||
* @interface /interface/getCatMenu
|
||||
* @method GET
|
||||
* @category interface
|
||||
* @foldnumber 10
|
||||
* @param {Number} project_id 项目id,不能为空
|
||||
* @returns {Object}
|
||||
* @example ./api/interface/getCatMenu
|
||||
*/
|
||||
* 获取分类列表
|
||||
* @interface /interface/getCatMenu
|
||||
* @method GET
|
||||
* @category interface
|
||||
* @foldnumber 10
|
||||
* @param {Number} project_id 项目id,不能为空
|
||||
* @returns {Object}
|
||||
* @example ./api/interface/getCatMenu
|
||||
*/
|
||||
|
||||
async getCatMenu(ctx) {
|
||||
let project_id = ctx.request.query.project_id;
|
||||
if (!project_id) {
|
||||
|
||||
if (!project_id || isNaN(project_id)) {
|
||||
return ctx.body = yapi.commons.resReturn(null, 400, '项目id不能为空');
|
||||
}
|
||||
let project = await this.projectModel.getBaseInfo(project_id);
|
||||
if (project.project_type === 'private') {
|
||||
if (await this.checkAuth(project._id, 'project', 'edit') !== true) {
|
||||
return ctx.body = yapi.commons.resReturn(null, 406, '没有权限');
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
let project = await this.projectModel.getBaseInfo(project_id);
|
||||
if (project.project_type === 'private') {
|
||||
if (await this.checkAuth(project._id, 'project', 'edit') !== true) {
|
||||
return ctx.body = yapi.commons.resReturn(null, 406, '没有权限');
|
||||
}
|
||||
}
|
||||
let res = await this.catModel.list(project_id);
|
||||
return ctx.body = yapi.commons.resReturn(res);
|
||||
} catch (e) {
|
||||
|
@ -360,11 +360,11 @@ class projectController extends baseController {
|
||||
})
|
||||
if (f) {
|
||||
item.follow = true;
|
||||
project_list.unshift(item);
|
||||
} else {
|
||||
item.follow = false;
|
||||
project_list.push(item);
|
||||
}
|
||||
project_list.push(item);
|
||||
|
||||
};
|
||||
|
||||
ctx.body = yapi.commons.resReturn({
|
||||
|
2
ykit.js
2
ykit.js
@ -103,8 +103,10 @@ module.exports = {
|
||||
//初始化配置
|
||||
baseConfig.devtool = 'cheap-module-eval-source-map'
|
||||
baseConfig.context = path.resolve(__dirname, './client');
|
||||
baseConfig.resolve.alias.client = '/client';
|
||||
baseConfig.resolve.alias.common = '/common';
|
||||
baseConfig.resolve.alias.plugins = '/plugins';
|
||||
baseConfig.resolve.alias.exts = '/exts';
|
||||
baseConfig.output.prd.path = 'static/prd';
|
||||
baseConfig.output.prd.publicPath = '';
|
||||
baseConfig.output.prd.filename = '[name]@[chunkhash][ext]'
|
||||
|
Loading…
Reference in New Issue
Block a user