Merge branch 'dev' of gitlab.corp.qunar.com:mfe/yapi into dev

This commit is contained in:
yhui.yang 2017-07-26 16:45:28 +08:00
commit 5268854b30
16 changed files with 315 additions and 62 deletions

View File

@ -2,7 +2,8 @@ import {
FETCH_INTERFACE_DATA, FETCH_INTERFACE_DATA,
LIST_INTERFACE_CLICK, LIST_INTERFACE_CLICK,
PROJECT_MEMBER_INTERFACE, PROJECT_MEMBER_INTERFACE,
DELETE_INTERFACE_DATA DELETE_INTERFACE_DATA,
SAVE_INTERFACE_PROJECT_ID
} from '../constants/action-types.js' } from '../constants/action-types.js'
export function fetchInterfaceData (value) { export function fetchInterfaceData (value) {
@ -30,3 +31,10 @@ export function deleteInterfaceData (value) {
payload: value payload: value
} }
} }
export function saveInterfaceProjectId (value) {
return {
type: SAVE_INTERFACE_PROJECT_ID,
payload: value
}
}

View File

@ -4,6 +4,7 @@ export const LIST_INTERFACE_CLICK = 'LIST_INTERFACE_CLICK'
export const PROJECT_MEMBER_INTERFACE = 'PROJECT_MEMBER_INTERFACE' export const PROJECT_MEMBER_INTERFACE = 'PROJECT_MEMBER_INTERFACE'
export const PUSH_INTERFACE_NAME = 'PUSH_INTERFACE_NAME' export const PUSH_INTERFACE_NAME = 'PUSH_INTERFACE_NAME'
export const DELETE_INTERFACE_DATA = 'DELETE_INTERFACE_DATA' export const DELETE_INTERFACE_DATA = 'DELETE_INTERFACE_DATA'
export const SAVE_INTERFACE_PROJECT_ID = 'SAVE_INTERFACE_PROJECT_ID'
// addInterFace // addInterFace
export const FETCH_ADD_INTERFACE_INPUT = 'FETCH_ADD_INTERFACE_INPUT' export const FETCH_ADD_INTERFACE_INPUT = 'FETCH_ADD_INTERFACE_INPUT'

View File

