mirror of
https://github.com/YMFE/yapi.git
synced 2025-02-11 13:40:32 +08:00
Merge branch 'dev' of gitlab.corp.qunar.com:mfe/yapi into dev
This commit is contained in:
commit
49e2e5c5b3
@ -40,4 +40,5 @@ module.exports = {
|
|||||||
"strict": 0,
|
"strict": 0,
|
||||||
"comma-dangle": ["error", "never"]
|
"comma-dangle": ["error", "never"]
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
"/fekit_modules/*",
|
"/fekit_modules/*",
|
||||||
"/node_modules/*",
|
"/node_modules/*",
|
||||||
"/bower_components/*",
|
"/bower_components/*",
|
||||||
|
"/plugins/*",
|
||||||
"/dev/*",
|
"/dev/*",
|
||||||
"/prd/*"
|
"/prd/*"
|
||||||
]
|
]
|
||||||
|
@ -65,6 +65,7 @@ export default class App extends Component {
|
|||||||
<Footer />
|
<Footer />
|
||||||
</div>
|
</div>
|
||||||
</Router>
|
</Router>
|
||||||
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
return r;
|
return r;
|
||||||
|
@ -3,6 +3,7 @@ import React, { Component } from 'react'
|
|||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import { Row, Col } from 'antd';
|
import { Row, Col } from 'antd';
|
||||||
import { Icon } from 'antd'
|
import { Icon } from 'antd'
|
||||||
|
import packageJson from '../../../package.json';
|
||||||
class Footer extends Component {
|
class Footer extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props)
|
super(props)
|
||||||
@ -100,7 +101,7 @@ Footer.defaultProps = {
|
|||||||
iconType: 'layout',
|
iconType: 'layout',
|
||||||
linkList: [
|
linkList: [
|
||||||
{
|
{
|
||||||
itemTitle: '版本: 1.0',
|
itemTitle: '版本: '+packageJson.version,
|
||||||
itemLink: 'javascript:'
|
itemLink: 'javascript:'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -1,64 +0,0 @@
|
|||||||
// file_id:2D7ABF69-3BC0-4175-98C9-5C3D5CB00158 -- nerver change this !!
|
|
||||||
|
|
||||||
/*
|
|
||||||
* file: qsso-auth.js
|
|
||||||
* URL: https://qsso.corp.qunar.com/lib/qsso-auth.js
|
|
||||||
* written by zhibin.ning
|
|
||||||
* version: 0.1
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var AUTH_SERVER = 'https://qsso.corp.qunar.com',
|
|
||||||
LOGIN_PAGE = '/login.php',
|
|
||||||
SORRY_PAGE = '/sorry.html';
|
|
||||||
|
|
||||||
if (location.hostname.match(/qunar\.ctripgroup\.com$/i)) {
|
|
||||||
AUTH_SERVER = 'https://qunar.ctripgroup.com/sec/qsso/api';
|
|
||||||
}
|
|
||||||
|
|
||||||
var qualifyURL = function (url, encode) {
|
|
||||||
url = url || '';
|
|
||||||
var ret = location.protocol + '//' + location.host + (url.substr(0, 1) === '/' ? '' : location.pathname.match(/.*\//)) + url;
|
|
||||||
if (encode) {
|
|
||||||
ret = encodeURIComponent(ret);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
};
|
|
||||||
|
|
||||||
var URLStringify = function (o) {
|
|
||||||
var ret = [];
|
|
||||||
for (var i in o) {
|
|
||||||
// ret.push( encodeURIComponent(i) + '=' + encodeURIComponent(o[i]) );
|
|
||||||
ret.push(i + '=' + o[i]);
|
|
||||||
}
|
|
||||||
return ret.join('&');
|
|
||||||
};
|
|
||||||
var qsso;
|
|
||||||
module.exports = qsso = {
|
|
||||||
'auth': function (loginURI, opt_ext) {
|
|
||||||
if (!location.hostname.match(/\.qunar(man|ops)?\.com$|\.qunarman\.com$|qunar\.it$|\.928383\.com$|^928383\.com$|qunar\.ctripgroup\.c(om|n)$|\.ctrip(corp)?\.com$|^opsdata\.me$|\.mofun\.com$/i)) {
|
|
||||||
location.href = AUTH_SERVER + SORRY_PAGE + '?host=' + qualifyURL('', true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var ret = qualifyURL(loginURI, true);
|
|
||||||
|
|
||||||
var redirectURL = AUTH_SERVER + LOGIN_PAGE + '?ret=' + ret + (opt_ext ? '&ext=' + encodeURIComponent(URLStringify(opt_ext)) : '');
|
|
||||||
// console.log(redirectURL);
|
|
||||||
location.href = redirectURL;
|
|
||||||
},
|
|
||||||
|
|
||||||
'attach': function (eid, loginURI, opt_ext) {
|
|
||||||
var login = function () {
|
|
||||||
qsso.auth(loginURI, opt_ext);
|
|
||||||
|
|
||||||
};
|
|
||||||
document.getElementById(eid).onclick = login;
|
|
||||||
if (location.hash.match('qsso-auto-login')) {
|
|
||||||
login();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
@ -19,7 +19,7 @@ class Subnav extends Component {
|
|||||||
<div className="m-subnav">
|
<div className="m-subnav">
|
||||||
<Menu
|
<Menu
|
||||||
onClick={this.handleClick}
|
onClick={this.handleClick}
|
||||||
defaultSelectedKeys={[this.props.default]}
|
selectedKeys={[this.props.default]}
|
||||||
mode="horizontal"
|
mode="horizontal"
|
||||||
className="g-row m-subnav-menu"
|
className="g-row m-subnav-menu"
|
||||||
>
|
>
|
||||||
@ -29,7 +29,7 @@ class Subnav extends Component {
|
|||||||
item.name = item.name[0] + ' ' + item.name[1];
|
item.name = item.name[0] + ' ' + item.name[1];
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<Menu.Item className="item" key={item.name}>
|
<Menu.Item className="item" key={item.name.replace(' ', '')}>
|
||||||
<Link to={item.path}>{this.props.data[index].name}</Link>
|
<Link to={item.path}>{this.props.data[index].name}</Link>
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
)
|
)
|
||||||
|
@ -7,8 +7,7 @@ import PropTypes from "prop-types";
|
|||||||
import { withRouter } from 'react-router';
|
import { withRouter } from 'react-router';
|
||||||
import { logoSVG, getImgPath } from '../../common.js';
|
import { logoSVG, getImgPath } from '../../common.js';
|
||||||
import { changeMenuItem } from '../../reducer/modules/menu'
|
import { changeMenuItem } from '../../reducer/modules/menu'
|
||||||
import Qsso from '../../components/Qsso/Qsso.js'
|
import Plugins from '../../plugin.js'
|
||||||
|
|
||||||
const HomeGuest = () => (
|
const HomeGuest = () => (
|
||||||
<div className="g-body">
|
<div className="g-body">
|
||||||
<div className="m-bg">
|
<div className="m-bg">
|
||||||
@ -37,7 +36,11 @@ const HomeGuest = () => (
|
|||||||
<div className="detail">高效、易用、功能强大的API管理平台<br /><span className="desc">旨在为开发、产品、测试人员提供更优雅的接口管理服务</span></div>
|
<div className="detail">高效、易用、功能强大的API管理平台<br /><span className="desc">旨在为开发、产品、测试人员提供更优雅的接口管理服务</span></div>
|
||||||
<div className="btn-group">
|
<div className="btn-group">
|
||||||
<Link to="/login"><Button type="primary" className="btn-home btn-login">登录 / 注册</Button></Link>
|
<Link to="/login"><Button type="primary" className="btn-home btn-login">登录 / 注册</Button></Link>
|
||||||
<Button className="btn-home btn-home-normal" id="qsso-login">QSSO 登录</Button>
|
{Plugins.third_login.listener != null ?
|
||||||
|
<Plugins.third_login.listener />
|
||||||
|
: null
|
||||||
|
}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Col>
|
</Col>
|
||||||
@ -181,7 +184,7 @@ class Home extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
Qsso.attach('qsso-login', '/api/user/login_by_token')
|
|
||||||
}
|
}
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
introList: PropTypes.array,
|
introList: PropTypes.array,
|
||||||
|
@ -68,6 +68,8 @@ $color-bg-lightblue: #c6e2ff;
|
|||||||
&:hover, &:focus {
|
&:hover, &:focus {
|
||||||
background-color: #f6f9fc;
|
background-color: #f6f9fc;
|
||||||
}
|
}
|
||||||
|
background-color: #fff;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ import { loginActions } from '../../reducer/modules/user';
|
|||||||
import { withRouter } from 'react-router'
|
import { withRouter } from 'react-router'
|
||||||
const FormItem = Form.Item;
|
const FormItem = Form.Item;
|
||||||
import './Login.scss'
|
import './Login.scss'
|
||||||
import Qsso from '../../components/Qsso/Qsso.js'
|
// import Qsso from '../../components/Qsso/Qsso.js'
|
||||||
|
|
||||||
const formItemStyle = {
|
const formItemStyle = {
|
||||||
marginBottom: '.16rem'
|
marginBottom: '.16rem'
|
||||||
@ -54,7 +54,7 @@ class Login extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
Qsso.attach('qsso-login','/api/user/login_by_token')
|
//Qsso.attach('qsso-login','/api/user/login_by_token')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -79,6 +79,7 @@ class Interface extends Component {
|
|||||||
render() {
|
render() {
|
||||||
const { action } = this.props.match.params;
|
const { action } = this.props.match.params;
|
||||||
const activeKey = action === 'api' ? 'api' : 'colOrCase';
|
const activeKey = action === 'api' ? 'api' : 'colOrCase';
|
||||||
|
// console.log(matchPath(this.props.location.pathname, contentRouter));
|
||||||
return <div className="web-content g-row" style={{ marginBottom: "15px" }}>
|
return <div className="web-content g-row" style={{ marginBottom: "15px" }}>
|
||||||
<Row gutter={16} >
|
<Row gutter={16} >
|
||||||
<Col span={6}>
|
<Col span={6}>
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
.menu-title {
|
.menu-title {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
overflow: hidden;
|
||||||
.case-delete-icon{
|
.case-delete-icon{
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,9 @@ const TreeNode = Tree.TreeNode;
|
|||||||
|
|
||||||
|
|
||||||
@connect(
|
@connect(
|
||||||
|
|
||||||
state => {
|
state => {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
list: state.inter.list,
|
list: state.inter.list,
|
||||||
inter: state.inter.curdata,
|
inter: state.inter.curdata,
|
||||||
@ -213,8 +215,38 @@ class InterfaceMenu extends Component {
|
|||||||
render() {
|
render() {
|
||||||
const matchParams = this.props.match.params;
|
const matchParams = this.props.match.params;
|
||||||
let menuList = this.props.list;
|
let menuList = this.props.list;
|
||||||
|
const searchBox = <div className="interface-filter">
|
||||||
|
<Input onChange={this.onFilter} value={this.state.filter} placeholder="Filter by name" style={{ width: "70%" }} />
|
||||||
|
<Tag color="#108ee9" onClick={() => this.changeModal('add_cat_modal_visible', true)} style={{ marginLeft: "15px" }} ><Icon type="plus" /></Tag>
|
||||||
|
<Modal
|
||||||
|
title="添加接口"
|
||||||
|
visible={this.state.visible}
|
||||||
|
onCancel={() => this.changeModal('visible', false)}
|
||||||
|
footer={null}
|
||||||
|
>
|
||||||
|
<AddInterfaceForm catdata={this.props.curProject.cat} catid={this.state.curCatid} onCancel={() => this.changeModal('visible', false)} onSubmit={this.handleAddInterface} />
|
||||||
|
</Modal>
|
||||||
|
|
||||||
|
<Modal
|
||||||
|
title="添加分类"
|
||||||
|
visible={this.state.add_cat_modal_visible}
|
||||||
|
onCancel={() => this.changeModal('add_cat_modal_visible', false)}
|
||||||
|
footer={null}
|
||||||
|
>
|
||||||
|
<AddInterfaceCatForm onCancel={() => this.changeModal('add_cat_modal_visible', false)} onSubmit={this.handleAddInterfaceCat} />
|
||||||
|
</Modal>
|
||||||
|
|
||||||
|
<Modal
|
||||||
|
title="修改分类"
|
||||||
|
visible={this.state.change_cat_modal_visible}
|
||||||
|
onCancel={() => this.changeModal('change_cat_modal_visible', false)}
|
||||||
|
footer={null}
|
||||||
|
>
|
||||||
|
<AddInterfaceCatForm catdata={this.state.curCatdata} onCancel={() => this.changeModal('change_cat_modal_visible', false)} onSubmit={this.handleChangeInterfaceCat} />
|
||||||
|
</Modal>
|
||||||
|
</div>
|
||||||
if(menuList.length === 0){
|
if(menuList.length === 0){
|
||||||
return null;
|
return searchBox;
|
||||||
}
|
}
|
||||||
const defaultExpandedKeys = () => {
|
const defaultExpandedKeys = () => {
|
||||||
const { router, inter, list } = this.props, rNull = { expands: [], selects: [] };
|
const { router, inter, list } = this.props, rNull = { expands: [], selects: [] };
|
||||||
@ -307,36 +339,7 @@ class InterfaceMenu extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return <div>
|
return <div>
|
||||||
<div className="interface-filter">
|
{searchBox}
|
||||||
<Input onChange={this.onFilter} value={this.state.filter} placeholder="Filter by name" style={{ width: "70%" }} />
|
|
||||||
<Tag color="#108ee9" onClick={() => this.changeModal('add_cat_modal_visible', true)} style={{ marginLeft: "15px" }} ><Icon type="plus" /></Tag>
|
|
||||||
<Modal
|
|
||||||
title="添加接口"
|
|
||||||
visible={this.state.visible}
|
|
||||||
onCancel={() => this.changeModal('visible', false)}
|
|
||||||
footer={null}
|
|
||||||
>
|
|
||||||
<AddInterfaceForm catdata={this.props.curProject.cat} catid={this.state.curCatid} onCancel={() => this.changeModal('visible', false)} onSubmit={this.handleAddInterface} />
|
|
||||||
</Modal>
|
|
||||||
|
|
||||||
<Modal
|
|
||||||
title="添加分类"
|
|
||||||
visible={this.state.add_cat_modal_visible}
|
|
||||||
onCancel={() => this.changeModal('add_cat_modal_visible', false)}
|
|
||||||
footer={null}
|
|
||||||
>
|
|
||||||
<AddInterfaceCatForm onCancel={() => this.changeModal('add_cat_modal_visible', false)} onSubmit={this.handleAddInterfaceCat} />
|
|
||||||
</Modal>
|
|
||||||
|
|
||||||
<Modal
|
|
||||||
title="修改分类"
|
|
||||||
visible={this.state.change_cat_modal_visible}
|
|
||||||
onCancel={() => this.changeModal('change_cat_modal_visible', false)}
|
|
||||||
footer={null}
|
|
||||||
>
|
|
||||||
<AddInterfaceCatForm catdata={this.state.curCatdata} onCancel={() => this.changeModal('change_cat_modal_visible', false)} onSubmit={this.handleChangeInterfaceCat} />
|
|
||||||
</Modal>
|
|
||||||
</div>
|
|
||||||
{menuList.length > 0 ?
|
{menuList.length > 0 ?
|
||||||
<Tree
|
<Tree
|
||||||
className="interface-list"
|
className="interface-list"
|
||||||
@ -356,7 +359,7 @@ class InterfaceMenu extends Component {
|
|||||||
</Dropdown>
|
</Dropdown>
|
||||||
</div>}
|
</div>}
|
||||||
key={'cat_' + item._id}
|
key={'cat_' + item._id}
|
||||||
className="interface-item-nav"
|
className={`interface-item-nav ${item.list.length?"":"cat_switch_hidden"}`}
|
||||||
>
|
>
|
||||||
{item.list.map(item_interface_create)}
|
{item.list.map(item_interface_create)}
|
||||||
|
|
||||||
|
@ -31,9 +31,10 @@ class View extends Component {
|
|||||||
|
|
||||||
req_body_form(req_body_type,req_body_form){
|
req_body_form(req_body_type,req_body_form){
|
||||||
if(req_body_type === 'json'){
|
if(req_body_type === 'json'){
|
||||||
|
let h = this.countEnter(this.props.curData.req_body_other);
|
||||||
return <div style={{display:this.props.curData.req_body_other?"block":"none"}} className="colBody">
|
return <div style={{display:this.props.curData.req_body_other?"block":"none"}} className="colBody">
|
||||||
<span className="colKey">请求Body:</span>
|
<span className="colKey">请求Body:</span>
|
||||||
<div id="vreq_body_json" style={{ minHeight: "200px" }}></div>
|
<div id="vreq_body_json" style={{ minHeight: h*16+20 }}></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
}else if(req_body_type === 'form'){
|
}else if(req_body_type === 'form'){
|
||||||
@ -92,9 +93,10 @@ class View extends Component {
|
|||||||
}
|
}
|
||||||
res_body(res_body_type,res_body){
|
res_body(res_body_type,res_body){
|
||||||
if(res_body_type === 'json'){
|
if(res_body_type === 'json'){
|
||||||
|
let h = this.countEnter(this.props.curData.req_body_other);
|
||||||
return <div style={{display:this.props.curData.res_body?"":"none"}} className="colBody">
|
return <div style={{display:this.props.curData.res_body?"":"none"}} className="colBody">
|
||||||
<span className="colKey">返回Body:</span>
|
<span className="colKey">返回Body:</span>
|
||||||
<div id="vres_body_json" style={{ minHeight: "200px" }}></div>
|
<div id="vres_body_json" style={{ minHeight: h*16+20 }}></div>
|
||||||
</div>
|
</div>
|
||||||
}else if(res_body_type === 'raw'){
|
}else if(res_body_type === 'raw'){
|
||||||
return <div style={{display:this.props.curData.res_body?"":"none"}} className="colBody">
|
return <div style={{display:this.props.curData.res_body?"":"none"}} className="colBody">
|
||||||
@ -135,9 +137,19 @@ class View extends Component {
|
|||||||
return <Table bordered size="small" pagination = {false} columns= {columns} dataSource = {dataSource} />;
|
return <Table bordered size="small" pagination = {false} columns= {columns} dataSource = {dataSource} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
countEnter(str){
|
||||||
|
let i = 0;
|
||||||
|
let c = 0;
|
||||||
|
if(!str||!str.indexOf) return 0;
|
||||||
|
while(str.indexOf('\n',i)>-1){
|
||||||
|
i = str.indexOf('\n',i) + 2;
|
||||||
|
c++;
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
bindAceEditor(){
|
bindAceEditor(){
|
||||||
if(this.props.curData.req_body_type === "json"&&this.props.curData.title){
|
if(this.props.curData.req_body_type === "json"&&this.props.curData.title){
|
||||||
|
// console.log(this.props.curData.req_body_other.indexOf("\n"));
|
||||||
mockEditor({
|
mockEditor({
|
||||||
container: 'vreq_body_json',
|
container: 'vreq_body_json',
|
||||||
data: this.props.curData.req_body_other,
|
data: this.props.curData.req_body_other,
|
||||||
|
@ -93,4 +93,9 @@
|
|||||||
text-indent: 2em;
|
text-indent: 2em;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// .ace_scroller{
|
||||||
|
// position: relative;
|
||||||
|
// margin-left: 50px;
|
||||||
|
// overflow:visible;
|
||||||
|
// }
|
||||||
}
|
}
|
@ -51,6 +51,13 @@
|
|||||||
background-color: #efefef
|
background-color: #efefef
|
||||||
}
|
}
|
||||||
.interface-list{
|
.interface-list{
|
||||||
|
.cat_switch_hidden{
|
||||||
|
.ant-tree-switcher{
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
a{
|
a{
|
||||||
color: #333
|
color: #333
|
||||||
}
|
}
|
||||||
@ -85,7 +92,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.right-content{
|
.right-content{
|
||||||
margin:3px;
|
margin:3px;
|
||||||
min-height: 5rem;
|
min-height: 5rem;
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import './plugin'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import ReactDOM from 'react-dom'
|
import ReactDOM from 'react-dom'
|
||||||
import App from './Application'
|
import App from './Application'
|
||||||
|
45
client/plugin.js
Normal file
45
client/plugin.js
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
const config = process.env.config;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* type single 只绑定一个监听函数,会返回处理结果
|
||||||
|
* mulit 绑定多个监听函数
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
var hooks = {
|
||||||
|
'third_login': {
|
||||||
|
type: 'single',
|
||||||
|
listener: null
|
||||||
|
},
|
||||||
|
'add_interface': {
|
||||||
|
type: 'mulit',
|
||||||
|
listener: []
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function bindHook(name, listener) {
|
||||||
|
if (!name) throw new Error('缺少hookname');
|
||||||
|
if (name in hooks === false) {
|
||||||
|
throw new Error('不存在的hookname');
|
||||||
|
}
|
||||||
|
if (hooks[name].type === 'multi') {
|
||||||
|
hooks[name].listener.push(listener);
|
||||||
|
} else {
|
||||||
|
hooks[name].listener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
var yapi = {
|
||||||
|
hooks: hooks,
|
||||||
|
bindHook: bindHook
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.plugins && Array.isArray(config.plugins)) {
|
||||||
|
config.plugins.forEach(plugin => {
|
||||||
|
let pluginModule = require(`plugins/yapi-plugin-${plugin}/client.js`);
|
||||||
|
pluginModule.call(yapi) ;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = hooks;
|
@ -1,3 +1,3 @@
|
|||||||
{
|
{
|
||||||
"watch": ["server/"]
|
"watch": ["server/", "common/", "plugins"]
|
||||||
}
|
}
|
5
npm-shrinkwrap.json
generated
5
npm-shrinkwrap.json
generated
@ -15012,6 +15012,11 @@
|
|||||||
"resolved": "https://repo.corp.qunar.com/artifactory/api/npm/npm-qunar/yallist/-/yallist-2.1.2.tgz",
|
"resolved": "https://repo.corp.qunar.com/artifactory/api/npm/npm-qunar/yallist/-/yallist-2.1.2.tgz",
|
||||||
"integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI="
|
"integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI="
|
||||||
},
|
},
|
||||||
|
"yapi-plugin-qsso": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/yapi-plugin-qsso/-/yapi-plugin-qsso-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-x1LS8R5Vdjep+a93M97v7LcdV+3tupqIOkxxS+uYh+rbYB568BZFEpvfR43L7PcBZcCaOcsCOJEsrw1rcq5rhQ=="
|
||||||
|
},
|
||||||
"yargs": {
|
"yargs": {
|
||||||
"version": "7.1.0",
|
"version": "7.1.0",
|
||||||
"resolved": "https://repo.corp.qunar.com/artifactory/api/npm/npm-qunar/yargs/-/yargs-7.1.0.tgz",
|
"resolved": "https://repo.corp.qunar.com/artifactory/api/npm/npm-qunar/yargs/-/yargs-7.1.0.tgz",
|
||||||
|
@ -98,6 +98,7 @@
|
|||||||
"universal-cookie": "^2.0.8",
|
"universal-cookie": "^2.0.8",
|
||||||
"url": "^0.11.0",
|
"url": "^0.11.0",
|
||||||
"validate-commit-msg": "^2.12.2",
|
"validate-commit-msg": "^2.12.2",
|
||||||
|
"yapi-plugin-qsso": "^1.0.2",
|
||||||
"ykit-config-antd": "^0.1.3"
|
"ykit-config-antd": "^0.1.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
@ -9,12 +9,14 @@ const bodyParser = require('koa-bodyparser');
|
|||||||
const router = require('./router.js');
|
const router = require('./router.js');
|
||||||
const websockify = require('koa-websocket');
|
const websockify = require('koa-websocket');
|
||||||
const websocket = require('./websocket.js');
|
const websocket = require('./websocket.js');
|
||||||
|
const plugins = require('./plugin.js');
|
||||||
|
|
||||||
yapi.connect = dbModule.connect();
|
|
||||||
const app = websockify(new Koa());
|
|
||||||
let indexFile = process.argv[2] === 'dev' ? 'dev.html' : 'index.html';
|
let indexFile = process.argv[2] === 'dev' ? 'dev.html' : 'index.html';
|
||||||
|
|
||||||
|
yapi.connect = dbModule.connect();
|
||||||
|
const app = websockify(new Koa());
|
||||||
|
yapi.app = app;
|
||||||
|
plugins();
|
||||||
app.use(mockServer);
|
app.use(mockServer);
|
||||||
app.use(bodyParser({multipart: true}));
|
app.use(bodyParser({multipart: true}));
|
||||||
app.use(router.routes());
|
app.use(router.routes());
|
||||||
|
@ -109,11 +109,9 @@ class userController extends baseController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async loginByToken(ctx) {
|
async loginByToken(ctx) {
|
||||||
let config = this.thirdQunarLogin();
|
//let config = this.thirdQunarLogin();
|
||||||
let token = ctx.request.body[config.tokenField] || ctx.request.query[config.tokenField];
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let ret = await config.request(token);
|
let ret = await yapi.emitHook('third_login', ctx);
|
||||||
let login = await this.handleThirdLogin(ret.email, ret.username);
|
let login = await this.handleThirdLogin(ret.email, ret.username);
|
||||||
|
|
||||||
if (login === true) {
|
if (login === true) {
|
||||||
|
59
server/plugin.js
Normal file
59
server/plugin.js
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
const yapi = require('./yapi.js');
|
||||||
|
const plugin_path = yapi.path.join(yapi.WEBROOT, 'node_modules')
|
||||||
|
var hooks = {
|
||||||
|
'third_login': {
|
||||||
|
type: 'single',
|
||||||
|
listener: null
|
||||||
|
},
|
||||||
|
'add_interface': {
|
||||||
|
type: 'mulit',
|
||||||
|
listener: []
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function bindHook(name, listener){
|
||||||
|
if(!name) throw new Error('缺少hookname');
|
||||||
|
if(name in hooks === false){
|
||||||
|
throw new Error('不存在的hookname');
|
||||||
|
}
|
||||||
|
if(hooks[name].type === 'multi'){
|
||||||
|
hooks[name].listener.push(listener);
|
||||||
|
}else{
|
||||||
|
hooks[name].listener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function emitHook(name){
|
||||||
|
if(!name) throw new Error('缺少hookname');
|
||||||
|
if(name in hooks === false){
|
||||||
|
throw new Error('不存在的hookname');
|
||||||
|
}
|
||||||
|
|
||||||
|
if(hooks[name] && typeof hooks[name] === 'object'){
|
||||||
|
if(hooks[name].type === 'single' && typeof hooks[name].listener === 'function'){
|
||||||
|
return hooks[name].listener.apply(yapi, Array.prototype.slice.call(arguments, 1));
|
||||||
|
}
|
||||||
|
if(Array.isArray(hooks[name.listener])){
|
||||||
|
hooks[name].listener.forEach(listener=>{
|
||||||
|
listener.apply(yapi, Array.prototype.slice.call(arguments,1))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
yapi.bindHook = bindHook;
|
||||||
|
yapi.emitHook = emitHook;
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = function(){
|
||||||
|
if(yapi.WEBCONFIG.plugins && Array.isArray(yapi.WEBCONFIG.plugins)){
|
||||||
|
yapi.WEBCONFIG.plugins.forEach(plugin=>{
|
||||||
|
if(!yapi.commons.fileExist(yapi.path.join(plugin_path, 'yapi-plugin-' + plugin + '/server.js'))){
|
||||||
|
throw new Error(`请安装插件(${plugin}), npm install yapi-plugin-${plugin}`)
|
||||||
|
}
|
||||||
|
let pluginModule = require(yapi.path.join(plugin_path, 'yapi-plugin-' + plugin + '/server.js'));
|
||||||
|
pluginModule.apply(yapi)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -39,6 +39,7 @@ function delInst(m) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
let r = {
|
let r = {
|
||||||
fs: fs,
|
fs: fs,
|
||||||
path: path,
|
path: path,
|
||||||
|
@ -5,15 +5,15 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||||
<title>YAPI-高效、易用、功能强大的api管理平台</title>
|
<title>YAPI-高效、易用、功能强大的api管理平台</title>
|
||||||
<link rel="icon" type="image/png" sizes="192x192" href="/image/favicon.png">
|
<link rel="icon" type="image/png" sizes="192x192" href="/image/favicon.png">
|
||||||
<link rel="stylesheet" href="http://127.0.0.1:4000/yapi/prd/index@dev.css">
|
<link rel="stylesheet" href="/prd/index.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="yapi" style="height: 100%;"></div>
|
<div id="yapi" style="height: 100%;"></div>
|
||||||
|
|
||||||
<script src="http://127.0.0.1:4000/prd/manifest@dev.js"></script>
|
<script src="/prd/manifest.js"></script>
|
||||||
<script src="http://127.0.0.1:4000/prd/lib2@dev.js"></script>
|
<script src="/prd/lib2.js"></script>
|
||||||
<script src="http://127.0.0.1:4000/prd/lib@dev.js"></script>
|
<script src="/prd/lib.js"></script>
|
||||||
<script src="http://127.0.0.1:4000/prd/index@dev.js"></script>
|
<script src="/prd/index.js"></script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
96
ykit.js
96
ykit.js
@ -1,12 +1,32 @@
|
|||||||
var path = require('path');
|
var path = require('path');
|
||||||
|
var fs = require('fs');
|
||||||
var AssetsPlugin = require('assets-webpack-plugin')
|
var AssetsPlugin = require('assets-webpack-plugin')
|
||||||
var CompressionPlugin = require('compression-webpack-plugin')
|
var CompressionPlugin = require('compression-webpack-plugin')
|
||||||
|
var config = require('../config.json');
|
||||||
var assetsPluginInstance = new AssetsPlugin({
|
var assetsPluginInstance = new AssetsPlugin({
|
||||||
filename: 'static/prd/assets.js',
|
filename: 'static/prd/assets.js',
|
||||||
processOutput: function (assets) {
|
processOutput: function (assets) {
|
||||||
return 'window.WEBPACK_ASSETS = ' + JSON.stringify(assets);
|
return 'window.WEBPACK_ASSETS = ' + JSON.stringify(assets);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
|
function fileExist (filePath){
|
||||||
|
try {
|
||||||
|
return fs.statSync(filePath).isFile();
|
||||||
|
} catch (err) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function initPlugins(){
|
||||||
|
if(config.plugins && Array.isArray(config.plugins)){
|
||||||
|
config.plugins = config.plugins.filter(item=>{
|
||||||
|
return fileExist(path.resolve(__dirname, 'node_modules/yapi-plugin-' + item + '/client.js'))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
initPlugins();
|
||||||
|
|
||||||
var compressPlugin = new CompressionPlugin({
|
var compressPlugin = new CompressionPlugin({
|
||||||
asset: "[path].gz[query]",
|
asset: "[path].gz[query]",
|
||||||
@ -81,21 +101,22 @@ function handleCommonsChunk(webpackConfig) {
|
|||||||
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
plugins: [{
|
// plugins: [{
|
||||||
name: 'antd',
|
// name: 'antd',
|
||||||
options: {
|
// options: {
|
||||||
modifyQuery: function (defaultQuery) { // 可查看和编辑 defaultQuery
|
// modifyQuery: function (defaultQuery) { // 可查看和编辑 defaultQuery
|
||||||
defaultQuery.plugins = [];
|
// defaultQuery.plugins = [];
|
||||||
defaultQuery.plugins.push(["transform-runtime", {
|
// defaultQuery.plugins.push(["transform-runtime", {
|
||||||
"polyfill": false,
|
// "polyfill": false,
|
||||||
"regenerator": true
|
// "regenerator": true
|
||||||
}]);
|
// }]);
|
||||||
defaultQuery.plugins.push('transform-decorators-legacy');
|
// defaultQuery.plugins.push('transform-decorators-legacy');
|
||||||
defaultQuery.plugins.push(["import", { libraryName: "antd"}])
|
// defaultQuery.plugins.push(["import", { libraryName: "antd"}])
|
||||||
return defaultQuery;
|
// return defaultQuery;
|
||||||
}
|
// },
|
||||||
}
|
// exclude: /node_modules(?!\/yapi\-plugin\-)/
|
||||||
}],
|
// }
|
||||||
|
// }],
|
||||||
// devtool: 'cheap-source-map',
|
// devtool: 'cheap-source-map',
|
||||||
config: function (ykit) {
|
config: function (ykit) {
|
||||||
return {
|
return {
|
||||||
@ -119,19 +140,25 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
baseConfig.plugins.push(new this.webpack.DefinePlugin({
|
baseConfig.plugins.push(new this.webpack.DefinePlugin({
|
||||||
'process.env.NODE_ENV': JSON.stringify(ENV_PARAMS)
|
'process.env.NODE_ENV': JSON.stringify(ENV_PARAMS),
|
||||||
|
'process.env.config': JSON.stringify(config)
|
||||||
}))
|
}))
|
||||||
|
|
||||||
//初始化配置
|
//初始化配置
|
||||||
baseConfig.devtool = 'cheap-module-eval-source-map'
|
baseConfig.devtool = 'cheap-module-eval-source-map'
|
||||||
baseConfig.context = path.resolve(__dirname, './client');
|
baseConfig.context = path.resolve(__dirname, './client');
|
||||||
baseConfig.resolve.alias.common = '/common';
|
baseConfig.resolve.alias.common = '/common';
|
||||||
|
baseConfig.resolve.alias.plugins = '/node_modules';
|
||||||
|
baseConfig.output.local.path = 'static/prd';
|
||||||
|
baseConfig.output.dev.path = 'static/prd';
|
||||||
baseConfig.output.prd.path = 'static/prd';
|
baseConfig.output.prd.path = 'static/prd';
|
||||||
baseConfig.output.prd.publicPath = '';
|
baseConfig.output.prd.publicPath = '';
|
||||||
baseConfig.output.prd.filename = '[name]@[chunkhash][ext]'
|
baseConfig.output.prd.filename = '[name]@[chunkhash][ext]'
|
||||||
|
|
||||||
//commonsChunk
|
//commonsChunk
|
||||||
handleCommonsChunk.call(this, baseConfig)
|
handleCommonsChunk.call(this, baseConfig);
|
||||||
|
|
||||||
|
|
||||||
baseConfig.module.loaders.push({
|
baseConfig.module.loaders.push({
|
||||||
test: /\.less$/,
|
test: /\.less$/,
|
||||||
loader: ykit.ExtractTextPlugin.extract(
|
loader: ykit.ExtractTextPlugin.extract(
|
||||||
@ -151,10 +178,39 @@ module.exports = {
|
|||||||
})
|
})
|
||||||
baseConfig.module.preLoaders.push({
|
baseConfig.module.preLoaders.push({
|
||||||
test: /\.(js|jsx)$/,
|
test: /\.(js|jsx)$/,
|
||||||
exclude: /node_modules/,
|
exclude: /node_modules|plugins/,
|
||||||
loader: "eslint-loader"
|
loader: require.resolve('eslint-loader')
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var testReg = /\.(js|jsx)$/,
|
||||||
|
exclude = /node_modules(?!\/yapi\-plugin\-)/,
|
||||||
|
query = {
|
||||||
|
cacheDirectory: true,
|
||||||
|
presets: [
|
||||||
|
["es2015", {"loose": true}],
|
||||||
|
'es2017',
|
||||||
|
'stage-0',
|
||||||
|
'stage-1',
|
||||||
|
'stage-2',
|
||||||
|
'react'
|
||||||
|
],
|
||||||
|
plugins: []
|
||||||
|
};
|
||||||
|
query.plugins.push(["transform-runtime", {
|
||||||
|
"polyfill": false,
|
||||||
|
"regenerator": true
|
||||||
|
}]);
|
||||||
|
query.plugins.push('transform-decorators-legacy');
|
||||||
|
query.plugins.push(["import", { libraryName: "antd"}])
|
||||||
|
|
||||||
|
|
||||||
|
baseConfig.module.loaders.push({
|
||||||
|
loader: require.resolve('babel-loader'),
|
||||||
|
test: testReg,
|
||||||
|
exclude: exclude,
|
||||||
|
query: query
|
||||||
|
})
|
||||||
|
|
||||||
if (this.env == 'prd') {
|
if (this.env == 'prd') {
|
||||||
baseConfig.plugins.push(assetsPluginInstance)
|
baseConfig.plugins.push(assetsPluginInstance)
|
||||||
baseConfig.plugins.push(compressPlugin)
|
baseConfig.plugins.push(compressPlugin)
|
||||||
|
Loading…
Reference in New Issue
Block a user