mirror of
https://github.com/YMFE/yapi.git
synced 2024-11-27 04:40:08 +08:00
feat: mock
This commit is contained in:
parent
a3dd8f4a3d
commit
e3c53bfede
@ -185,6 +185,23 @@ function handleMockWord(word) {
|
||||
return Mock.mock(word);
|
||||
}
|
||||
|
||||
/**
|
||||
* 合并后新的对象属性与 Obj 一致,nextObj 有对应属性则取 nextObj 属性值,否则取 Obj 属性值
|
||||
* @param {Object} Obj 旧对象
|
||||
* @param {Object} nextObj 新对象
|
||||
* @return {Object} 合并后的对象
|
||||
*/
|
||||
exports.safeAssign = (Obj, nextObj) => {
|
||||
let keys = Object.keys(nextObj);
|
||||
return Object.keys(Obj).reduce((result, value) => {
|
||||
if (keys.indexOf(value) >= 0) {
|
||||
result[value] = nextObj[value];
|
||||
} else {
|
||||
result[value] = Obj[value];
|
||||
}
|
||||
return result;
|
||||
}, {});
|
||||
};
|
||||
|
||||
exports.simpleJsonPathParse = simpleJsonPathParse;
|
||||
exports.handleMockWord = handleMockWord;
|
||||
|
30
client/reducer/modules/mockCol.js
Normal file
30
client/reducer/modules/mockCol.js
Normal file
@ -0,0 +1,30 @@
|
||||
import axios from 'axios'
|
||||
|
||||
// Actions
|
||||
const FETCH_MOCK_COL = 'yapi/mockCol/FETCH_MOCK_COL';
|
||||
|
||||
// Reducer
|
||||
const initialState = {
|
||||
list: []
|
||||
}
|
||||
|
||||
export default (state = initialState, action) => {
|
||||
switch (action.type) {
|
||||
case FETCH_MOCK_COL:
|
||||
return {
|
||||
...state,
|
||||
list: action.payload.data.data
|
||||
}
|
||||
default:
|
||||
return state
|
||||
}
|
||||
}
|
||||
|
||||
// Action Creators
|
||||
export async function fetchMockCol(interfaceId) {
|
||||
let result = await axios.get('/api/plugin/advmock/case/list?interface_id=' + interfaceId);
|
||||
return {
|
||||
type: FETCH_MOCK_COL,
|
||||
payload: result.data
|
||||
}
|
||||
}
|
@ -8,6 +8,7 @@ import news from './news.js'
|
||||
import addInterface from './addInterface.js'
|
||||
import menu from './menu.js'
|
||||
import follow from './follow.js'
|
||||
import mockCol from './mockCol.js'
|
||||
|
||||
export default combineReducers({
|
||||
group,
|
||||
@ -18,5 +19,6 @@ export default combineReducers({
|
||||
news,
|
||||
addInterface,
|
||||
menu,
|
||||
follow
|
||||
follow,
|
||||
mockCol
|
||||
})
|
||||
|
258
exts/yapi-plugin-advanced-mock/MockCol/CaseDesModal.js
Normal file
258
exts/yapi-plugin-advanced-mock/MockCol/CaseDesModal.js
Normal file
@ -0,0 +1,258 @@
|
||||
import React, { Component } from 'react'
|
||||
// import axios from 'axios'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Button, Form, Input, Switch, Select, Icon, Modal } from 'antd';
|
||||
import { safeAssign } from '../../../client/common.js';
|
||||
import { httpCodes } from '../index.js';
|
||||
|
||||
const Option = Select.Option;
|
||||
const FormItem = Form.Item;
|
||||
const formItemLayout = {
|
||||
labelCol: {
|
||||
xs: { span: 24 },
|
||||
sm: { span: 5 }
|
||||
},
|
||||
wrapperCol: {
|
||||
xs: { span: 24 },
|
||||
sm: { span: 12 }
|
||||
}
|
||||
};
|
||||
|
||||
@Form.create()
|
||||
export default class CaseDesModal extends Component {
|
||||
static propTypes = {
|
||||
form: PropTypes.object,
|
||||
caseData: PropTypes.object,
|
||||
onCancel: PropTypes.func,
|
||||
onOk: PropTypes.func,
|
||||
isAdd: PropTypes.bool,
|
||||
visible: PropTypes.bool
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
preProcess = caseData => {
|
||||
// const a = {
|
||||
// interface_id: { type: Number, required: true },
|
||||
// project_id: {type: Number, required: true},
|
||||
// ip: {type: String},
|
||||
// ip_enable: {type: Boolean, default: false},
|
||||
// name: {type: String, required: true},
|
||||
// code: {type: Number, default: 200},
|
||||
// deplay: {type: Number, default: 0},
|
||||
// headers: [{
|
||||
// name: {type: String, required: true},
|
||||
// value: {type: String}
|
||||
// }],
|
||||
// params: mongoose.Schema.Types.Mixed,
|
||||
// uid: String,
|
||||
// up_time: Number,
|
||||
// res_body: {type: String, required: true}
|
||||
// }
|
||||
const initCaseData = {
|
||||
ip: '',
|
||||
ip_enable: false,
|
||||
name: '',
|
||||
code: '200',
|
||||
deplay: 0,
|
||||
headers: [{name: '', value: ''}],
|
||||
paramsArr: [{name: '', value: ''}],
|
||||
res_body: ''
|
||||
}
|
||||
caseData.paramsArr = caseData.params && caseData.params.length ? Object.keys(caseData.params).map(key => {
|
||||
return { name: key, value: caseData.params[key] }
|
||||
}) : [{name: '', value: ''}];
|
||||
caseData.headers = caseData.headers && caseData.headers.length ? caseData.headers : [{name: '', value: ''}];
|
||||
caseData = safeAssign(initCaseData, caseData);
|
||||
return caseData;
|
||||
}
|
||||
|
||||
endProcess = caseData => {
|
||||
const headers = [];
|
||||
const params = {};
|
||||
caseData.headers.forEach(item => {
|
||||
if (item.name) {
|
||||
headers.push({
|
||||
name: item.name,
|
||||
value: item.value
|
||||
})
|
||||
}
|
||||
});
|
||||
caseData.paramsArr.forEach(item => {
|
||||
if (item.name) {
|
||||
params[item.name] = item.value
|
||||
}
|
||||
})
|
||||
caseData.headers = headers;
|
||||
caseData.params = params;
|
||||
delete caseData.paramsArr;
|
||||
return caseData;
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.props.form.setFieldsValue(this.preProcess(this.props.caseData))
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (this.props.caseData !== nextProps.caseData) {
|
||||
this.props.form.setFieldsValue(this.preProcess(this.props.caseData))
|
||||
}
|
||||
}
|
||||
|
||||
handleOk = () => {
|
||||
const form = this.props.form;
|
||||
this.props.onOk(this.endProcess(form.getFieldsValue()));
|
||||
}
|
||||
|
||||
render() {
|
||||
const { getFieldDecorator, getFieldValue } = this.props.form;
|
||||
const { isAdd, visible, onCancel } = this.props;
|
||||
// const { caseData } = this.props;
|
||||
// const headers = caseData.headers || [{name: '', value: ''}];
|
||||
// const params = caseData.params || {'': ''};
|
||||
// const paramsArr = Object.keys(params).map(key => {
|
||||
// return { name: key, value: params[key] }
|
||||
// })
|
||||
|
||||
return (
|
||||
<Modal
|
||||
title={isAdd ? '添加期望' : '编辑期望'}
|
||||
visible={visible}
|
||||
maskClosable={false}
|
||||
onOk={this.handleOk}
|
||||
onCancel={() => onCancel()}
|
||||
>
|
||||
<Form>
|
||||
<FormItem
|
||||
{...formItemLayout}
|
||||
label="期望名称"
|
||||
>
|
||||
{getFieldDecorator('name', {
|
||||
rules: [{ required: true, message: '请输入期望名称!' }]
|
||||
})(
|
||||
<Input placeholder="请输入期望名称" />
|
||||
)}
|
||||
</FormItem>
|
||||
<FormItem label="IP 过滤">
|
||||
{getFieldDecorator('ip_enable', {
|
||||
valuePropName: 'checked',
|
||||
rules: [{ type: 'boolean' }]
|
||||
})(
|
||||
<Switch />
|
||||
)}
|
||||
</FormItem>
|
||||
<FormItem
|
||||
{...formItemLayout}
|
||||
>
|
||||
{getFieldDecorator('ip')(
|
||||
<Input placeholder="请输入过滤的 IP 地址" />
|
||||
)}
|
||||
</FormItem>
|
||||
<FormItem
|
||||
{...formItemLayout}
|
||||
label="HTTP CODE"
|
||||
>
|
||||
{getFieldDecorator('code')(
|
||||
<Select search>
|
||||
{
|
||||
httpCodes.map(code => <Option key={''+code} value={''+code}>{''+code}</Option>)
|
||||
}
|
||||
</Select>
|
||||
)}
|
||||
</FormItem>
|
||||
<FormItem
|
||||
{...formItemLayout}
|
||||
label="延时"
|
||||
>
|
||||
{getFieldDecorator('deplay', {
|
||||
initialValue: 0,
|
||||
rules: [{ required: true, message: '请输入延时时间!', type: 'integer' }]
|
||||
})(
|
||||
<Input placeholder="请输入延时时间" />
|
||||
)}
|
||||
</FormItem>
|
||||
{
|
||||
getFieldDecorator('headers', { initialValue: [] }) &&
|
||||
getFieldValue('headers').map((item, index) => (
|
||||
<div key={index}>
|
||||
<FormItem
|
||||
{...formItemLayout}
|
||||
label={index ? '' : 'HTTP 头'}
|
||||
>
|
||||
{getFieldDecorator(`headers[${index}].name`)(
|
||||
<Input />
|
||||
)}
|
||||
</FormItem>
|
||||
<FormItem
|
||||
{...formItemLayout}
|
||||
>
|
||||
{getFieldDecorator(`headers[${index}].value`)(
|
||||
<Input />
|
||||
)}
|
||||
</FormItem>
|
||||
</div>
|
||||
))
|
||||
}
|
||||
<FormItem>
|
||||
<Button type="dashed" onClick={this.add} style={{ width: '60%' }}>
|
||||
<Icon type="plus" /> 添加 HTTP 头
|
||||
</Button>
|
||||
</FormItem>
|
||||
|
||||
{
|
||||
getFieldDecorator('paramsArr', { initialValue: [] }) &&
|
||||
getFieldValue('paramsArr').map((item, index) => (
|
||||
<div key={index}>
|
||||
<FormItem
|
||||
label={index ? '' : '参数'}
|
||||
>
|
||||
{getFieldDecorator(`paramsArr[${index}].name`)(
|
||||
<Input />
|
||||
)}
|
||||
{getFieldValue('paramsArr').length > 1 ? (
|
||||
<Icon
|
||||
className="dynamic-delete-button"
|
||||
type="minus-circle-o"
|
||||
onClick={() => this.remove(index)}
|
||||
/>
|
||||
) : null}
|
||||
</FormItem>
|
||||
<FormItem
|
||||
>
|
||||
{getFieldDecorator(`paramsArr[${index}].value`)(
|
||||
<Input />
|
||||
)}
|
||||
{getFieldValue('paramsArr').length > 1 ? (
|
||||
<Icon
|
||||
className="dynamic-delete-button"
|
||||
type="minus-circle-o"
|
||||
onClick={() => this.remove(index)}
|
||||
/>
|
||||
) : null}
|
||||
</FormItem>
|
||||
</div>
|
||||
))
|
||||
}
|
||||
<FormItem>
|
||||
<Button type="dashed" onClick={this.add} style={{ width: '60%' }}>
|
||||
<Icon type="plus" /> 添加参数
|
||||
</Button>
|
||||
</FormItem>
|
||||
|
||||
<FormItem
|
||||
{...formItemLayout}
|
||||
label="返回 JSON"
|
||||
>
|
||||
{getFieldDecorator('res_body', {
|
||||
rules: [{ required: true, message: '请输入期望名称!' }]
|
||||
})(
|
||||
<Input placeholder="返回 JSON" />
|
||||
)}
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
}
|
106
exts/yapi-plugin-advanced-mock/MockCol/MockCol.js
Normal file
106
exts/yapi-plugin-advanced-mock/MockCol/MockCol.js
Normal file
@ -0,0 +1,106 @@
|
||||
import React, { Component } from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
// import axios from 'axios'
|
||||
import PropTypes from 'prop-types'
|
||||
import { withRouter } from 'react-router-dom';
|
||||
import { Table, Button } from 'antd';
|
||||
import { fetchMockCol } from '../../../client/reducer/modules/mockCol'
|
||||
import { formatTime } from '../../../client/common.js';
|
||||
import CaseDesModal from './CaseDesModal';
|
||||
|
||||
@connect(
|
||||
state => {
|
||||
return {
|
||||
list: state.mockCol.list
|
||||
}
|
||||
},
|
||||
{
|
||||
fetchMockCol
|
||||
}
|
||||
)
|
||||
@withRouter
|
||||
export default class MockCol extends Component {
|
||||
static propTypes = {
|
||||
list: PropTypes.array,
|
||||
match: PropTypes.object,
|
||||
fetchMockCol: PropTypes.func
|
||||
}
|
||||
|
||||
state = {
|
||||
caseData: {},
|
||||
caseDesModalVisible: false,
|
||||
isAdd: false
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
const interfaceId = this.props.match.params.actionId
|
||||
this.props.fetchMockCol(interfaceId);
|
||||
}
|
||||
|
||||
handleOk = (caseData) => {
|
||||
if (this.state.isAdd) {
|
||||
caseData = Object.assign({
|
||||
...caseData,
|
||||
interface_id: 0,
|
||||
project_id: 0,
|
||||
uid: 0
|
||||
})
|
||||
// addCase()
|
||||
} else {
|
||||
// saveCase()
|
||||
}
|
||||
console.log(caseData)
|
||||
}
|
||||
|
||||
saveFormRef = (form) => {
|
||||
this.form = form;
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
const data = this.props.list;
|
||||
const { isAdd, caseData, caseDesModalVisible } = this.state;
|
||||
|
||||
const columns = [{
|
||||
title: '期望名称',
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
render: text => <a href="#">{text}</a>
|
||||
}, {
|
||||
title: 'ip',
|
||||
dataIndex: 'ip',
|
||||
key: 'ip'
|
||||
}, {
|
||||
title: '创建人',
|
||||
dataIndex: 'username',
|
||||
key: 'username'
|
||||
}, {
|
||||
title: '编辑时间',
|
||||
key: 'action',
|
||||
render: text => formatTime(text)
|
||||
}, {
|
||||
title: '操作',
|
||||
dataIndex: 'address',
|
||||
key: 'address'
|
||||
}];
|
||||
|
||||
return (
|
||||
<div style={{ padding: '20px 10px' }}>
|
||||
<Button type="primary" onClick={() => this.setState({isAdd: true, caseDesModalVisible: true})}>添加期望</Button>
|
||||
<Table columns={columns} dataSource={data} />
|
||||
<CaseDesModal
|
||||
visible={caseDesModalVisible}
|
||||
isAdd={isAdd}
|
||||
caseData={caseData}
|
||||
onOk={this.handleOk}
|
||||
onCancel={() => this.setState({caseDesModalVisible: false})}
|
||||
ref={this.saveFormRef}
|
||||
></CaseDesModal>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
import AdvMock from './AdvMock.js'
|
||||
import AdvMock from './MockCol/MockCol.js'
|
||||
|
||||
module.exports = function(){
|
||||
this.bindHook('interface_tab', function(tabs){
|
||||
|
Loading…
Reference in New Issue
Block a user