re commit
This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
import React from 'react';
|
||||
import {Modal, Grid, Divider} from 'semantic-ui-react';
|
||||
|
||||
function randomColor() {
|
||||
var colors = [
|
||||
'red',
|
||||
'orange',
|
||||
'yellow',
|
||||
'olive',
|
||||
'green',
|
||||
'teal',
|
||||
'blue',
|
||||
'violet',
|
||||
'purple',
|
||||
'pink',
|
||||
'brown',
|
||||
'grey'
|
||||
];
|
||||
colors.sort(function () {
|
||||
return 0.5 - Math.random();
|
||||
});
|
||||
return colors.shift();
|
||||
}
|
||||
|
||||
function ParseTree(props) {
|
||||
let {root, ln, lc} = props;
|
||||
let ops = {
|
||||
"0": "等於",
|
||||
"1": "大於",
|
||||
"2": "小於",
|
||||
"3": "大於等於",
|
||||
"4": "小於等於",
|
||||
"5": "不等於",
|
||||
"8": "AND",
|
||||
"9": "OR"
|
||||
};
|
||||
|
||||
function GenLN(props) {
|
||||
let {data, isRoot} = props;
|
||||
return (
|
||||
<Grid.Column color={randomColor()} width={isRoot
|
||||
? 16
|
||||
: 8}>
|
||||
<div>{`ID:${data.jcioclntuid || ''} / Name:${data.lnname || ''} / Action:${data.lnaction || ''}`}</div>
|
||||
<Divider horizontal={true}>{ops[data.lnlcop]}</Divider>
|
||||
<GenNode ids={[data.lnlcid1, data.lnlcid2]}/>
|
||||
</Grid.Column>
|
||||
)
|
||||
}
|
||||
function GenLC(props) {
|
||||
let {data} = props;
|
||||
return (
|
||||
<Grid.Column color={randomColor()} width={8}>
|
||||
<div>{`ID:${data.jcioclctuid || ''} / Name:${data.lcname || ''} / Action:${data.lcaction || ''}`}</div>
|
||||
<hr/>
|
||||
<div>{`${data.lcioid} ${ops[data.lcioop]} ${data.lciovalue}`}</div>
|
||||
</Grid.Column>
|
||||
)
|
||||
}
|
||||
|
||||
function GenNode(props) {
|
||||
let {ids} = props;
|
||||
let isRoot = ids.length == 1 && ids[0].substr(2) == root
|
||||
? true
|
||||
: false;
|
||||
let arr = [];
|
||||
for (let i in ids) {
|
||||
let id = ids[i];
|
||||
if (/^ln/.test(id)) {
|
||||
let idn = id.match(/^ln(\d+)$/);
|
||||
if (!idn || idn.length < 1)
|
||||
continue;
|
||||
let num = idn[1];
|
||||
for (let j in ln) {
|
||||
if (ln[j].jcioclntuid == num) {
|
||||
arr.push(<GenLN key={`ln${ln[j].kcioclntuid}`} data={ln[j]} isRoot={isRoot}/>)
|
||||
}
|
||||
}
|
||||
} else if (/^lc/.test(id)) {
|
||||
let idn = id.match(/^lc(\d+)$/);
|
||||
if (!idn || idn.length < 1)
|
||||
continue;
|
||||
let num = idn[1];
|
||||
for (let j in lc) {
|
||||
if (lc[j].jcioclctuid == num) {
|
||||
arr.push(<GenLC key={`lc${lc[j].jcioclctuid}`} data={lc[j]}/>)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Grid>
|
||||
{arr.map(t => t)
|
||||
}
|
||||
</Grid>
|
||||
)
|
||||
}
|
||||
|
||||
return <GenNode ids={[`ln${root}`]}/>
|
||||
}
|
||||
|
||||
const LinkInfo = ({
|
||||
i18n,
|
||||
open,
|
||||
root,
|
||||
ln,
|
||||
lc,
|
||||
onClose
|
||||
}) => {
|
||||
|
||||
return (
|
||||
<Modal size="fullscreen" open={open} onClose={() => {
|
||||
onClose()
|
||||
}}>
|
||||
<Modal.Content>
|
||||
<ParseTree root={root} ln={ln} lc={lc}/>
|
||||
</Modal.Content>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
export default LinkInfo;
|
||||
@@ -0,0 +1,22 @@
|
||||
import React from 'react';
|
||||
import {Table, Button} from 'semantic-ui-react';
|
||||
|
||||
const ListItem = ({i18n, data, swActive, delItem, showInfo}) => {
|
||||
|
||||
return (
|
||||
<Table.Row>
|
||||
<Table.Cell>
|
||||
<Button type="button" size="tiny" basic content="Delete" onClick={()=>{delItem(data.jcioclntuid || '')}}/>
|
||||
<Button type="button" size="tiny" basic content={data.lnactive == 1 ? 'Disable' : 'Enable'} onClick={()=>{swActive(data.jcioclntuid || '')}} />
|
||||
</Table.Cell>
|
||||
<Table.Cell>{data.jcioclntuid || ''}</Table.Cell>
|
||||
<Table.Cell>{data.lnname || ''}</Table.Cell>
|
||||
<Table.Cell>{data.lnactive == 1 ? '啟用' : '停用'}</Table.Cell>
|
||||
<Table.Cell>
|
||||
<Button type="button" size="tiny" basic content="顯示資訊" onClick={()=>{showInfo(data.jcioclntuid)}} />
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
)
|
||||
}
|
||||
|
||||
export default ListItem ;
|
||||
@@ -0,0 +1,100 @@
|
||||
import React from 'react';
|
||||
import {Container, Segment, Table, Button} from 'semantic-ui-react';
|
||||
import {getRequest} from '../../../actions';
|
||||
import {Link} from 'react-router';
|
||||
import ListItem from './ListItem';
|
||||
import LinkInfoModal from './LinkInfoModal';
|
||||
|
||||
const defState = {
|
||||
infoModal: {
|
||||
open: false,
|
||||
ln: [],
|
||||
lc: [],
|
||||
root: ''
|
||||
}
|
||||
}
|
||||
|
||||
class ActionLinkPage extends React.Component {
|
||||
state = {
|
||||
...defState
|
||||
}
|
||||
|
||||
componentDidMount(){
|
||||
this.props.getList();
|
||||
|
||||
this.props.router.setRouteLeaveHook(this.props.route, () => {
|
||||
this.props.clearList();
|
||||
})
|
||||
}
|
||||
|
||||
swLinkActive = (id) => {
|
||||
if(!id) return ;
|
||||
this.props.swLink({id});
|
||||
}
|
||||
delLink = (id) => {
|
||||
if(!id) return ;
|
||||
this.props.delLink({id});
|
||||
}
|
||||
openInfoModal = (id) => {
|
||||
if(!id) return ;
|
||||
|
||||
fetch('/api/link/getlink', getRequest({id}))
|
||||
.then(response=>response.json())
|
||||
.then(json => {
|
||||
if(json.status != 1 ) return this.props.showDialog(json.message);
|
||||
this.setState({
|
||||
infoModal:{
|
||||
open: true,
|
||||
root: id,
|
||||
ln: json.data.rt.ln || [],
|
||||
lc: json.data.rt.lc || []
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
closeInfoModal = () => {
|
||||
this.setState({
|
||||
infoModal:{
|
||||
...defState.infoModal
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
render(){
|
||||
let {i18n, list} = this.props;
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<Segment className="clearfix">
|
||||
<Button as={Link} to="/admin/addlink" basic color="green" floated="right" icon="plus" content="新增" style={{marginBottom: '10px'}} />
|
||||
<Table>
|
||||
<Table.Header>
|
||||
<Table.Row>
|
||||
<Table.HeaderCell>操作</Table.HeaderCell>
|
||||
<Table.HeaderCell>ID</Table.HeaderCell>
|
||||
<Table.HeaderCell>名稱</Table.HeaderCell>
|
||||
<Table.HeaderCell>啟用狀態</Table.HeaderCell>
|
||||
<Table.HeaderCell>觸發內容</Table.HeaderCell>
|
||||
</Table.Row>
|
||||
</Table.Header>
|
||||
<Table.Body>
|
||||
{
|
||||
list.map((t,idx) => (
|
||||
<ListItem key={idx} i18n={i18n} data={t} swActive={this.swLinkActive} delItem={this.delLink} showInfo={this.openInfoModal} />
|
||||
))
|
||||
}
|
||||
</Table.Body>
|
||||
</Table>
|
||||
</Segment>
|
||||
<LinkInfoModal i18n={i18n}
|
||||
open={this.state.infoModal.open}
|
||||
root={this.state.infoModal.root}
|
||||
ln={this.state.infoModal.ln}
|
||||
lc={this.state.infoModal.lc}
|
||||
onClose={this.closeInfoModal} />
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default ActionLinkPage;
|
||||
@@ -0,0 +1,132 @@
|
||||
import React from 'react';
|
||||
import {Grid, Form, Segment, Input} from 'semantic-ui-react';
|
||||
|
||||
const ops = [
|
||||
{
|
||||
"code": "0",
|
||||
"name": "等於"
|
||||
}, {
|
||||
"code": "1",
|
||||
"name": "大於"
|
||||
}, {
|
||||
"code": "2",
|
||||
"name": "小於"
|
||||
}, {
|
||||
"code": "3",
|
||||
"name": "大於等於"
|
||||
}, {
|
||||
"code": "4",
|
||||
"name": "小於等於"
|
||||
}, {
|
||||
"code": "5",
|
||||
"name": "不等於"
|
||||
}, {
|
||||
"code": "8",
|
||||
"name": "AND"
|
||||
}, {
|
||||
"code": "9",
|
||||
"name": "OR"
|
||||
}
|
||||
]
|
||||
|
||||
class UnitItem extends React.Component {
|
||||
|
||||
render() {
|
||||
let {unit, data, getList} = this.props;
|
||||
return (
|
||||
<Grid.Column>
|
||||
<Segment>
|
||||
<Form.Field>
|
||||
<label>選擇元件</label>
|
||||
<select
|
||||
value={data.st}
|
||||
onChange={e => {
|
||||
getList(unit, e.target.value);
|
||||
}}>
|
||||
<option value="">請選擇元件</option>
|
||||
<option value="leone">LeOne</option>
|
||||
<option value="di">DigitInput</option>
|
||||
<option value="time">時間</option>
|
||||
<option value="unit">已建立群組</option>
|
||||
</select>
|
||||
</Form.Field>
|
||||
{
|
||||
!data.st
|
||||
? null
|
||||
: (<UnitPanel data={data}/>)
|
||||
}
|
||||
</Segment>
|
||||
</Grid.Column>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const UnitPanel = ({data}) => {
|
||||
if (data.st == 'di') {
|
||||
return (
|
||||
<div>
|
||||
<LC_List data={data} />
|
||||
<select>
|
||||
<option value="">選擇狀態</option>
|
||||
<option value="0">0</option>
|
||||
<option value="1">1</option>
|
||||
</select>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
if(data.st == 'leone') {
|
||||
return (
|
||||
<div>
|
||||
<LC_List data={data} />
|
||||
<select>
|
||||
<option value="">選擇感測器</option>
|
||||
<option value="leone_ttrigger1">溫度</option>
|
||||
<option value="leone_htrigger1">濕度</option>
|
||||
</select>
|
||||
<Input size="mini" placeholder="請輸入數值" />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
if(data.st == 'unit') {
|
||||
return (
|
||||
<div>
|
||||
<select>
|
||||
<option value="">選擇群組</option>
|
||||
{
|
||||
data.list.map((t,idx) => (
|
||||
<option key={idx} value={t.id}>{t.name}</option>
|
||||
))
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
const LC_List = ({data}) => {
|
||||
return (
|
||||
<div>
|
||||
<select>
|
||||
<option value="">選擇裝置</option>
|
||||
{
|
||||
data.list.map((t, idx) => (
|
||||
<option key={idx} value={t.id}>{t.name}</option>
|
||||
))
|
||||
}
|
||||
</select>
|
||||
<select>
|
||||
<option value="">選擇條件</option>
|
||||
{
|
||||
ops.map((t,idx) => {
|
||||
if(t.code == 8 || t.code == 9) return ;
|
||||
return (<option key={idx} value={t.code}>{t.name}</option>)
|
||||
})
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default UnitItem;
|
||||
@@ -0,0 +1,138 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
Container,
|
||||
Segment,
|
||||
Form,
|
||||
Input,
|
||||
Button,
|
||||
Checkbox,
|
||||
Grid
|
||||
} from 'semantic-ui-react';
|
||||
import {getRequest} from '../../../actions';
|
||||
import UnitItem from './UnitItem';
|
||||
|
||||
const defState = {
|
||||
groups: {},
|
||||
edit: {
|
||||
active: false,
|
||||
name: '',
|
||||
type: 'ln',
|
||||
op: '',
|
||||
id1: {
|
||||
st: '',
|
||||
list: [],
|
||||
data: {}
|
||||
},
|
||||
id2: {
|
||||
st: '',
|
||||
list: [],
|
||||
data: {}
|
||||
}
|
||||
}
|
||||
}
|
||||
const gtype = {
|
||||
lc: {
|
||||
type: 'lc',
|
||||
id: '',
|
||||
op: '',
|
||||
value: ''
|
||||
},
|
||||
ln: {
|
||||
type: 'ln'
|
||||
}
|
||||
}
|
||||
|
||||
class ActionLinkAdd extends React.Component {
|
||||
state = {
|
||||
...defState
|
||||
}
|
||||
|
||||
getSelectList = (unit, type = '') => {
|
||||
if (!unit) {
|
||||
return;
|
||||
}
|
||||
let edit = {
|
||||
...this.state.edit
|
||||
};
|
||||
if (!(unit in edit)) {
|
||||
return;
|
||||
}
|
||||
edit[unit].st = type;
|
||||
edit[unit].data = {
|
||||
...gtype.lc
|
||||
}
|
||||
if (type != 'di' && type != 'leone') {
|
||||
return this.setState({edit});
|
||||
}
|
||||
|
||||
if (type == 'di' || type == 'leone') {
|
||||
this.props.toggleLoading(1);
|
||||
let json = {
|
||||
type
|
||||
};
|
||||
fetch('/api/system/getselectlist', getRequest(json))
|
||||
.then(response => response.json())
|
||||
.then(json => {
|
||||
if (json.status != 1)
|
||||
return this.props.showDialog(json.message);
|
||||
edit[unit].list = json.data.record || [];
|
||||
this.setState({edit}, () => {
|
||||
this.props.toggleLoading(0);
|
||||
});
|
||||
});
|
||||
}
|
||||
if(type == 'unit') {
|
||||
let list = [];
|
||||
for(let i in this.state.groups){
|
||||
list.push({id: i, name: this.state.groups[i].name});
|
||||
}
|
||||
edit[unit].list = list;
|
||||
edit[unit].data = {
|
||||
...gtype.ln
|
||||
}
|
||||
this.setState({edit})
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<Form as={Segment}>
|
||||
<Form.Field>
|
||||
<Checkbox label="啟用連動"/>
|
||||
</Form.Field>
|
||||
<Form.Field>
|
||||
<label>建立條件群組</label>
|
||||
<Segment color="red">
|
||||
<Form.Field>
|
||||
<Input label="節點名稱"/>
|
||||
</Form.Field>
|
||||
<Form.Field>
|
||||
<label>觸發條件</label>
|
||||
<select>
|
||||
<option value="">請選擇觸發條件</option>
|
||||
<option value="8">AND</option>
|
||||
<option value="9">OR</option>
|
||||
</select>
|
||||
</Form.Field>
|
||||
<Grid columns={2} padded>
|
||||
<UnitItem unit="id1" data={this.state.edit.id1} getList={this.getSelectList}/>
|
||||
<UnitItem unit="id2" data={this.state.edit.id2} getList={this.getSelectList}/>
|
||||
</Grid>
|
||||
<div
|
||||
style={{
|
||||
textAlign: 'right'
|
||||
}}>
|
||||
<Button type="button" basic size="tiny" color="blue" content="加入"/>
|
||||
<Button type="button" basic size="tiny" color="green" content="清除"/>
|
||||
</div>
|
||||
</Segment>
|
||||
</Form.Field>
|
||||
</Form>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default ActionLinkAdd;
|
||||
@@ -0,0 +1,28 @@
|
||||
import React from 'react';
|
||||
import {Table, Input, Checkbox, Label} from 'semantic-ui-react';
|
||||
|
||||
const DiItem = ({i18n, cusKey, data, onNameChange, onLogicChange, status}) => {
|
||||
|
||||
return (
|
||||
<Table.Row>
|
||||
<Table.Cell>
|
||||
<Label content={cusKey}/>
|
||||
</Table.Cell>
|
||||
<Table.Cell width={4}>
|
||||
<Input fluid name="diname" value={data.diname || ''} onChange={(e) => onNameChange(cusKey, e.target.value)} />
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
<Checkbox toggle={true} label={i18n&&i18n.t ? i18n.t('page.dio.form.label.logic') : ''} checked={data.dilogic == 1 ? true : false} onChange={(e, d) => onLogicChange(cusKey, d.checked)}/>
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
<span>{i18n&&i18n.t ? i18n.t('page.dio.form.label.di_status') : ''} <Label color={status == 0 ? 'green' : 'red'} size="tiny" content={
|
||||
i18n&&i18n.t ?
|
||||
(status == 0 ? i18n.t('page.dio.form.label.di_not_triggered') : i18n.t('page.dio.form.label.di_triggered')) :
|
||||
"Loading..."
|
||||
}/></span>
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
)
|
||||
}
|
||||
|
||||
export default DiItem;
|
||||
@@ -0,0 +1,24 @@
|
||||
import React from 'react';
|
||||
import {Table, Input, Checkbox, Label} from 'semantic-ui-react';
|
||||
|
||||
const DoItem = ({i18n, cusKey, data, onNameChange, onLogicChange, status, onDoRun}) => {
|
||||
|
||||
return (
|
||||
<Table.Row>
|
||||
<Table.Cell>
|
||||
<Label content={cusKey}/>
|
||||
</Table.Cell>
|
||||
<Table.Cell width={4}>
|
||||
<Input fluid name="doname" value={data.doname || ''} onChange={(e) => {onNameChange(cusKey, e.target.value)}} />
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
<Checkbox toggle={true} label={i18n&&i18n.t ? i18n.t('page.dio.form.label.logic') : ''} checked={data.dologic == 1 ? true : false } onChange={(e, d)=>{onLogicChange(cusKey, d.checked)}} />
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
<Checkbox toggle={true} label={i18n&&i18n.t ? i18n.t('page.dio.form.label.do_ctrl') : ''} checked={status == 1} onChange={(e,d) => { onDoRun(cusKey, d.checked) }} />
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
)
|
||||
}
|
||||
|
||||
export default DoItem;
|
||||
@@ -0,0 +1,175 @@
|
||||
import React from 'react';
|
||||
import {Container, Grid, Segment, Header, CheckBox, Table, Input, Button} from 'semantic-ui-react';
|
||||
import DoItem from './DoItem';
|
||||
import DiItem from './DiItem';
|
||||
|
||||
class DIO extends React.Component {
|
||||
state = {
|
||||
do: [],
|
||||
di: [],
|
||||
doSt: {},
|
||||
diSt: {}
|
||||
}
|
||||
|
||||
tick = null
|
||||
|
||||
onNameChange = (key, name) => {
|
||||
let reg = new RegExp(`^${key}$`, 'i');
|
||||
if(/^do/i.test(key)) {
|
||||
let dos = [...this.state.do];
|
||||
for(let i in dos){
|
||||
if(reg.test(dos[i].doid)){
|
||||
dos[i].doname = name;
|
||||
this.setState({
|
||||
do: dos
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
let dis = [...this.state.di];
|
||||
for(let i in dis){
|
||||
if(reg.test(dis[i].diid)){
|
||||
dis[i].diname = name;
|
||||
this.setState({
|
||||
di: dis
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onLogicChange = (key, st) => {
|
||||
let reg = new RegExp(`^${key}$`, 'i');
|
||||
if(/^do/i.test(key)) {
|
||||
let dos = [...this.state.do];
|
||||
for(let i in dos){
|
||||
if(reg.test(dos[i].doid)){
|
||||
dos[i].dologic = st ? 1 : 0;
|
||||
this.setState({
|
||||
do: dos
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
let dis = [...this.state.di];
|
||||
for(let i in dis){
|
||||
if(reg.test(dis[i].diid)){
|
||||
dis[i].dilogic = st ? 1 : 0;
|
||||
this.setState({
|
||||
di: dis
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateSetting = () => {
|
||||
let dos = [...this.state.do];
|
||||
let dis = [...this.state.di];
|
||||
let json = {};
|
||||
json.do = {};
|
||||
json.di = {};
|
||||
for(let i in dos) {
|
||||
json.do[dos[i].doid] = {
|
||||
name: dos[i].doname,
|
||||
logic: dos[i].dologic
|
||||
}
|
||||
}
|
||||
for(let i in dis){
|
||||
json.di[dis[i].diid] ={
|
||||
name: dis[i].diname,
|
||||
logic: dis[i].dilogic
|
||||
}
|
||||
}
|
||||
|
||||
this.props.setDIOInfo(json);
|
||||
}
|
||||
|
||||
doRun = (key, val) => {
|
||||
let reg = /^do([0-9]+)$/i;
|
||||
let m = key.match(reg);
|
||||
if(!m || !m[1]) return ;
|
||||
let pin = m[1];
|
||||
if(pin in this.state.doSt){
|
||||
let tmp = {...this.state.doSt};
|
||||
tmp[pin] = val ? 1 : 0;
|
||||
this.setState({
|
||||
doSt: tmp
|
||||
})
|
||||
}
|
||||
this.props.dotRun(pin, val ? 1 : 0);
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
this.setState({
|
||||
do: nextProps.dio.do,
|
||||
di: nextProps.dio.di,
|
||||
diSt: nextProps.dio.diSt,
|
||||
doSt: nextProps.dio.doSt
|
||||
});
|
||||
}
|
||||
|
||||
updateTick = () => {
|
||||
this.props.getIO();
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.props.getDIOInfo();
|
||||
this.props.getIO();
|
||||
this.tick = setInterval(this.updateTick, 5000);
|
||||
|
||||
this.props.router.setRouteLeaveHook(this.props.route, () => {
|
||||
this.props.clearList();
|
||||
})
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
clearInterval(this.tick);
|
||||
}
|
||||
|
||||
render () {
|
||||
let {i18n} = this.props;
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<Grid columns={2}>
|
||||
<Grid.Column>
|
||||
<Header as="h4" color="blue" content={i18n&&i18n.t ? i18n.t('page.dio.title.do'): ''}/>
|
||||
<Table>
|
||||
<Table.Body>
|
||||
{
|
||||
[1,2,3,4,5,6,7,8].map(t => {
|
||||
let tmp = this.state.do.filter(tt => tt.doid == `do${t}`);
|
||||
let dost = this.state.doSt[t] || 0;
|
||||
return <DoItem i18n={i18n} key={t} cusKey={`Do${t}`} data={tmp[0] || {}} onLogicChange={this.onLogicChange} onNameChange={this.onNameChange} status={dost} onDoRun={this.doRun}/>
|
||||
})
|
||||
}
|
||||
</Table.Body>
|
||||
</Table>
|
||||
</Grid.Column>
|
||||
<Grid.Column>
|
||||
<Header as="h4" color="blue" content={i18n&&i18n.t ? i18n.t('page.dio.title.di'): ''}/>
|
||||
<Table>
|
||||
<Table.Body>
|
||||
{
|
||||
[1,2,3,4,5,6,7,8].map(t => {
|
||||
let tmp = this.state.di.filter(tt => tt.diid == `di${t}`);
|
||||
let dist = this.state.diSt[t] || 0;
|
||||
return <DiItem i18n={i18n} key={t} cusKey={`Di${t}`} data={tmp[0] || {}} onLogicChange={this.onLogicChange} onNameChange={this.onNameChange} status={dist} />
|
||||
})
|
||||
}
|
||||
</Table.Body>
|
||||
</Table>
|
||||
</Grid.Column>
|
||||
</Grid>
|
||||
<Button type="button" style={{marginTop: '10px'}} fluid content={i18n&&i18n.t ? i18n.t('page.dio.form.button.update_setting') : ''} onClick={() => {this.updateSetting()}} />
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default DIO;
|
||||
@@ -0,0 +1,17 @@
|
||||
import React from 'react';
|
||||
import {List, Button, Label} from 'semantic-ui-react';
|
||||
|
||||
const SelectedItem = ({i18n, data, idx, removeSelect}) => {
|
||||
|
||||
return (
|
||||
<List.Item>
|
||||
<List.Content floated="right">
|
||||
<Button type="button" size="mini" content={i18n&&i18n.t ? i18n.t('page.iogroup.form.button.remove') : ''} onClick={() => {removeSelect(idx)}} />
|
||||
</List.Content>
|
||||
<Label content={data.type || ''} />
|
||||
{data.name || ''}
|
||||
</List.Item>
|
||||
)
|
||||
}
|
||||
|
||||
export default SelectedItem;
|
||||
@@ -0,0 +1,129 @@
|
||||
import React from 'react';
|
||||
import {Container, Segment, Form, Button, List, Input} from 'semantic-ui-react';
|
||||
import DeviceSelect from '../../Common/DeviceSelect';
|
||||
import SelectedItem from './SelectedItem';
|
||||
|
||||
class IOCmdPage extends React.Component {
|
||||
state = {
|
||||
showTemp: false,
|
||||
selectItem: []
|
||||
}
|
||||
|
||||
querySelectList = (type) => {
|
||||
this.props.clearSelectList();
|
||||
if(!type) return ;
|
||||
this.props.getSelectList({type});
|
||||
}
|
||||
|
||||
checkShowTemp = (cmd) => {
|
||||
this.setState({
|
||||
showTemp: cmd == 2 ? true : false
|
||||
})
|
||||
}
|
||||
|
||||
addSelect = (data) => {
|
||||
let tmp = this.state.selectItem.filter(t => t.id == data.id);
|
||||
if(tmp.length > 0) return ;
|
||||
this.setState({
|
||||
selectItem: [...this.state.selectItem, data]
|
||||
});
|
||||
}
|
||||
|
||||
removeSelect = (idx) => {
|
||||
this.state.selectItem.splice(idx, 1);
|
||||
this.setState({
|
||||
selectItem: this.state.selectItem
|
||||
})
|
||||
}
|
||||
|
||||
runCmd = (data) => {
|
||||
let {i18n} = this.props;
|
||||
if(!data.cmd) return this.props.showDialog(i18n&&i18n.t ? i18n.t('tip.select_action') : '');
|
||||
if(data.cmd == 2){
|
||||
if(!data.temp) return this.props.showDialog(i18n&&i18n.t ? i18n.t('tip.input_empty_temp') : '');
|
||||
if(!(data.temp > 16 && data.temp < 30)) return this.props.showDialog(i18n&&i18n.t ? i18n.t('tip.temp_format') : '');
|
||||
|
||||
data.cmd = `${data.cmd} ${data.temp}`;
|
||||
}
|
||||
|
||||
let ids = this.state.selectItem.map(t => t.id);
|
||||
|
||||
let json = {
|
||||
...data,
|
||||
devs: ids.join(',')
|
||||
}
|
||||
|
||||
this.props.runCmd(json);
|
||||
|
||||
this.setState({
|
||||
showTemp: false,
|
||||
selectItem: []
|
||||
}, ()=>{
|
||||
this.props.clearSelectList();
|
||||
})
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.props.clearSelectList();
|
||||
}
|
||||
|
||||
render() {
|
||||
let {i18n,permissions,devs} = this.props;
|
||||
let actlist = i18n&&i18n.getResource&&i18n.language ? i18n.getResource(i18n.language + '.translation.action_list') : [];
|
||||
return (
|
||||
<Container>
|
||||
<Segment>
|
||||
<Form onSubmit={(e,d) => {
|
||||
e.preventDefault();
|
||||
this.runCmd(d.formData);
|
||||
}} serializer={e => {
|
||||
let json = {
|
||||
cmd: '',
|
||||
temp: ''
|
||||
};
|
||||
let sel = e.querySelector('select[name="cmd"]');
|
||||
if(sel && 'value' in sel) json.cmd = sel.value;
|
||||
let temp = e.querySelector('input[name="temp"]');
|
||||
if(temp && 'value' in temp) json.temp = temp.value;
|
||||
|
||||
if(e.reset) e.reset();
|
||||
|
||||
return json;
|
||||
}}>
|
||||
<Form.Field>
|
||||
<label>{i18n&&i18n.t ? i18n.t('page.iocmd.form.label.action') : ''}</label>
|
||||
<select name="cmd" onChange={e => {
|
||||
this.checkShowTemp(e.target.value);
|
||||
}}>
|
||||
<option value="">{i18n&&i18n.t ? i18n.t('select.action') : ''}</option>
|
||||
{
|
||||
actlist.map((t,idx) => <option key={idx} value={t.cmd}>{t.name}</option>)
|
||||
}
|
||||
</select>
|
||||
</Form.Field>
|
||||
{
|
||||
this.state.showTemp ?
|
||||
(<Form.Field>
|
||||
<Input name="temp" label={i18n&&i18n.t ? i18n.t('page.iocmd.form.label.temp') : ''} />
|
||||
</Form.Field>) : null
|
||||
}
|
||||
<DeviceSelect i18n={i18n} devs={devs} page="iocmd" showGroup={true} permissions={permissions} querySelectList={this.querySelectList} addSelect={this.addSelect} />
|
||||
<Form.Field>
|
||||
<label>{i18n&&i18n.t ? i18n.t('page.iocmd.form.label.selected_device') : ''}</label>
|
||||
<Segment>
|
||||
<List divided relaxed={true}>
|
||||
{
|
||||
this.state.selectItem.map((t,idx) => <SelectedItem key={idx} i18n={i18n} data={t} idx={idx} removeSelect={this.removeSelect} />)
|
||||
}
|
||||
</List>
|
||||
</Segment>
|
||||
</Form.Field>
|
||||
<Button type="submit" fluid content={i18n&&i18n.t ? i18n.t('page.iocmd.form.button.submit') : ''} />
|
||||
</Form>
|
||||
</Segment>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default IOCmdPage;
|
||||
@@ -0,0 +1,51 @@
|
||||
import React from 'react';
|
||||
import {Modal, Form, Input, Segment, Grid, Button, Header, List} from 'semantic-ui-react';
|
||||
import SelectedItem from './SelectedItem';
|
||||
import DeviceSelect from '../../Common/DeviceSelect';
|
||||
|
||||
const GroupModal = ({i18n, open, type, data, devs, permissions, onClose, onSubmit, selected, removeSelect, addSelect, querySelectList}) => {
|
||||
|
||||
return (
|
||||
<Modal open={open}>
|
||||
<Modal.Header content={i18n&&i18n.t ? (type == 1 ? i18n.t('page.iogroup.form.title.edit') : i18n.t('page.iogroup.form.title.add')) : ''} />
|
||||
<Modal.Content>
|
||||
<Form onSubmit={(e,d) => {
|
||||
e.preventDefault();
|
||||
onSubmit(type, d.formData);
|
||||
}} serializer={e => {
|
||||
let json = {
|
||||
name: '',
|
||||
id: data.iogroupuid || 0
|
||||
};
|
||||
let n = e.querySelector('input[name="name"]');
|
||||
if(n && 'value' in n) json.name = n.value;
|
||||
|
||||
return json;
|
||||
}}>
|
||||
<Form.Field>
|
||||
<Input label={i18n&&i18n.t?i18n.t('page.iogroup.form.label.name') : ''} name="name" defaultValue={data.iogroupname || ''} />
|
||||
</Form.Field>
|
||||
<DeviceSelect i18n={i18n} devs={devs} page="iogroup" showGroup={false} permissions={permissions} addSelect={addSelect} querySelectList={querySelectList} />
|
||||
<Segment>
|
||||
<Header as="h4" content={i18n&&i18n.t ? i18n.t('page.iogroup.form.label.selected_device') : ''} />
|
||||
<List divided verticalAlign="middle">
|
||||
{
|
||||
selected.map((t, idx) => <SelectedItem i18n={i18n} key={idx} data={t} idx={idx} removeSelect={removeSelect}/>)
|
||||
}
|
||||
</List>
|
||||
</Segment>
|
||||
<Grid columns={2}>
|
||||
<Grid.Column>
|
||||
<Button fluid type="submit" content={i18n&&i18n.t?i18n.t('page.leone.form.button.submit'):''}/>
|
||||
</Grid.Column>
|
||||
<Grid.Column>
|
||||
<Button fluid type="button" content={i18n&&i18n.t?i18n.t('page.leone.form.button.cancel'):''} onClick={() => {onClose()}}/>
|
||||
</Grid.Column>
|
||||
</Grid>
|
||||
</Form>
|
||||
</Modal.Content>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
export default GroupModal;
|
||||
@@ -0,0 +1,55 @@
|
||||
import React from 'react';
|
||||
import {Table, Button, Label, Item} from 'semantic-ui-react';
|
||||
|
||||
const ListItem = ({i18n, data, dos, les, openItemModal, onDelete, openModal}) => {
|
||||
let devs = data.iogroupid || '';
|
||||
let dev = devs.split(',');
|
||||
let items = [];
|
||||
if(dev.length > 0){
|
||||
for(let i in dev){
|
||||
if(/^do/i.test(dev[i])){
|
||||
for(let j in dos){
|
||||
if(`do${dos[j].douid}` == dev[i]) {
|
||||
items.push({
|
||||
type: 'DigitOutput',
|
||||
name: dos[j].doname,
|
||||
id: dev[i]
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}else if(/^le/i.test(dev[i])){
|
||||
for(let j in les){
|
||||
if(`le${les[j].leonelistuid}` == dev[i]) {
|
||||
items.push({
|
||||
type: 'LeOne',
|
||||
name: les[j].leonename,
|
||||
id: dev[i]
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return (
|
||||
<Table.Row>
|
||||
<Table.Cell>
|
||||
<Button type="button" basic size="tiny" color="red" content={i18n&&i18n.t ? i18n.t('page.iogroup.table.button.del') : ''} onClick={()=>{onDelete(data.iogroupuid)}} />
|
||||
<Button type="button" basic size="tiny" color="blue" content={i18n&&i18n.t ? i18n.t('page.iogroup.table.button.edit') : ''} onClick={() => {openModal(1, data, items)}}/>
|
||||
</Table.Cell>
|
||||
<Table.Cell>{data.iogroupname}</Table.Cell>
|
||||
<Table.Cell>
|
||||
{
|
||||
items.length > 0 ?
|
||||
(items.length == 1 ?
|
||||
<Item><Label content={items[0].type} />{items[0].name}</Item>:
|
||||
<Button size="tiny" basic content={i18n&&i18n.t ? i18n.t('page.iogroup.table.button.showgroup') : ''} onClick={()=>{openItemModal(items)}}/> ) :
|
||||
''
|
||||
}
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
)
|
||||
}
|
||||
|
||||
export default ListItem;
|
||||
@@ -0,0 +1,17 @@
|
||||
import React from 'react';
|
||||
import {List, Button, Label} from 'semantic-ui-react';
|
||||
|
||||
const SelectedItem = ({i18n, data, idx, removeSelect}) => {
|
||||
|
||||
return (
|
||||
<List.Item>
|
||||
<List.Content floated="right">
|
||||
<Button type="button" size="mini" content={i18n&&i18n.t ? i18n.t('page.iogroup.form.button.remove') : ''} onClick={() => {removeSelect(idx)}} />
|
||||
</List.Content>
|
||||
<Label content={data.type || ''} />
|
||||
{data.name || ''}
|
||||
</List.Item>
|
||||
)
|
||||
}
|
||||
|
||||
export default SelectedItem;
|
||||
@@ -0,0 +1,152 @@
|
||||
import React from 'react';
|
||||
import {Container, Table, Button, Segment, Modal, Item, Label} from 'semantic-ui-react';
|
||||
import ListItem from './ListItem';
|
||||
import GroupModal from './GroupModal';
|
||||
|
||||
class IOGroupPage extends React.Component {
|
||||
state = {
|
||||
modal: false,
|
||||
modalType: 0,
|
||||
modalData: {},
|
||||
modalSelect: [],
|
||||
showItem: false,
|
||||
items: []
|
||||
}
|
||||
|
||||
showGroupItems = (items = []) => {
|
||||
|
||||
this.setState({
|
||||
showItem: true,
|
||||
items
|
||||
})
|
||||
}
|
||||
closeItemModal = () => {
|
||||
this.setState({
|
||||
showItem: false,
|
||||
items: []
|
||||
})
|
||||
}
|
||||
|
||||
openModal = (type, data= {}, items=[]) => {
|
||||
this.props.clearSelectList();
|
||||
this.setState({
|
||||
modal: true,
|
||||
modalType: type,
|
||||
modalData: data,
|
||||
modalSelect: items
|
||||
})
|
||||
}
|
||||
closeModal = () => {
|
||||
this.setState({
|
||||
modal: false,
|
||||
modalData: {},
|
||||
modalSelect: []
|
||||
})
|
||||
}
|
||||
submitModal = (type, data ={}) => {
|
||||
let {i18n} = this.props;
|
||||
if(!data.name || (type == 1 && !data.id)) return this.props.showDialog(i18n&&i18n.t ? i18n.t('tip.input_empty') : '');
|
||||
|
||||
let ids = this.state.modalSelect.map(t => t.id);
|
||||
|
||||
let json = {
|
||||
...data,
|
||||
devs: ids.join(',')
|
||||
};
|
||||
|
||||
if(type == 1) {
|
||||
this.props.editIOGroup(json);
|
||||
}else {
|
||||
this.props.addIOGroup(json);
|
||||
}
|
||||
|
||||
this.closeModal()
|
||||
}
|
||||
|
||||
querySelectList = (type) => {
|
||||
this.props.clearSelectList();
|
||||
if(!type) return ;
|
||||
this.props.getSelectList({type});
|
||||
}
|
||||
|
||||
removeSelect = (idx) => {
|
||||
this.state.modalSelect.splice(idx, 1);
|
||||
this.setState({
|
||||
modalSelect: this.state.modalSelect
|
||||
})
|
||||
}
|
||||
|
||||
addSelect = (data = {}) => {
|
||||
let tmp = this.state.modalSelect.filter(t => t.id == data.id);
|
||||
if(tmp.length > 0) return ;
|
||||
this.setState({
|
||||
modalSelect: [...this.state.modalSelect, data]
|
||||
})
|
||||
}
|
||||
|
||||
delIOGroup = (id) => {
|
||||
if(!id) return ;
|
||||
this.props.delIOGroup({id});
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.props.getIOGroupList();
|
||||
|
||||
this.props.router.setRouteLeaveHook(this.props.route, () => {
|
||||
this.props.clearList();
|
||||
})
|
||||
}
|
||||
|
||||
render () {
|
||||
let {i18n, list, dos, leones, permissions, devs} = this.props;
|
||||
return (
|
||||
<Container>
|
||||
<Segment className="clearfix">
|
||||
<Button basic type="button" color="green" floated="right" style={{marginBottom: '15px'}} icon="plus" content={i18n&&i18n.t ? i18n.t('page.iogroup.table.button.add') : ''} onClick={() => {this.openModal(0)}} />
|
||||
<Table>
|
||||
<Table.Header>
|
||||
<Table.Row>
|
||||
<Table.HeaderCell>{i18n&&i18n.t ? i18n.t('page.iogroup.table.operate') : ''}</Table.HeaderCell>
|
||||
<Table.HeaderCell>{i18n&&i18n.t ? i18n.t('page.iogroup.table.name') : ''}</Table.HeaderCell>
|
||||
<Table.HeaderCell>{i18n&&i18n.t ? i18n.t('page.iogroup.table.groups') : ''}</Table.HeaderCell>
|
||||
</Table.Row>
|
||||
</Table.Header>
|
||||
<Table.Body>
|
||||
{
|
||||
list.map((t, idx) => <ListItem i18n={i18n} key={idx} data={t} dos={dos} les={leones} openItemModal={this.showGroupItems} onDelete={this.delIOGroup} openModal={this.openModal}/>)
|
||||
}
|
||||
</Table.Body>
|
||||
</Table>
|
||||
</Segment>
|
||||
<ShowGroupItem open={this.state.showItem} items={this.state.items} onClose={this.closeItemModal} />
|
||||
<GroupModal i18n={i18n}
|
||||
open={this.state.modal}
|
||||
data={this.state.modalData}
|
||||
type={this.state.modalType}
|
||||
onClose={this.closeModal}
|
||||
onSubmit={this.submitModal}
|
||||
permissions={permissions}
|
||||
devs={devs}
|
||||
selected={this.state.modalSelect}
|
||||
removeSelect={this.removeSelect}
|
||||
addSelect={this.addSelect}
|
||||
querySelectList={this.querySelectList} />
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const ShowGroupItem = ({i18n,open,items, onClose}) => {
|
||||
|
||||
return (
|
||||
<Modal open={open} onClose={() => {onClose()}} size="small">
|
||||
<Modal.Content>
|
||||
{
|
||||
items.map((t, idx) => <Item key={idx}><Label content={t.type}/>{t.name}</Item>)
|
||||
}
|
||||
</Modal.Content>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
export default IOGroupPage;
|
||||
@@ -0,0 +1,52 @@
|
||||
import React from 'react';
|
||||
import {Modal, Form, Header, Grid, Button, Input} from 'semantic-ui-react';
|
||||
|
||||
const CmdModal = ({i18n, open, id, devname, cmd, onSubmit, onClose}) => {
|
||||
let actlist = i18n&&i18n.getResource&&i18n.language ? i18n.getResource(i18n.language + '.translation.action_list') : [];
|
||||
let act = actlist.filter(t => t.cmd == cmd);
|
||||
|
||||
return (
|
||||
<Modal open={open} closeOnDimmerClick={false}>
|
||||
<Modal.Content>
|
||||
<Form onSubmit={(e, d) => {
|
||||
e.preventDefault();
|
||||
onSubmit(d.formData);
|
||||
}} serializer={e => {
|
||||
let json = {
|
||||
devs: `le${id}`
|
||||
};
|
||||
|
||||
json.cmd = cmd;
|
||||
if(json.cmd == 2){
|
||||
let el = e.querySelector('input[name="temp"]');
|
||||
if(el && 'value' in el){
|
||||
json.cmd = `${json.cmd} ${el.value}`
|
||||
}
|
||||
}
|
||||
|
||||
return json;
|
||||
}}>
|
||||
<Header as="h4" content={devname || ''}/>
|
||||
<Header as="h4" content={`${i18n&&i18n.t?i18n.t('page.leone.form.label.run_command'):''} ${act[0] ? act[0].name : ''}`} />
|
||||
{
|
||||
cmd && cmd == '2' ?
|
||||
(<Form.Field>
|
||||
<Input fluid name="temp" label={i18n&&i18n.t ? i18n.t('page.leone.form.label.temp') : ''}/>
|
||||
</Form.Field>) :
|
||||
null
|
||||
}
|
||||
<Grid columns={2} style={{marginTop: '15px'}}>
|
||||
<Grid.Column>
|
||||
<Button fluid type="submit" content={i18n&&i18n.t?i18n.t('page.leone.form.button.submit'):''}/>
|
||||
</Grid.Column>
|
||||
<Grid.Column>
|
||||
<Button fluid type="button" content={i18n&&i18n.t?i18n.t('page.leone.form.button.cancel'):''} onClick={() => {onClose()}}/>
|
||||
</Grid.Column>
|
||||
</Grid>
|
||||
</Form>
|
||||
</Modal.Content>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
export default CmdModal;
|
||||
@@ -0,0 +1,46 @@
|
||||
import React from 'react';
|
||||
import {Modal, Form, Input, Grid, Button} from 'semantic-ui-react';
|
||||
|
||||
const LeOneModal = ({i18n, open, type, data, onSubmit, onClose}) => {
|
||||
|
||||
return (
|
||||
<Modal open={open}>
|
||||
<Modal.Header content={i18n&&i18n.t ? (type == 1 ? i18n.t('page.leone.form.title.edit') : i18n.t('page.leone.form.title.add')) : '' } />
|
||||
<Modal.Content>
|
||||
<Form onSubmit={(e,d) => {
|
||||
e.preventDefault();
|
||||
onSubmit(type, d.formData);
|
||||
}} serializer={e => {
|
||||
let json = {
|
||||
id: data.leonelistuid || 0,
|
||||
name: e.querySelector('input[name="name"]').value,
|
||||
ip: e.querySelector('input[name="ip"]').value,
|
||||
password: e.querySelector('input[name="password"]').value
|
||||
};
|
||||
|
||||
return json ;
|
||||
}}>
|
||||
<Form.Field>
|
||||
<Input label={i18n&&i18n.t?i18n.t('page.leone.form.label.name'):''} name="name" defaultValue={data.leonename || ''} />
|
||||
</Form.Field>
|
||||
<Form.Field>
|
||||
<Input label={i18n&&i18n.t?i18n.t('page.leone.form.label.ip'):''} name="ip" disabled={type == 1} defaultValue={data.leoneip || ''} />
|
||||
</Form.Field>
|
||||
<Form.Field>
|
||||
<Input label={i18n&&i18n.t?i18n.t('page.leone.form.label.password'):''} name="password" defaultValue={data.leonepassword || ''} />
|
||||
</Form.Field>
|
||||
<Grid columns={2}>
|
||||
<Grid.Column>
|
||||
<Button fluid type="submit" content={i18n&&i18n.t?i18n.t('page.leone.form.button.submit'):''}/>
|
||||
</Grid.Column>
|
||||
<Grid.Column>
|
||||
<Button fluid type="button" content={i18n&&i18n.t?i18n.t('page.leone.form.button.cancel'):''} onClick={() => {onClose()}}/>
|
||||
</Grid.Column>
|
||||
</Grid>
|
||||
</Form>
|
||||
</Modal.Content>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
export default LeOneModal;
|
||||
@@ -0,0 +1,46 @@
|
||||
import React from 'react';
|
||||
import {Table, Button} from 'semantic-ui-react';
|
||||
|
||||
const ListItem = ({i18n, data, status, delLeone, editLeone, runCmd}) => {
|
||||
let stats = i18n&&i18n.getResource&&i18n.language ? i18n.getResource(i18n.language + '.translation.leone_stats') : [];
|
||||
let actlist = i18n&&i18n.getResource&&i18n.language ? i18n.getResource(i18n.language + '.translation.action_list') : [];
|
||||
let st = stats.filter(t => t.mode == status.mode);
|
||||
let tunit = i18n&&i18n.t ? [i18n.t('time_unit.sec'), i18n.t('time_unit.min'), i18n.t('time_unit.hour'), i18n.t('time_unit.day')] : [];
|
||||
let idx = 0;
|
||||
let mtime = Math.floor(Date.now() / 1000) - status.mtime;
|
||||
while(idx < 3){
|
||||
if(mtime >= 60){
|
||||
mtime = Math.floor(mtime / 60);
|
||||
idx++;
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (
|
||||
<Table.Row>
|
||||
<Table.Cell>
|
||||
<Button type="button" basic size="tiny" color="red" content={i18n&&i18n.t ? i18n.t('page.leone.table.button.del') : ''} onClick={() => {delLeone(data.leonelistuid)}} />
|
||||
<Button type="button" basic size="tiny" color="blue" content={i18n&&i18n.t ? i18n.t('page.leone.table.button.edit') : ''} onClick={() => {editLeone(1, data)}} />
|
||||
</Table.Cell>
|
||||
<Table.Cell>{data.leonename}</Table.Cell>
|
||||
<Table.Cell>{data.leoneip}</Table.Cell>
|
||||
<Table.Cell>{`${status.ts == '9999' || !isFinite(status.ts) ? '-' : `${status.ts} ${String.fromCharCode(8451)}`} / ${status.hs == '9999' || !isFinite(status.hs) ? '-' : `${status.hs} %`}`}</Table.Cell>
|
||||
<Table.Cell>{st[0]&&st[0].name ? st[0].name : status.mode}</Table.Cell>
|
||||
<Table.Cell>{data.leonepassword}</Table.Cell>
|
||||
<Table.Cell>{`${mtime}${tunit[idx]}${i18n&&i18n.t? i18n.t('time_unit.ago') : ''}`}</Table.Cell>
|
||||
<Table.Cell>
|
||||
<select onChange={(e)=>{
|
||||
runCmd(data.leonelistuid, data.leonename, e.target.value);
|
||||
e.target.selectedIndex = 0;
|
||||
}}>
|
||||
<option value="">{i18n&&i18n.t ? i18n.t('tip.select_action') : ''}</option>
|
||||
{
|
||||
actlist.map((t, idx) => <option key={idx} value={t.cmd}>{t.name}</option>)
|
||||
}
|
||||
</select>
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
)
|
||||
}
|
||||
|
||||
export default ListItem;
|
||||
@@ -0,0 +1,52 @@
|
||||
import React from 'react';
|
||||
import {Container, Table, Segment, Form, Grid, Button, Input} from 'semantic-ui-react';
|
||||
|
||||
const ScanForm = ({i18n, onSubmit}) => {
|
||||
|
||||
return (
|
||||
<Form onSubmit={(e, data) => {
|
||||
e.preventDefault();
|
||||
onSubmit(data.formData);
|
||||
}} serializer={e => {
|
||||
let json = {
|
||||
ip1: e.querySelector('input[name="ip1"]').value,
|
||||
ip2: e.querySelector('input[name="ip2"]').value,
|
||||
ip3: e.querySelector('input[name="ip3"]').value,
|
||||
password: e.querySelector('input[name="pass"]').value
|
||||
};
|
||||
|
||||
return json;
|
||||
}}>
|
||||
<Grid verticalAlign="middle">
|
||||
<Grid.Column computer={8} mobile={16}>
|
||||
<Form.Group inline={true}>
|
||||
<Form.Field>
|
||||
<label>{i18n&&i18n.t ? i18n.t('page.leone.form.label.ip') : ''}</label>
|
||||
<Input style={{width: '60px'}} defaultValue="192" name="ip1"/>
|
||||
</Form.Field>
|
||||
<Form.Field>
|
||||
<Input style={{width: '60px'}} defaultValue="168" name="ip2"/>
|
||||
</Form.Field>
|
||||
<Form.Field>
|
||||
<Input style={{width: '60px'}} defaultValue="1" name="ip3"/>
|
||||
</Form.Field>
|
||||
<Form.Field>
|
||||
<Input style={{width: '60px'}} defaultValue="*" disabled/>
|
||||
</Form.Field>
|
||||
</Form.Group>
|
||||
<Form.Group inline={true}>
|
||||
<Form.Field>
|
||||
<label>{i18n&&i18n.t ? i18n.t('page.leone.form.label.password') : ''}</label>
|
||||
<Input name="pass" />
|
||||
</Form.Field>
|
||||
</Form.Group>
|
||||
</Grid.Column>
|
||||
<Grid.Column computer={8} mobile={16}>
|
||||
<Button type="submit" fluid icon="search" content={i18n&&i18n.t ? i18n.t('page.leone.form.button.scan') : ''} />
|
||||
</Grid.Column>
|
||||
</Grid>
|
||||
</Form>
|
||||
)
|
||||
}
|
||||
|
||||
export default ScanForm;
|
||||
@@ -0,0 +1,123 @@
|
||||
import React from 'react';
|
||||
import {Modal, Grid, Label, Button, Table, Checkbox} from 'semantic-ui-react';
|
||||
import ScanItem from './SelectScanItem';
|
||||
|
||||
class SelectScan extends React.Component {
|
||||
|
||||
state = {
|
||||
list: [],
|
||||
page: 1,
|
||||
per: 10,
|
||||
totalpage: 1
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if(this.state.list.length !== nextProps.list) {
|
||||
let totalpage = Math.ceil( nextProps.list.length / this.state.per ) || 1;
|
||||
this.setState({
|
||||
list: nextProps.list,
|
||||
totalpage
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
onItemSelect = (idx, checked) => {
|
||||
let list = [...this.state.list];
|
||||
if(list[idx]){
|
||||
list[idx].checked = checked;
|
||||
this.setState({
|
||||
list
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
changePage = (p = 1) => {
|
||||
p = p < 1 ? 1 : p;
|
||||
p = p > this.state.totalpage ? this.state.totalpage : p;
|
||||
this.setState({
|
||||
page: p
|
||||
});
|
||||
}
|
||||
|
||||
calSelect = () => {
|
||||
let a = this.state.list.filter(t => t.checked);
|
||||
return a.length;
|
||||
}
|
||||
|
||||
checkAllSelect = (s, e) => {
|
||||
let arr = this.state.list.slice(s,e);
|
||||
let tmp = arr.filter(t => !t.checked);
|
||||
if(tmp.length > 0) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
changeAllCheck = (s, e, chk) => {
|
||||
let arr = [...this.state.list];
|
||||
for(let i=s; i<e; i++){
|
||||
arr[i].checked = chk;
|
||||
}
|
||||
this.setState({
|
||||
list: arr
|
||||
});
|
||||
}
|
||||
|
||||
submitData = () => {
|
||||
let json = {
|
||||
id: []
|
||||
};
|
||||
for(let i in this.state.list) {
|
||||
if(this.state.list[i].leonelistuid) json.id.push(this.state.list[i].leonelistuid)
|
||||
}
|
||||
|
||||
this.props.onSubmit(json);
|
||||
}
|
||||
|
||||
render () {
|
||||
let {i18n, onClose} = this.props;
|
||||
|
||||
let sIdx = this.state.per * (this.state.page - 1);
|
||||
let eIdx = sIdx + this.state.per;
|
||||
eIdx = eIdx > this.state.list.length ? this.state.list.length : eIdx;
|
||||
let arr = this.state.list.slice(sIdx, eIdx);
|
||||
|
||||
return (
|
||||
<Modal open={this.state.list.length > 0 ? true : false} closeOnDimmerClick={false} >
|
||||
<Modal.Header content={i18n&&i18n.t ? i18n.t('page.leone.form.title.select-dev') : ''} />
|
||||
<Modal.Content>
|
||||
<div className="clearfix">
|
||||
<Label content={`${i18n&&i18n.t?i18n.t('page.leone.form.label.select_num') : ''} ${this.calSelect()}`} basic color="blue"/>
|
||||
<div style={{float: 'right'}}>
|
||||
<Button type="button" content={i18n&&i18n.t?i18n.t('page.leone.form.button.prevpage') : ''} onClick={() => {this.changePage(this.state.page - 1)}} size="tiny" basic color="blue"/>
|
||||
<Label basic content={`${this.state.page} / ${this.state.totalpage}`}/>
|
||||
<Button type="button" content={i18n&&i18n.t?i18n.t('page.leone.form.button.nextpage') : ''} onClick={() => {this.changePage(this.state.page + 1)}} size="tiny" basic color="blue"/>
|
||||
</div>
|
||||
</div>
|
||||
<Table>
|
||||
<Table.Header>
|
||||
<Table.Row>
|
||||
<Table.HeaderCell><Checkbox checked={this.checkAllSelect(sIdx, eIdx)} onChange={(e,d)=>{ this.changeAllCheck(sIdx, eIdx, d.checked) }} /></Table.HeaderCell>
|
||||
<Table.HeaderCell>{i18n&&i18n.t ? i18n.t('page.leone.form.label.name') : ''}</Table.HeaderCell>
|
||||
<Table.HeaderCell>{i18n&&i18n.t ? i18n.t('page.leone.form.label.name') : ''}</Table.HeaderCell>
|
||||
</Table.Row>
|
||||
</Table.Header>
|
||||
<Table.Body>
|
||||
{
|
||||
arr.map((t, idx) => <ScanItem key={idx} i18n={i18n} data={t} idx={idx} onChange={this.onItemSelect}/>)
|
||||
}
|
||||
</Table.Body>
|
||||
</Table>
|
||||
<Grid columns={2}>
|
||||
<Grid.Column>
|
||||
<Button content={i18n&&i18n.t ? i18n.t('page.leone.form.button.submit') : ''} fluid onClick={() => {this.submitData()}}/>
|
||||
</Grid.Column>
|
||||
<Grid.Column>
|
||||
<Button content={i18n&&i18n.t ? i18n.t('page.leone.form.button.cancel') : ''} fluid onClick={() => {onClose()}} />
|
||||
</Grid.Column>
|
||||
</Grid>
|
||||
</Modal.Content>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default SelectScan;
|
||||
@@ -0,0 +1,12 @@
|
||||
import React from 'react';
|
||||
import {Table, Checkbox} from 'semantic-ui-react';
|
||||
|
||||
const ScanItem = ({i18n, data, idx, onChange}) => (
|
||||
<Table.Row>
|
||||
<Table.Cell><Checkbox onChange={(e,d) => {onChange(idx, d.checked)}} checked={data.checked} /></Table.Cell>
|
||||
<Table.Cell>{data.leonename}</Table.Cell>
|
||||
<Table.Cell>{data.leoneip}</Table.Cell>
|
||||
</Table.Row>
|
||||
)
|
||||
|
||||
export default ScanItem;
|
||||
@@ -0,0 +1,174 @@
|
||||
import React from 'react';
|
||||
import {Container, Table, Segment, Form, Grid, Button} from 'semantic-ui-react';
|
||||
import ScanForm from './ScanForm';
|
||||
import {add_dialog_msg} from '../../../actions';
|
||||
import SelectScan from './SelectScan';
|
||||
import ListItem from './ListItem';
|
||||
import LeOneModal from './LeOneModal';
|
||||
import CmdModal from './CmdModal';
|
||||
|
||||
class LeOnePage extends React.Component {
|
||||
state = {
|
||||
modal: false,
|
||||
modalType: 0,
|
||||
modalData: {},
|
||||
cmd: false,
|
||||
cmdData: {
|
||||
id: 0,
|
||||
name: '',
|
||||
cmd: ''
|
||||
}
|
||||
}
|
||||
|
||||
scanSubmit = (data) => {
|
||||
let {i18n} = this.props;
|
||||
|
||||
if(!data.ip1.trim() || !data.ip2.trim() || !data.ip3.trim() || !data.password.trim())
|
||||
return this.props.showDialog(i18n&&i18n.t ? i18n.t('tip.input_empty') : '');
|
||||
|
||||
// send to scan
|
||||
let json = {
|
||||
ip: `${data.ip1}.${data.ip2}.${data.ip3}`,
|
||||
password: data.password
|
||||
};
|
||||
|
||||
this.props.scanLeOne(json);
|
||||
}
|
||||
|
||||
doDelLeOne = (id) => {
|
||||
let {i18n} = this.props;
|
||||
if(!id) return;
|
||||
this.props.delLeOne({id});
|
||||
}
|
||||
|
||||
openModal = (type, data = {}) => {
|
||||
this.setState({
|
||||
modal: true,
|
||||
modalType: type == 1 ? 1 : 0,
|
||||
modalData: data
|
||||
});
|
||||
}
|
||||
|
||||
closeModal = () => {
|
||||
this.setState({
|
||||
modal: false,
|
||||
modalData: {}
|
||||
});
|
||||
}
|
||||
|
||||
submitModal = (type, data ={}) => {
|
||||
let {i18n} = this.props;
|
||||
if((type == 1 && !data.id) || !data.name || !data.password || (type == 0 && !data.ip)) return this.props.showDialog(i18n&&i18n.t?i18n.t('tip.input_empty') : '')
|
||||
|
||||
if(type == 0){
|
||||
this.props.addLeOne(data);
|
||||
}else{
|
||||
this.props.editLeOne(data);
|
||||
}
|
||||
|
||||
this.closeModal();
|
||||
}
|
||||
|
||||
openCmdModal = (id, name, cmd) => {
|
||||
this.setState({
|
||||
cmd: true,
|
||||
cmdData: {
|
||||
id,name,cmd
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
closeCmdModal = () => {
|
||||
this.setState({
|
||||
cmd: false,
|
||||
cmdData: {
|
||||
id: 0,
|
||||
name: '',
|
||||
cmd: ''
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
submitCmdModal = (data) => {
|
||||
let {i18n} = this.props;
|
||||
if(!data.devs || !data.cmd) return this.props.showDialog(i18n&&i18n.t ? i18n.t('tip.input_empty') : '');
|
||||
if(data.cmd.trim() == 2) return this.props.showDialog(i18n&&i18n.t ? i18n.t('tip.input_empty_temp') : '');
|
||||
|
||||
let cmds = data.cmd.split(' ');
|
||||
if(cmds.length != 2) return this.props.showDialog(i18n&&i18n.t ? i18n.t('tip.input_empty') : '');
|
||||
if(cmds[0] == 2 && (cmds[1] <16 || cmds[1] > 30) ) return this.props.showDialog(i18n&&i18n.t ? i18n.t('tip.temp_format') : '');
|
||||
this.props.runCmd(data);
|
||||
this.closeCmdModal()
|
||||
}
|
||||
|
||||
tick = null;
|
||||
|
||||
runTick = () => {
|
||||
if(!this.props.scanning){
|
||||
this.props.getLeOneList(0);
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.props.getLeOneList();
|
||||
this.tick = setInterval(this.runTick, 10000);
|
||||
this.props.router.setRouteLeaveHook(this.props.route, () => {
|
||||
this.props.clearList();
|
||||
})
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
clearInterval(this.tick);
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
|
||||
}
|
||||
|
||||
render () {
|
||||
let {i18n, scanList, clearScan, addScanLeOne, list, status} = this.props;
|
||||
return (
|
||||
<Container>
|
||||
<Segment>
|
||||
<ScanForm i18n={i18n} onSubmit={this.scanSubmit} />
|
||||
</Segment>
|
||||
<Segment className="clearfix">
|
||||
<Button type="button" basic color="green" content={i18n&&i18n.t ? i18n.t('page.leone.table.button.add') : ''} style={{marginBottom: '10px'}} icon="plus" floated="right" onClick={() => {this.openModal(0)}} />
|
||||
<Table>
|
||||
<Table.Header>
|
||||
<Table.Row>
|
||||
<Table.HeaderCell>{i18n&&i18n.t ? i18n.t('page.leone.table.operate') : ''}</Table.HeaderCell>
|
||||
<Table.HeaderCell>{i18n&&i18n.t ? i18n.t('page.leone.table.name') : ''}</Table.HeaderCell>
|
||||
<Table.HeaderCell>{i18n&&i18n.t ? i18n.t('page.leone.table.ip') : ''}</Table.HeaderCell>
|
||||
<Table.HeaderCell>{i18n&&i18n.t ? i18n.t('page.leone.table.hsts') : ''}</Table.HeaderCell>
|
||||
<Table.HeaderCell>{i18n&&i18n.t ? i18n.t('page.leone.table.mode') : ''}</Table.HeaderCell>
|
||||
<Table.HeaderCell>{i18n&&i18n.t ? i18n.t('page.leone.table.password') : ''}</Table.HeaderCell>
|
||||
<Table.HeaderCell>{i18n&&i18n.t ? i18n.t('page.leone.table.update_time') : ''}</Table.HeaderCell>
|
||||
<Table.HeaderCell>{i18n&&i18n.t ? i18n.t('page.leone.table.control') : ''}</Table.HeaderCell>
|
||||
</Table.Row>
|
||||
</Table.Header>
|
||||
<Table.Body>
|
||||
{
|
||||
list.map(t => {
|
||||
let st = {};
|
||||
for(let i in status){
|
||||
if(status[i].ip == t.leoneip) {
|
||||
st = status[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
return <ListItem i18n={i18n} key={t.leonelistuid} status={st} data={t} delLeone={this.doDelLeOne} editLeone={this.openModal} runCmd={this.openCmdModal}/>
|
||||
})
|
||||
}
|
||||
</Table.Body>
|
||||
</Table>
|
||||
</Segment>
|
||||
<SelectScan i18n={i18n} list={scanList} onClose={clearScan} onSubmit={addScanLeOne}/>
|
||||
<LeOneModal i18n={i18n} open={this.state.modal} type={this.state.modalType} data={this.state.modalData} onSubmit={this.submitModal} onClose={this.closeModal} />
|
||||
<CmdModal i18n={i18n} open={this.state.cmd} id={this.state.cmdData.id} devname={this.state.cmdData.name} cmd={this.state.cmdData.cmd} onSubmit={this.submitCmdModal} onClose={this.closeCmdModal} />
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default LeOnePage;
|
||||
@@ -0,0 +1,32 @@
|
||||
import React from 'react';
|
||||
import {Table} from 'semantic-ui-react';
|
||||
import {convertTime} from '../../../tools';
|
||||
|
||||
const LogItem = ({i18n, data}) => {
|
||||
if(!(i18n && i18n.t)) return null;
|
||||
let defMsg = '';
|
||||
if(/^(do|di)/i.test(data.iolabel)){
|
||||
defMsg = i18n.t('page.log.description.dio');
|
||||
}else if(/^leone/i.test(data.iolabel)){
|
||||
defMsg = i18n.t('page.log.description.leone');
|
||||
}else if(/^iogroup/i.test(data.iolabel)){
|
||||
defMsg = i18n.t('page.log.description.iogroup');
|
||||
}
|
||||
let msg = defMsg
|
||||
.replace(/\$io_label\$/, data.iolabel)
|
||||
.replace(/\$io_name\$/, data.ioname)
|
||||
.replace(/\$io_logic\$/, data.iosetting1)
|
||||
.replace(/\$io_trigger_time\$/, convertTime(data.ioeventtst))
|
||||
.replace(/\$io_trigger_status\$/, data.ioevent);
|
||||
return (
|
||||
<Table.Row>
|
||||
<Table.Cell>{convertTime(data.ioeventtst)}</Table.Cell>
|
||||
<Table.Cell>{data.iosetting3}</Table.Cell>
|
||||
<Table.Cell>{data.iosetting2}</Table.Cell>
|
||||
<Table.Cell>{data.ioevent}</Table.Cell>
|
||||
<Table.Cell>{msg}</Table.Cell>
|
||||
</Table.Row>
|
||||
)
|
||||
}
|
||||
|
||||
export default LogItem;
|
||||
@@ -0,0 +1,46 @@
|
||||
import React from 'react';
|
||||
import {Container, Table, Button, Label} from 'semantic-ui-react';
|
||||
import LogItem from './LogItem';
|
||||
|
||||
class LogPage extends React.Component {
|
||||
|
||||
componentDidMount(){
|
||||
this.props.getList();
|
||||
this.props.router.setRouteLeaveHook(this.props.route, () => {
|
||||
this.props.clearList();
|
||||
})
|
||||
}
|
||||
|
||||
loadPage = (p = 1) => {
|
||||
this.props.getList(p);
|
||||
}
|
||||
|
||||
render () {
|
||||
let {i18n, list, page} = this.props;
|
||||
return (
|
||||
<Container>
|
||||
<Table>
|
||||
<Table.Header>
|
||||
<Table.Row>
|
||||
<Table.HeaderCell>{i18n&&i18n.t ? i18n.t('page.log.table.datetime') : ''}</Table.HeaderCell>
|
||||
<Table.HeaderCell>{i18n&&i18n.t ? i18n.t('page.log.table.username') : ''}</Table.HeaderCell>
|
||||
<Table.HeaderCell>{i18n&&i18n.t ? i18n.t('page.log.table.status') : ''}</Table.HeaderCell>
|
||||
<Table.HeaderCell>{i18n&&i18n.t ? i18n.t('page.log.table.event') : ''}</Table.HeaderCell>
|
||||
<Table.HeaderCell>{i18n&&i18n.t ? i18n.t('page.log.table.description') : ''}</Table.HeaderCell>
|
||||
</Table.Row>
|
||||
</Table.Header>
|
||||
<Table.Body>
|
||||
{ list.map(t => <LogItem key={t.jciocertuid} i18n={i18n} data={t} />) }
|
||||
</Table.Body>
|
||||
</Table>
|
||||
<div style={{textAlign: 'center'}}>
|
||||
<Button content={i18n&&i18n.t ? i18n.t('page.log.table.button.prevpage') : ''} size="small" labelPosition="left" basic={true} color="black" icon="arrow left" onClick={() => {this.loadPage(page.prevpage)}} />
|
||||
<Label basic={true} color="blue" content={`${page.page || 1} / ${page.totalpage || 1}`} />
|
||||
<Button content={i18n&&i18n.t ? i18n.t('page.log.table.button.nextpage') : ''} size="small" labelPosition="right" basic={true} color="black" icon="arrow right" onClick={() => {this.loadPage(page.nextpage)}} />
|
||||
</div>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default LogPage;
|
||||
@@ -0,0 +1,40 @@
|
||||
import React from 'react';
|
||||
import {Table, Input, Form, Button} from 'semantic-ui-react';
|
||||
|
||||
const AIOForm = ({i18n, open, type, data, onSubmit, onClose}) => {
|
||||
if(!open) return null;
|
||||
let input = {
|
||||
name: data.name || '',
|
||||
portnum: data.portnum || '',
|
||||
scale_min: data.scale_min || 0,
|
||||
scale_max: data.scale_max || 0,
|
||||
range_min: data.range_min || 0,
|
||||
range_max: data.range_max || 0
|
||||
}
|
||||
return (
|
||||
<Table.Row>
|
||||
<Table.Cell><Input name="name" onChange={(e,d)=>{input.name = d.value}} defaultValue={data.name || ''}/></Table.Cell>
|
||||
<Table.Cell><Input name="portnum" onChange={(e,d)=>{input.portnum = d.value}} defaultValue={data.portnum || ''}/></Table.Cell>
|
||||
<Table.Cell>
|
||||
<Input name="range_min" size="small" label="Min" onChange={(e,d)=>{input.range_min = d.value}} defaultValue={data.range_min || '0'}/>
|
||||
<Input name="range_max" size="small" label="Max" onChange={(e,d)=>{input.range_max = d.value}} defaultValue={data.range_max || '0'}/>
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
<Input name="scale_min" size="small" label="Min" onChange={(e,d)=>{input.scale_min = d.value}} defaultValue={data.scale_min || '0'}/>
|
||||
<Input name="scale_max" size="small" label="Max" onChange={(e,d)=>{input.scale_max = d.value}} defaultValue={data.scale_max || '0'}/>
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
<Button basic size="tiny" content="Submit" type="button" onClick={()=>{
|
||||
let json = {
|
||||
...input,
|
||||
id: data.uid || ''
|
||||
}
|
||||
onSubmit(type, json);
|
||||
}} />
|
||||
<Button basic size="tiny" content="Cancel" type="button" onClick={()=>{onClose()}} />
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
)
|
||||
}
|
||||
|
||||
export default AIOForm;
|
||||
@@ -0,0 +1,20 @@
|
||||
import React from 'react';
|
||||
import {Table, Button} from 'semantic-ui-react';
|
||||
|
||||
const AIOListItem = ({i18n, data, editAIO, delAIO}) => {
|
||||
|
||||
return (
|
||||
<Table.Row>
|
||||
<Table.Cell>{data.name || ''}</Table.Cell>
|
||||
<Table.Cell>{data.portnum || ''}</Table.Cell>
|
||||
<Table.Cell>{data.range_min || 0} ~ {data.range_max || 0}</Table.Cell>
|
||||
<Table.Cell>{data.scale_min || 0} ~ {data.scale_max || 0}</Table.Cell>
|
||||
<Table.Cell>
|
||||
<Button type="button" basic size="tiny" content="Edit" onClick={()=>{editAIO(1, data)}} />
|
||||
<Button type="button" basic size="tiny" content="Delete" onClick={()=>{delAIO(data.uid || '')}} />
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
)
|
||||
}
|
||||
|
||||
export default AIOListItem;
|
||||
@@ -0,0 +1,72 @@
|
||||
import React from 'react';
|
||||
import {Modal, Table, Button, Input, Form} from 'semantic-ui-react';
|
||||
import ListItem from './AIOListItem';
|
||||
import AIOForm from './AIOForm';
|
||||
|
||||
class AIOModal extends React.Component {
|
||||
state = {
|
||||
editMode: false,
|
||||
data: {},
|
||||
type: 0
|
||||
}
|
||||
|
||||
openEditField = (type, data = {}) => {
|
||||
this.closeEditField(()=>{
|
||||
this.setState({
|
||||
editMode: true,
|
||||
data,
|
||||
type
|
||||
});
|
||||
});
|
||||
}
|
||||
closeEditField = (cb) => {
|
||||
this.setState({
|
||||
editMode: false,
|
||||
data: {}
|
||||
}, ()=>{
|
||||
if(cb && typeof cb == 'function') cb()
|
||||
});
|
||||
}
|
||||
submitAIO = (type, data) => {
|
||||
data.iouid = this.props.iouid;
|
||||
this.props.onSubmit(type, data);
|
||||
this.closeEditField();
|
||||
}
|
||||
|
||||
render() {
|
||||
let {i18n, iouid, open, list, onClose, delAIO} = this.props;
|
||||
|
||||
return (
|
||||
<Modal size="large" open={open} onClose={()=>{onClose()}}>
|
||||
<Modal.Content className="clearfix">
|
||||
<Button basic size="tiny" color="green" floated="right" style={{marginBottom: '10px'}} icon="plus" content="Add Set" onClick={()=>{
|
||||
this.openEditField(0);
|
||||
}}/>
|
||||
<Table size="small">
|
||||
<Table.Header>
|
||||
<Table.Row>
|
||||
<Table.HeaderCell>名稱</Table.HeaderCell>
|
||||
<Table.HeaderCell>接口號碼</Table.HeaderCell>
|
||||
<Table.HeaderCell>Range(Min-Max)</Table.HeaderCell>
|
||||
<Table.HeaderCell>Scale(Min-Max)</Table.HeaderCell>
|
||||
<Table.HeaderCell>操作</Table.HeaderCell>
|
||||
</Table.Row>
|
||||
</Table.Header>
|
||||
<Table.Body>
|
||||
{
|
||||
list.map((t,idx) => (
|
||||
<ListItem key={idx} i18n={i18n} data={t} editAIO={this.openEditField} delAIO={delAIO}/>
|
||||
))
|
||||
}
|
||||
</Table.Body>
|
||||
<Table.Footer>
|
||||
<AIOForm i18n={i18n} open={this.state.editMode} type={this.state.type} data={this.state.data} onSubmit={this.submitAIO} onClose={this.closeEditField}/>
|
||||
</Table.Footer>
|
||||
</Table>
|
||||
</Modal.Content>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default AIOModal;
|
||||
@@ -0,0 +1,25 @@
|
||||
import React from 'react';
|
||||
import {Menu, Header} from 'semantic-ui-react';
|
||||
import DevListItem from './DeviceListItem';
|
||||
|
||||
const DeviceList = ({i18n, list, delModbus, editModbus, showDev, selectDevToShow}) => {
|
||||
|
||||
return (
|
||||
<Menu vertical={true}>
|
||||
<Menu.Item>
|
||||
<Menu.Header content="裝置列表" />
|
||||
<Menu.Menu>
|
||||
{
|
||||
list.map((t, idx) => {
|
||||
return (
|
||||
<DevListItem key={idx} i18n={i18n} idx={idx} data={t} delModbus={delModbus} editModbus={editModbus} showDev={showDev} selectDevToShow={selectDevToShow}/>
|
||||
)
|
||||
})
|
||||
}
|
||||
</Menu.Menu>
|
||||
</Menu.Item>
|
||||
</Menu>
|
||||
)
|
||||
}
|
||||
|
||||
export default DeviceList;
|
||||
@@ -0,0 +1,19 @@
|
||||
import React from 'react';
|
||||
import {List, Button, Icon} from 'semantic-ui-react';
|
||||
|
||||
const DeviceListItem = ({i18n, idx, data, delModbus, editModbus, showDev, selectDevToShow}) =>{
|
||||
|
||||
return (
|
||||
<List.Item active={data.uid == showDev}>
|
||||
<span style={{cursor: 'pointer'}} onClick={() => {
|
||||
selectDevToShow(data.uid);
|
||||
}}>
|
||||
{data.name} / Node:{data.node}
|
||||
</span>
|
||||
<Icon style={{cursor: 'pointer'}} name="trash" onClick={()=>{delModbus(data.uid || '')}}/>
|
||||
<Icon style={{cursor: 'pointer'}} name="write" onClick={()=>{editModbus(1, data)}}/>
|
||||
</List.Item>
|
||||
)
|
||||
}
|
||||
|
||||
export default DeviceListItem;
|
||||
@@ -0,0 +1,63 @@
|
||||
import React from 'react';
|
||||
import {Modal, Form, Button, Grid, Input } from 'semantic-ui-react';
|
||||
|
||||
const IOModal = ({i18n, open, type, data, onSubmit, onClose}) => {
|
||||
|
||||
let iotype = i18n&&i18n.getResource&&i18n.language ? i18n.getResource(i18n.language + '.translation.porttype') : [];
|
||||
|
||||
return (
|
||||
<Modal open={open}>
|
||||
<Modal.Header content={type == 1 ? '修改資料' : '新增資料'} />
|
||||
<Modal.Content>
|
||||
<Form onSubmit={(e,d)=>{
|
||||
e.preventDefault();
|
||||
onSubmit(type, d.formData);
|
||||
}} serializer={e=>{
|
||||
let json = {
|
||||
id: data.uid || '',
|
||||
addr: '',
|
||||
num: '',
|
||||
type: ''
|
||||
};
|
||||
|
||||
let addr = e.querySelector('input[name="addr"]');
|
||||
if(addr && 'value' in addr) json.addr = addr.value;
|
||||
let num = e.querySelector('input[name="num"]');
|
||||
if(num && 'value' in num) json.num = num.value;
|
||||
let type = e.querySelector('select[name="io_type"]');
|
||||
if(type && 'value' in type) json.type = type.value;
|
||||
|
||||
return json;
|
||||
}}>
|
||||
<Form.Field>
|
||||
<label>接口類型</label>
|
||||
<select name="io_type" defaultValue={data.type || ''} disabled={type == 1}>
|
||||
<option value="">請選擇類型</option>
|
||||
{
|
||||
iotype.map((t,idx) => (
|
||||
<option key={idx} value={t.code}>{t.name}</option>
|
||||
))
|
||||
}
|
||||
</select>
|
||||
</Form.Field>
|
||||
<Form.Field>
|
||||
<Input name="addr" label="起始位址" defaultValue={data.addr || ''} />
|
||||
</Form.Field>
|
||||
<Form.Field>
|
||||
<Input name="num" label="數量" defaultValue={data.num || ''} />
|
||||
</Form.Field>
|
||||
<Grid columns={2}>
|
||||
<Grid.Column>
|
||||
<Button type="submit" fluid content="Submit" />
|
||||
</Grid.Column>
|
||||
<Grid.Column>
|
||||
<Button type="button" fluid content="Cancel" onClick={()=>{onClose()}}/>
|
||||
</Grid.Column>
|
||||
</Grid>
|
||||
</Form>
|
||||
</Modal.Content>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
export default IOModal ;
|
||||
@@ -0,0 +1,89 @@
|
||||
import React from 'react';
|
||||
import {Menu, Segment, Table, Header, Label} from 'semantic-ui-react';
|
||||
import {convertTime} from '../../../tools';
|
||||
import IOPanelListItem from './IOPanelListItem';
|
||||
|
||||
class IOPanel extends React.Component {
|
||||
state = {
|
||||
tabIdx: '1'
|
||||
}
|
||||
|
||||
tabItemClick = (e, el) => {
|
||||
this.setState({
|
||||
tabIdx: el.name
|
||||
}, ()=>{
|
||||
this.props.getStatus({id: this.props.data.uid || '', type: this.state.tabIdx});
|
||||
});
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nprops) {
|
||||
if(nprops.data && nprops.data.uid) {
|
||||
if(this.props.data && this.props.data.uid){
|
||||
if(this.props.data.uid != nprops.data.uid) {
|
||||
this.props.getStatus({id: nprops.data.uid, type: this.state.tabIdx});
|
||||
}
|
||||
}else{
|
||||
this.props.getStatus({id: nprops.data.uid, type: this.state.tabIdx});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
render(){
|
||||
let {i18n, show, data, ioModal, delIOList, showAIOSet} = this.props;
|
||||
if(!show) return null;
|
||||
|
||||
let iolist = data.iolist || [];
|
||||
let ios = iolist.filter(t => {
|
||||
if(t.type == this.state.tabIdx) return t;
|
||||
});
|
||||
let status = data.status || {};
|
||||
let ss = status[this.state.tabIdx] || [];
|
||||
return (
|
||||
<div>
|
||||
<Menu attached="top" tabular>
|
||||
<Menu.Item content="DigitOutput" name="1" active={this.state.tabIdx == "1"} onClick={this.tabItemClick} />
|
||||
<Menu.Item content="DigitInput" name="2" active={this.state.tabIdx == "2"} onClick={this.tabItemClick} />
|
||||
<Menu.Item content="AnalogyOutput" name="3" active={this.state.tabIdx == "3"} onClick={this.tabItemClick} />
|
||||
<Menu.Item content="AnalogyInput" name="4" active={this.state.tabIdx == "4"} onClick={this.tabItemClick} />
|
||||
<Menu.Menu position="right">
|
||||
<Menu.Item content="AddIO" icon="plus" onClick={()=>{ioModal(0)}}/>
|
||||
</Menu.Menu>
|
||||
</Menu>
|
||||
<Segment attached="bottom">
|
||||
<Table>
|
||||
<Table.Header>
|
||||
<Table.Row>
|
||||
<Table.HeaderCell>起始位置</Table.HeaderCell>
|
||||
<Table.HeaderCell>接口數量</Table.HeaderCell>
|
||||
<Table.HeaderCell>操作</Table.HeaderCell>
|
||||
</Table.Row>
|
||||
</Table.Header>
|
||||
<Table.Body>
|
||||
{
|
||||
ios.map((t,idx) => (
|
||||
<IOPanelListItem key={idx} i18n={i18n} data={t} ioModal={ioModal} delIOList={delIOList} showAIOSet={showAIOSet} />
|
||||
))
|
||||
}
|
||||
</Table.Body>
|
||||
</Table>
|
||||
|
||||
<Segment>
|
||||
<Header as="h3" content="接口資訊"/>
|
||||
{
|
||||
ss.map((t,idx) => (
|
||||
<div key={idx}>
|
||||
<Label basic color="blue" content={`PortNum:${t.port}`}/>
|
||||
<Label basic color="blue" content={`原始數值:${t.value}`}/>
|
||||
<Label basic color="blue" content={`轉換數值:${t.value2}`}/>
|
||||
<Label basic color="green" content={`最後更新於:${convertTime(t.tst, true)}`}/>
|
||||
</div>
|
||||
))
|
||||
}
|
||||
</Segment>
|
||||
</Segment>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default IOPanel;
|
||||
@@ -0,0 +1,24 @@
|
||||
import React from 'react';
|
||||
import {Table, Button} from 'semantic-ui-react';
|
||||
|
||||
const IOPanelListItem = ({i18n, data, ioModal, delIOList, showAIOSet}) => {
|
||||
|
||||
return (
|
||||
<Table.Row>
|
||||
<Table.Cell>{data.addr || ''}</Table.Cell>
|
||||
<Table.Cell>{data.num || ''}</Table.Cell>
|
||||
<Table.Cell>
|
||||
<Button type="button" basic content="修改" onClick={()=>{ioModal(1, data)}}/>
|
||||
<Button type="button" basic content="刪除" onClick={()=>{delIOList(data.uid || '')}}/>
|
||||
{
|
||||
data.type == 3 || data.type == 4 ?
|
||||
(
|
||||
<Button type="button" basic content="顯示設定" onClick={()=>{showAIOSet(data.uid)}} />
|
||||
):null
|
||||
}
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
)
|
||||
}
|
||||
|
||||
export default IOPanelListItem;
|
||||
@@ -0,0 +1,49 @@
|
||||
import React from 'react';
|
||||
import {Modal, Form, Input, Grid, Button} from 'semantic-ui-react';
|
||||
|
||||
const ModbusModal = ({i18n, open, type, data, onSubmit, onClose}) => {
|
||||
if(!i18n || Object.keys(i18n).length == 0) return null;
|
||||
|
||||
return (
|
||||
<Modal open={open}>
|
||||
<Modal.Header content={type == 1 ? '修改裝置' : '新增裝置'} />
|
||||
<Modal.Content>
|
||||
<Form onSubmit={(e, d) => {
|
||||
e.preventDefault();
|
||||
onSubmit(type, d.formData);
|
||||
}} serializer={e => {
|
||||
let json = {
|
||||
name: '',
|
||||
node: '',
|
||||
id: data.uid || '',
|
||||
original_node: data.node || ''
|
||||
};
|
||||
|
||||
let n = e.querySelector('input[name="name"]');
|
||||
if(n && 'value' in n) json.name = n.value;
|
||||
let nn = e.querySelector('input[name="node"]');
|
||||
if(nn && 'value' in nn) json.node = nn.value;
|
||||
|
||||
return json ;
|
||||
}}>
|
||||
<Form.Field>
|
||||
<Input name="name" defaultValue={data.name || ''} label="Name"/>
|
||||
</Form.Field>
|
||||
<Form.Field>
|
||||
<Input name="node" defaultValue={data.node || ''} label="Node"/>
|
||||
</Form.Field>
|
||||
<Grid columns={2}>
|
||||
<Grid.Column>
|
||||
<Button content="Submit" fluid type="submit" />
|
||||
</Grid.Column>
|
||||
<Grid.Column>
|
||||
<Button content="Cancel" fluid type="button" onClick={()=>{onClose()}} />
|
||||
</Grid.Column>
|
||||
</Grid>
|
||||
</Form>
|
||||
</Modal.Content>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
export default ModbusModal;
|
||||
@@ -0,0 +1,210 @@
|
||||
import React from 'react';
|
||||
import {Container, Segment, List, Menu, Item, Grid} from 'semantic-ui-react';
|
||||
import DeviceList from './DeviceList';
|
||||
import ModbusModal from './ModbusModal';
|
||||
import IOPanel from './IOPanel';
|
||||
import IOModal from './IOModal';
|
||||
import AIOModal from './AIOModal';
|
||||
|
||||
const defIOModalState = {
|
||||
open: false,
|
||||
data: {},
|
||||
type: 0
|
||||
}
|
||||
const defAIOModalState = {
|
||||
open: false,
|
||||
list: [],
|
||||
iouid: 0
|
||||
}
|
||||
|
||||
class ModbusPage extends React.Component {
|
||||
state = {
|
||||
mbModal: false,
|
||||
mbType: 0,
|
||||
mbData: {},
|
||||
showDev: "",
|
||||
ioModal:{
|
||||
...defIOModalState
|
||||
},
|
||||
aioModal:{
|
||||
...defAIOModalState
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.props.getList();
|
||||
|
||||
this.props.router.setRouteLeaveHook(this.props.route, () => {
|
||||
this.props.clearList();
|
||||
});
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nprop) {
|
||||
if(this.state.aioModal.open) {
|
||||
this.openAIOModal(this.state.aioModal.iouid, nprop.list);
|
||||
}
|
||||
}
|
||||
|
||||
delModbus = id => {
|
||||
if(!id) return ;
|
||||
this.props.delModbus({id});
|
||||
}
|
||||
|
||||
openModbusModal = (type, data = {}) => {
|
||||
this.setState({
|
||||
mbModal: true,
|
||||
mbType: type,
|
||||
mbData: data
|
||||
});
|
||||
}
|
||||
closeModbusModal = () => {
|
||||
this.setState({
|
||||
mbModal: false,
|
||||
mbData: {}
|
||||
})
|
||||
}
|
||||
submitModbusModal = (type, data = {}) => {
|
||||
let {i18n} = this.props;
|
||||
if(type == 1 && (!data.id)) return this.props.showDialog(i18n&&i18n.t ? i18n.t('tip.input_empty') : '');
|
||||
if(!data.name || !('node' in data) || data.node.length == 0) return this.props.showDialog(i18n&&i18n.t ? i18n.t('tip.input_empty') : '');
|
||||
|
||||
if(type == 1){
|
||||
this.props.editModbus(data);
|
||||
}else{
|
||||
this.props.addModbus(data);
|
||||
}
|
||||
this.closeModbusModal();
|
||||
}
|
||||
selectDevToShow = (uid) => {
|
||||
this.setState({
|
||||
showDev: uid
|
||||
});
|
||||
this.props.getMBData({id: uid});
|
||||
}
|
||||
|
||||
openIOModal = (type, data = {}) => {
|
||||
this.setState({
|
||||
ioModal: {
|
||||
open: true,
|
||||
type,
|
||||
data
|
||||
}
|
||||
});
|
||||
}
|
||||
closeIOModal = () =>{
|
||||
this.setState({
|
||||
ioModal: {
|
||||
...defIOModalState
|
||||
}
|
||||
})
|
||||
}
|
||||
submitIOModal = (type, data) => {
|
||||
let {i18n} = this.props;
|
||||
if((type == 1 && !data.id) || !('addr' in data) || !('num' in data) || !('type' in data)) return this.props.showDialog(i18n.t('tip.input_empty'));
|
||||
|
||||
data.devuid = this.state.showDev;
|
||||
if(type == 1){
|
||||
this.props.editIOList(data);
|
||||
}else{
|
||||
data.id = this.state.showDev;
|
||||
this.props.addIOList(data);
|
||||
}
|
||||
this.closeIOModal();
|
||||
}
|
||||
delIOList = (id) => {
|
||||
if(!id) return ;
|
||||
this.props.delIOList({id, devuid: this.state.showDev});
|
||||
}
|
||||
openAIOModal = (id, nlist = []) => {
|
||||
if(!id) return ;
|
||||
let slist = nlist.length == 0 ? this.props.list : nlist;
|
||||
let dev = slist.filter(t => {
|
||||
if(t.uid == this.state.showDev) return t;
|
||||
});
|
||||
if(dev.length == 0) return ;
|
||||
let aio = dev[0].aioset || [];
|
||||
let list = aio.filter(t => {
|
||||
if(t.iouid == id) return t;
|
||||
});
|
||||
this.setState({
|
||||
aioModal:{
|
||||
open: true,
|
||||
list,
|
||||
iouid: id
|
||||
}
|
||||
});
|
||||
}
|
||||
closeAIOModal = () => {
|
||||
this.setState({
|
||||
aioModal:{
|
||||
...defAIOModalState
|
||||
}
|
||||
});
|
||||
}
|
||||
submitAIO = (type, data) => {
|
||||
data.devuid = this.state.showDev;
|
||||
if(type == 1){
|
||||
this.props.editAIO(data);
|
||||
}else{
|
||||
this.props.addAIO(data);
|
||||
}
|
||||
// this.closeAIOModal();
|
||||
}
|
||||
delAIO = (id) => {
|
||||
if(!id) return ;
|
||||
this.props.delAIO({id, devuid: this.state.showDev});
|
||||
}
|
||||
|
||||
render() {
|
||||
let {i18n, list} = this.props;
|
||||
|
||||
let dev = list.filter(t => {
|
||||
if(t.uid == this.state.showDev) return t;
|
||||
});
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<Menu>
|
||||
<Menu.Menu position="right">
|
||||
<Menu.Item name="新增裝置" icon="plus" onClick={()=>{this.openModbusModal(0)}}/>
|
||||
</Menu.Menu>
|
||||
</Menu>
|
||||
<Grid>
|
||||
<Grid.Column width={4}>
|
||||
<DeviceList i18n={i18n}
|
||||
list={list}
|
||||
delModbus={this.delModbus}
|
||||
editModbus={this.openModbusModal}
|
||||
showDev={this.state.showDev}
|
||||
selectDevToShow={this.selectDevToShow}/>
|
||||
</Grid.Column>
|
||||
<Grid.Column width={12}>
|
||||
<IOPanel i18n={i18n}
|
||||
show={dev.length > 0}
|
||||
data={dev[0]}
|
||||
ioModal={this.openIOModal}
|
||||
delIOList={this.delIOList}
|
||||
getStatus={this.props.getMBIOStatus}
|
||||
showAIOSet={this.openAIOModal} />
|
||||
</Grid.Column>
|
||||
</Grid>
|
||||
<ModbusModal i18n={i18n} open={this.state.mbModal} data={this.state.mbData} type={this.state.mbType} onSubmit={this.submitModbusModal} onClose={this.closeModbusModal} />
|
||||
<IOModal i18n={i18n}
|
||||
open={this.state.ioModal.open}
|
||||
type={this.state.ioModal.type}
|
||||
data={this.state.ioModal.data}
|
||||
onClose={this.closeIOModal}
|
||||
onSubmit={this.submitIOModal} />
|
||||
<AIOModal i18n={i18n}
|
||||
open={this.state.aioModal.open}
|
||||
iouid={this.state.aioModal.iouid}
|
||||
list={this.state.aioModal.list}
|
||||
onSubmit={this.submitAIO}
|
||||
delAIO={this.delAIO}
|
||||
onClose={this.closeAIOModal} />
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default ModbusPage;
|
||||
@@ -0,0 +1,120 @@
|
||||
import React from 'react';
|
||||
import {Table, Button, Item, Label} from 'semantic-ui-react';
|
||||
|
||||
const ListItem = ({i18n, idx, data, dos, les, ios, changeActive, openModal, delItem, showGroup}) => {
|
||||
let actlist = i18n&&i18n.getResource&&i18n.language ? i18n.getResource(i18n.language + '.translation.action_list') : [];
|
||||
let weekArr = i18n&&i18n.t ? [
|
||||
i18n.t('week.mon'),
|
||||
i18n.t('week.tue'),
|
||||
i18n.t('week.wed'),
|
||||
i18n.t('week.thu'),
|
||||
i18n.t('week.fri'),
|
||||
i18n.t('week.sat'),
|
||||
i18n.t('week.sun')
|
||||
] : [];
|
||||
|
||||
let timeStr = '';
|
||||
let min = data.ioscheduleparam1 || '';
|
||||
let hour = data.ioscheduleparam2 || '';
|
||||
let day = data.ioscheduleparam3 || '';
|
||||
let month = data.ioscheduleparam4 || '';
|
||||
let week = data.ioscheduleparam5 || '';
|
||||
if(week != '-'){
|
||||
let w = week.split(',');
|
||||
let ws = [];
|
||||
w.sort();
|
||||
for(let i in w){
|
||||
ws.push(weekArr[w[i] - 1] || '');
|
||||
}
|
||||
timeStr = `${ws.join(',')} ${hour}:${min}`;
|
||||
}else{
|
||||
timeStr = `${month}/${day} ${hour}:${min}`;
|
||||
}
|
||||
|
||||
let act = data.ioschedulecmd || '';
|
||||
act = act.split(',');
|
||||
let actcmd = '';
|
||||
let actname = '';
|
||||
if(act.length == 2){
|
||||
if(act[0] == 2){
|
||||
actcmd = '2'
|
||||
}else{
|
||||
actcmd = act.join(' ');
|
||||
}
|
||||
}
|
||||
if(actcmd.length > 0){
|
||||
for(let i in actlist){
|
||||
if(actlist[i].cmd == actcmd){
|
||||
actname = actlist[i].name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let devs = data.ioscheduleio || '';
|
||||
let dev = devs.split(',');
|
||||
let items = [];
|
||||
if(dev.length > 0){
|
||||
for(let i in dev){
|
||||
if(/^do/i.test(dev[i])){
|
||||
for(let j in dos){
|
||||
if(`do${dos[j].douid}` == dev[i]) {
|
||||
items.push({
|
||||
type: 'DigitOutput',
|
||||
name: dos[j].doname,
|
||||
id: dev[i]
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}else if(/^le/i.test(dev[i])){
|
||||
for(let j in les){
|
||||
if(`le${les[j].leonelistuid}` == dev[i]) {
|
||||
items.push({
|
||||
type: 'LeOne',
|
||||
name: les[j].leonename,
|
||||
id: dev[i]
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}else if(/^iogroup/i.test(dev[i])){
|
||||
for(let j in ios){
|
||||
if(`iogroup${ios[j].iogroupuid}` == dev[i]){
|
||||
items.push({
|
||||
type: 'IOGroup',
|
||||
name: ios[j].iogroupname,
|
||||
id: dev[i]
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Table.Row>
|
||||
<Table.Cell>
|
||||
<Button basic size="tiny" color={data.ioscheduleactive == 1 ? 'orange' : 'olive'}
|
||||
content={i18n&&i18n.t ? (data.ioscheduleactive == 1 ? i18n.t('page.schedule.table.button.disable') : i18n.t('page.schedule.table.button.enable')) : ''}
|
||||
onClick={()=>{ changeActive(data.ioscheduleuid || ''); }} />
|
||||
<Button basic size="tiny" color="red" content={i18n&&i18n.t ? i18n.t('page.schedule.table.button.del') : ''} onClick={() => {delItem(data.ioscheduleuid || '')}} />
|
||||
<Button basic size="tiny" color="blue" content={i18n&&i18n.t ? i18n.t('page.schedule.table.button.edit') : ''} onClick={() => {openModal(1, data, items);}} />
|
||||
</Table.Cell>
|
||||
<Table.Cell>{data.ioschedulename || ''}</Table.Cell>
|
||||
<Table.Cell>{timeStr}</Table.Cell>
|
||||
<Table.Cell>{actname}</Table.Cell>
|
||||
<Table.Cell>{i18n&&i18n.t ? (data.ioscheduleactive == 1 ? i18n.t('page.schedule.table.button.enable') : i18n.t('page.schedule.table.button.disable')) : ''}</Table.Cell>
|
||||
<Table.Cell>
|
||||
{
|
||||
items.length > 0 ?
|
||||
(items.length == 1 ?
|
||||
<Item><Label content={items[0].type} />{items[0].name}</Item>:
|
||||
<Button size="tiny" basic content={i18n&&i18n.t ? i18n.t('page.schedule.table.button.showgroup') : ''} onClick={()=>{showGroup(items)}}/> ) :
|
||||
''
|
||||
}
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
)
|
||||
}
|
||||
|
||||
export default ListItem;
|
||||
@@ -0,0 +1,158 @@
|
||||
import React from 'react';
|
||||
import {Modal, Form, Checkbox, Input, Radio, Segment, Header, List, Grid, Button} from 'semantic-ui-react';
|
||||
import DateTime from 'react-datetime';
|
||||
import DeviceSelect from '../../Common/DeviceSelect';
|
||||
import SelectedItem from './SelectedItem';
|
||||
|
||||
class ScheduleModal extends React.Component {
|
||||
|
||||
render(){
|
||||
let {i18n, open, data, type, devs, permissions, querySelectList, onSubmit, onClose} = this.props;
|
||||
let {showTemp, week, cmd, temp, dateType, selected, addSelect, removeSelected, changeDateType, checkShowTemp, changeWeek} = this.props;
|
||||
let actlist = i18n&&i18n.getResource&&i18n.language ? i18n.getResource(i18n.language + '.translation.action_list') : [];
|
||||
|
||||
let act = data.ioschedulecmd || '';
|
||||
act = act.split(',');
|
||||
let defcmd = '';
|
||||
let deftemp = '';
|
||||
if(act.length == 2){
|
||||
if(act[0] == '2') {
|
||||
defcmd = act[0];
|
||||
deftemp = act[1];
|
||||
}else {
|
||||
defcmd = act.join(' ');
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal open={open}>
|
||||
<Modal.Header content={i18n&&i18n.t ? (type == 1 ? i18n.t('page.schedule.form.title.edut') : i18n.t('page.schedule.form.title.add')) : ''}/>
|
||||
<Modal.Content>
|
||||
<Form onSubmit={(e, d) => {
|
||||
e.preventDefault();
|
||||
onSubmit(type, d.formData);
|
||||
}} serializer={e => {
|
||||
let json = {
|
||||
active: false,
|
||||
name: '',
|
||||
cmd: '',
|
||||
temp: '',
|
||||
time: '',
|
||||
date: '',
|
||||
id: data.ioscheduleuid || ''
|
||||
};
|
||||
|
||||
let active = e.querySelector('input[name="active"]');
|
||||
if(active && 'checked' in active) json.active = active.checked;
|
||||
let name = e.querySelector('input[name="name"]');
|
||||
if(name && 'value' in name) json.name = name.value;
|
||||
let cmd = e.querySelector('select[name="act"]');
|
||||
if(cmd && 'value' in cmd) json.cmd = cmd.value;
|
||||
let time = e.querySelector('#timeDiv input');
|
||||
if(time && 'value' in time) json.time = time.value;
|
||||
let date = e.querySelector('#dateDiv input');
|
||||
if(date && 'value' in date) json.date = date.value;
|
||||
let temp = e.querySelector('input[name="temp"]');
|
||||
if(temp && 'value' in temp) json.temp = temp.value;
|
||||
|
||||
return json;
|
||||
}}>
|
||||
<Form.Field>
|
||||
{/*<label>{i18n&&i18n.t ? i18n.t('page.schedule.form.label.enable') : ''}</label>*/}
|
||||
<Checkbox defaultChecked={data.ioscheduleactive == 1 ? true : false} name="active" label={i18n&&i18n.t ? i18n.t('page.schedule.form.label.enable') : ''} />
|
||||
</Form.Field>
|
||||
<Form.Field>
|
||||
<Input label={i18n&&i18n.t ? i18n.t('page.schedule.form.label.name') : ''} name="name" defaultValue={data.ioschedulename} />
|
||||
</Form.Field>
|
||||
<Form.Field>
|
||||
<label>{i18n&&i18n.t?i18n.t('page.schedule.form.label.action') : ''}</label>
|
||||
<select name="act" value={cmd} onChange={(e) => { checkShowTemp(e.target.value); }}>
|
||||
<option value="">{i18n&&i18n.t ? i18n.t('select.select_action') : ''}</option>
|
||||
{
|
||||
actlist.map((t, idx) => {
|
||||
{/*let selected = defcmd == t.cmd ? 'selected' : 'false';*/}
|
||||
return (
|
||||
<option key={idx} value={t.cmd} >{t.name}</option>
|
||||
)
|
||||
})
|
||||
}
|
||||
</select>
|
||||
</Form.Field>
|
||||
{
|
||||
showTemp ?
|
||||
(<Form.Field>
|
||||
<Input label={i18n&&i18n.t ? i18n.t('page.schedule.form.label.temp') : ''} name="temp" defaultValue={temp} />
|
||||
</Form.Field>)
|
||||
: null
|
||||
}
|
||||
<Form.Field id="timeDiv">
|
||||
<label>{i18n&&i18n.t?i18n.t('page.schedule.form.label.time') : ''}</label>
|
||||
<DateTime dateFormat={false} timeFormat="HH:mm" defaultValue={data.ioscheduleparam1&&data.ioscheduleparam2 ? `${data.ioscheduleparam2}:${data.ioscheduleparam1}` : ''} />
|
||||
</Form.Field>
|
||||
<Form.Field>
|
||||
<label>{i18n&&i18n.t ? i18n.t('page.schedule.form.label.datetype') : ''}</label>
|
||||
<Radio label={i18n&&i18n.t ? i18n.t('page.schedule.form.label.type_week') : ''} name="dtRadio" value="w" checked={dateType == 'w'} onChange={(e, {value}) => {changeDateType(value)}} />
|
||||
<Radio label={i18n&&i18n.t ? i18n.t('page.schedule.form.label.type_date') : ''} name="dtRadio" value="d" checked={dateType == 'd'} onChange={(e, {value}) => {changeDateType(value)}} />
|
||||
</Form.Field>
|
||||
{
|
||||
dateType == 'w' ?
|
||||
(
|
||||
<Form.Group inline>
|
||||
<label>{i18n&&i18n.t ? i18n.t('page.schedule.form.label.week') : ''}</label>
|
||||
<Form.Field>
|
||||
<Checkbox label={i18n&&i18n.t ? i18n.t('week.mon') : ''} value="1" checked={week.find(t => t == 1) ? true : false} onChange={(e, {value, checked}) => {changeWeek(checked, value)}}/>
|
||||
</Form.Field>
|
||||
<Form.Field>
|
||||
<Checkbox label={i18n&&i18n.t ? i18n.t('week.tue') : ''} value="2" checked={week.find(t => t == 2) ? true : false} onChange={(e, {value, checked}) => {changeWeek(checked, value)}}/>
|
||||
</Form.Field>
|
||||
<Form.Field>
|
||||
<Checkbox label={i18n&&i18n.t ? i18n.t('week.wed') : ''} value="3" checked={week.find(t => t == 3) ? true : false} onChange={(e, {value, checked}) => {changeWeek(checked, value)}}/>
|
||||
</Form.Field>
|
||||
<Form.Field>
|
||||
<Checkbox label={i18n&&i18n.t ? i18n.t('week.thu') : ''} value="4" checked={week.find(t => t == 4) ? true : false} onChange={(e, {value, checked}) => {changeWeek(checked, value)}}/>
|
||||
</Form.Field>
|
||||
<Form.Field>
|
||||
<Checkbox label={i18n&&i18n.t ? i18n.t('week.fri') : ''} value="5" checked={week.find(t => t == 5) ? true : false} onChange={(e, {value, checked}) => {changeWeek(checked, value)}}/>
|
||||
</Form.Field>
|
||||
<Form.Field>
|
||||
<Checkbox label={i18n&&i18n.t ? i18n.t('week.sat') : ''} value="6" checked={week.find(t => t == 6) ? true : false} onChange={(e, {value, checked}) => {changeWeek(checked, value)}}/>
|
||||
</Form.Field>
|
||||
<Form.Field>
|
||||
<Checkbox label={i18n&&i18n.t ? i18n.t('week.sun') : ''} value="7" checked={week.find(t => t == 7) ? true : false} onChange={(e, {value, checked}) => {changeWeek(checked, value)}}/>
|
||||
</Form.Field>
|
||||
</Form.Group>
|
||||
) :
|
||||
(
|
||||
<Form.Field id="dateDiv">
|
||||
<label>{i18n&&i18n.t?i18n.t('page.schedule.form.label.date'):''}</label>
|
||||
<DateTime timeFormat={false} dateFormat="MM-DD" defaultValue={`${data.ioscheduleparam4}-${data.ioscheduleparam3}`} />
|
||||
</Form.Field>
|
||||
)
|
||||
}
|
||||
<DeviceSelect i18n={i18n} devs={devs} addSelect={addSelect} showGroup={true} permissions={permissions} querySelectList={querySelectList} page="schedule" />
|
||||
<Segment>
|
||||
<Header as="h4" content={i18n&&i18n.t ? i18n.t('page.schedule.form.label.selected_device') : ''} />
|
||||
<List verticalAlign="middle" divided>
|
||||
{
|
||||
selected.map((t, idx) => (
|
||||
<SelectedItem key={idx} i18n={i18n} data={t} idx={idx} removeSelected={removeSelected} />
|
||||
))
|
||||
}
|
||||
</List>
|
||||
</Segment>
|
||||
<Grid columns={2}>
|
||||
<Grid.Column>
|
||||
<Button fluid type="submit" content={i18n&&i18n.t?i18n.t('page.leone.form.button.submit'):''}/>
|
||||
</Grid.Column>
|
||||
<Grid.Column>
|
||||
<Button fluid type="button" content={i18n&&i18n.t?i18n.t('page.leone.form.button.cancel'):''} onClick={() => {onClose()}}/>
|
||||
</Grid.Column>
|
||||
</Grid>
|
||||
</Form>
|
||||
</Modal.Content>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default ScheduleModal;
|
||||
@@ -0,0 +1,17 @@
|
||||
import React from 'react';
|
||||
import {List, Button, Label} from 'semantic-ui-react';
|
||||
|
||||
const SelectedItem = ({i18n, idx, data, removeSelected}) => {
|
||||
|
||||
return(
|
||||
<List.Item>
|
||||
<List.Content floated="right">
|
||||
<Button type="button" size="mini" content={i18n&&i18n.t ? i18n.t('page.schedule.form.button.remove') : ''} onClick={() => {removeSelected(idx)}} />
|
||||
</List.Content>
|
||||
<Label content={data.type || ''} />
|
||||
{data.name || ''}
|
||||
</List.Item>
|
||||
)
|
||||
}
|
||||
|
||||
export default SelectedItem;
|
||||
@@ -0,0 +1,297 @@
|
||||
import React from 'react';
|
||||
import {Container, Segment, Table, Button, Modal, Item, Label} from 'semantic-ui-react';
|
||||
import ListItem from './ListItem';
|
||||
import ScheduleModal from './ScheduleModal';
|
||||
|
||||
class SchedulePage extends React.Component {
|
||||
|
||||
state ={
|
||||
modal: false,
|
||||
modalType: 0,
|
||||
modalData: {},
|
||||
modalWeek: [],
|
||||
modalShowTemp: false,
|
||||
modalDateType: 'w',
|
||||
modalSelected: [],
|
||||
modalCmd: '',
|
||||
modalTemp: '',
|
||||
itemModal: false,
|
||||
itemModalData: []
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.props.getScheduleList();
|
||||
this.props.router.setRouteLeaveHook(this.props.route, () => {
|
||||
this.props.clearList();
|
||||
})
|
||||
}
|
||||
|
||||
changeActive = (id) => {
|
||||
if(!id) return ;
|
||||
this.props.swSchedule({id});
|
||||
}
|
||||
|
||||
delItem = (id) => {
|
||||
if(!id) return ;
|
||||
this.props.delSchedule({id});
|
||||
}
|
||||
|
||||
openModal = (type, data = {}, items = []) => {
|
||||
let json = {
|
||||
modal: true,
|
||||
modalType: type,
|
||||
modalData: data,
|
||||
modalSelected: [...items]
|
||||
}
|
||||
if(type == 1){
|
||||
let dtype = '';
|
||||
if(data.ioscheduleparam5 && data.ioscheduleparam5 != '-'){
|
||||
let ws = data.ioscheduleparam5.split(',');
|
||||
let arr = [];
|
||||
dtype = 'w';
|
||||
for(let i in ws){
|
||||
if(isFinite(ws[i]) && ws[i] >= 1 && ws[i] <= 7){
|
||||
arr = [...arr, ws[i]];
|
||||
}
|
||||
}
|
||||
json = {
|
||||
...json,
|
||||
modalWeek: [...arr]
|
||||
};
|
||||
// this.setState({
|
||||
// week: [...arr]
|
||||
// });
|
||||
}else{
|
||||
dtype = 'd';
|
||||
}
|
||||
|
||||
let act = data.ioschedulecmd || '';
|
||||
act = act.split(',');
|
||||
if(act.length == 2){
|
||||
if(act[0] == '2') {
|
||||
json = {
|
||||
...json,
|
||||
modalShowTemp: true,
|
||||
modalCmd: act[0],
|
||||
modalTemp: act[1]
|
||||
}
|
||||
}else {
|
||||
json ={
|
||||
...json,
|
||||
modalShowTemp: false,
|
||||
modalCmd: act.join(' '),
|
||||
modalTemp: ''
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
json = {
|
||||
...json,
|
||||
modalDateType: dtype
|
||||
}
|
||||
// this.setState({
|
||||
// modalDateType: dtype
|
||||
// })
|
||||
}
|
||||
this.setState({
|
||||
...json
|
||||
});
|
||||
}
|
||||
|
||||
closeModal = () => {
|
||||
this.setState({
|
||||
modal: false,
|
||||
modalType: 0,
|
||||
modalData: {},
|
||||
modalWeek: [],
|
||||
modalShowTemp: false,
|
||||
modalDateType: 'w',
|
||||
modalSelected: [],
|
||||
modalCmd: '',
|
||||
modalTemp: ''
|
||||
})
|
||||
}
|
||||
|
||||
submitModal = (type, data) => {
|
||||
let {i18n, showDialog} = this.props;
|
||||
let json = {};
|
||||
if(type == 1 && !data.id) return showDialog(i18n&&i18n.t ? i18n.t('tip.input_empty') : '');
|
||||
if(!data.name || !data.time || !data.cmd || (data.cmd == 2 && !data.temp) || (this.state.modalDateType == 'd' && !data.date))
|
||||
return showDialog(i18n&&i18n.t ? i18n.t('tip.input_empty') : '');
|
||||
|
||||
if((this.state.modalDateType == 'w' && this.state.modalWeek.length == 0)) return showDialog(i18n&&i18n.t ? i18n.t('tip.select_week') : '');
|
||||
|
||||
json.name = data.name;
|
||||
json.active = data.active ? 1 : 0;
|
||||
|
||||
if(!/^\d{1,2}:\d{1,2}$/.test(data.time)) return showDialog(i18n&&i18n.t ? i18n.t('tip.input_format') : '');
|
||||
let tarr = data.time.split(':');
|
||||
if(tarr[0] < 0 || tarr[0] > 23 || tarr[1] < 0 || tarr[1] > 59) return showDialog(i18n&&i18n.t ? i18n.t('tip.time_range') : '');
|
||||
json.min = tarr[1];
|
||||
json.hour = tarr[0];
|
||||
|
||||
if(this.state.modalDateType == 'w'){
|
||||
json.week = this.state.modalWeek.join(',');
|
||||
}else{
|
||||
json.day = '';
|
||||
json.month = '';
|
||||
if(!/^\d{1,2}\-\d{1,2}$/.test(data.date)) return showDialog(i18n&&i18n.t ? i18n.t('tip.date_format') : '');
|
||||
let darr = data.date.split('-');
|
||||
if(darr[0] < 1 || darr[0] > 12 || darr[1] < 1 || darr[1] > 31) return showDialog(i18n&&i18n.t ? i18n.t('tip.date_range') : '');
|
||||
json.day = darr[1];
|
||||
json.month = darr[0];
|
||||
}
|
||||
|
||||
let tmp = this.state.modalSelected.map(t => t.id);
|
||||
json.devs = tmp.join(',');
|
||||
|
||||
if(data.cmd == 2){
|
||||
if(!data.temp) return showDialog(i18n&&i18n.t ? i18n.t('tip.input_empty_temp') : '');
|
||||
if(!(data.temp >= 16 && data.temp <= 30)) return showDialog(i18n&&i18n.t ? i18n.t('tip.temp_format') : '');
|
||||
json.action = `${data.cmd},${data.temp}`;
|
||||
}else{
|
||||
json.action = data.cmd.replace(' ', ',');
|
||||
}
|
||||
|
||||
json.id = data.id;
|
||||
|
||||
if(type == 0){
|
||||
this.props.addSchedule(json);
|
||||
}else{
|
||||
this.props.editSchedule(json);
|
||||
}
|
||||
|
||||
this.closeModal();
|
||||
}
|
||||
|
||||
showGroup = (items) => {
|
||||
this.setState({
|
||||
itemModal: true,
|
||||
itemModalData: [...items]
|
||||
});
|
||||
}
|
||||
closeGroupModal = () => {
|
||||
this.setState({
|
||||
itemModal: false,
|
||||
itemModalData: []
|
||||
});
|
||||
}
|
||||
|
||||
querySelectList = (type) => {
|
||||
this.props.getSelectList({type});
|
||||
}
|
||||
|
||||
// ================================
|
||||
|
||||
addSelect = (data) => {
|
||||
if(!data) return;
|
||||
this.setState({
|
||||
modalSelected: [...this.state.modalSelected, data]
|
||||
})
|
||||
}
|
||||
|
||||
removeSelected = (idx) => {
|
||||
let items = [...this.state.modalSelected];
|
||||
items.splice(idx, 1);
|
||||
this.setState({
|
||||
modalSelected: [...items]
|
||||
});
|
||||
}
|
||||
|
||||
checkShowTemp = (val) => {
|
||||
this.setState({
|
||||
modalShowTemp: val == 2 ? true : false,
|
||||
modalCmd: val
|
||||
});
|
||||
}
|
||||
|
||||
changeDateType = (type) => {
|
||||
if(!type) return;
|
||||
this.setState({
|
||||
modalDateType: type
|
||||
})
|
||||
}
|
||||
|
||||
changeWeek = (checked, value) => {
|
||||
let week = this.state.modalWeek;
|
||||
if(checked){
|
||||
if(week.indexOf(value) == -1){
|
||||
week.push(value);
|
||||
}
|
||||
}else{
|
||||
if(week.indexOf(value) != -1){
|
||||
week.splice(week.indexOf(value), 1);
|
||||
}
|
||||
}
|
||||
this.setState({
|
||||
modalWeek: [...week]
|
||||
});
|
||||
}
|
||||
|
||||
// ================================
|
||||
|
||||
render() {
|
||||
let {i18n, devs, list, dos, les, ios, permissions} = this.props;
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<Segment className="clearfix">
|
||||
<Button type="button" floated="right" icon="plus" basic color="green" content={i18n&&i18n.t ? i18n.t('page.schedule.table.button.add') : ''} style={{marginBottom: '15px'}} onClick={() => {this.openModal(0)}}/>
|
||||
<Table>
|
||||
<Table.Header>
|
||||
<Table.Row>
|
||||
<Table.HeaderCell>{i18n&&i18n.t ? i18n.t('page.schedule.table.operate') : ''}</Table.HeaderCell>
|
||||
<Table.HeaderCell>{i18n&&i18n.t ? i18n.t('page.schedule.table.name') : ''}</Table.HeaderCell>
|
||||
<Table.HeaderCell>{i18n&&i18n.t ? i18n.t('page.schedule.table.schedule_time') : ''}</Table.HeaderCell>
|
||||
<Table.HeaderCell>{i18n&&i18n.t ? i18n.t('page.schedule.table.action') : ''}</Table.HeaderCell>
|
||||
<Table.HeaderCell>{i18n&&i18n.t ? i18n.t('page.schedule.table.active_status') : ''}</Table.HeaderCell>
|
||||
<Table.HeaderCell>{i18n&&i18n.t ? i18n.t('page.schedule.table.device') : ''}</Table.HeaderCell>
|
||||
</Table.Row>
|
||||
</Table.Header>
|
||||
<Table.Body>
|
||||
{
|
||||
list.map((t,idx) => (<ListItem key={idx} i18n={i18n} data={t} idx={idx} dos={dos} ios={ios} les={les} openModal={this.openModal} changeActive={this.changeActive} delItem={this.delItem} showGroup={this.showGroup} />))
|
||||
}
|
||||
</Table.Body>
|
||||
</Table>
|
||||
</Segment>
|
||||
<ShowGroupItem i18n={i18n} open={this.state.itemModal} items={this.state.itemModalData} onClose={this.closeGroupModal} />
|
||||
<ScheduleModal i18n={i18n}
|
||||
open={this.state.modal}
|
||||
data={this.state.modalData}
|
||||
type={this.state.modalType}
|
||||
querySelectList={this.querySelectList}
|
||||
permissions={permissions}
|
||||
devs={devs}
|
||||
selected={this.state.modalSelected}
|
||||
week={this.state.modalWeek}
|
||||
showTemp={this.state.modalShowTemp}
|
||||
dateType={this.state.modalDateType}
|
||||
cmd={this.state.modalCmd}
|
||||
temp={this.state.modalTemp}
|
||||
addSelect={this.addSelect}
|
||||
checkShowTemp={this.checkShowTemp}
|
||||
removeSelected={this.removeSelected}
|
||||
changeDateType={this.changeDateType}
|
||||
changeWeek={this.changeWeek}
|
||||
onClose={this.closeModal}
|
||||
onSubmit={this.submitModal} />
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const ShowGroupItem = ({i18n,open,items, onClose}) => {
|
||||
|
||||
return (
|
||||
<Modal open={open} onClose={() => {onClose()}} size="small">
|
||||
<Modal.Content>
|
||||
{
|
||||
items.map((t, idx) => <Item key={idx}><Label content={t.type}/>{t.name}</Item>)
|
||||
}
|
||||
</Modal.Content>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
export default SchedulePage;
|
||||
@@ -0,0 +1,159 @@
|
||||
import React from 'react';
|
||||
import {} from '../../../actions';
|
||||
import Datetime from 'react-datetime';
|
||||
import {Container, Segment, Form, Header, Menu, Grid, Table, Input, Button} from 'semantic-ui-react';
|
||||
|
||||
class NetForm extends React.Component {
|
||||
state = {
|
||||
input: this.props.network && 'NETWORKMODE' in this.props.network && this.props.network['NETWORKMODE'] == 1 ? false : true,
|
||||
ip: '',
|
||||
netmask: '',
|
||||
gateway: '',
|
||||
dns: ''
|
||||
}
|
||||
|
||||
changeActive = (active) => {
|
||||
this.setState({input: active});
|
||||
}
|
||||
|
||||
setInputState = (name, val) => {
|
||||
let json = {};
|
||||
json[name] = val;
|
||||
this.setState(json);
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
// if(this.props.network['IP'] != nextProps.network['IP']){
|
||||
// this.setState({ip: nextProps.network.ip});
|
||||
this.setInputState('ip', nextProps.network['IP']);
|
||||
// }
|
||||
// if(this.props.network['NETMASK'] != nextProps.network['NETMASK']){
|
||||
// this.setState({netmask: nextProps.network.netmask});
|
||||
this.setInputState('netmask', nextProps.network['NETMASK']);
|
||||
// }
|
||||
// if(this.props.network['GATEWAY'] != nextProps.network['GATEWAY']){
|
||||
// this.setState({gateway: nextProps.network['GATEWAY]});
|
||||
this.setInputState('gateway', nextProps.network['GATEWAY']);
|
||||
// }
|
||||
// if(this.props.network['DNS'] !== nextProps.network['DNS']){
|
||||
// this.setState({dns: nextProps.network['DNS]});
|
||||
this.setInputState('dns', nextProps.network['DNS']);
|
||||
// }
|
||||
}
|
||||
|
||||
render() {
|
||||
let {i18n, network, onSubmit} = this.props;
|
||||
return (
|
||||
<div>
|
||||
<Menu widths={2}>
|
||||
<Menu.Item active={this.state.input} content={i18n && 't' in i18n ? i18n.t('page.system_info.form.button.dhcpip') : ''} onClick={()=>{this.changeActive(true)}}/>
|
||||
<Menu.Item active={!this.state.input} content={i18n && 't' in i18n ? i18n.t('page.system_info.form.button.manualip') : ''} onClick={()=>{this.changeActive(false)}}/>
|
||||
</Menu>
|
||||
<Form onSubmit={(e,data) => {
|
||||
e.preventDefault();
|
||||
onSubmit(data.formData);
|
||||
}} serializer={e => {
|
||||
let json = {
|
||||
ip: e.querySelector('input[name="ip"]').value,
|
||||
netmask: e.querySelector('input[name="netmask"]').value,
|
||||
gateway: e.querySelector('input[name="gateway"]').value,
|
||||
dns: e.querySelector('input[name="dns"]').value,
|
||||
dhcpMode: this.state.input
|
||||
}
|
||||
|
||||
return json;
|
||||
}}>
|
||||
<Table>
|
||||
<Table.Body>
|
||||
<Table.Row>
|
||||
<Table.Cell width={8} content={i18n && 't' in i18n ? i18n.t('page.system_info.form.label.ip') : ''} textAlign="center"/>
|
||||
<Table.Cell width={8} textAlign="center" >
|
||||
<Input fluid name="ip" value={this.state.ip} disabled={this.state.input} onChange={e=>{this.setInputState('ip', e.target.value)}}/>
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
<Table.Row>
|
||||
<Table.Cell width={8} content={i18n && 't' in i18n ? i18n.t('page.system_info.form.label.netmask') : ''} textAlign="center"/>
|
||||
<Table.Cell width={8} textAlign="center" >
|
||||
<Input fluid name="netmask" value={this.state.netmask} disabled={this.state.input} onChange={e=>{this.setInputState('netmask', e.target.value)}}/>
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
<Table.Row>
|
||||
<Table.Cell width={8} content={i18n && 't' in i18n ? i18n.t('page.system_info.form.label.gateway') : ''} textAlign="center"/>
|
||||
<Table.Cell width={8} textAlign="center" >
|
||||
<Input fluid name="gateway" value={this.state.gateway} disabled={this.state.input} onChange={e=>{this.setInputState('gateway', e.target.value)}}/>
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
<Table.Row>
|
||||
<Table.Cell width={8} content={i18n && 't' in i18n ? i18n.t('page.system_info.form.label.dns') : ''} textAlign="center"/>
|
||||
<Table.Cell width={8} textAlign="center" >
|
||||
<Input fluid name="dns" value={this.state.dns} disabled={this.state.input} onChange={e=>{this.setInputState('dns', e.target.value)}}/>
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
</Table.Body>
|
||||
<Table.Footer>
|
||||
<Table.Row>
|
||||
<Table.Cell colSpan="2">
|
||||
<Button type="submit" fluid content={i18n && 't' in i18n ? i18n.t('page.system_info.form.button.update_network') :''}/>
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
</Table.Footer>
|
||||
</Table>
|
||||
</Form>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/*const NetForm = ({i18n, onSubmit, network}) => (
|
||||
<Form onSubmit={(e,data) => {
|
||||
e.preventDefault();
|
||||
onSubmit(data.formData);
|
||||
}} serializer={e => {
|
||||
let json = {
|
||||
ip: e.querySelector('input[name="ip"]').value,
|
||||
netmask: e.querySelector('input[name="netmask"]').value,
|
||||
gateway: e.querySelector('input[name="gateway"]').value,
|
||||
dns: e.querySelector('input[name="dns"]').value
|
||||
}
|
||||
|
||||
return json;
|
||||
}}>
|
||||
<Table>
|
||||
<Table.Body>
|
||||
<Table.Row>
|
||||
<Table.Cell width={8} content={i18n && 't' in i18n ? i18n.t('page.system_info.form.label.ip') : ''} textAlign="center"/>
|
||||
<Table.Cell width={8} textAlign="center" >
|
||||
<Input fluid name="ip" value={network['IP'] || ''} />
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
<Table.Row>
|
||||
<Table.Cell width={8} content={i18n && 't' in i18n ? i18n.t('page.system_info.form.label.netmask') : ''} textAlign="center"/>
|
||||
<Table.Cell width={8} textAlign="center" >
|
||||
<Input fluid name="netmask" value={network['NETMASK'] || ''} />
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
<Table.Row>
|
||||
<Table.Cell width={8} content={i18n && 't' in i18n ? i18n.t('page.system_info.form.label.gateway') : ''} textAlign="center"/>
|
||||
<Table.Cell width={8} textAlign="center" >
|
||||
<Input fluid name="gateway" value={network['GATEWAY'] || ''} />
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
<Table.Row>
|
||||
<Table.Cell width={8} content={i18n && 't' in i18n ? i18n.t('page.system_info.form.label.dns') : ''} textAlign="center"/>
|
||||
<Table.Cell width={8} textAlign="center" >
|
||||
<Input fluid name="dns" value={network['DNS'] || ''} />
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
</Table.Body>
|
||||
<Table.Footer>
|
||||
<Table.Row>
|
||||
<Table.Cell colSpan="2">
|
||||
<Button type="submit" fluid content={i18n && 't' in i18n ? i18n.t('page.system_info.form.button.update_network') :''}/>
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
</Table.Footer>
|
||||
</Table>
|
||||
</Form>
|
||||
)*/
|
||||
|
||||
export default NetForm;
|
||||
@@ -0,0 +1,40 @@
|
||||
import React from 'react';
|
||||
import {} from '../../../actions';
|
||||
import Datetime from 'react-datetime';
|
||||
import {Container, Segment, Form, Header, Menu, Grid, Table, Input, Button} from 'semantic-ui-react';
|
||||
import {convertTime} from '../../../tools';
|
||||
|
||||
const TimeForm = ({i18n, time, onSubmit}) => {
|
||||
return (
|
||||
<Form onSubmit={(e,data) => {
|
||||
e.preventDefault();
|
||||
onSubmit(data.formData);
|
||||
}} serializer={e => {
|
||||
let json = {};
|
||||
|
||||
json.time = e.querySelector('input').value || '';
|
||||
|
||||
return json;
|
||||
}}>
|
||||
<Table>
|
||||
<Table.Body>
|
||||
<Table.Row>
|
||||
<Table.Cell width={8} content={i18n && 't' in i18n ? i18n.t('page.system_info.form.label.sysdate') : ''} textAlign="center"/>
|
||||
<Table.Cell width={8} textAlign="center" >
|
||||
<Datetime dateFormat="YYYY-MM-DD" timeFormat="HH:mm" value={convertTime(time)} input={true} />
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
</Table.Body>
|
||||
<Table.Footer>
|
||||
<Table.Row>
|
||||
<Table.Cell colSpan="2">
|
||||
<Button type="submit" fluid content={i18n && 't' in i18n ? i18n.t('page.system_info.form.button.update_time') :''} />
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
</Table.Footer>
|
||||
</Table>
|
||||
</Form>
|
||||
)
|
||||
}
|
||||
|
||||
export default TimeForm;
|
||||
@@ -0,0 +1,57 @@
|
||||
import React from 'react';
|
||||
import {toggle_loading, get_network_info, get_system_time, add_dialog_msg,set_network_info, set_system_time} from '../../../actions';
|
||||
import Datetime from 'react-datetime';
|
||||
import {Container, Segment, Form, Header, Menu, Grid, Table, Input} from 'semantic-ui-react';
|
||||
import NetForm from './NetForm';
|
||||
import TimeForm from './TimeForm';
|
||||
import {convertTime,padding} from '../../../tools';
|
||||
|
||||
class SysInfo extends React.Component {
|
||||
|
||||
componentDidMount(){
|
||||
let {dispatch} = this.props;
|
||||
// get network
|
||||
dispatch(get_network_info());
|
||||
//get time
|
||||
dispatch(get_system_time());
|
||||
}
|
||||
|
||||
netSubmit = (data) => {
|
||||
let {dispatch, i18n} = this.props;
|
||||
if(!data.dhcpMode){
|
||||
if(!data.ip || !data.netmask || !data.gateway || !data.dns) return dispatch(add_dialog_msg(i18n && 't' in i18n ? i18n.t('tip.input_empty') : ''));
|
||||
}
|
||||
|
||||
dispatch(set_network_info(data.dhcpMode, data.ip, data.netmask, data.gateway, data.dns));
|
||||
}
|
||||
|
||||
timeSubmit = (data) => {
|
||||
let {dispatch, i18n} = this.props;
|
||||
let regex_date = /^([0-9]{4})\-([0-9]{2})\-([0-9]{2})\s([0-9]{1,2}):([0-9]{1,2})$/;
|
||||
if(!('time' in data) || !data.time.trim() || !regex_date.test(data.time.trim())) return dispatch(add_dialog_msg(i18n && 't' in i18n ? i18n.t('tip.datetime_format') : ''));
|
||||
let m = data.time.trim().match(regex_date);
|
||||
if(!m) return dispatch(add_dialog_msg(i18n && 't' in i18n ? i18n.t('tip.datetime_format') : ''));
|
||||
// MMDDHHmmYYYY
|
||||
let dstr = `${m[2]}${m[3]}${padding(m[4], 2)}${padding(m[5], 2)}${m[1]}`;
|
||||
|
||||
dispatch(set_system_time(dstr));
|
||||
}
|
||||
|
||||
render() {
|
||||
let {i18n, network, time} = this.props;
|
||||
return (
|
||||
<Container>
|
||||
<Segment>
|
||||
<Header as="h2" content={i18n && 't' in i18n ? i18n.t('page.system_info.title.sysinfo') : ''} />
|
||||
<NetForm i18n={i18n} network={network} onSubmit={this.netSubmit}/>
|
||||
</Segment>
|
||||
<Segment style={{marginBottom: '100px'}}>
|
||||
<Header as="h2" content={i18n && 't' in i18n ? i18n.t('page.system_info.title.timeinfo') : ''} />
|
||||
<TimeForm i18n={i18n} time={time} onSubmit={this.timeSubmit}/>
|
||||
</Segment>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default SysInfo;
|
||||
@@ -0,0 +1,26 @@
|
||||
import React from 'react';
|
||||
import {Table, Button} from 'semantic-ui-react';
|
||||
|
||||
const ListItem = ({i18n, user, openModal, delUser}) => {
|
||||
let write = sessionStorage.getItem('write_privilege');
|
||||
let account = sessionStorage.getItem('account');
|
||||
|
||||
return (
|
||||
<Table.Row>
|
||||
<Table.Cell>{user.account}</Table.Cell>
|
||||
<Table.Cell>
|
||||
{user.write_privilege == 1 ? 'W' : ''}{user.write_privilege == 1 && user.read_privilege == 1 ? ' / ' : ''}{user.read_privilege == 1 ? 'R' : ''}
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
{
|
||||
(write == 1 && (user.account != 'admin' || (account == 'admin') ) ) || account == user.account ?
|
||||
<Button type="button" content={i18n && i18n.t ? i18n.t('page.userlist.table.button.edit') : ''} onClick={() => openModal(user.account)}/> :
|
||||
null
|
||||
}
|
||||
{write == 1 && user.account != 'admin' ? <Button type="button" content={i18n && i18n.t ? i18n.t('page.userlist.table.button.del') : ''} onClick={()=>delUser(user.account)}/> : null }
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
)
|
||||
}
|
||||
|
||||
export default ListItem;
|
||||
@@ -0,0 +1,50 @@
|
||||
import React from 'react';
|
||||
import {Modal, Form, Input, Grid, Button, Checkbox} from 'semantic-ui-react';
|
||||
|
||||
|
||||
const UModal = ({i18n, open, type, data, closeModal, onSubmit}) => {
|
||||
return (
|
||||
<Modal closeOnDimmerClick={false} open={open}>
|
||||
<Modal.Content>
|
||||
<Form onSubmit={(e, data) => {
|
||||
e.preventDefault();
|
||||
onSubmit(data.formData);
|
||||
}}
|
||||
serializer={e=>{
|
||||
let json = {
|
||||
type,
|
||||
account: e.querySelector('input[name="account"]').value,
|
||||
password: e.querySelector('input[name="password"]').value,
|
||||
read_privilege: e.querySelector('input[name="read_privilege"]').checked ? 1 : 0,
|
||||
write_privilege: e.querySelector('input[name="write_privilege"]').checked ? 1 : 0
|
||||
};
|
||||
|
||||
return json;
|
||||
}}>
|
||||
<Form.Field>
|
||||
<Input label={i18n && i18n.t ? i18n.t('page.userlist.form.label.account') : ''} name="account" disabled={type == 1} defaultValue={type == 1 ? data.account : ''} />
|
||||
</Form.Field>
|
||||
<Form.Field>
|
||||
<Input type="password" label={i18n && i18n.t ? i18n.t('page.userlist.form.label.password') : ''} name="password" />
|
||||
</Form.Field>
|
||||
<Form.Field>
|
||||
<Checkbox label={i18n && i18n.t ? i18n.t('page.userlist.form.label.read_privilege') : ''} defaultChecked={data.read_privilege == 1} name="read_privilege" />
|
||||
</Form.Field>
|
||||
<Form.Field>
|
||||
<Checkbox label={i18n && i18n.t ? i18n.t('page.userlist.form.label.write_privilege') : ''} defaultChecked={data.write_privilege == 1} name="write_privilege" />
|
||||
</Form.Field>
|
||||
<Grid>
|
||||
<Grid.Column width={8}>
|
||||
<Button type="submit" fluid content={i18n && i18n.t ? i18n.t('page.userlist.form.button.submit') : ''} />
|
||||
</Grid.Column>
|
||||
<Grid.Column width={8}>
|
||||
<Button type="button" fluid content={i18n && i18n.t ? i18n.t('page.userlist.form.button.cancel') : ''} onClick={() => closeModal()} />
|
||||
</Grid.Column>
|
||||
</Grid>
|
||||
</Form>
|
||||
</Modal.Content>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
export default UModal;
|
||||
@@ -0,0 +1,89 @@
|
||||
import React from 'react';
|
||||
import {Container, Segment, Header, Table, Button, Modal} from 'semantic-ui-react';
|
||||
import ListItem from './ListItem';
|
||||
import {get_user_list, add_dialog_msg, edit_user, add_user, del_user} from '../../../actions';
|
||||
import UModal from './UserModal';
|
||||
|
||||
class UList extends React.Component {
|
||||
|
||||
state ={
|
||||
edit: false,
|
||||
// 0 is add , 1 is edit
|
||||
editType: 0,
|
||||
editData: {}
|
||||
}
|
||||
|
||||
openModal = (acc) => {
|
||||
if(!acc) return this.setState({edit: true, editType: 0});
|
||||
let {users} = this.props;
|
||||
let user = users.filter(t => t.account == acc);
|
||||
this.setState({
|
||||
edit: true,
|
||||
editType: 1,
|
||||
editData: user[0] || {}
|
||||
});
|
||||
}
|
||||
|
||||
closeModal = () => {
|
||||
this.setState({edit: false, editData: {}});
|
||||
}
|
||||
|
||||
onModalSubmit = (data) => {
|
||||
let {i18n} = this.props;
|
||||
if(data.type == 0 && (!data.account || !data.password)) return this.props.showDialog(i18n && i18n.t ? i18n.t('tip.input_empty') : '');
|
||||
this.setState({edit: false, editData: {}});
|
||||
if(data.type == 1){
|
||||
this.props.editUser(data);
|
||||
}else{
|
||||
this.props.addUser(data);
|
||||
}
|
||||
}
|
||||
|
||||
delUser = (acc) => {
|
||||
if(!acc) return ;
|
||||
this.props.delUser({account: acc});
|
||||
}
|
||||
|
||||
componentDidMount(){
|
||||
this.props.getList();
|
||||
|
||||
this.props.router.setRouteLeaveHook(this.props.route, () => {
|
||||
this.props.clearList();
|
||||
})
|
||||
}
|
||||
|
||||
render () {
|
||||
let {i18n, users} = this.props;
|
||||
return (
|
||||
<Container>
|
||||
<Segment>
|
||||
<Header as="h2" content={i18n && 't' in i18n ? i18n.t('page.userlist.title.userlist') : ''} />
|
||||
<Table>
|
||||
<Table.Header>
|
||||
<Table.Row>
|
||||
<Table.HeaderCell width={6} content={i18n && i18n.t ? i18n.t('page.userlist.table.account') : ''} />
|
||||
<Table.HeaderCell width={6} content={i18n && i18n.t ? i18n.t('page.userlist.table.privilege') : ''} />
|
||||
<Table.HeaderCell width={4} content={i18n && i18n.t ? i18n.t('page.userlist.table.operate') : ''} />
|
||||
</Table.Row>
|
||||
</Table.Header>
|
||||
<Table.Body>
|
||||
{
|
||||
users.map(t => <ListItem key={t.account} i18n={i18n} user={t} openModal={this.openModal} delUser={this.delUser}/>)
|
||||
}
|
||||
</Table.Body>
|
||||
<Table.Footer>
|
||||
<Table.Row>
|
||||
<Table.Cell colSpan="3">
|
||||
<Button type="button" fluid content={i18n && i18n.t ? i18n.t('page.userlist.table.button.add') : ''} onClick={()=>this.openModal()}/>
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
</Table.Footer>
|
||||
</Table>
|
||||
</Segment>
|
||||
<UModal i18n={i18n} open={this.state.edit} type={this.state.editType} data={this.state.editData} closeModal={this.closeModal} onSubmit={this.onModalSubmit}/>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default UList;
|
||||
@@ -0,0 +1,64 @@
|
||||
import React from 'react';
|
||||
import {Form, Button} from 'semantic-ui-react';
|
||||
|
||||
const DeviceSelect = ({i18n, querySelectList, page, permissions, devs, addSelect, showGroup}) => {
|
||||
let devName = null;
|
||||
let devType = null;
|
||||
return (
|
||||
<Form.Group inline>
|
||||
<Form.Field>
|
||||
<label>{i18n&&i18n.t?i18n.t(`page.${page || ''}.form.label.select_device`) : ''}</label>
|
||||
<select ref={node => devType = node} onChange={(e) => {
|
||||
querySelectList(e.target.value);
|
||||
}}>
|
||||
<option value="">{i18n&&i18n.t?i18n.t('select.dev_type') : ''}</option>
|
||||
{
|
||||
permissions.dio ?
|
||||
<option value="do">{i18n&&i18n.t ? i18n.t('select.digitoutput') : ''}</option> : null
|
||||
}
|
||||
{
|
||||
permissions.leone ?
|
||||
<option value="leone">{i18n&&i18n.t ? i18n.t('select.leone') : ''}</option> : null
|
||||
}
|
||||
{
|
||||
permissions.iogroup && showGroup ?
|
||||
<option value="iogroup">{i18n&&i18n.t ? i18n.t('select.iogroup') : ''}</option> : null
|
||||
}
|
||||
</select>
|
||||
</Form.Field>
|
||||
<Form.Field>
|
||||
<select ref={node => devName = node}>
|
||||
{
|
||||
devs.map((t, idx) => <option key={idx} value={t.id || ''}>{t.name || ''}</option>)
|
||||
}
|
||||
</select>
|
||||
</Form.Field>
|
||||
<Form.Field>
|
||||
<Button type="button" basic size="mini" content={i18n&&i18n.t?i18n.t(`page.${page || ''}.form.button.join`) : ''} onClick={()=>{
|
||||
let type = '';
|
||||
let devname = '';
|
||||
let devid = '';
|
||||
let typev = '';
|
||||
if(devType != null) {
|
||||
type = devType.options[devType.selectedIndex].innerHTML;
|
||||
typev = devType.value == 'leone' ? 'le' : devType.value;
|
||||
}
|
||||
if(devName != null) {
|
||||
if(devName.options.length == 0) return ;
|
||||
devname = devName.options[devName.selectedIndex].innerHTML;
|
||||
devid = `${typev}${devName.value}`;
|
||||
}
|
||||
let json = {
|
||||
type,
|
||||
name: devname,
|
||||
id: devid
|
||||
};
|
||||
if(!devType.value || !type || !devname) return ;
|
||||
addSelect(json);
|
||||
}} />
|
||||
</Form.Field>
|
||||
</Form.Group>
|
||||
)
|
||||
}
|
||||
|
||||
export default DeviceSelect;
|
||||
@@ -0,0 +1,14 @@
|
||||
import React from 'react';
|
||||
import {Modal, Button} from 'semantic-ui-react';
|
||||
|
||||
const Dialog = ({obj, getNext}) => (
|
||||
<Modal open={obj && obj.msg != '' ? true : false} onClose={() => getNext(obj.act)} style={{zIndex: "2001"}}>
|
||||
<Modal.Content>{obj && obj.msg ? obj.msg : ''}</Modal.Content>
|
||||
<Modal.Actions>
|
||||
<Button onClick={() => getNext(obj.act)} content="OK" />
|
||||
</Modal.Actions>
|
||||
</Modal>
|
||||
);
|
||||
|
||||
|
||||
export default Dialog;
|
||||
@@ -0,0 +1,10 @@
|
||||
import React from 'react';
|
||||
import {Loader, Dimmer} from 'semantic-ui-react';
|
||||
|
||||
const Loading = ({active}) => (
|
||||
<Dimmer active={active} style={{zIndex: '2000'}}>
|
||||
<Loader size="large" />
|
||||
</Dimmer>
|
||||
)
|
||||
|
||||
export default Loading;
|
||||
@@ -0,0 +1,29 @@
|
||||
import React from 'react';
|
||||
import {Form, Segment, Input, Button} from 'semantic-ui-react';
|
||||
|
||||
const loginForm = ({i18n, page, onSubmit}) => {
|
||||
let account;
|
||||
let password;
|
||||
return (
|
||||
<Form size="large" onSubmit={(e, data) => {
|
||||
e.preventDefault();
|
||||
onSubmit(data.formData);
|
||||
}} serializer={e => {
|
||||
let acc = e.querySelector('input[name="acc"]').value;
|
||||
let pass = e.querySelector('input[name="pass"]').value;
|
||||
return {account: acc, password: pass};
|
||||
}}>
|
||||
<Segment stacked={true} >
|
||||
<Form.Field>
|
||||
<Input icon="user" iconPosition="left" name="acc" placeholder={typeof i18n.t == 'function' ? i18n.t(`${page}.input.placeholder.account`) : ''} />
|
||||
</Form.Field>
|
||||
<Form.Field>
|
||||
<Input icon="lock" iconPosition="left" name="pass" type="password" placeholder={typeof i18n.t == 'function' ? i18n.t(`${page}.input.placeholder.password`) : ''} />
|
||||
</Form.Field>
|
||||
<Button type="submit" color="teal" size="large" fluid={true} content={typeof i18n.t == 'function' ? i18n.t(`${page}.button.login`) : ''} />
|
||||
</Segment>
|
||||
</Form>
|
||||
);
|
||||
}
|
||||
|
||||
export default loginForm;
|
||||
@@ -0,0 +1,99 @@
|
||||
import React from 'react';
|
||||
import i18next from 'i18next';
|
||||
import {Grid, Header} from 'semantic-ui-react';
|
||||
import LoginForm from './Form.js';
|
||||
import Dialog from '../../containers/DialogControl';
|
||||
import {add_dialog_msg, toggle_loading} from '../../actions';
|
||||
import {connect} from 'react-redux';
|
||||
import Loading from '../../containers/LoadingControl';
|
||||
|
||||
class Root extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
i18n: {}
|
||||
};
|
||||
}
|
||||
|
||||
handleSubmit = (data) => {
|
||||
let {i18n} = this.state;
|
||||
if (typeof data.account != 'string' || !data.account.trim() || typeof data.password != 'string' || !data.password.trim()) {
|
||||
// show dialog
|
||||
this.props.dispatch(add_dialog_msg(i18n && 't' in i18n ? i18n.t('tip.input_empty') : ''));
|
||||
return;
|
||||
}
|
||||
|
||||
this.props.dispatch(toggle_loading(1));
|
||||
fetch('/api/system/login', {
|
||||
method: 'post',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({data})
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(json => {
|
||||
this.props.dispatch(toggle_loading(0));
|
||||
if(json.status != 1) {
|
||||
this.props.dispatch(add_dialog_msg(json.message));
|
||||
return ;
|
||||
}
|
||||
|
||||
sessionStorage.setItem('write_privilege', json.data.record[0].write_privilege);
|
||||
sessionStorage.setItem('read_privilege', json.data.record[0].read_privilege);
|
||||
sessionStorage.setItem('account', json.data.record[0].account);
|
||||
|
||||
sessionStorage.setItem('token', json.data.token);
|
||||
if(json.data.rt.permission && json.data.rt.permission.length > 0) {
|
||||
sessionStorage.setItem('permissions', JSON.stringify(json.data.rt.permission[0]));
|
||||
}
|
||||
|
||||
// this.props.dispatch(add_dialog_msg('登入成功', () => {
|
||||
location.replace('/admin');
|
||||
// }))
|
||||
})
|
||||
.catch(err => this.props.dispatch(add_dialog_msg('登入失敗')));
|
||||
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
let lang = navigator
|
||||
.language
|
||||
.substring(0, 2);
|
||||
fetch(`/locales/${lang}.json`).then(response => {
|
||||
if (response.status == 200)
|
||||
return response.json();
|
||||
return {}
|
||||
}).then(json => {
|
||||
i18next.init({
|
||||
lng: lang,
|
||||
resources: json
|
||||
}, () => {
|
||||
this.setState({i18n: i18next});
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
render() {
|
||||
const {i18n} = this.state;
|
||||
const page = 'page.login';
|
||||
return (
|
||||
<div style={{
|
||||
height: '100%'
|
||||
}}>
|
||||
<Loading />
|
||||
<Dialog/>
|
||||
<Grid verticalAlign="middle" centered className="login-grid">
|
||||
<Grid.Column className="login-column">
|
||||
<Header textAlign="center" content={'JCNet WebIO'} as="h2" color="teal"/>
|
||||
<LoginForm i18n={this.state.i18n} page={page} onSubmit={this.handleSubmit}/>
|
||||
</Grid.Column>
|
||||
</Grid>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default connect()(Root)
|
||||
@@ -0,0 +1,14 @@
|
||||
import React from 'react';
|
||||
import {Sidebar, Menu, Segment, Icon} from 'semantic-ui-react';
|
||||
import {Link} from 'react-router';
|
||||
|
||||
const MItem = ({toLink, txt, onClick, permission}) => {
|
||||
if(permission == 1) {
|
||||
return (
|
||||
<Menu.Item as={Link} to={toLink} content={txt} onClick={onClick} />
|
||||
)
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export default MItem;
|
||||
@@ -0,0 +1,40 @@
|
||||
import React from 'react';
|
||||
import {Sidebar, Menu, Segment, Icon, Container} from 'semantic-ui-react';
|
||||
import {Link} from 'react-router';
|
||||
import MItem from './Item';
|
||||
|
||||
const MainMenu = ({i18n, show, toggleMenu, children, permissions}) => (
|
||||
<div style={{height: '100%'}}>
|
||||
<Sidebar.Pushable as={Segment} style={{zIndex: 100}}>
|
||||
<Sidebar as={Menu} animation="push" width="thin" visible={show} icon="labeled" vertical inverted>
|
||||
<MItem toLink="/admin" txt={i18n && 't' in i18n ? i18n.t('menu.item.systeminfo') : ''} permission={true} onClick={() => toggleMenu()} />
|
||||
<MItem toLink="/admin/user" txt={i18n && 't' in i18n ? i18n.t('menu.item.userlist') : ''} permission={true} onClick={() => toggleMenu()} />
|
||||
<MItem toLink="/admin/dio" txt={i18n && 't' in i18n ? i18n.t('menu.item.dio') : ''} permission={permissions.dio} onClick={() => toggleMenu()} />
|
||||
<MItem toLink="/admin/log" txt={i18n && 't' in i18n ? i18n.t('menu.item.log') : ''} permission={permissions.log} onClick={()=>toggleMenu()} />
|
||||
<MItem toLink="/admin/leone" txt={i18n && 't'in i18n ? i18n.t('menu.item.leone') : ''} permission={permissions.leone} onClick={()=>toggleMenu()} />
|
||||
<MItem toLink="/admin/iogroup" txt={i18n && 't' in i18n ? i18n.t('menu.item.iogroup') : ''} permission={permissions.iogroup} onClick={()=>toggleMenu()} />
|
||||
<MItem toLink="/admin/iocmd" txt={i18n && 't' in i18n ? i18n.t('menu.item.iocmd') : ''} permission={permissions.iocmd} onClick={()=>toggleMenu()} />
|
||||
<MItem toLink="/admin/schedule" txt={i18n && 't' in i18n ? i18n.t('menu.item.schedule') : ''} permission={permissions.schedule} onClick={()=>toggleMenu()} />
|
||||
<MItem toLink="/admin/modbus" txt={i18n && 't' in i18n ? i18n.t('menu.item.modbus') : ''} permission={permissions.modbus} onClick={()=>toggleMenu()} />
|
||||
<MItem toLink="/admin/link" txt={i18n && 't' in i18n ? i18n.t('menu.item.link') : ''} permission={permissions.link} onClick={()=>toggleMenu()} />
|
||||
<MItem toLink="/admin" txt={i18n && 't' in i18n ? i18n.t('menu.item.logout') : ''} permission={true} onClick={()=>{
|
||||
sessionStorage.clear();
|
||||
location.replace('/');
|
||||
}} />
|
||||
</Sidebar>
|
||||
<Sidebar.Pusher style={{backgroundColor: '#eee'}}>
|
||||
<Menu fixed="top" >
|
||||
<Menu.Item onClick={() => toggleMenu(show ? false : true)} >
|
||||
<Icon name="sidebar" />
|
||||
{i18n && 't' in i18n ? i18n.t('menu.title') : ''}
|
||||
</Menu.Item>
|
||||
</Menu>
|
||||
<Container style={{paddingTop: '45px', paddingBottom: '40px'}}>
|
||||
{children}
|
||||
</Container>
|
||||
</Sidebar.Pusher>
|
||||
</Sidebar.Pushable>
|
||||
</div>
|
||||
);
|
||||
|
||||
export default MainMenu;
|
||||
Reference in New Issue
Block a user