@ -11,6 +11,7 @@ import ReqHeader from './ReqHeader/ReqHeader.js'
import ReqParams from './ReqParams/ReqParams.js' import ReqParams from './ReqParams/ReqParams.js'
import ResParams from './ResParams/ResParams.js' import ResParams from './ResParams/ResParams.js'
import Result from './Result/Result.js' import Result from './Result/Result.js'
import MockUrl from './MockUrl/MockUrl.js'
import InterfaceTest from './InterfaceTest/InterfaceTest.js' import InterfaceTest from './InterfaceTest/InterfaceTest.js'
import { import {
saveForms, saveForms,
@ -23,6 +24,7 @@ import {
pushInterfaceMethod pushInterfaceMethod
} from '../../actions/addInterface.js' } from '../../actions/addInterface.js'
let projectId = ''
const success = () => { const success = () => {
message.success('保存成功!') message.success('保存成功!')
} }
@ -71,7 +73,8 @@ class AddInterface extends Component {
this.state = { this.state = {
isLoading: '', isLoading: '',
isSave: false, isSave: false,
mockJson: '' mockJson: '',
mockURL: ''
} }
} }
@ -106,7 +109,6 @@ class AddInterface extends Component {
url.match(regTwo) url.match(regTwo)
return RegExp.$1 return RegExp.$1
} }
} }
verificationURL () { verificationURL () {
@ -117,9 +119,22 @@ class AddInterface extends Component {
} }
} }
getMockURL (project_id, result) {
const params = {id: project_id}
axios.get('/project/get', {params: params}).
then( data => {
const { protocol, prd_host, basepath } = data.data.data
const mockURL = `${protocol}://${prd_host}${basepath}${result.path}`
this.setState({
mockURL: mockURL
})
})
}
editState (data) { editState (data) {
const props = this.props const props = this.props
const { path, title, req_params_other, res_body, req_headers, project_id, method } = data const { path, title, req_params_other, res_body, req_headers, project_id, method } = data
props.pushInputValue(path) props.pushInputValue(path)
props.pushInterfaceMethod(method) props.pushInterfaceMethod(method)
props.pushInterfaceName(title) props.pushInterfaceName(title)
@ -127,6 +142,7 @@ class AddInterface extends Component {
props.getResParams(res_body) props.getResParams(res_body)
props.addReqHeader(req_headers) props.addReqHeader(req_headers)
props.fetchInterfaceProject(project_id) props.fetchInterfaceProject(project_id)
projectId = project_id
} }
initInterfaceData (interfaceId) { initInterfaceData (interfaceId) {
@ -142,6 +158,8 @@ class AddInterface extends Component {
this.editState(result) this.editState(result)
// 初始化 mock // 初始化 mock
this.mockData() this.mockData()
this.getMockURL(projectId, result)
}) })
.catch(e => { .catch(e => {
console.log(e) console.log(e)
@ -175,7 +193,6 @@ class AddInterface extends Component {
resParams = JSON.parse(this.props.resParams) resParams = JSON.parse(this.props.resParams)
json = JSON.stringify(Mock.mock(resParams), null, 2) json = JSON.stringify(Mock.mock(resParams), null, 2)
} }
console.log('json', json)
this.setState({ this.setState({
mockJson: json mockJson: json
}) })
@ -184,13 +201,13 @@ class AddInterface extends Component {
@autobind @autobind
saveForms () { saveForms () {
let postURL = undefined let postURL = undefined
const { interfaceName, url, seqGroup, reqParams, resParams } = this.props const { interfaceName, url, seqGroup, reqParams, resParams, method } = this.props
const ifTrue = this.verificationURL() const ifTrue = this.verificationURL()
const interfaceId = this.getInterfaceId() const interfaceId = this.getInterfaceId()
const params = { const params = {
title: interfaceName, title: interfaceName,
path: url, path: url,
method: 'POST', method: method,
req_headers: seqGroup, req_headers: seqGroup,
project_id: interfaceId, project_id: interfaceId,
req_params_type: 'json', req_params_type: 'json',
@ -221,8 +238,8 @@ class AddInterface extends Component {
render () { render () {
const TabPane = Tabs.TabPane const TabPane = Tabs.TabPane
const { isLoading, isSave, mockJson='' } = this.state const { isLoading, isSave, mockJson='', mockURL } = this.state
console.log('mockJson', mockJson) console.log(mockURL)
return ( return (
<section className="add-interface-box"> <section className="add-interface-box">
<div className="content"> <div className="content">
@ -235,6 +252,7 @@ class AddInterface extends Component {
<ReqParams data={this.props} /> <ReqParams data={this.props} />
<ResParams /> <ResParams />
<Result isSave={isSave} mockJson={mockJson} /> <Result isSave={isSave} mockJson={mockJson} />
<MockUrl mockURL={mockURL} />
</TabPane> </TabPane>
{ {
// <TabPane tab="Mock" key="2">mock</TabPane> // <TabPane tab="Mock" key="2">mock</TabPane>

View File

@ -170,6 +170,23 @@
} }
} }
/* .mock-url-box.css */
.mock-url-box {
clear: both;
padding: 10px 0 0 0;
margin: 0 0 0 20px;
p {
width: 70%;
height: 35px;
line-height: 35px;
border: 1px #DDD solid;
display: inline-block;
vertical-align: -4px;
margin: 0 10px 0 0;
padding: 0 0 0 10px;
}
}
.loading { .loading {
display: none; display: none;
width: 100%; width: 100%;

View File

@ -0,0 +1,46 @@
import '../AddInterface.scss'
import React, { Component } from 'react'
import { Button, message } from 'antd'
import Clipboard from 'clipboard'
import PropTypes from 'prop-types'
const success = () => {
message.success('复制成功!')
}
class MockUrl extends Component {
static propTypes = {
mockURL: PropTypes.string
}
constructor(props) {
super(props)
}
componentDidMount () {
setTimeout(this.clipboard, 500)
}
clipboard () {
const btn = document.querySelector('#mock-clipboard')
const txt = document.querySelector('#mock-p').innerHTML
console.log('txt', txt)
new Clipboard(btn, {
text: () => txt,
target () {
success()
}
})
}
render () {
return (
<section className="mock-url-box">
<p id="mock-p">{this.props.mockURL}</p>
<Button type="primary" id="mock-clipboard">复制</Button>
</section>
)
}
}
export default MockUrl

View File

@ -40,6 +40,7 @@ class ReqMethod extends Component {
@autobind @autobind
handleChange (value) { handleChange (value) {
console.log('value', value)
this.props.pushInterfaceMethod(value) this.props.pushInterfaceMethod(value)
} }
@ -57,20 +58,15 @@ class ReqMethod extends Component {
render () { render () {
const { Option } = Select const { Option } = Select
const { url, interfaceName } = this.props const { url, interfaceName, method } = this.props
return ( return (
<table> <table>
<tbody> <tbody>
<tr> <tr>
<th>协议 :</th> <th>协议 :</th>
<td> <td>
<span className="h3">请求协议</span>
<Select defaultValue="HTTP" style={{ width: 220}} onChange={this.handleChange} size="large">
<Option value="HTTP">HTTP</Option>
<Option value="HTTPS">HTTPS</Option>
</Select>
<span className="h3">请求方式</span> <span className="h3">请求方式</span>
<Select defaultValue="POST" style={{ width: 220 }} onChange={this.handleChange} size="large"> <Select defaultValue={method} style={{ width: 220 }} onChange={this.handleChange} size="large">
<Option value="POST">POST</Option> <Option value="POST">POST</Option>
<Option value="GET">GET</Option> <Option value="GET">GET</Option>
<Option value="PUT">PUT</Option> <Option value="PUT">PUT</Option>

View File

@ -10,7 +10,8 @@ import moment from 'moment'
import { import {
fetchInterfaceData, fetchInterfaceData,
projectMember, projectMember,
closeProjectMember closeProjectMember,
saveInterfaceProjectId
} from '../../actions/interfaceAction.js' } from '../../actions/interfaceAction.js'
@connect( @connect(
@ -24,7 +25,8 @@ import {
{ {
fetchInterfaceData, fetchInterfaceData,
projectMember, projectMember,
closeProjectMember closeProjectMember,
saveInterfaceProjectId
} }
) )
@ -33,6 +35,7 @@ class Interface extends Component {
fetchInterfaceData: PropTypes.func, fetchInterfaceData: PropTypes.func,
interfaceData: PropTypes.array, interfaceData: PropTypes.array,
projectMember: PropTypes.func, projectMember: PropTypes.func,
saveInterfaceProjectId: PropTypes.func,
closeProjectMember: PropTypes.func, closeProjectMember: PropTypes.func,
modalVisible: PropTypes.bool modalVisible: PropTypes.bool
} }
@ -49,6 +52,8 @@ class Interface extends Component {
} }
} }
this.props.saveInterfaceProjectId(interfaceId)
axios.get('/interface/list', params) axios.get('/interface/list', params)
.then(result => { .then(result => {
result = result.data.data result = result.data.data

View File

@ -22,7 +22,7 @@ class InterfaceList extends Component {
render () { render () {
const { projectMember } = this.props const { projectMember } = this.props
const getInterfaceId = this.getInterfaceId() const getInterfaceId = this.getInterfaceId()
console.log(`/AddInterface/${getInterfaceId}`)
return ( return (
<div className="interface-btngroup"> <div className="interface-btngroup">
<Link to={`/AddInterface/${getInterfaceId}`}><Button className="interface-btn" type="primary" icon="plus">添加接口</Button></Link> <Link to={`/AddInterface/${getInterfaceId}`}><Button className="interface-btn" type="primary" icon="plus">添加接口</Button></Link>

View File

@ -1,5 +1,5 @@
import React, { Component } from 'react' import React, { Component } from 'react'
import { Table, Button } from 'antd' import { Table } from 'antd'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import axios from 'axios' import axios from 'axios'
import { connect } from 'react-redux' import { connect } from 'react-redux'
@ -21,6 +21,7 @@ class InterfaceTable extends Component {
static propTypes = { static propTypes = {
interfaceData: PropTypes.array, interfaceData: PropTypes.array,
data: PropTypes.array, data: PropTypes.array,
projectId: PropTypes.string,
deleteInterfaceData: PropTypes.func deleteInterfaceData: PropTypes.func
} }
@ -70,6 +71,7 @@ class InterfaceTable extends Component {
'key': 'action', 'key': 'action',
render: (data) => { render: (data) => {
const deleteInterface = this.deleteInterface.bind(this, data._id) const deleteInterface = this.deleteInterface.bind(this, data._id)
console.log(data)
return ( return (
<span> <span>
<Link to={`/AddInterface/edit/${data._id}`}><span>编辑</span></Link> <Link to={`/AddInterface/edit/${data._id}`}><span>编辑</span></Link>

View File

@ -10,7 +10,8 @@ const Option = AutoComplete.Option;
state => { state => {
console.log(state); console.log(state);
return { return {
curUid: state.login.uid + '' curUid: state.login.uid + '',
curUserName: state.login.userName
} }
} }
) )
@ -26,7 +27,8 @@ class LeftMenu extends Component {
} }
static propTypes = { static propTypes = {
curUid: PropTypes.string curUid: PropTypes.string,
curUserName: PropTypes.string
} }
//延迟搜索 //延迟搜索
@ -80,6 +82,9 @@ class LeftMenu extends Component {
const { dataSource } = this.state; const { dataSource } = this.state;
return (<div className="user-list"> return (<div className="user-list">
<div className='cur-user'>
<div className='user-name'><span>用户名 : </span>{`${this.props.curUserName}`}</div>
</div>
<Row type="flex" justify="start" className="search"> <Row type="flex" justify="start" className="search">
<Col span="24"> <Col span="24">
<div className="certain-category-search-wrapper" style={{ width: "100%" }}> <div className="certain-category-search-wrapper" style={{ width: "100%" }}>
@ -98,7 +103,7 @@ class LeftMenu extends Component {
</div> </div>
</Col> </Col>
</Row> </Row>
<Menu defaultSelectedKeys={[location.hash]}> <Menu mode='inline' defaultSelectedKeys={[location.hash]}>
{content} {content}
</Menu> </Menu>
</div> </div>

View File

@ -1,5 +1,5 @@
import React, { Component } from 'react' import React, { Component } from 'react'
import { Row, Col, Icon, Input, Button, Select, message } from 'antd' import { Row, Col, Input, Button, Select, message } from 'antd'
import axios from 'axios'; import axios from 'axios';
import {formatTime} from '../../common.js' import {formatTime} from '../../common.js'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
@ -131,7 +131,8 @@ class Profile extends Component {
if (this.state.usernameEdit === false) { if (this.state.usernameEdit === false) {
userNameEditHtml = <div > userNameEditHtml = <div >
<span className="text">{userinfo.username}</span>&nbsp;&nbsp; <span className="text">{userinfo.username}</span>&nbsp;&nbsp;
<span className="text-button" onClick={() => { this.handleEdit('usernameEdit', true) }}><Icon type="edit" />修改</span> {/*<span className="text-button" onClick={() => { this.handleEdit('usernameEdit', true) }}><Icon type="edit" />修改</span>*/}
<Button size={'small'} icon="edit" onClick={() => { this.handleEdit('usernameEdit', true) }}>修改</Button>
</div> </div>
} else { } else {
userNameEditHtml = <div> userNameEditHtml = <div>
@ -146,7 +147,8 @@ class Profile extends Component {
if (this.state.emailEdit === false) { if (this.state.emailEdit === false) {
emailEditHtml = <div > emailEditHtml = <div >
<span className="text">{userinfo.email}</span>&nbsp;&nbsp; <span className="text">{userinfo.email}</span>&nbsp;&nbsp;
<span className="text-button" onClick={() => { this.handleEdit('emailEdit', true) }} ><Icon type="edit" />修改</span> {/*<span className="text-button" onClick={() => { this.handleEdit('emailEdit', true) }} ><Icon type="edit" />修改</span>*/}
<Button size={'small'} icon="edit" onClick={() => { this.handleEdit('emailEdit', true) }}>修改</Button>
</div> </div>
} else { } else {
emailEditHtml = <div> emailEditHtml = <div>
@ -161,7 +163,8 @@ class Profile extends Component {
if (this.state.roleEdit === false) { if (this.state.roleEdit === false) {
roleEditHtml = <div> roleEditHtml = <div>
<span className="text">{roles[userinfo.role]}</span>&nbsp;&nbsp; <span className="text">{roles[userinfo.role]}</span>&nbsp;&nbsp;
<span className="text-button" onClick={() => { this.handleEdit('roleEdit', true) }} ><Icon type="edit" />修改</span> {/*<span className="text-button" onClick={() => { this.handleEdit('roleEdit', true) }} ><Icon type="edit" />修改</span>*/}
<Button size={'small'} icon="edit" onClick={() => { this.handleEdit('roleEdit', true) }}>修改</Button>
</div> </div>
} else { } else {
roleEditHtml = <Select defaultValue={_userinfo.role} onChange={ this.changeRole} style={{ width: 150 }} > roleEditHtml = <Select defaultValue={_userinfo.role} onChange={ this.changeRole} style={{ width: 150 }} >

View File

@ -6,7 +6,7 @@
margin: .88rem auto 0 auto; margin: .88rem auto 0 auto;
// font-size: 0.14rem; // font-size: 0.14rem;
min-height:433px;
margin-top: 40px; margin-top: 40px;
margin-bottom: 55px; margin-bottom: 55px;
@ -23,10 +23,21 @@
} }
ul{border:none} ul{border:none}
} }
.user-name{
padding: 10px 0px;
text-align: center;
background-color: #34495e;
color: white;
span{
margin-right: 10px;
}
}
.router-content{
min-height:calc(100% - 2.47rem);
}
.user-table { .user-table {
-webkit-box-flex: 1; -webkit-box-flex: 1;
padding: 15px; padding: 24px;
margin-left: 15px; margin-left: 15px;
border-radius:5px; border-radius:5px;
box-shadow: 0 2px 4px 0 rgba(0,0,0,0.20); box-shadow: 0 2px 4px 0 rgba(0,0,0,0.20);

View File

@ -2,13 +2,15 @@ import {
FETCH_INTERFACE_DATA, FETCH_INTERFACE_DATA,
LIST_INTERFACE_CLICK, LIST_INTERFACE_CLICK,
PROJECT_MEMBER_INTERFACE, PROJECT_MEMBER_INTERFACE,
DELETE_INTERFACE_DATA DELETE_INTERFACE_DATA,
SAVE_INTERFACE_PROJECT_ID
} from '../../constants/action-types.js' } from '../../constants/action-types.js'
const initialState = { const initialState = {
interfaceData: [], interfaceData: [],
modalVisible: false, modalVisible: false,
interfaceName: '' interfaceName: '',
projectId: ''
} }
export default (state = initialState, action) => { export default (state = initialState, action) => {
@ -33,6 +35,11 @@ export default (state = initialState, action) => {
...state, ...state,
interfaceData: action.payload interfaceData: action.payload
} }
case SAVE_INTERFACE_PROJECT_ID:
return {
...state,
projectId: action.payload
}
default: default:
return state return state
} }

View File

@ -2,13 +2,15 @@ import {
FETCH_INTERFACE_DATA, FETCH_INTERFACE_DATA,
LIST_INTERFACE_CLICK, LIST_INTERFACE_CLICK,
PROJECT_MEMBER_INTERFACE, PROJECT_MEMBER_INTERFACE,
DELETE_INTERFACE_DATA DELETE_INTERFACE_DATA,
SAVE_INTERFACE_PROJECT_ID
} from '../../constants/action-types.js' } from '../../constants/action-types.js'
const initialState = { const initialState = {
interfaceData: [], interfaceData: [],
modalVisible: false, modalVisible: false,
interfaceName: '' interfaceName: '',
projectId: ''
} }
export default (state = initialState, action) => { export default (state = initialState, action) => {
@ -33,6 +35,11 @@ export default (state = initialState, action) => {
...state, ...state,
interfaceData: action.payload interfaceData: action.payload
} }
case SAVE_INTERFACE_PROJECT_ID:
return {
...state,
projectId: action.payload
}
default: default:
return state return state
} }

View File

@ -1,32 +1,154 @@
const fs = require('fs-extra'); const fs = require('fs-extra');
const path = require('path');
const gulp = require('gulp'); const gulp = require('gulp');
const babel = require('gulp-babel'); const babel = require('gulp-babel');
const watch = require('gulp-watch'); const ora = require('ora');
const nodemon = require('nodemon'); const chalk = require('chalk');
const dist = './server_dist/' const { spawn } = require('child_process');
let spinner = ora('请稍等...').start();
const DIST = 'server_dist/';
const SRC = 'server/**/*.js';
gulp.task('default', ['clearLib', 'compileJS']); function generateBabel(status) {
const babelProcess = babel({
gulp.task('clearLib', [], function() {
return fs.removeSync(dist)
});
gulp.task('compileJS', ['clearLib'], function() {
var babelProcess = babel({
presets: ['es2015', "stage-3"], presets: ['es2015', "stage-3"],
plugins: ['transform-runtime'] plugins: ['transform-runtime']
})
babelProcess.on('error', function(e) {
console.log(e);
process.exit(1);
}); });
gulp.src('server/**/*.!(js)').pipe(gulp.dest(dist)); babelProcess.on('error', function (e) {
const restart = status ? status.count < 2 : true;
console.error(e);
output('error', 'babel 编译失败!', restart);
return watch(['server/**/*.js'], { if (status) {
verbose: true, status.count++;
ignoreInitial: false }
}).pipe(babelProcess).pipe(gulp.dest(dist)); });
})
return babelProcess;
}
function excuteCmd(cmd, args, opts) {
const command = spawn(cmd, args, opts);
command.stdout.on('data', data => {
output('log', `${cmd}: ${data.toString()}`, true);
});
command.stderr.on('data', data => {
output('log', `${cmd}: ${data.toString()}`, true);
});
command.on('close', code => {
if (code !== 0) {
output('log', `${cmd}: ${data.toString()}`);
}
});
}
function output(type, message, restart = false) {
spinner.stop();
if (type === 'success') {
message = '✔ ' + message;
console.log(chalk.green(message));
} else if (type === 'error') {
message = '✖ ' + message;
console.log(chalk.red(message));
} else {
console.log(message);
}
if (restart) {
spinner.start();
}
}
gulp.task('removeDist', [], function () {
return fs.removeSync(DIST)
});
gulp.task('initialBuild', ['removeDist'], () => {
spinner.text = '初始编译...';
return gulp.src(SRC)
.pipe(generateBabel())
.pipe(gulp.dest(DIST))
.on('end', () => {
output('success', '初始编译成功!');
spinner = ora({
text: '等待文件变更...',
spinner: 'pong',
color: 'green'
}).start();
excuteCmd('node_modules/.bin/nodemon', ['-q', 'server_dist/app.js', 'dev'], {
cwd: __dirname
});
excuteCmd('ykit', ['s', '-p', '4000'], {
cwd: path.resolve(__dirname, '../')
});
});
});
gulp.task('default', ['initialBuild'], () => {
gulp.watch(SRC, (event) => {
spinner.text = `正在编译 ${event.path}...`;
gulp.src(event.path).pipe(generateBabel())
.pipe(gulp.dest(DIST)).on('end', () => {
output('success', `成功编译 ${event.path}`);
spinner = ora({
text: 'waiting changes...',
spinner: 'pong',
color: 'green'
});
spinner.start();
});
});
});
gulp.task('build', () => {
let status = {
count: 0
};
let ykitOutput = '';
spinner.text = '正在编译...';
gulp.src(SRC)
.pipe(generateBabel(status))
.pipe(gulp.dest(DIST))
.on('error', (err) => {
status.count++;
output('error', err, status.count < 2);
})
.on('end', () => {
status.count++;
output('success', '后端编译成功!', status.count < 2);
});
const ykitBuild = spawn('ykit', ['pack', '-m'], {
cwd: __dirname
});
ykitBuild.stderr.on('data', data => {
ykitOutput += data.toString();
});
ykitBuild.stdout.on('data', data => {
ykitOutput += data.toString();
});
ykitBuild.on('close', code => {
if (code === 0) {
status.count++;
output('success', '前端编译成功!', status.count < 2);
} else {
status.count++;
output('error', '前端编译失败!', status.count < 2);
output('log', ykitOutput);
}
});
});

View File

@ -5,23 +5,26 @@
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
"build-server": "babel server -d server_dist", "build-server": "babel server -d server_dist",
"dev-server": "nodemon server_dist/app.js" "dev-server": "nodemon server_dist/app.js",
"install-server" : "node server_dist/install.js",
"dev": "gulp --silent",
"build": "gulp build --silent"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git@gitlab.corp.qunar.com:wenxiong.su/yapi.git" "url": "git@gitlab.corp.qunar.com:mfe/yapi.git"
}, },
"author": "", "author": "",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"@qnpm/ykit-config-qunar": "^0.8.2",
"assets-webpack-plugin": "^3.5.1", "assets-webpack-plugin": "^3.5.1",
"axios": "^0.16.2", "axios": "^0.16.2",
"babel-plugin-transform-decorators-legacy": "^1.3.4", "babel-plugin-transform-decorators-legacy": "^1.3.4",
"clipboard": "^1.7.1",
"copy-webpack-plugin": "^4.0.1", "copy-webpack-plugin": "^4.0.1",
"core-decorators": "^0.17.0", "core-decorators": "^0.17.0",
"fast-sass-loader": "^1.2.5",
"cross-request": "^1.0.1", "cross-request": "^1.0.1",
"fast-sass-loader": "^1.2.5",
"fs-extra": "^3.0.1", "fs-extra": "^3.0.1",
"json2html": "0.0.8", "json2html": "0.0.8",
"jsoneditor": "^5.9.3", "jsoneditor": "^5.9.3",
@ -75,6 +78,7 @@
"babel-register": "^6.9.0", "babel-register": "^6.9.0",
"babel-runtime": "^6.9.2", "babel-runtime": "^6.9.2",
"buffer-shims": "^1.0.0", "buffer-shims": "^1.0.0",
"chalk": "^2.0.1",
"css-loader": "^0.28.4", "css-loader": "^0.28.4",
"eslint": "^3.19.0", "eslint": "^3.19.0",
"eslint-plugin-import": "^2.2.0", "eslint-plugin-import": "^2.2.0",
@ -89,6 +93,7 @@
"gulp-watch": "^4.3.11", "gulp-watch": "^4.3.11",
"node-sass": "^4.5.3", "node-sass": "^4.5.3",
"nodemon": "^1.11.0", "nodemon": "^1.11.0",
"ora": "^1.3.0",
"prop-types": "^15.5.10", "prop-types": "^15.5.10",
"react": "^15.6.1", "react": "^15.6.1",
"react-dom": "^15.6.1", "react-dom": "^15.6.1",