10 changed files with 240 additions and 14 deletions
@ -0,0 +1,29 @@ |
|||||
|
export interface ILocalConfig { |
||||
|
ip: string; |
||||
|
port: string; |
||||
|
} |
||||
|
|
||||
|
export const localConfig: ILocalConfig = { |
||||
|
ip: '127.0.0.1', |
||||
|
port: '3500' |
||||
|
}; |
||||
|
|
||||
|
export const updateLocalConfig = (config: ILocalConfig) => { |
||||
|
localConfig.ip = config.ip || localConfig.ip; |
||||
|
localConfig.port = config.port || localConfig.port; |
||||
|
} |
||||
|
|
||||
|
export const localConnect = () => { |
||||
|
return fetch(`http://${localConfig.ip}:${localConfig.port}/api/connect`, { |
||||
|
method: 'GET', |
||||
|
headers: {'content-type': 'application/json'} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
export const localSave = (data: any) => { |
||||
|
fetch(`http://${localConfig.ip}:${localConfig.port}/api/save`, { |
||||
|
method: 'POST', |
||||
|
headers: {'content-type': 'application/json'}, |
||||
|
body: JSON.stringify(data) |
||||
|
}); |
||||
|
} |
@ -0,0 +1,64 @@ |
|||||
|
import React, {useState, useEffect, useRef} from 'react'; |
||||
|
|
||||
|
import 'antd/es/form/style'; |
||||
|
import 'antd/es/modal/style'; |
||||
|
import 'antd/es/input/style'; |
||||
|
import styles from './index.module.less'; |
||||
|
|
||||
|
import {Input, Form, Modal} from 'antd'; |
||||
|
import {FormInstance} from 'antd/lib/form'; |
||||
|
import {ILocalConfig, localConfig, updateLocalConfig} from '../../../api'; |
||||
|
|
||||
|
const PORT_REGEX = /^\d{1,5}$/; |
||||
|
const IP_REGEX = /^(localhost)|(((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})(\.((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})){3})$/; |
||||
|
const makeRules = (regex: RegExp, errTip: string) => { |
||||
|
return [ |
||||
|
{required: true, message: '不能为空!'}, |
||||
|
{validator: (_: any, val: string) => regex.test(val) ? Promise.resolve() : Promise.reject(errTip)} |
||||
|
]; |
||||
|
} |
||||
|
|
||||
|
interface IEditorModalProps { |
||||
|
visible: boolean; |
||||
|
onOk: () => void; |
||||
|
onCancel: () => void; |
||||
|
} |
||||
|
|
||||
|
const EditModal: React.FC<IEditorModalProps> = props => { |
||||
|
|
||||
|
const {visible, onOk, onCancel} = props; |
||||
|
const formRef = useRef<FormInstance>(null); |
||||
|
|
||||
|
// events
|
||||
|
const onClickOk = (): void => { |
||||
|
formRef.current && formRef.current.validateFields().then((formValues) => { |
||||
|
onOk(); |
||||
|
updateLocalConfig(formValues as ILocalConfig); |
||||
|
}).catch(err => { |
||||
|
console.log(err.message); |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
return ( |
||||
|
<Modal |
||||
|
className={styles.editModal} |
||||
|
visible={visible} |
||||
|
okText={'保存'} |
||||
|
cancelText={'取消'} |
||||
|
title={'本地连接配置'} |
||||
|
onOk={onClickOk} |
||||
|
onCancel={onCancel} |
||||
|
> |
||||
|
<Form ref={formRef} labelCol={{span: 4}} initialValues={localConfig}> |
||||
|
<Form.Item label={'ip'} name={'ip'} rules={makeRules(IP_REGEX, 'IP格式不合法')}> |
||||
|
<Input/> |
||||
|
</Form.Item> |
||||
|
<Form.Item label={'port'} name={'port'} rules={makeRules(PORT_REGEX, 'port格式不合法')}> |
||||
|
<Input/> |
||||
|
</Form.Item> |
||||
|
</Form> |
||||
|
</Modal> |
||||
|
); |
||||
|
}; |
||||
|
|
||||
|
export default EditModal; |
@ -0,0 +1,22 @@ |
|||||
|
.container { |
||||
|
|
||||
|
display: flex; |
||||
|
flex-direction: row; |
||||
|
align-items: center; |
||||
|
margin-right: 20px; |
||||
|
|
||||
|
.error { |
||||
|
cursor: pointer; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.editModal { |
||||
|
|
||||
|
width: 450px; |
||||
|
|
||||
|
:global { |
||||
|
.ant-form-item:last-child { |
||||
|
margin-bottom: 0; |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,100 @@ |
|||||
|
import React, {useState, useEffect} from 'react'; |
||||
|
|
||||
|
import 'antd/es/tag/style'; |
||||
|
import 'antd/es/modal/style'; |
||||
|
import 'antd/es/message/style'; |
||||
|
import styles from './index.module.less'; |
||||
|
|
||||
|
import {Graph} from '@antv/x6'; |
||||
|
import EditModal from './editModal'; |
||||
|
import {Tag, Modal, message} from 'antd'; |
||||
|
import {localConnect} from '../../../api'; |
||||
|
|
||||
|
enum Status { |
||||
|
connected = 'success', |
||||
|
disconnected = 'error' |
||||
|
} |
||||
|
|
||||
|
interface IProps { |
||||
|
flowChart: Graph | undefined; |
||||
|
} |
||||
|
|
||||
|
const PULSE_RATE = 10 * 1000; // try to connect to local servet per 10 seconds
|
||||
|
|
||||
|
const ConnectStatus: React.FC<IProps> = (props) => { |
||||
|
|
||||
|
const {flowChart} = props; |
||||
|
const [visible, setVisible] = useState<boolean>(false); |
||||
|
const [projectName, setProjectName] = useState<string>(''); |
||||
|
const [status, setStatus] = useState<Status>(Status.disconnected); |
||||
|
|
||||
|
// life
|
||||
|
useEffect(() => { |
||||
|
confirmToSync(); |
||||
|
const timer = setInterval(syncLocal, PULSE_RATE); |
||||
|
return () => clearInterval(timer); |
||||
|
}, []); |
||||
|
|
||||
|
// network
|
||||
|
const syncLocal = () => { |
||||
|
return localConnect().then(res => res.json()).then((data = {}) => { |
||||
|
const {projectName} = data; |
||||
|
setStatus(Status.connected); |
||||
|
setProjectName(projectName); |
||||
|
return data; |
||||
|
}).catch((err) => { |
||||
|
setStatus(Status.disconnected); |
||||
|
console.log('connect local failed, the error is:', err.message); |
||||
|
}); |
||||
|
}; |
||||
|
const confirmToSync = () => { |
||||
|
syncLocal().then(data => { |
||||
|
const {dsl} = data; |
||||
|
dsl && Modal.confirm({ |
||||
|
title: '本地连接成功,是否将数据同步至当前项目?', |
||||
|
onOk() { |
||||
|
try { |
||||
|
console.log(props.flowChart); |
||||
|
flowChart && flowChart.fromJSON(dsl); |
||||
|
} catch(err) { |
||||
|
message.error('同步失败!'); |
||||
|
} |
||||
|
} |
||||
|
}); |
||||
|
}); |
||||
|
}; |
||||
|
|
||||
|
// events
|
||||
|
const onOpenEditModal = (): void => { |
||||
|
setVisible(true); |
||||
|
}; |
||||
|
const onCloseEditModal = (): void => { |
||||
|
setVisible(false); |
||||
|
}; |
||||
|
const onOk = (): void => { |
||||
|
onCloseEditModal(); |
||||
|
confirmToSync(); |
||||
|
}; |
||||
|
|
||||
|
return ( |
||||
|
<div className={styles.container}> |
||||
|
{status === Status.connected && ( |
||||
|
<Tag color={'success'}> |
||||
|
{[projectName, '本地连接成功'].join(' ')} |
||||
|
</Tag> |
||||
|
)} |
||||
|
{status === Status.disconnected && ( |
||||
|
<Tag className={styles.error} color={'error'} onClick={onOpenEditModal}> |
||||
|
本地连接失败 点击修改配置 |
||||
|
</Tag> |
||||
|
)} |
||||
|
<EditModal |
||||
|
visible={visible} |
||||
|
onOk={onOk} |
||||
|
onCancel={onCloseEditModal} |
||||
|
/> |
||||
|
</div> |
||||
|
); |
||||
|
}; |
||||
|
|
||||
|
export default ConnectStatus; |
Loading…
Reference in new issue