| | |
| | | const MenuDesign = asyncLoadComponent(() => import('@/views/menudesign')) |
| | | const BillPrint = asyncLoadComponent(() => import('@/views/billprint')) |
| | | const PrintT = asyncLoadComponent(() => import('@/views/printTemplate')) |
| | | const Interface = asyncLoadComponent(() => import('@/views/interface')) |
| | | |
| | | const routers = [ |
| | | {path: '/login', name: 'login', component: Login, auth: false}, |
| | |
| | | {path: '/mobdesign/:param', name: 'mobdesign', component: MobDesign, auth: true}, |
| | | {path: '/menudesign/:param', name: 'menudesign', component: MenuDesign, auth: true}, |
| | | {path: '/billprint/:param', name: 'billprint', component: BillPrint, auth: true}, |
| | | {path: '/paramsmain/:param', name: 'pmain', component: Main, auth: true} |
| | | {path: '/paramsmain/:param', name: 'pmain', component: Main, auth: true}, |
| | | {path: '/interface', name: 'interface', component: Interface, auth: true} |
| | | ] |
| | | |
| | | export default class RouteConfig extends Component { |
| | |
| | | return ( |
| | | <HashRouter> |
| | | <Switch> |
| | | { |
| | | routers.map((item, index) => { |
| | | {routers.map((item, index) => { |
| | | return ( |
| | | <Route key={index} path={item.path} name={item.name} exact render={ props => { |
| | | return this.controlRoute(item, props) |
| | | }}/> |
| | | <Route key={index} path={item.path} name={item.name} exact render={ props => this.controlRoute(item, props)}/> |
| | | ) |
| | | }) |
| | | } |
| | | })} |
| | | <Redirect exact from="/" to="login"/> |
| | | <Route component= {NotFound}/> |
| | | </Switch> |
| | |
| | | const Header = asyncComponent(() => import('@/mob/header')) |
| | | const MutilForm = asyncComponent(() => import('./mutilform')) |
| | | const TransForm = asyncComponent(() => import('./transform')) |
| | | const ScriptForm = asyncComponent(() => import('./scriptform')) |
| | | const SubMutilForm = asyncComponent(() => import('./submutilform')) |
| | | |
| | | let base_url = '' |
| | |
| | | title: '操作', |
| | | key: 'action', |
| | | align: 'center', |
| | | width: '230px', |
| | | render: (text, record) => ( |
| | | <div> |
| | | <Button type="link" onClick={() => this.setState({ selectTran: record, transVisible: 'edit' })} style={{color: '#8E44AD'}}>修改</Button> |
| | | <div onClick={() => this.forbid = true}> |
| | | <Button type="link" onClick={() => this.setState({ editTran: record, transVisible: 'edit' })} style={{color: '#8E44AD'}}>修改</Button> |
| | | <Button type="link" onClick={() => this.deleteTran(record)} style={{color: '#ff4d4f'}}>删除</Button> |
| | | <Button type="link" onClick={() => this.enableTran(record)} style={{color: '#26C281'}}>启用</Button> |
| | | </div> |
| | |
| | | translist: [], |
| | | tranSearchKey: '', |
| | | selectTran: null, |
| | | editTran: null, |
| | | transIndex: 1, |
| | | transTotal: 0 |
| | | transTotal: 0, |
| | | scriptcolumns: [ |
| | | { title: '关键字', dataIndex: 'KeyWords', key: 'KeyWords', align: 'left' }, |
| | | { title: '描述', dataIndex: 'Remark', key: 'Remark', align: 'left' }, |
| | | { title: '类型', dataIndex: 'TypeName', key: 'TypeName', align: 'left' }, |
| | | { title: '排序', dataIndex: 'Sort', key: 'Sort', align: 'left' }, |
| | | ], |
| | | scriptVisible: false, |
| | | scriptlist: [], |
| | | scriptSearchKey: '', |
| | | scriptIndex: 1, |
| | | scriptTotal: 0, |
| | | } |
| | | |
| | | forbid = false |
| | | |
| | | UNSAFE_componentWillMount() { |
| | | document.body.className = '' |
| | |
| | | if (result.status) { |
| | | this.setState({ |
| | | loading: false, |
| | | translist: result.data |
| | | translist: result.data, |
| | | selectTran: null, |
| | | scriptlist: [], |
| | | transTotal: result.total |
| | | }) |
| | | } else { |
| | | this.setState({ |
| | |
| | | }) |
| | | } |
| | | |
| | | getScriptList = () => { |
| | | const { scriptSearchKey, scriptIndex, selectTran } = this.state |
| | | |
| | | if (!selectTran || !selectTran.ID) { |
| | | notification.warning({ |
| | | top: 92, |
| | | message: '缺少传输号ID!', |
| | | duration: 3 |
| | | }) |
| | | return |
| | | } |
| | | |
| | | let param = { |
| | | func: 's_get_sVersionDetail', |
| | | dataM: 'Y', |
| | | PageSize: 10, |
| | | PageIndex: scriptIndex, |
| | | OrderCol: 'Sort desc', |
| | | BID: selectTran.ID, |
| | | } |
| | | |
| | | if (scriptSearchKey) { |
| | | param.TypeName = scriptSearchKey |
| | | param.KeyWords = scriptSearchKey |
| | | param.Remark = scriptSearchKey |
| | | } |
| | | |
| | | this.setState({ |
| | | loading: true |
| | | }) |
| | | |
| | | Api.getCloudConfig(param).then(result => { |
| | | if (result.status) { |
| | | this.setState({ |
| | | loading: false, |
| | | scriptlist: result.data, |
| | | scriptTotal: result.total, |
| | | selectScriptKeys: [] |
| | | }) |
| | | } else { |
| | | this.setState({ |
| | | loading: false |
| | | }) |
| | | notification.warning({ |
| | | top: 92, |
| | | message: result.message, |
| | | duration: 5 |
| | | }) |
| | | } |
| | | }) |
| | | } |
| | | |
| | | scriptSearch = (value) => { |
| | | this.setState({scriptSearchKey: value, scriptIndex: 1}, () => { |
| | | this.getScriptList() |
| | | }) |
| | | } |
| | | |
| | | changeScriptTable = (pagination) => { |
| | | this.setState({ |
| | | scriptIndex: pagination.current |
| | | }, () => { |
| | | this.getScriptList() |
| | | }) |
| | | } |
| | | |
| | | changeTable = (pagination) => { |
| | | this.setState({ |
| | | transIndex: pagination.current |
| | |
| | | } |
| | | |
| | | tranSearch = (value) => { |
| | | this.setState({tranSearchKey: value}, () => { |
| | | this.setState({tranSearchKey: value, transIndex: 1}, () => { |
| | | this.getTransList() |
| | | }) |
| | | } |
| | | |
| | | submitTrans = () => { |
| | | const { transVisible, selectTran } = this.state |
| | | const { transVisible, editTran } = this.state |
| | | |
| | | this.transRef.handleConfirm().then(res => { |
| | | this.setState({ |
| | |
| | | } else { |
| | | param.func = 's_sVersion_upt' |
| | | param.ProgramName = res.ProgramName |
| | | param.ID = selectTran.ID |
| | | param.ID = editTran.ID |
| | | } |
| | | |
| | | Api.getCloudConfig(param).then(result => { |
| | |
| | | }) |
| | | } |
| | | |
| | | submitScript = () => { |
| | | // const { selectTran } = this.state |
| | | |
| | | this.scriptRef.handleConfirm().then(res => { |
| | | this.setState({ |
| | | confirmloading: true |
| | | }) |
| | | // let param = {} |
| | | // s_sVersionDetail_Add |
| | | // s_sVersionDetail_CloudAdd |
| | | |
| | | // Api.getCloudConfig(param).then(result => { |
| | | // if (result.status) { |
| | | // notification.success({ |
| | | // top: 92, |
| | | // message: '操作成功!', |
| | | // duration: 3 |
| | | // }) |
| | | // this.setState({ |
| | | // scriptIndex: 1, |
| | | // confirmloading: false, |
| | | // scriptVisible: false |
| | | // }, () => { |
| | | // this.getScriptList() |
| | | // }) |
| | | // } else { |
| | | // this.setState({ |
| | | // confirmloading: false |
| | | // }) |
| | | // notification.warning({ |
| | | // top: 92, |
| | | // message: result.message, |
| | | // duration: 5 |
| | | // }) |
| | | // } |
| | | // }, () => { |
| | | // this.setState({ |
| | | // confirmloading: false |
| | | // }) |
| | | // }) |
| | | }) |
| | | } |
| | | |
| | | deleteTran = (record) => { |
| | | const _this = this |
| | | |
| | |
| | | top: 92, |
| | | message: '操作成功!', |
| | | duration: 3 |
| | | }) |
| | | |
| | | _this.setState({ |
| | | selectTran: null, |
| | | }) |
| | | _this.getTransList() |
| | | } else { |
| | |
| | | top: 92, |
| | | message: '操作成功!', |
| | | duration: 3 |
| | | }) |
| | | |
| | | _this.setState({ |
| | | selectTran: record, |
| | | }) |
| | | _this.getTransList() |
| | | } else { |
| | |
| | | |
| | | return item |
| | | }) |
| | | |
| | | if (!selectApp && applist[0]) { |
| | | selectApp = applist[0] |
| | | } |
| | | |
| | | this.setState({ |
| | | loading: false, |
| | |
| | | this.setState({ selectApp }) |
| | | } |
| | | |
| | | onTransChange = selectedRowKeys => { |
| | | const { translist } = this.state |
| | | let selectTran = translist.filter(item => item.ID === selectedRowKeys[0])[0] |
| | | onScriptChange = selectedRowKeys => { |
| | | this.setState({ selectScriptKeys: selectedRowKeys }) |
| | | } |
| | | |
| | | this.setState({ selectTran }) |
| | | onScriptSelect = (record) => { |
| | | const { selectScriptKeys } = this.state |
| | | |
| | | if (selectScriptKeys.includes(record.ID)) { |
| | | this.setState({ selectScriptKeys: selectScriptKeys.filter(key => key !== record.ID) }) |
| | | } else { |
| | | this.setState({ selectScriptKeys: [...selectScriptKeys, record.ID]}) |
| | | } |
| | | } |
| | | |
| | | deleteScripts = () => { |
| | | const { selectScriptKeys, selectTran } = this.state |
| | | |
| | | if (selectScriptKeys.length === 0) { |
| | | notification.warning({ |
| | | top: 92, |
| | | message: '请选择要删除的脚本!', |
| | | duration: 3 |
| | | }) |
| | | return |
| | | } |
| | | |
| | | let params = selectScriptKeys.map(key => { |
| | | return { |
| | | func: 's_sVersionDetail_del', |
| | | BID: selectTran.ID, |
| | | ID: key |
| | | } |
| | | }) |
| | | |
| | | const _this = this |
| | | |
| | | confirm({ |
| | | content: '确定要执行吗?', |
| | | onOk() { |
| | | return new Promise(resolve => { |
| | | let deffers = params.map((param, i) => { |
| | | return new Promise(resolve => { |
| | | setTimeout(() => { |
| | | Api.getCloudConfig(param).then(res => { |
| | | resolve(res) |
| | | }, () => { |
| | | resolve({status: false, message: '删除失败!'}) |
| | | }) |
| | | }, i * 150) |
| | | }) |
| | | }) |
| | | Promise.all(deffers).then(result => { |
| | | let errorMsg = '' |
| | | result.forEach(res => { |
| | | if (!res.status) { |
| | | errorMsg = res.message |
| | | } |
| | | }) |
| | | if (errorMsg) { |
| | | notification.warning({ |
| | | top: 92, |
| | | message: errorMsg, |
| | | duration: 3 |
| | | }) |
| | | } else { |
| | | notification.success({ |
| | | top: 92, |
| | | message: '执行成功。', |
| | | duration: 3 |
| | | }) |
| | | _this.setState({ |
| | | scriptIndex: 1 |
| | | }, () => { |
| | | _this.getScriptList() |
| | | }) |
| | | } |
| | | resolve() |
| | | }) |
| | | }) |
| | | }, |
| | | onCancel() {} |
| | | }) |
| | | } |
| | | |
| | | onTransChange = selectedRowKeys => { |
| | | const { translist, selectTran } = this.state |
| | | let _selectTran = translist.filter(item => item.ID === selectedRowKeys[0])[0] |
| | | |
| | | this.setState({ selectTran: _selectTran }) |
| | | |
| | | if (!selectTran || selectTran.ID !== _selectTran.ID) { |
| | | this.setState({ scriptIndex: 1 }, () => { |
| | | this.getScriptList() |
| | | }) |
| | | } |
| | | } |
| | | |
| | | onTransSelect = (record) => { |
| | | const { selectTran } = this.state |
| | | |
| | | this.setState({ selectTran: record }) |
| | | |
| | | if (!selectTran || selectTran.ID !== record.ID) { |
| | | this.setState({ scriptIndex: 1 }, () => { |
| | | this.getScriptList() |
| | | }) |
| | | } |
| | | } |
| | | |
| | | /** |
| | |
| | | } |
| | | |
| | | render () { |
| | | const { loading, visible, subVisible, columns, transcolumns, applist, translist, transVisible, selectApp, selectTran, selectSubApp } = this.state |
| | | const { loading, visible, subVisible, columns, transcolumns, applist, translist, transVisible, selectApp, selectTran, selectSubApp, scriptVisible, scriptlist, scriptcolumns, selectScriptKeys } = this.state |
| | | |
| | | return ( |
| | | <div className="mk-app-manage"> |
| | |
| | | <Header view="manage" /> |
| | | {loading ? |
| | | <div className="loading-mask"> |
| | | <div className="ant-spin-blur"></div> |
| | | <Spin /> |
| | | <Spin size="large" /> |
| | | </div> : null |
| | | } |
| | | <div className="view-wrap"> |
| | |
| | | pagination={{ |
| | | current: this.state.transIndex, |
| | | pageSize: 10, |
| | | total: this.state.transTotal || 0 |
| | | total: this.state.transTotal || 0, |
| | | showTotal: (total, range) => `${range[0]}-${range[1]} 共 ${total} 条` |
| | | }} |
| | | rowSelection={{ type: 'radio', selectedRowKeys: selectTran ? [selectTran.ID] : [], onChange: this.onTransChange }} |
| | | onRow={(record) => ({ onClick: () => this.setState({ selectTran: record })})} |
| | | onRow={(record) => ({ onClick: () => { |
| | | if (this.forbid) { |
| | | this.forbid = false |
| | | return |
| | | } |
| | | this.onTransSelect(record) |
| | | }})} |
| | | onChange={this.changeTable} |
| | | /> |
| | | </div> |
| | | {/* <div className={'script-table' + (this.state.transTotal <= 10 ? ' no-footer' : '')}> |
| | | {selectTran ? <div className="script-table"> |
| | | <div className="app-action"> |
| | | <Button className="mk-green" onClick={() => this.setState({ scriptVisible: 'plus' })}>添加脚本</Button> |
| | | <Search placeholder="综合搜索" onSearch={value => this.scriptSearch(value)} enterButton /> |
| | | <Button className="mk-green" onClick={() => this.setState({ scriptVisible: true })}>添加脚本</Button> |
| | | <Button className="mk-danger" onClick={this.deleteScripts} style={{marginLeft: '15px'}}>删除</Button> |
| | | <Search placeholder="综合搜索" defaultValue={this.state.scriptSearchKey} onSearch={value => this.scriptSearch(value)} enterButton /> |
| | | </div> |
| | | <Table |
| | | rowKey="ID" |
| | | columns={transcolumns} |
| | | dataSource={translist} |
| | | columns={scriptcolumns} |
| | | dataSource={scriptlist} |
| | | pagination={{ |
| | | current: this.state.transIndex, |
| | | current: this.state.scriptIndex, |
| | | pageSize: 10, |
| | | total: this.state.transTotal || 0 |
| | | total: this.state.scriptTotal || 0, |
| | | showTotal: (total, range) => `${range[0]}-${range[1]} 共 ${total} 条` |
| | | }} |
| | | rowSelection={{ type: 'radio', selectedRowKeys: selectTran ? [selectTran.ID] : [], onChange: this.onTransChange }} |
| | | onRow={(record) => ({ onClick: () => this.setState({ selectTran: record })})} |
| | | onChange={this.changeTable} |
| | | rowSelection={{ type: 'checkbox', selectedRowKeys: selectScriptKeys, onChange: this.onScriptChange }} |
| | | onRow={(record) => ({ onClick: () => this.onScriptSelect(record)})} |
| | | onChange={this.changeScriptTable} |
| | | /> |
| | | </div> */} |
| | | </div> : null} |
| | | </div> |
| | | <div className="right-view"> |
| | | {selectApp ? <div className="app-title">{selectApp.remark}</div> : null} |
| | |
| | | title={'编辑应用'} |
| | | width={'600px'} |
| | | maskClosable={false} |
| | | visible={!!visible} |
| | | onCancel={() => this.setState({visible: false})} |
| | | visible={visible !== false} |
| | | onCancel={() => this.setState({visible: false, confirmloading: false})} |
| | | confirmLoading={this.state.confirmloading} |
| | | onOk={this.submitCard} |
| | | cancelText="取消" |
| | |
| | | title={transVisible === 'plus' ? '添加传输号' : '编辑传输号'} |
| | | width={'600px'} |
| | | maskClosable={false} |
| | | visible={!!transVisible} |
| | | onCancel={() => this.setState({transVisible: false})} |
| | | visible={transVisible !== false} |
| | | onCancel={() => this.setState({transVisible: false, confirmloading: false})} |
| | | confirmLoading={this.state.confirmloading} |
| | | onOk={this.submitTrans} |
| | | cancelText="取消" |
| | | okText="确定" |
| | | destroyOnClose |
| | | > |
| | | <TransForm type={transVisible} card={transVisible === 'edit' ? selectTran : ''} wrappedComponentRef={(inst) => this.transRef = inst} inputSubmit={this.submitTrans} /> |
| | | <TransForm type={transVisible} card={transVisible === 'edit' ? this.state.editTran : ''} wrappedComponentRef={(inst) => this.transRef = inst} inputSubmit={this.submitTrans} /> |
| | | </Modal> |
| | | <Modal |
| | | title={'添加脚本'} |
| | | width={750} |
| | | maskClosable={false} |
| | | visible={scriptVisible} |
| | | onCancel={() => this.setState({scriptVisible: false, confirmloading: false})} |
| | | confirmLoading={this.state.confirmloading} |
| | | onOk={this.submitScript} |
| | | cancelText="取消" |
| | | okText="确定" |
| | | destroyOnClose |
| | | > |
| | | <ScriptForm applist={applist} wrappedComponentRef={(inst) => this.scriptRef = inst} inputSubmit={this.submitScript} /> |
| | | </Modal> |
| | | <Modal |
| | | title={'编辑子应用'} |
| | | width={'850px'} |
| | | maskClosable={false} |
| | | visible={!!subVisible} |
| | | onCancel={() => this.setState({subVisible: false})} |
| | | visible={subVisible !== false} |
| | | onCancel={() => this.setState({subVisible: false, confirmloading: false})} |
| | | confirmLoading={this.state.confirmloading} |
| | | onOk={this.submitSubCard} |
| | | cancelText="取消" |
| | |
| | | min-height: 100vh; |
| | | padding: 70px 30px; |
| | | |
| | | .loading-mask { |
| | | position: fixed; |
| | | top: 0px; |
| | | bottom: 0px; |
| | | left: 0px; |
| | | right: 0px; |
| | | z-index: 2; |
| | | background: rgba(255, 255, 255, 0.35); |
| | | |
| | | .ant-spin { |
| | | position: absolute; |
| | | left: 50%; |
| | | top: 50%; |
| | | } |
| | | } |
| | | .mob-header-container { |
| | | padding-right: 0px; |
| | | z-index: 10; |
| | |
| | | flex: 1; |
| | | width: 60%; |
| | | padding-right: 5px; |
| | | .trans-table { |
| | | margin-top: 30px; |
| | | .trans-table, .script-table { |
| | | margin-top: 40px; |
| | | .ant-input-search { |
| | | width: 250px; |
| | | float: right; |
New file |
| | |
| | | import React, {Component} from 'react' |
| | | import PropTypes from 'prop-types' |
| | | import { Form, Row, Col, Input, Select, notification } from 'antd' |
| | | import moment from 'moment' |
| | | |
| | | import Api from '@/api' |
| | | import Utils from '@/utils/utils.js' |
| | | import './index.scss' |
| | | |
| | | const { TextArea } = Input |
| | | |
| | | class ScriptForm extends Component { |
| | | static propTpyes = { |
| | | applist: PropTypes.array, |
| | | inputSubmit: PropTypes.func |
| | | } |
| | | |
| | | state = { |
| | | type: 'subapp', |
| | | sublist: [], |
| | | views: [], |
| | | appId: '', |
| | | subAppId: '' |
| | | } |
| | | |
| | | viewList = {} |
| | | |
| | | UNSAFE_componentWillMount() { |
| | | const { applist } = this.props |
| | | |
| | | let sublist = [] |
| | | let appId = '' |
| | | let subAppId = '' |
| | | if (applist[0]) { |
| | | sublist = applist[0].sublist || [] |
| | | appId = applist[0].ID + ',' + applist[0].kei_no |
| | | |
| | | if (sublist[0]) { |
| | | subAppId = sublist[0].ID + ',' + sublist[0].lang + ',' + sublist[0].typename |
| | | } |
| | | } |
| | | |
| | | this.viewList = {} |
| | | |
| | | this.setState({sublist, appId, subAppId}) |
| | | } |
| | | |
| | | /** |
| | | * @description 获取表单值 |
| | | */ |
| | | handleConfirm = () => { |
| | | return new Promise(resolve => { |
| | | this.props.form.validateFieldsAndScroll((err, values) => { |
| | | if (!err) { |
| | | resolve(values) |
| | | } |
| | | }) |
| | | }) |
| | | } |
| | | |
| | | changeType = (val) => { |
| | | this.setState({type: val}, () => { |
| | | this.getViews() |
| | | }) |
| | | } |
| | | |
| | | changeApp = (val) => { |
| | | const { applist } = this.props |
| | | |
| | | let app = applist.filter(item => `${item.ID},${item.kei_no}` === val)[0] |
| | | |
| | | let appId = '' |
| | | let subAppId = '' |
| | | let sublist = [] |
| | | if (app) { |
| | | sublist = app.sublist || [] |
| | | appId = app.ID + ',' + app.kei_no |
| | | |
| | | if (sublist[0]) { |
| | | subAppId = sublist[0].ID + ',' + sublist[0].lang + ',' + sublist[0].typename |
| | | } |
| | | } |
| | | |
| | | this.setState({sublist, subAppId, appId}, () => { |
| | | this.getViews() |
| | | }) |
| | | this.props.form.setFieldsValue({subAppId}) |
| | | } |
| | | |
| | | changeSubApp = (val) => { |
| | | this.setState({subAppId: val}, () => { |
| | | this.getViews() |
| | | }) |
| | | } |
| | | |
| | | getViews = () => { |
| | | const { type, appId, subAppId } = this.state |
| | | |
| | | if (type !== 'view' || !appId || !subAppId) return |
| | | |
| | | this.setState({views: []}) |
| | | this.props.form.setFieldsValue({viewId: ''}) |
| | | |
| | | let kei = appId.split(',')[1] |
| | | let m = subAppId.split(',') |
| | | |
| | | let _param = { |
| | | func: 's_get_app_menus', |
| | | TypeCharOne: kei, |
| | | typename: m[2], |
| | | lang: m[1], |
| | | LText: `select '${window.GLOB.appkey}'`, |
| | | timestamp: moment().format('YYYY-MM-DD HH:mm:ss') |
| | | } |
| | | |
| | | _param.secretkey = Utils.encrypt(_param.LText, _param.timestamp) |
| | | |
| | | Api.getCloudConfig(_param).then(res => { |
| | | if (!res.status) { |
| | | notification.warning({ |
| | | top: 92, |
| | | message: res.message, |
| | | duration: 5 |
| | | }) |
| | | return |
| | | } |
| | | |
| | | this.setState({views: res.menus}) |
| | | }) |
| | | } |
| | | |
| | | /** |
| | | * @description 回车提交 |
| | | */ |
| | | handleSubmit = (e) => { |
| | | e.preventDefault() |
| | | this.props.inputSubmit() |
| | | } |
| | | |
| | | render() { |
| | | const { applist } = this.props |
| | | const { getFieldDecorator } = this.props.form |
| | | const { sublist, appId, subAppId, type, views } = this.state |
| | | const formItemLayout = { |
| | | labelCol: { |
| | | xs: { span: 24 }, |
| | | sm: { span: 8 } |
| | | }, |
| | | wrapperCol: { |
| | | xs: { span: 24 }, |
| | | sm: { span: 16 } |
| | | } |
| | | } |
| | | return ( |
| | | <Form {...formItemLayout} className="app-script-form"> |
| | | <Row gutter={24}> |
| | | <Col span={12}> |
| | | <Form.Item label="类型"> |
| | | {getFieldDecorator('VType', { |
| | | initialValue: 'subapp', |
| | | rules: [{ |
| | | required: true, |
| | | message: '请选择类型!' |
| | | }] |
| | | })( |
| | | <Select onChange={this.changeType}> |
| | | <Select.Option value="subapp">子应用</Select.Option> |
| | | <Select.Option value="view">页面</Select.Option> |
| | | </Select> |
| | | )} |
| | | </Form.Item> |
| | | </Col> |
| | | <Col span={12}> |
| | | <Form.Item label="应用"> |
| | | {getFieldDecorator('appId', { |
| | | initialValue: appId, |
| | | rules: [{ |
| | | required: true, |
| | | message: '请选择应用!' |
| | | }] |
| | | })( |
| | | <Select onChange={this.changeApp}> |
| | | {applist.map(item => { |
| | | return <Select.Option key={item.ID} value={item.ID + ',' + item.kei_no}>{item.remark}</Select.Option> |
| | | })} |
| | | </Select> |
| | | )} |
| | | </Form.Item> |
| | | </Col> |
| | | <Col span={12}> |
| | | <Form.Item label="子应用"> |
| | | {getFieldDecorator('subAppId', { |
| | | initialValue: subAppId, |
| | | rules: [{ |
| | | required: true, |
| | | message: '请选择子应用!' |
| | | }] |
| | | })( |
| | | <Select onChange={this.changeSubApp}> |
| | | {sublist.map(item => { |
| | | return <Select.Option key={item.ID} value={item.ID + ',' + item.lang + ',' + item.typename}>{`${item.typename}(${item.lang !== 'zh-CN' ? '英文' : '中文'})${item.title || ''}`}</Select.Option> |
| | | })} |
| | | </Select> |
| | | )} |
| | | </Form.Item> |
| | | </Col> |
| | | {type === 'view' ? <Col span={12}> |
| | | <Form.Item label="页面"> |
| | | {getFieldDecorator('viewId', { |
| | | initialValue: '', |
| | | rules: [{ |
| | | required: true, |
| | | message: '请选择页面!' |
| | | }] |
| | | })( |
| | | <Select> |
| | | {views.map(item => { |
| | | return <Select.Option key={item.MenuID} value={item.MenuID}>{item.MenuName}</Select.Option> |
| | | })} |
| | | </Select> |
| | | )} |
| | | </Form.Item> |
| | | </Col> : null} |
| | | <Col span={24} className="remark"> |
| | | <Form.Item label="说明"> |
| | | {getFieldDecorator('Remark', { |
| | | initialValue: '', |
| | | rules: [{ |
| | | max: 512, |
| | | message: '说明不可超过512个字符!' |
| | | }] |
| | | })(<TextArea autoSize={{ minRows: 2, maxRows: 6 }} />)} |
| | | </Form.Item> |
| | | </Col> |
| | | </Row> |
| | | </Form> |
| | | ) |
| | | } |
| | | } |
| | | |
| | | export default Form.create()(ScriptForm) |
New file |
| | |
| | | .app-script-form { |
| | | padding: 0px 24px 20px; |
| | | |
| | | .remark { |
| | | .ant-form-item-label { |
| | | width: 16%; |
| | | } |
| | | .ant-form-item-control-wrapper { |
| | | width: 84%; |
| | | } |
| | | } |
| | | } |
| | |
| | | import { withRouter } from 'react-router-dom' |
| | | import {connect} from 'react-redux' |
| | | import { is, fromJS } from 'immutable' |
| | | import { Dropdown, Menu, Icon, Modal, Form, notification, Switch, Button } from 'antd' |
| | | import { Dropdown, Menu, Icon, Modal, notification, Switch, Button } from 'antd' |
| | | |
| | | import asyncComponent from '@/utils/asyncComponent' |
| | | import { |
| | |
| | | {!editLevel && options.sysType === 'local' && window.GLOB.systemType !== 'production' && this.props.memberLevel >= 20 ? |
| | | <span onClick={() => {window.open('#/appmanage')}} className="mobile" type="edit"> 应用管理 <Icon type="arrow-right" /></span> : null |
| | | } |
| | | {!editLevel && options.sysType === 'local' && this.props.memberLevel >= 20 ? |
| | | <span onClick={() => {window.open('#/interface')}} className="interface" type="edit"> 接口调试 <Icon type="arrow-right" /></span> : null |
| | | } |
| | | {/* window.btoa(window.encodeURIComponent(JSON.stringify({ MenuType: 'home', MenuId: 'home_page_id', MenuName: '首页' }))) */} |
| | | {!editLevel && window.GLOB.systemType !== 'production' && this.props.memberLevel >= 20 ? |
| | | <span className="home-edit" onClick={() => {window.open('#/menudesign/JTdCJTIyTWVudVR5cGUlMjIlM0ElMjJob21lJTIyJTJDJTIyTWVudUlkJTIyJTNBJTIyaG9tZV9wYWdlX2lkJTIyJTJDJTIyTWVudU5hbWUlMjIlM0ElMjIlRTklQTYlOTYlRTklQTElQjUlMjIlN0Q=')}}> |
| | |
| | | } |
| | | } |
| | | |
| | | export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Form.create()(Header))) |
| | | export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Header)) |
| | |
| | | color: #1890ff; |
| | | cursor: pointer; |
| | | } |
| | | .interface { |
| | | position: absolute; |
| | | top: 170px; |
| | | right: 50px; |
| | | color: #1890ff; |
| | | cursor: pointer; |
| | | } |
| | | .home-edit { |
| | | position: absolute; |
| | | top: 100px; |
New file |
| | |
| | | import axios from 'axios' |
| | | import md5 from 'md5' |
| | | import jsSHA from 'jssha' |
| | | import { notification } from 'antd' |
| | | |
| | | window.GLOB.WebSql = null |
| | | |
| | | if (window.openDatabase) { |
| | | let service = window.GLOB.service ? '-' + window.GLOB.service.replace('/', '') : '' |
| | | try { |
| | | window.GLOB.WebSql = openDatabase(`mkdb${service}`, '1', 'mk-pc-database', 50 * 1024 * 1024) |
| | | window.GLOB.WebSql.transaction(tx => { |
| | | tx.executeSql('CREATE TABLE IF NOT EXISTS INTERFACES (uuid varchar(50), createDate varchar(50), method varchar(50), interface text, params text, headers text, active varchar(50), raw text, formData text, CDefine1 varchar(50), CDefine2 varchar(50), CDefine3 varchar(50), CDefine4 varchar(50), CDefine5 text)', [], () => { |
| | | |
| | | }, () => { |
| | | // eslint-disable-next-line |
| | | throw 'CREATE TABLE ERROR' |
| | | }) |
| | | }) |
| | | } catch (e) { |
| | | console.warn('WebSql 初始化失败!') |
| | | window.GLOB.WebSql = null |
| | | } |
| | | } |
| | | |
| | | axios.defaults.crossDomain = true |
| | | axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8' |
| | | axios.defaults.withCredentials = false |
| | | |
| | | axios.interceptors.request.use((config) => { |
| | | return config |
| | | }, (error) => { |
| | | return Promise.reject(error) |
| | | }) |
| | | |
| | | axios.interceptors.response.use((response) => { |
| | | return Promise.resolve(response) |
| | | }, (error) => { |
| | | return Promise.reject(error) |
| | | }) |
| | | |
| | | class Api { |
| | | /** |
| | | * @description 登录系统, 获取用户信息 |
| | | */ |
| | | dologon (url, method, header, n) { |
| | | let config = { |
| | | url, |
| | | method |
| | | } |
| | | |
| | | if (header) { |
| | | config.headers = header |
| | | } |
| | | |
| | | if (n) { |
| | | let _param = JSON.parse(n) |
| | | let param = {} |
| | | |
| | | Object.keys(_param).forEach(key => { |
| | | param[key.toLowerCase()] = _param[key] |
| | | }) |
| | | |
| | | if (param.type && param.username && param.password && param.timestamp) { |
| | | if (param.type === 'S') { |
| | | let shaObj = new jsSHA('SHA-1', 'TEXT') |
| | | shaObj.update(param.password) |
| | | param.password = shaObj.getHash('HEX').toUpperCase() |
| | | param.password = md5(param.username + param.password + param.timestamp) |
| | | } else if (/^mk_/ig.test(param.type)) { |
| | | let shaObj = new jsSHA('SHA-1', 'TEXT') |
| | | shaObj.update(param.password) |
| | | param.password = shaObj.getHash('HEX').toUpperCase() |
| | | param.password = md5(param.privatekey + param.username + param.password + param.timestamp) |
| | | |
| | | delete param.privatekey |
| | | } |
| | | } |
| | | |
| | | config.data = JSON.stringify(param) |
| | | } |
| | | |
| | | return axios(config) |
| | | } |
| | | |
| | | /** |
| | | * @description 通用请求 |
| | | */ |
| | | normalRequest (url, method, header, n) { |
| | | let config = { |
| | | url, |
| | | method |
| | | } |
| | | |
| | | if (header) { |
| | | config.headers = header |
| | | } |
| | | if (n) { |
| | | config.data = n |
| | | } |
| | | |
| | | return axios(config) |
| | | } |
| | | |
| | | writeInWebSql (data) { |
| | | if (!window.GLOB.WebSql) { |
| | | notification.warning({ top: 92, message: 'WebSql开启失败!', duration: 5 }) |
| | | return |
| | | } |
| | | return new Promise((resolve, reject) => { |
| | | window.GLOB.WebSql.transaction(tx => { |
| | | tx.executeSql(`INSERT INTO INTERFACES (uuid, createDate, method, interface, params, headers, active, raw, formData) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, data, (tx, results) => { |
| | | resolve(results) |
| | | }, () => { |
| | | resolve() |
| | | }) |
| | | }) |
| | | }) |
| | | } |
| | | |
| | | getInterfaces () { |
| | | if (!window.GLOB.WebSql) { |
| | | notification.warning({ top: 92, message: 'WebSql开启失败!', duration: 5 }) |
| | | return |
| | | } |
| | | return new Promise((resolve, reject) => { |
| | | window.GLOB.WebSql.transaction(tx => { |
| | | tx.executeSql(`SELECT * FROM INTERFACES`, [], (tx, results) => { |
| | | // let paramItem = results.rows[0] |
| | | resolve(results) |
| | | }, () => { |
| | | window.GLOB.WebSql = null |
| | | reject() |
| | | }) |
| | | }) |
| | | }) |
| | | } |
| | | |
| | | delInterface (uuid) { |
| | | if (!window.GLOB.WebSql) { |
| | | notification.warning({ top: 92, message: 'WebSql开启失败!', duration: 5 }) |
| | | return |
| | | } |
| | | return new Promise((resolve, reject) => { |
| | | window.GLOB.WebSql.transaction(tx => { |
| | | tx.executeSql(`DELETE FROM INTERFACES where uuid = '${uuid}'`, [], (tx, results) => { |
| | | resolve(results) |
| | | }, () => { |
| | | resolve() |
| | | }) |
| | | }) |
| | | }) |
| | | } |
| | | |
| | | /** |
| | | * @description 清空接口调用记录 |
| | | */ |
| | | clearInterfaces () { |
| | | if (!window.GLOB.WebSql) { |
| | | notification.warning({ top: 92, message: 'WebSql开启失败!', duration: 5 }) |
| | | return |
| | | } |
| | | return new Promise((resolve, reject) => { |
| | | window.GLOB.WebSql.transaction(tx => { |
| | | tx.executeSql(`DELETE FROM INTERFACES`, [], (tx, results) => { |
| | | resolve(results) |
| | | }, () => { |
| | | resolve() |
| | | }) |
| | | }) |
| | | }) |
| | | } |
| | | } |
| | | |
| | | export default new Api() |
New file |
| | |
| | | import React, {Component} from 'react' |
| | | import { withRouter } from 'react-router-dom' |
| | | |
| | | import Utils from '@/utils/utils.js' |
| | | import options from '@/store/options.js' |
| | | import avatar from '@/assets/img/avatar.jpg' |
| | | import MainLogo from '@/assets/img/main-logo.png' |
| | | import './index.scss' |
| | | |
| | | class Header extends Component { |
| | | state = { |
| | | userName: sessionStorage.getItem('CloudUserName'), |
| | | avatar: Utils.getrealurl(sessionStorage.getItem('CloudAvatar')), |
| | | } |
| | | |
| | | UNSAFE_componentWillMount() { |
| | | if (options.sysType !== 'local' || !sessionStorage.getItem('LoginUID')) { |
| | | sessionStorage.clear() |
| | | this.props.history.replace('/login') |
| | | } |
| | | } |
| | | |
| | | close = () => { |
| | | window.close() |
| | | } |
| | | |
| | | render () { |
| | | |
| | | return ( |
| | | <header className="interface-header-container"> |
| | | <div className="header-logo"><img src={MainLogo} alt=""/></div> |
| | | <div className="title">接口调试</div> |
| | | <div className="header-setting"> |
| | | <span className="close" onClick={this.close}>关闭</span> |
| | | <img src={this.state.avatar || avatar} alt=""/> |
| | | <span> |
| | | <span className="username">{this.state.userName}</span> |
| | | </span> |
| | | </div> |
| | | </header> |
| | | ) |
| | | } |
| | | } |
| | | |
| | | export default withRouter(Header) |
New file |
| | |
| | | .interface-header-container { |
| | | position: fixed; |
| | | z-index: 20; |
| | | left: 0; |
| | | top: 0; |
| | | font-weight: bold!important; |
| | | width: 100%; |
| | | height: 48px; |
| | | background: #000; |
| | | |
| | | .header-logo { |
| | | float: left; |
| | | width: 180px; |
| | | line-height: 48px; |
| | | text-align: center; |
| | | padding-left: 5px; |
| | | box-sizing: border-box; |
| | | opacity: 1; |
| | | img { |
| | | max-width: 100%; |
| | | max-height: 40px; |
| | | } |
| | | } |
| | | |
| | | .title { |
| | | position: absolute; |
| | | top: 10px; |
| | | left: 50%; |
| | | transform: translateX(-50%); |
| | | color: #ffffff; |
| | | font-size: 18px; |
| | | } |
| | | |
| | | .header-setting { |
| | | float: right; |
| | | line-height: 48px; |
| | | margin-right: 10px; |
| | | .close { |
| | | margin-right: 20px; |
| | | cursor: pointer; |
| | | padding: 10px; |
| | | } |
| | | img { |
| | | width: 29px; |
| | | height: 29px; |
| | | border-radius: 30px; |
| | | margin-right: 7px; |
| | | } |
| | | span { |
| | | color: #ffffff; |
| | | font-size: 0.95rem; |
| | | .username { |
| | | display: inline-block; |
| | | height: 30px; |
| | | max-width: 95px; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | white-space: nowrap; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
New file |
| | |
| | | import React, {Component} from 'react' |
| | | import { fromJS } from 'immutable' |
| | | import { Input, Modal, Empty, Icon } from 'antd' |
| | | import moment from 'moment' |
| | | |
| | | import Api from '@/views/interface/api' |
| | | import Utils from '@/utils/utils.js' |
| | | import MKEmitter from '@/utils/events.js' |
| | | import './index.scss' |
| | | |
| | | const { Search } = Input |
| | | const { confirm } = Modal |
| | | |
| | | class History extends Component { |
| | | state = { |
| | | list: [], |
| | | historys: [], |
| | | searchKey: '' |
| | | } |
| | | |
| | | componentDidMount() { |
| | | MKEmitter.addListener('insertInterface', this.insertInterface) |
| | | setTimeout(() => { |
| | | Api.getInterfaces().then(res => { |
| | | if (!res || !res.rows) return |
| | | |
| | | let rows = [...res.rows] |
| | | rows.sort((a,b) => { |
| | | return a.createDate < b.createDate ? 1 : -1 |
| | | }) |
| | | |
| | | let list = [] |
| | | let item = null |
| | | |
| | | rows.forEach(m => { |
| | | let date = m.createDate.substring(0, 10) |
| | | |
| | | if (m.params) { |
| | | try { |
| | | m.params = JSON.parse(m.params) |
| | | } catch { |
| | | m.params = [] |
| | | } |
| | | } else { |
| | | m.params = [] |
| | | } |
| | | |
| | | if (m.headers) { |
| | | try { |
| | | m.headers = JSON.parse(m.headers) |
| | | } catch { |
| | | m.headers = [] |
| | | } |
| | | } else { |
| | | m.headers = [] |
| | | } |
| | | |
| | | if (m.formData) { |
| | | try { |
| | | m.formData = JSON.parse(m.formData) |
| | | } catch { |
| | | m.formData = [] |
| | | } |
| | | } else { |
| | | m.formData = [] |
| | | } |
| | | |
| | | if (item && item.date !== date) { |
| | | list.push(item) |
| | | item = null |
| | | } |
| | | |
| | | if (!item) { |
| | | item = {date, sublist: []} |
| | | item.sublist.push(m) |
| | | } else if (item && item.date === date) { |
| | | item.sublist.push(m) |
| | | } |
| | | }) |
| | | |
| | | if (item) { |
| | | list.push(item) |
| | | } |
| | | |
| | | this.setState({list, historys: fromJS(list).toJS()}) |
| | | }) |
| | | }, 200) |
| | | } |
| | | |
| | | /** |
| | | * @description 组件销毁,清除state更新 |
| | | */ |
| | | componentWillUnmount () { |
| | | this.setState = () => { |
| | | return |
| | | } |
| | | MKEmitter.removeListener('insertInterface', this.insertInterface) |
| | | } |
| | | |
| | | clear = () => { |
| | | const _this = this |
| | | confirm({ |
| | | content: 'Are you sure you want to clear all your history requests?', |
| | | onOk() { |
| | | Api.clearInterfaces().then(res => { |
| | | if (res && res.rows.length === 0) { |
| | | _this.setState({list: [], historys: []}) |
| | | Modal.success({ |
| | | title: '清除成功。' |
| | | }) |
| | | } else { |
| | | Modal.error({ |
| | | title: '清除失败!请刷新重试。' |
| | | }) |
| | | } |
| | | }) |
| | | }, |
| | | onCancel() {} |
| | | }) |
| | | } |
| | | |
| | | delete = (m) => { |
| | | const { searchKey } = this.state |
| | | Api.delInterface(m.uuid).then(res => { |
| | | if (res) { |
| | | let list = this.state.list.filter(item => { |
| | | item.sublist = item.sublist.filter(cell => cell.uuid !== m.uuid) |
| | | |
| | | return item.sublist.length > 0 |
| | | }) |
| | | |
| | | let historys = fromJS(list).toJS() |
| | | if (searchKey) { |
| | | historys = historys.filter(item => { |
| | | item.sublist = item.sublist.filter(cell => cell.interface.indexOf(searchKey) > -1) |
| | | |
| | | return item.sublist.length > 0 |
| | | }) |
| | | } |
| | | |
| | | this.setState({list, historys}) |
| | | } else { |
| | | Modal.error({ |
| | | title: '删除失败!请刷新重试。' |
| | | }) |
| | | } |
| | | }) |
| | | } |
| | | |
| | | insertInterface = (item) => { |
| | | item.uuid = Utils.getuuid() |
| | | item.createDate = moment().format('YYYY-MM-DD HH:mm:ss') |
| | | |
| | | Api.writeInWebSql([item.uuid, item.createDate, item.method, item.interface, JSON.stringify(item.params), JSON.stringify(item.headers), item.active, item.raw, JSON.stringify(item.formData)]).then(res => { |
| | | if (res) { |
| | | let list = fromJS(this.state.list).toJS() |
| | | |
| | | if (list[0]) { |
| | | if (list[0].date === item.createDate.substring(0, 10)) { |
| | | list[0].sublist.unshift(item) |
| | | } else { |
| | | list.unshift({ |
| | | date: item.createDate.substring(0, 10), |
| | | sublist: [item] |
| | | }) |
| | | } |
| | | } else { |
| | | list.push({ |
| | | date: item.createDate.substring(0, 10), |
| | | sublist: [item] |
| | | }) |
| | | } |
| | | |
| | | let historys = fromJS(list).toJS() |
| | | if (this.state.searchKey) { |
| | | historys = historys.filter(item => { |
| | | item.sublist = item.sublist.filter(cell => cell.interface.indexOf(this.state.searchKey) > -1) |
| | | |
| | | return item.sublist.length > 0 |
| | | }) |
| | | } |
| | | |
| | | this.setState({ list, historys }) |
| | | } else { |
| | | Modal.error({ |
| | | title: '添加失败!请刷新重试。' |
| | | }) |
| | | } |
| | | }) |
| | | } |
| | | |
| | | use = (m) => { |
| | | MKEmitter.emit('useInterface', fromJS(m).toJS()) |
| | | } |
| | | |
| | | changeSearch = (value) => { |
| | | const { list } = this.state |
| | | |
| | | let historys = fromJS(list).toJS() |
| | | if (value) { |
| | | historys = historys.filter(item => { |
| | | item.sublist = item.sublist.filter(cell => cell.interface.indexOf(value) > -1) |
| | | |
| | | return item.sublist.length > 0 |
| | | }) |
| | | } |
| | | |
| | | this.setState({searchKey: value, historys}) |
| | | } |
| | | |
| | | render () { |
| | | const { historys } = this.state |
| | | |
| | | return ( |
| | | <aside className="interface-side-menu"> |
| | | <Search placeholder="Filter" onSearch={value => this.changeSearch(value)}/> |
| | | <div className="title"> |
| | | History |
| | | <span onClick={this.clear}>Clear all</span> |
| | | </div> |
| | | <div className="list-view"> |
| | | {historys.length === 0 ? |
| | | <Empty /> : |
| | | historys.map((item, index) => ( |
| | | <div className="list-line" key={index}> |
| | | <div className="line-title">{item.date}</div> |
| | | {item.sublist.map(m => ( |
| | | <div className="line-item" key={m.uuid}> |
| | | <div className="method">POST</div> |
| | | <div className="inter">{m.interface}</div> |
| | | <div className="action"> |
| | | <Icon type="delete" onClick={() => this.delete(m)} /> |
| | | <Icon type="right" onClick={() => this.use(m)} /> |
| | | </div> |
| | | </div> |
| | | ))} |
| | | </div> |
| | | )) |
| | | } |
| | | </div> |
| | | </aside> |
| | | ) |
| | | } |
| | | } |
| | | |
| | | export default History |
New file |
| | |
| | | .interface-side-menu { |
| | | display: inline-block; |
| | | width: 300px; |
| | | border-right: 2px solid #e8e8e8; |
| | | height: 100%; |
| | | |
| | | .ant-input-search { |
| | | margin: 10px 20px; |
| | | width: calc(100% - 40px); |
| | | .ant-input { |
| | | border-radius: 20px; |
| | | } |
| | | } |
| | | .title { |
| | | padding-left: 20px; |
| | | font-size: 16px; |
| | | border-bottom: 1px solid #e8e8e8; |
| | | padding-bottom: 3px; |
| | | span { |
| | | font-size: 14px; |
| | | float: right; |
| | | color: #fa541c; |
| | | margin-right: 10px; |
| | | cursor: pointer; |
| | | } |
| | | } |
| | | .list-view { |
| | | .ant-empty { |
| | | margin-top: 50px; |
| | | } |
| | | .list-line { |
| | | border-bottom: 1px solid #e8e8e8; |
| | | .line-title { |
| | | padding: 5px 15px; |
| | | color: rgba(0, 0, 0, 0.85); |
| | | } |
| | | .line-item { |
| | | position: relative; |
| | | display: flex; |
| | | padding-left: 25px; |
| | | margin-bottom: 8px; |
| | | transition: all 0.3s; |
| | | .method { |
| | | width: 42px; |
| | | color: #faad14; |
| | | font-size: 12px; |
| | | font-weight: 600; |
| | | line-height: 40px; |
| | | } |
| | | .inter { |
| | | width: 225px; |
| | | height: 42px; |
| | | word-break: break-all; |
| | | text-overflow: ellipsis; |
| | | display: -webkit-box; |
| | | -webkit-box-orient: vertical; |
| | | -webkit-line-clamp: 2; |
| | | overflow: hidden; |
| | | } |
| | | .action { |
| | | width: 70px; |
| | | position: absolute; |
| | | line-height: 40px; |
| | | right: 0px; |
| | | height: 42px; |
| | | background: #ffffff; |
| | | padding-left: 15px; |
| | | opacity: 0; |
| | | transition: all 0.3s; |
| | | i { |
| | | cursor: pointer; |
| | | } |
| | | i:first-child { |
| | | margin-right: 12px; |
| | | } |
| | | .anticon-delete { |
| | | color: #fa541c; |
| | | } |
| | | .anticon-right { |
| | | color: #1890ff; |
| | | } |
| | | } |
| | | } |
| | | .line-item:hover { |
| | | background: #e9e9e9; |
| | | .action { |
| | | opacity: 1; |
| | | background: #e9e9e9; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | .list-view { |
| | | height: calc(100vh - 128px); |
| | | overflow-x: hidden; |
| | | overflow-y: auto; |
| | | } |
| | | .list-view::-webkit-scrollbar { |
| | | width: 5px; |
| | | } |
| | | .list-view::-webkit-scrollbar-thumb { |
| | | border-radius: 5px; |
| | | box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.09); |
| | | background: rgba(0, 0, 0, 0.09); |
| | | } |
| | | .list-view::-webkit-scrollbar-track { |
| | | box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.05); |
| | | border-radius: 3px; |
| | | border: 1px solid rgba(0, 0, 0, 0.07); |
| | | background: rgba(0, 0, 0, 0); |
| | | } |
| | | } |
New file |
| | |
| | | import React, {Component} from 'react' |
| | | import { ConfigProvider } from 'antd' |
| | | import enUS from 'antd/es/locale/en_US' |
| | | import zhCN from 'antd/es/locale/zh_CN' |
| | | |
| | | // import Api from '@/views/interface/api' |
| | | // import asyncComponent from '@/utils/asyncComponent' |
| | | // import options from '@/store/options.js' |
| | | import Header from './header' |
| | | import History from './history' |
| | | import WorkSpace from './workspace' |
| | | |
| | | import './index.scss' |
| | | |
| | | const _locale = sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS |
| | | |
| | | class Interface extends Component { |
| | | componentDidMount() { |
| | | |
| | | // |
| | | } |
| | | |
| | | render () { |
| | | return ( |
| | | <div className="interface-view"> |
| | | <ConfigProvider locale={_locale}> |
| | | <Header key="header"/> |
| | | <History key="history"/> |
| | | <WorkSpace key="workspace"/> |
| | | </ConfigProvider> |
| | | </div> |
| | | ) |
| | | } |
| | | } |
| | | |
| | | export default Interface |
New file |
| | |
| | | .interface-view { |
| | | padding-top: 48px; |
| | | width: 100vw; |
| | | height: 100vh; |
| | | overflow: hidden; |
| | | } |
New file |
| | |
| | | import React, {Component} from 'react' |
| | | import PropTypes from 'prop-types' |
| | | import { Table, Input, Form, Icon } from 'antd' |
| | | import Utils from '@/utils/utils.js' |
| | | import './index.scss' |
| | | |
| | | const EditableContext = React.createContext() |
| | | |
| | | const EditableRow = ({ form, index, ...props }) => ( |
| | | <EditableContext.Provider value={form}> |
| | | <tr {...props} /> |
| | | </EditableContext.Provider> |
| | | ) |
| | | |
| | | const EditableFormRow = Form.create()(EditableRow) |
| | | |
| | | class EditableCell extends Component { |
| | | state = { |
| | | editing: false |
| | | } |
| | | |
| | | toggleEdit = () => { |
| | | const { dataIndex } = this.props |
| | | |
| | | if (!dataIndex) return |
| | | |
| | | const editing = !this.state.editing |
| | | this.setState({ editing }, () => { |
| | | if (editing && this.input && this.input.select) { |
| | | this.input.select() |
| | | } else if (editing && this.input && this.input.focus) { |
| | | this.input.focus() |
| | | } |
| | | }) |
| | | } |
| | | |
| | | save = e => { |
| | | const { record, handleSave } = this.props |
| | | this.form.validateFields((error, values) => { |
| | | handleSave({ ...record, ...values }) |
| | | if (error && error[e.currentTarget.id]) { |
| | | return |
| | | } |
| | | this.toggleEdit() |
| | | }) |
| | | } |
| | | |
| | | renderCell = form => { |
| | | this.form = form |
| | | const { children, dataIndex, record } = this.props |
| | | const { editing } = this.state |
| | | |
| | | return editing ? ( |
| | | <Form.Item style={{ margin: 0 }}> |
| | | {form.getFieldDecorator(dataIndex, { |
| | | initialValue: record[dataIndex] |
| | | })(<Input ref={node => (this.input = node)} autoComplete="off" onPressEnter={this.save} onBlur={this.save} />)} |
| | | </Form.Item> |
| | | ) : ( |
| | | <div |
| | | className="editable-cell-value-wrap" |
| | | onClick={this.toggleEdit} |
| | | > |
| | | {children} |
| | | </div> |
| | | ) |
| | | } |
| | | |
| | | render() { |
| | | const { dataIndex, title, record, index, handleSave, children, ...restProps } = this.props |
| | | return ( |
| | | <td {...restProps}> |
| | | <EditableContext.Consumer style={{padding: 0}}>{this.renderCell}</EditableContext.Consumer> |
| | | </td> |
| | | ) |
| | | } |
| | | } |
| | | |
| | | class EditTable extends Component { |
| | | static propTpyes = { |
| | | data: PropTypes.array, |
| | | onChange: PropTypes.func |
| | | } |
| | | |
| | | state = { |
| | | dataSource: [], |
| | | selectedRowKeys: [], |
| | | count: 0, |
| | | columns: [{ |
| | | dataIndex: 'key', |
| | | title: 'KEY', |
| | | width: '33%' |
| | | }, { |
| | | dataIndex: 'value', |
| | | title: 'VALUE', |
| | | width: '33%' |
| | | }, { |
| | | dataIndex: 'description', |
| | | title: 'DESCRIPTION', |
| | | className: 'no-border', |
| | | width: '33%' |
| | | }, { |
| | | dataIndex: '', |
| | | title: '', |
| | | width: '20px', |
| | | render: (text, record) => { |
| | | return (<Icon type="close" onClick={() => this.delete(record)}/>) |
| | | } |
| | | }] |
| | | } |
| | | |
| | | UNSAFE_componentWillMount () { |
| | | const { data } = this.props |
| | | |
| | | let _data = data || [] |
| | | let selectedRowKeys = [] |
| | | if (_data && _data.length > 0) { |
| | | _data.forEach(item => { |
| | | if (item.selected) { |
| | | selectedRowKeys.push(item.uuid) |
| | | } |
| | | }) |
| | | } else { |
| | | _data = [{ |
| | | uuid: Utils.getuuid(), |
| | | key: '', |
| | | value: '', |
| | | description: '', |
| | | selected: true |
| | | }] |
| | | selectedRowKeys.push(_data[0].uuid) |
| | | this.props.onChange(_data) |
| | | } |
| | | |
| | | this.setState({ |
| | | dataSource: _data, |
| | | selectedRowKeys |
| | | }) |
| | | } |
| | | |
| | | handleDelete = key => { |
| | | const { dataSource } = this.state |
| | | let _data = dataSource.filter(item => item.key !== key) |
| | | |
| | | this.setState({ dataSource: _data }, () => { |
| | | this.props.onChange(_data) |
| | | }) |
| | | } |
| | | |
| | | delete = (item) => { |
| | | const { dataSource, selectedRowKeys } = this.state |
| | | |
| | | let _data = dataSource.filter(cell => cell.uuid !== item.uuid) |
| | | let _keys = selectedRowKeys.filter(key => key !== item.uuid) |
| | | |
| | | if (_data.length === 0) { |
| | | _data = [{ |
| | | uuid: Utils.getuuid(), |
| | | key: '', |
| | | value: '', |
| | | description: '', |
| | | selected: true |
| | | }] |
| | | _keys = [_data[0].uuid] |
| | | this.props.onChange(_data) |
| | | } |
| | | |
| | | this.setState({ |
| | | dataSource: _data, |
| | | selectedRowKeys: _keys |
| | | }, () => { |
| | | this.props.onChange(_data) |
| | | }) |
| | | } |
| | | |
| | | handleAdd = (e) => { |
| | | e.stopPropagation() |
| | | const { dataSource, selectedRowKeys } = this.state |
| | | const item = { |
| | | uuid: Utils.getuuid(), |
| | | key: '', |
| | | value: '', |
| | | description: '', |
| | | selected: true |
| | | } |
| | | |
| | | let _data = [...dataSource, item] |
| | | |
| | | this.setState({ |
| | | dataSource: _data, |
| | | selectedRowKeys: [...selectedRowKeys, item.uuid] |
| | | }, () => { |
| | | this.props.onChange(_data) |
| | | }) |
| | | } |
| | | |
| | | handleSave = row => { |
| | | const newData = this.state.dataSource.map(item => { |
| | | if (row.uuid === item.uuid) return row |
| | | return item |
| | | }) |
| | | |
| | | this.setState({ dataSource: newData }, () => { |
| | | this.props.onChange(newData) |
| | | }) |
| | | } |
| | | |
| | | onChange = selectedRowKeys => { |
| | | const newData = this.state.dataSource.map(item => { |
| | | item.selected = selectedRowKeys.includes(item.uuid) |
| | | return item |
| | | }) |
| | | |
| | | this.setState({ dataSource: newData, selectedRowKeys }, () => { |
| | | this.props.onChange(newData) |
| | | }) |
| | | } |
| | | |
| | | render() { |
| | | const { dataSource, selectedRowKeys } = this.state |
| | | const components = { |
| | | body: { |
| | | row: EditableFormRow, |
| | | cell: EditableCell |
| | | } |
| | | } |
| | | const columns = this.state.columns.map(col => { |
| | | return { |
| | | ...col, |
| | | onCell: record => ({ |
| | | record, |
| | | dataIndex: col.dataIndex, |
| | | title: col.title, |
| | | handleSave: this.handleSave, |
| | | }) |
| | | } |
| | | }) |
| | | return ( |
| | | <div className="params-edit-table"> |
| | | <Icon className="add-row" type="plus" onClick={this.handleAdd} /> |
| | | <Table |
| | | rowKey="uuid" |
| | | components={components} |
| | | bordered |
| | | dataSource={dataSource} |
| | | columns={columns} |
| | | rowSelection={{ type: 'checkbox', selectedRowKeys, onChange: this.onChange }} |
| | | pagination={false} |
| | | /> |
| | | </div> |
| | | ) |
| | | } |
| | | } |
| | | |
| | | export default EditTable |
New file |
| | |
| | | .params-edit-table { |
| | | .add-row { |
| | | position: absolute; |
| | | z-index: 1; |
| | | right: 10px; |
| | | top: 0px; |
| | | padding: 5px; |
| | | font-size: 22px; |
| | | color: #26C281; |
| | | } |
| | | .ant-table table { |
| | | border-radius: 0; |
| | | } |
| | | .no-border { |
| | | border-right: 0!important; |
| | | } |
| | | .ant-table-thead > tr { |
| | | > th { |
| | | padding: 10px 10px; |
| | | } |
| | | .ant-table-selection-column { |
| | | .ant-table-header-column { |
| | | display: none; |
| | | } |
| | | } |
| | | } |
| | | .ant-table-tbody { |
| | | > tr { |
| | | > td { |
| | | background: #ffffff!important; |
| | | padding: 2px 10px; |
| | | .ant-input { |
| | | height: 28px; |
| | | } |
| | | .ant-form-item { |
| | | height: 30px; |
| | | line-height: 30px; |
| | | .ant-form-item-control { |
| | | line-height: 30px; |
| | | } |
| | | } |
| | | .anticon-close { |
| | | opacity: 0; |
| | | } |
| | | } |
| | | } |
| | | > tr:hover { |
| | | > td { |
| | | background: #ffffff!important; |
| | | .anticon-close { |
| | | opacity: 1; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | .editable-cell-value-wrap { |
| | | cursor: pointer; |
| | | height: 36px; |
| | | width: 300px; |
| | | display: table-cell; |
| | | vertical-align: middle; |
| | | word-wrap: break-word; |
| | | word-break: break-word; |
| | | .ant-input { |
| | | height: 30px; |
| | | padding: 0 11px; |
| | | } |
| | | } |
| | | .ant-form-item-control-wrapper { |
| | | width: 100%; |
| | | } |
| | | .ant-table-placeholder { |
| | | padding: 5px 16px; |
| | | .ant-empty-normal { |
| | | margin: 0; |
| | | } |
| | | } |
| | | .operation-btn { |
| | | margin-right: 10px; |
| | | cursor: pointer; |
| | | } |
| | | .ant-form-explain { |
| | | font-size: 12px; |
| | | } |
| | | } |
New file |
| | |
| | | import React, {Component} from 'react' |
| | | import { Icon, Tabs } from 'antd' |
| | | |
| | | import Utils from '@/utils/utils.js' |
| | | import MKEmitter from '@/utils/events.js' |
| | | import Request from './request' |
| | | import './index.scss' |
| | | import { fromJS } from 'immutable' |
| | | |
| | | |
| | | class WorkSpace extends Component { |
| | | state = { |
| | | tabviews: [{ |
| | | uuid: Utils.getuuid(), |
| | | createDate: '', |
| | | method: 'POST', |
| | | interface: '', |
| | | params: [], |
| | | headers: [], |
| | | active: 'raw', |
| | | raw: '', |
| | | formData: [] |
| | | }] |
| | | } |
| | | |
| | | componentDidMount() { |
| | | MKEmitter.addListener('useInterface', this.useInterface) |
| | | } |
| | | |
| | | /** |
| | | * @description 组件销毁,清除state更新 |
| | | */ |
| | | componentWillUnmount () { |
| | | this.setState = () => { |
| | | return |
| | | } |
| | | MKEmitter.removeListener('useInterface', this.useInterface) |
| | | } |
| | | |
| | | useInterface = (item) => { |
| | | item.uuid = Utils.getuuid() |
| | | this.setState({tabviews: [...this.state.tabviews, item]}) |
| | | } |
| | | |
| | | handleTabview = (view) => { |
| | | let tabviews = fromJS(this.state.tabviews).toJS() |
| | | tabviews = tabviews.filter(item => item.uuid !== view.uuid) |
| | | |
| | | this.setState({tabviews}, () => { |
| | | if (tabviews.length > 0) return |
| | | |
| | | setTimeout(() => { |
| | | this.setState({tabviews: [{ |
| | | uuid: Utils.getuuid(), |
| | | createDate: '', |
| | | method: 'POST', |
| | | interface: '', |
| | | params: [], |
| | | headers: [], |
| | | active: 'raw', |
| | | raw: '', |
| | | formData: [] |
| | | }]}) |
| | | }, 300) |
| | | }) |
| | | } |
| | | |
| | | handleAdd = () => { |
| | | this.setState({tabviews: [...this.state.tabviews, { |
| | | uuid: Utils.getuuid(), |
| | | createDate: '', |
| | | method: 'POST', |
| | | interface: '', |
| | | params: [], |
| | | headers: [], |
| | | active: 'raw', |
| | | raw: '', |
| | | formData: [] |
| | | }]}) |
| | | } |
| | | |
| | | render () { |
| | | const { tabviews } = this.state |
| | | |
| | | return ( |
| | | <div className="workspace-wrap"> |
| | | <Icon className="add-view" type="plus" onClick={this.handleAdd} /> |
| | | <Tabs type="card"> |
| | | {tabviews.map(view => { |
| | | return ( |
| | | <Tabs.TabPane |
| | | tab={ |
| | | <span className="control"> |
| | | <span className="method"> |
| | | {view.method || 'POST'} |
| | | </span> |
| | | <span className="interface"> |
| | | {view.interface || 'Untitled Request'} |
| | | </span> |
| | | <Icon type="close" onClick={() => this.handleTabview(view)}/> |
| | | </span> |
| | | } |
| | | key={view.uuid} |
| | | > |
| | | <Request config={view} /> |
| | | </Tabs.TabPane> |
| | | ) |
| | | })} |
| | | </Tabs> |
| | | </div> |
| | | ) |
| | | } |
| | | } |
| | | |
| | | export default WorkSpace |
New file |
| | |
| | | .workspace-wrap { |
| | | display: inline-block; |
| | | width: calc(100vw - 300px); |
| | | height: 100%; |
| | | vertical-align: top; |
| | | padding-top: 10px; |
| | | position: relative; |
| | | .add-view { |
| | | position: absolute; |
| | | right: 25px; |
| | | top: 12px; |
| | | z-index: 2; |
| | | padding: 5px; |
| | | cursor: pointer; |
| | | font-size: 22px; |
| | | color: #26C281; |
| | | } |
| | | |
| | | .ant-tabs.ant-tabs-card .ant-tabs-card-bar { |
| | | >.ant-tabs-nav-container { |
| | | margin-right: 100px; |
| | | } |
| | | padding-left: 5px; |
| | | .ant-tabs-tab { |
| | | margin-right: 7px; |
| | | padding: 0 10px; |
| | | .method { |
| | | color: #faad14; |
| | | font-size: 12px; |
| | | font-weight: 600; |
| | | margin-right: 5px; |
| | | vertical-align: top; |
| | | } |
| | | .interface { |
| | | display: inline-block; |
| | | color: rgba(0, 0, 0, 0.65); |
| | | width: 200px; |
| | | white-space: nowrap; |
| | | text-overflow: ellipsis; |
| | | overflow: hidden; |
| | | vertical-align: top; |
| | | } |
| | | .anticon-close { |
| | | color:rgba(0, 0, 0, 0.65); |
| | | margin: 0; |
| | | } |
| | | } |
| | | .ant-tabs-tab.ant-tabs-tab-active { |
| | | border-top-color: #fa541c; |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | import React, {Component} from 'react' |
| | | import { fromJS } from 'immutable' |
| | | import md5 from 'md5' |
| | | import { Input, Select, Button, Tabs, Radio, Modal } from 'antd' |
| | | |
| | | import Api from '@/views/interface/api' |
| | | import Utils from '@/utils/utils.js' |
| | | import EditTable from '../editTable' |
| | | import CodeMirror from '@/templates/zshare/codemirror' |
| | | import MKEmitter from '@/utils/events.js' |
| | | import './index.scss' |
| | | |
| | | const InputGroup = Input.Group |
| | | const { Option } = Select |
| | | |
| | | class Request extends Component { |
| | | state = { |
| | | active: 'raw', |
| | | body: null, |
| | | response: null, |
| | | status: '' |
| | | } |
| | | |
| | | UNSAFE_componentWillMount() { |
| | | const { config } = this.props |
| | | |
| | | this.setState({active: config.active, config: fromJS(config).toJS()}) |
| | | } |
| | | |
| | | componentDidMount() { |
| | | |
| | | } |
| | | |
| | | /** |
| | | * @description 组件销毁,清除state更新 |
| | | */ |
| | | componentWillUnmount () { |
| | | this.setState = () => { |
| | | return |
| | | } |
| | | } |
| | | |
| | | onChange = (e) => { |
| | | const { config } = this.state |
| | | |
| | | this.setState({active: e.target.value, config: {...config, active: e.target.value}}) |
| | | } |
| | | |
| | | rawChange = (val) => { |
| | | const { config } = this.state |
| | | |
| | | this.setState({config: {...config, raw: val}}) |
| | | } |
| | | |
| | | changeFormData = (vals) => { |
| | | const { config } = this.state |
| | | |
| | | this.setState({config: {...config, formData: vals}}) |
| | | } |
| | | |
| | | changeHeader = (vals) => { |
| | | const { config } = this.state |
| | | |
| | | this.setState({config: {...config, headers: vals}}) |
| | | } |
| | | |
| | | changeParams = (vals) => { |
| | | const { config } = this.state |
| | | |
| | | this.setState({config: {...config, params: vals}}) |
| | | } |
| | | |
| | | changeMethod = (val) => { |
| | | const { config } = this.state |
| | | |
| | | this.setState({config: {...config, method: val}}) |
| | | } |
| | | |
| | | changeInter = (e) => { |
| | | const { config } = this.state |
| | | |
| | | this.setState({config: {...config, interface: e.target.value}}) |
| | | } |
| | | |
| | | send = () => { |
| | | const { config } = this.state |
| | | |
| | | let raws = null |
| | | if (!config.interface) { |
| | | Modal.error({ |
| | | title: '请填入接口地址!' |
| | | }) |
| | | return |
| | | } else if (config.active === 'raw') { |
| | | if (config.raw) { |
| | | try { |
| | | raws = JSON.parse(config.raw) |
| | | } catch { |
| | | Modal.error({ |
| | | title: '参数格式错误,必须为JSON格式!' |
| | | }) |
| | | return |
| | | } |
| | | } |
| | | } |
| | | |
| | | let url = config.interface |
| | | |
| | | let m = [] |
| | | config.params.forEach(item => { |
| | | if (!item.selected || !item.key) return |
| | | m.push(`${item.key}=${item.value}`) |
| | | }) |
| | | |
| | | m = m.join('&') |
| | | |
| | | if (m) { |
| | | if (/\?/ig.test(url)) { |
| | | url = url + '&' + m |
| | | } else { |
| | | url = url + '?' + m |
| | | } |
| | | } |
| | | |
| | | let header = null |
| | | config.headers.forEach(item => { |
| | | if (!item.selected || !item.key) return |
| | | |
| | | header = header || {} |
| | | |
| | | header[item.key] = item.value |
| | | }) |
| | | |
| | | let n = null |
| | | if (config.active === 'raw' && raws) { |
| | | n = JSON.stringify(raws) |
| | | } else if (config.active === 'formData') { |
| | | config.formData.forEach(item => { |
| | | if (!item.selected || !item.key) return |
| | | |
| | | n = n || {} |
| | | |
| | | n[item.key] = item.value |
| | | }) |
| | | n = JSON.stringify(n) |
| | | } |
| | | |
| | | if (/logon/ig.test(url)) { |
| | | Api.dologon(url, config.method, header, n).then(res => { |
| | | this.handleResponse(res) |
| | | }, (err) => { |
| | | this.handleResponse(err) |
| | | }) |
| | | } else if (/dostars/ig.test(url)) { |
| | | if (n) { |
| | | n = JSON.parse(n) |
| | | n = this.encryptParam(n) |
| | | n = JSON.stringify(n) |
| | | } |
| | | Api.normalRequest(url, config.method, header, n).then(res => { |
| | | this.handleResponse(res) |
| | | }, (err) => { |
| | | this.handleResponse(err) |
| | | }) |
| | | } else { |
| | | Api.normalRequest(url, config.method, header, n).then(res => { |
| | | this.handleResponse(res) |
| | | }, (err) => { |
| | | this.handleResponse(err) |
| | | }) |
| | | } |
| | | } |
| | | |
| | | handleResponse = (res) => { |
| | | let body = null |
| | | |
| | | if (res && res.data) { |
| | | try { |
| | | body = JSON.stringify(res.data, null, 2) |
| | | |
| | | body = body.replace(/\n/ig, '<br/>') |
| | | body = body.replace(/\s/ig, ' ') |
| | | } catch { |
| | | body = null |
| | | } |
| | | } |
| | | |
| | | let status = '' |
| | | if (res.status) { |
| | | status = res.status + res.statusText |
| | | } else if (res.name === 'Error') { |
| | | status = res.message |
| | | body = `请求异常${status === 'Network Error' ? ',可能原因:1、网络异常;2、接口跨域。' : '!'}` |
| | | } |
| | | |
| | | this.setState({response: res, body, status}) |
| | | } |
| | | |
| | | encryptParam (param) { |
| | | param.nonc = Utils.getuuid() |
| | | |
| | | let keys = Object.keys(param).sort() |
| | | let values = '' |
| | | keys.forEach(key => { |
| | | if (key.toLowerCase() === 'rduri' || key.toLowerCase() === 't') return |
| | | if (param[key] === undefined) { |
| | | delete param[key] |
| | | } else if (typeof(param[key]) === 'object') { |
| | | values += key + JSON.stringify(param[key]) |
| | | } else { |
| | | values += key + param[key] |
| | | } |
| | | }) |
| | | param.sign = md5(values) |
| | | param.t = new Date().getTime() |
| | | |
| | | return param |
| | | } |
| | | |
| | | save = () => { |
| | | const { config } = this.state |
| | | |
| | | if (!config.interface) { |
| | | Modal.error({ |
| | | title: '请填入接口地址!' |
| | | }) |
| | | return |
| | | } |
| | | |
| | | MKEmitter.emit('insertInterface', config) |
| | | } |
| | | |
| | | render () { |
| | | const { active, config, response, body, status } = this.state |
| | | |
| | | let hasParam = config.params.filter(item => item.selected && item.key).length > 0 |
| | | let hasHeader = config.headers.filter(item => item.selected && item.key).length |
| | | let hasBody = false |
| | | |
| | | if (active === 'raw' && config.raw) { |
| | | hasBody = true |
| | | } else if (active === 'formData' && config.formData.filter(item => item.selected && item.key).length > 0) { |
| | | hasBody = true |
| | | } |
| | | |
| | | return ( |
| | | <div className="request-wrap"> |
| | | <div className="request-interface"> |
| | | <InputGroup compact> |
| | | <Select defaultValue={config.method} onChange={this.changeMethod}> |
| | | <Option value="POST">POST</Option> |
| | | <Option value="GET">GET</Option> |
| | | </Select> |
| | | <Input placeholder="Enter request URL" defaultValue={config.interface} onChange={this.changeInter}/> |
| | | </InputGroup> |
| | | <Button type="primary" onClick={this.send}>Send</Button> |
| | | <Button onClick={this.save}>Save</Button> |
| | | </div> |
| | | <Tabs animated={false}> |
| | | <Tabs.TabPane forceRender={true} tab={<span className={hasParam ? 'active' : ''}>Params</span>} key="Params"> |
| | | <EditTable data={config.params} onChange={this.changeParams}/> |
| | | </Tabs.TabPane> |
| | | <Tabs.TabPane forceRender={true} tab={<span>Headers{hasHeader ? <span className="number">{`(${hasHeader})`}</span> : ''}</span>} key="Headers"> |
| | | <EditTable data={config.headers} onChange={this.changeHeader}/> |
| | | </Tabs.TabPane> |
| | | <Tabs.TabPane forceRender={true} tab={<span className={hasBody ? 'active' : ''}>Body</span>} key="Body"> |
| | | <div className="body-class"> |
| | | <Radio.Group onChange={this.onChange} value={active}> |
| | | <Radio value={'none'}>none</Radio> |
| | | <Radio value={'formData'}>formData</Radio> |
| | | <Radio value={'raw'}>raw</Radio> |
| | | </Radio.Group> |
| | | </div> |
| | | <div className={'body-content ' + (active === 'none' ? 'show' : '')}> |
| | | <div className="no-body">This request does not have a body</div> |
| | | </div> |
| | | <div className={'body-content ' + (active === 'formData' ? 'show' : '')}> |
| | | <EditTable data={config.formData} onChange={this.changeFormData}/> |
| | | </div> |
| | | <div className={'body-content ' + (active === 'raw' ? 'show' : '')}> |
| | | <CodeMirror value={config.raw} mode="text/javascript" onChange={this.rawChange} /> |
| | | </div> |
| | | </Tabs.TabPane> |
| | | </Tabs> |
| | | <div className="response"> |
| | | {response ? <div className="header"> |
| | | {body ? 'Body' : 'Response'} |
| | | {status ? <span className="status">Status: <span className={status === '200OK' ? 'green' : ''}>{status}</span></span> : null} |
| | | </div> : <div className="header"> |
| | | Response |
| | | <span className="empty">Hit the Send button to get a response.</span> |
| | | </div>} |
| | | <div style={{paddingLeft: '3px', paddingTop: '3px'}} dangerouslySetInnerHTML={{__html: body}}></div> |
| | | </div> |
| | | </div> |
| | | ) |
| | | } |
| | | } |
| | | |
| | | export default Request |
New file |
| | |
| | | .request-wrap { |
| | | position: relative; |
| | | padding: 0px 10px; |
| | | height: calc(100vh - 115px); |
| | | overflow-x: hidden; |
| | | overflow-y: auto; |
| | | |
| | | .request-interface { |
| | | background: #ffffff; |
| | | margin-bottom: 10px; |
| | | .ant-select-selection { |
| | | height: 40px; |
| | | width: 90px; |
| | | } |
| | | .ant-select-selection__rendered { |
| | | line-height: 40px; |
| | | } |
| | | .ant-input { |
| | | height: 40px; |
| | | width: calc(100% - 100px); |
| | | } |
| | | .ant-input-group { |
| | | display: inline-block; |
| | | width: calc(100% - 210px); |
| | | vertical-align: top; |
| | | } |
| | | .ant-btn { |
| | | height: 40px; |
| | | width: 90px; |
| | | } |
| | | .ant-btn-primary { |
| | | margin-right: 10px; |
| | | } |
| | | } |
| | | .ant-tabs.ant-tabs-line { |
| | | .ant-tabs-top-bar { |
| | | margin-bottom: 0px; |
| | | border: 0; |
| | | .ant-tabs-nav { |
| | | .ant-tabs-tab { |
| | | color: rgba(0, 0, 0, 0.65); |
| | | padding-bottom: 5px; |
| | | span { |
| | | position: relative; |
| | | } |
| | | .number { |
| | | color: #26C281; |
| | | margin-left: 3px; |
| | | font-size: 13px; |
| | | } |
| | | span.active::after { |
| | | content: ' '; |
| | | display: block; |
| | | position: absolute; |
| | | right: -12px; |
| | | top: 2px; |
| | | width: 8px; |
| | | height: 8px; |
| | | border-radius: 8px; |
| | | background-color: #26C281; |
| | | } |
| | | } |
| | | .ant-tabs-tab.ant-tabs-tab-active { |
| | | color: rgba(0, 0, 0, 0.85); |
| | | } |
| | | } |
| | | .ant-tabs-ink-bar { |
| | | background-color: #fa541c; |
| | | } |
| | | } |
| | | } |
| | | .body-class { |
| | | height: 40px; |
| | | line-height: 40px; |
| | | padding-left: 15px; |
| | | border-top: 1px solid #e8e8e8; |
| | | } |
| | | .body-content { |
| | | display: none; |
| | | .no-body { |
| | | color: rgba(0, 0, 0, 0.45); |
| | | border-top: 1px solid #e8e8e8; |
| | | text-align: center; |
| | | height: 40px; |
| | | line-height: 40px; |
| | | } |
| | | } |
| | | .body-content.show { |
| | | display: block; |
| | | } |
| | | .anticon-fullscreen { |
| | | display: none; |
| | | } |
| | | .code-mirror-wrap .code-mirror-area { |
| | | border-radius: 0; |
| | | } |
| | | .response { |
| | | min-height: 400px; |
| | | border-left: 1px solid #e8e8e8; |
| | | border-right: 1px solid #e8e8e8; |
| | | .header { |
| | | position: relative; |
| | | height: 40px; |
| | | background-color: #fafafa; |
| | | line-height: 40px; |
| | | padding-left: 10px; |
| | | border-bottom: 1px solid #e8e8e8; |
| | | .empty { |
| | | position: absolute; |
| | | top: 150px; |
| | | left: 50%; |
| | | transform: translateX(-50%); |
| | | font-size: 20px; |
| | | color:rgba(0, 0, 0, 0.45) |
| | | } |
| | | .status { |
| | | font-size: 13px; |
| | | float: right; |
| | | margin-right: 40px; |
| | | span.green { |
| | | color: #26C281; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | .request-wrap::-webkit-scrollbar { |
| | | width: 5px; |
| | | } |
| | | .request-wrap::-webkit-scrollbar-thumb { |
| | | border-radius: 5px; |
| | | box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.09); |
| | | background: rgba(0, 0, 0, 0.09); |
| | | } |
| | | .request-wrap::-webkit-scrollbar-track { |
| | | box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.05); |
| | | border-radius: 3px; |
| | | border: 1px solid rgba(0, 0, 0, 0.07); |
| | | background: rgba(0, 0, 0, 0); |
| | | } |