update wristband api and add wristband ui

This commit is contained in:
Jay 2017-03-31 09:19:16 +08:00
parent e1ce5290da
commit f8f3cbe0d8
16 changed files with 1928 additions and 1126 deletions

View File

@ -30,7 +30,8 @@
"schedule": true, "schedule": true,
"modbus": true, "modbus": true,
"link": true, "link": true,
"ipcam": true "ipcam": true,
"wristband": true
}, },
"cmdpath":{ "cmdpath":{
"manualip": "/home/www/cmd/manualip", "manualip": "/home/www/cmd/manualip",

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -274,6 +274,7 @@
"modbuslog": "Modbus Log", "modbuslog": "Modbus Log",
"link": "連動", "link": "連動",
"ipcam": "網路攝影機", "ipcam": "網路攝影機",
"wristband": "藍芽手環",
"logout": "登出" "logout": "登出"
} }
}, },

View File

@ -267,7 +267,7 @@ router
if (row[0].c > 0) return n('ERR0054'); if (row[0].c > 0) return n('ERR0054');
let query = "insert into ??.?? (`devuid`,`type`,`addr`,`num`,`datalen`,`ctime`,`mtime`) values (?, ?, ?, ?, unix_timestamp(), unix_timestamp())"; let query = "insert into ??.?? (`devuid`,`type`,`addr`,`num`,`datalen`,`ctime`,`mtime`) values (?, ?, ?, ?, ?, unix_timestamp(), unix_timestamp())";
let param = [config.db.db5, 'iolist', arr.data.id, arr.data.type, arr.data.addr, arr.data.num, dlen]; let param = [config.db.db5, 'iolist', arr.data.id, arr.data.type, arr.data.addr, arr.data.num, dlen];
res.db.query(query, param, (err, row) => { res.db.query(query, param, (err, row) => {
if (err) return n('ERR8001'); if (err) return n('ERR8001');
@ -329,6 +329,8 @@ router
if (!arr.data) return n('ERR0000'); if (!arr.data) return n('ERR0000');
if (!arr.data.id) return n('ERR0028'); if (!arr.data.id) return n('ERR0028');
res.db.query(`use ${config.db.db5}`);
let query = "delete i, a from ??.?? i \ let query = "delete i, a from ??.?? i \
left join ??.?? a \ left join ??.?? a \
on a.`iouid` = i.`uid` \ on a.`iouid` = i.`uid` \
@ -407,6 +409,7 @@ router
if (!arr.data.iouid) return n('ERR0028'); if (!arr.data.iouid) return n('ERR0028');
if (!arr.data.name) return n('ERR0026'); if (!arr.data.name) return n('ERR0026');
if (!('portnum' in arr.data)) return n('ERR0048'); if (!('portnum' in arr.data)) return n('ERR0048');
if (!('type' in arr.data)) return n('ERR0009');
if (!('range_min' in arr.data)) return n('ERR0050'); if (!('range_min' in arr.data)) return n('ERR0050');
if (!('range_max' in arr.data)) return n('ERR0051'); if (!('range_max' in arr.data)) return n('ERR0051');
if (!('scale_min' in arr.data)) return n('ERR0052'); if (!('scale_min' in arr.data)) return n('ERR0052');
@ -419,9 +422,9 @@ router
if (row[0].count > 0) return n('ERR0054'); if (row[0].count > 0) return n('ERR0054');
let q = "insert into ??.?? (`iouid`, `name`, `portnum`, `range_min`, `range_max`, `scale_min`, `scale_max`, `ctime`, `mtime`) values \ let q = "insert into ??.?? (`iouid`, `name`, `portnum`, `type`, `range_min`, `range_max`, `scale_min`, `scale_max`, `ctime`, `mtime`) values \
(?, ?, ?, ?, ?, ?, ?, unix_timestamp(), unix_timestamp())"; (?, ?, ?, ?, ?, ?, ?, unix_timestamp(), unix_timestamp())";
let p = [config.db.db5, 'aioset', arr.data.iouid, arr.data.name, arr.data.portnum, arr.data.range_min, arr.data.range_max, arr.data.scale_min, arr.data.scale_max]; let p = [config.db.db5, 'aioset', arr.data.iouid, arr.data.name, arr.data.portnum, arr.data.type, arr.data.range_min, arr.data.range_max, arr.data.scale_min, arr.data.scale_max];
res.db.query(q, p, (err, row) => { res.db.query(q, p, (err, row) => {
if (err) return n('ERR8001'); if (err) return n('ERR8001');
@ -441,7 +444,8 @@ router
if (!arr.data.id) return n('ERR0028'); if (!arr.data.id) return n('ERR0028');
if (!arr.data.iouid) return n('ERR0028'); if (!arr.data.iouid) return n('ERR0028');
if (!arr.data.name) return n('ERR0026'); if (!arr.data.name) return n('ERR0026');
if (!arr.data.portnum) return n('ERR0048'); if (!('portnum' in arr.data)) return n('ERR0048');
if (!('type' in arr.data)) return n('ERR0009');
if (!('range_min' in arr.data)) return n('ERR0050'); if (!('range_min' in arr.data)) return n('ERR0050');
if (!('range_max' in arr.data)) return n('ERR0051'); if (!('range_max' in arr.data)) return n('ERR0051');
if (!('scale_min' in arr.data)) return n('ERR0052'); if (!('scale_min' in arr.data)) return n('ERR0052');
@ -460,13 +464,14 @@ router
let query = "update ??.?? set \ let query = "update ??.?? set \
`name` = ?, \ `name` = ?, \
`portnum` = ?, \ `portnum` = ?, \
`type` = ?, \
`range_min` = ?, \ `range_min` = ?, \
`range_max` = ?, \ `range_max` = ?, \
`scale_min` = ?, \ `scale_min` = ?, \
`scale_max` = ?, \ `scale_max` = ?, \
`mtime` = unix_timestamp() \ `mtime` = unix_timestamp() \
where `uid` = ?"; where `uid` = ?";
let param = [config.db.db5, 'aioset', arr.data.name, arr.data.portnum, arr.data.range_min, arr.data.range_max, arr.data.scale_min, arr.data.scale_max, arr.data.id]; let param = [config.db.db5, 'aioset', arr.data.name, arr.data.portnum, arr.data.type, arr.data.range_min, arr.data.range_max, arr.data.scale_min, arr.data.scale_max, arr.data.id];
res.db.query(query, param, (err, row) => { res.db.query(query, param, (err, row) => {
if (err) return n('ERR8002'); if (err) return n('ERR8002');
@ -520,6 +525,8 @@ router
dev.`uid` in (?) \ dev.`uid` in (?) \
and ( log.`tst` >= ? \ and ( log.`tst` >= ? \
and log.`tst` <= ? ) \ and log.`tst` <= ? ) \
and io.`uid` is not null \
and ( aio.`name` is not null or log.`type` in (1,2)) \
order by log.`uid` desc, log.`tst` desc \ order by log.`uid` desc, log.`tst` desc \
limit 0, 100"; limit 0, 100";
let param = [config.db.db10, 'jcmbrt', config.db.db5, 'device', config.db.db5, 'iolist', config.db.db5, 'aioset', arr.data.ids, arr.data.stime, arr.data.etime]; let param = [config.db.db10, 'jcmbrt', config.db.db5, 'device', config.db.db5, 'iolist', config.db.db5, 'aioset', arr.data.ids, arr.data.stime, arr.data.etime];

View File

@ -47,7 +47,72 @@ router
res.api_res = { res.api_res = {
record: [] record: []
}; };
n(); let q = "select count(*) as c from ??.?? where `mac` = ?";
let p = [config.db.db9, 'wristband', arr.mac];
res.db.query(q, p, (err, row) => {
let pros = [];
if(!(err || row.length == 0 || row[0].c > 0)){
let q = "insert into ??.?? values (null, ?, '', unix_timestamp(), unix_timestamp())";
let p = [config.db.db9, 'wristband', arr.mac];
pros.push(tool.promiseQuery(res,q,p,'q1'));
}
let lq = "insert into ??.?? (`mac`, `devid`, `val2`, `val3`, `val4`, `val5`, `val6`, `val7`, `val8`, `val9`, `val10`, `val11`, `timestamp`, `ctime`, `mtime`) values \
(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, unix_timestamp(), unix_timestamp()) ON DUPLICATE KEY \
update \
`devid` = ?, \
`val2` = ?, \
`val3` = ?, \
`val4` = ?, \
`val5` = ?, \
`val6` = ?, \
`val7` = ?, \
`val8` = ?, \
`val9` = ?, \
`val10` = ?, \
`val11` = ?, \
`timestamp` = ?, \
`mtime` = unix_timestamp()";
let lp = [config.db.db9, 'lastdata',
arr.mac,
arr.devid,
arr.val2 || '',
arr.val3 || '',
arr.val4 || '',
arr.val5 || '',
arr.val6 || '',
arr.val7 || '',
arr.val8 || '',
arr.val9 || '',
arr.val10 || '',
arr.val11 || '',
arr.timestamp || '',
arr.devid,
arr.val2 || '',
arr.val3 || '',
arr.val4 || '',
arr.val5 || '',
arr.val6 || '',
arr.val7 || '',
arr.val8 || '',
arr.val9 || '',
arr.val10 || '',
arr.val11 || '',
arr.timestamp || '']
pros.push(tool.promiseQuery(res,lq,lp,'q2'));
Promise.all(pros)
.then(r => {
n()
})
.catch(err => {
console.log(err);
n();
})
})
// n();
}) })
}) })
.post('*', async(req, res, n) => { .post('*', async(req, res, n) => {
@ -60,17 +125,46 @@ router
n(); n();
}) })
.post('/getstatus', (req,res,n) => { .post('/getstatus', (req,res,n) => {
let query = "select * from \ // let query = "select * from \
(\ // (\
select xx.*, l.`name` from ??.?? xx \ // select xx.`mac`, xx.`val11`, dd.`val2`, dd.`val3`, dd.`val4`, dd.`val5`, dd.`val6`, dd.`val7`, dd.`val8`, dd.`val9`, dd.`val10`, dd.`timestamp`, l.`name` \
left join ??.?? l \ // from ??.?? xx \
on l.`serialnumber` = xx.`devid` \ // left join ??.?? l \
where xx.`timestamp` > unix_timestamp() - 10 \ // on l.`serialnumber` = xx.`devid` \
order by xx.`val11` desc, xx.`timestamp` desc \ // left join ( \
limit 65535\ // select * from (\
) x \ // select * from ??.?? \
group by `mac`"; // where `timestamp` > unix_timestamp() - 20 \
let param = [config.db.db9, 'rawdata', config.db.db9, 'location'] // order by `timestamp` desc \
// ) t1 group by `mac`\
// ) dd \
// on dd.`mac` = xx.`mac`\
// where xx.`timestamp` > unix_timestamp() - 20 \
// order by xx.`val11` desc, xx.`timestamp` desc \
// limit 2147483647\
// ) x \
// group by `mac`";
// let param = [config.db.db9, 'rawdata', config.db.db9, 'location', config.db.db9, 'rawdata']
let query = "select w.`name`, l.`name` as locname, l2.`name` as last_locname, ll.*\
from ??.?? w\
left join ( \
select * from ( \
select * from ??.?? \
where `timestamp` > unix_timestamp() - 30 order by conv(`val11`, 16, 10) desc limit 65535000\
) tmp group by `mac` \
) tmp2 \
on tmp2.`mac` = w.`mac` \
left join ??.?? ll \
on ll.`mac` = w.`mac` \
left join ??.?? l \
on \
l.`serialnumber` = tmp2.`devid` \
left join ??.?? l2 \
on \
l2.`serialnumber` = ll.`devid` \
order by w.`uid`";
let param = [config.db.db9, 'wristband', config.db.db9, 'rawdata', config.db.db9, 'lastdata', config.db.db9, 'location', config.db.db9, 'location',];
res.db.query(query, param, (err,row) => { res.db.query(query, param, (err,row) => {
if(err) return n('ERR8000'); if(err) return n('ERR8000');

View File

@ -5,7 +5,8 @@ const AIOForm = ({i18n, open, type, data, onSubmit, onClose}) => {
if(!open) return null; if(!open) return null;
let input = { let input = {
name: data.name || '', name: data.name || '',
portnum: data.portnum || '', portnum: data.portnum,
type: data.type,
scale_min: data.scale_min || 0, scale_min: data.scale_min || 0,
scale_max: data.scale_max || 0, scale_max: data.scale_max || 0,
range_min: data.range_min || 0, range_min: data.range_min || 0,
@ -14,7 +15,8 @@ const AIOForm = ({i18n, open, type, data, onSubmit, onClose}) => {
return ( return (
<Table.Row> <Table.Row>
<Table.Cell><Input name="name" onChange={(e,d)=>{input.name = d.value}} defaultValue={data.name || ''}/></Table.Cell> <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="portnum" onChange={(e,d)=>{input.portnum = d.value}} defaultValue={data.portnum}/></Table.Cell>
<Table.Cell><Input name="type" onChange={(e,d)=>{input.type = d.value}} defaultValue={data.type}/></Table.Cell>
<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_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'}/> <Input name="range_max" size="small" label="Max" onChange={(e,d)=>{input.range_max = d.value}} defaultValue={data.range_max || '0'}/>

View File

@ -6,7 +6,8 @@ const AIOListItem = ({i18n, data, editAIO, delAIO}) => {
return ( return (
<Table.Row> <Table.Row>
<Table.Cell>{data.name || ''}</Table.Cell> <Table.Cell>{data.name || ''}</Table.Cell>
<Table.Cell>{data.portnum || ''}</Table.Cell> <Table.Cell>{data.portnum}</Table.Cell>
<Table.Cell>{data.type}</Table.Cell>
<Table.Cell>{data.range_min || 0} ~ {data.range_max || 0}</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>{data.scale_min || 0} ~ {data.scale_max || 0}</Table.Cell>
<Table.Cell> <Table.Cell>

View File

@ -47,6 +47,7 @@ class AIOModal extends React.Component {
<Table.Row> <Table.Row>
<Table.HeaderCell>名稱</Table.HeaderCell> <Table.HeaderCell>名稱</Table.HeaderCell>
<Table.HeaderCell>接口號碼</Table.HeaderCell> <Table.HeaderCell>接口號碼</Table.HeaderCell>
<Table.HeaderCell>資料類型</Table.HeaderCell>
<Table.HeaderCell>Range(Min-Max)</Table.HeaderCell> <Table.HeaderCell>Range(Min-Max)</Table.HeaderCell>
<Table.HeaderCell>Scale(Min-Max)</Table.HeaderCell> <Table.HeaderCell>Scale(Min-Max)</Table.HeaderCell>
<Table.HeaderCell>操作</Table.HeaderCell> <Table.HeaderCell>操作</Table.HeaderCell>

View File

@ -0,0 +1,22 @@
import React from 'react';
import {Table} from 'semantic-ui-react';
import {convertTime} from '../../../../tools';
const ListItem = ({i18n, data}) => {
return (
<Table.Row>
<Table.Cell>{data.mac}</Table.Cell>
<Table.Cell>{data.locname ? data.locname : data.last_locname}</Table.Cell>
<Table.Cell>{data.val3 ? parseInt(data.val3, 16) : ''}</Table.Cell>
<Table.Cell>{data.val4 ? `${parseInt(data.val4, 16)}%` : ''}</Table.Cell>
<Table.Cell>{data.val2 ? `${parseInt(data.val2, 16)}` : ''}</Table.Cell>
<Table.Cell>{data.val5 ? `${parseInt(data.val5, 16)}` : ''}</Table.Cell>
<Table.Cell>{data.val6 ? `${parseInt(data.val6, 16)}` : ''}</Table.Cell>
<Table.Cell>{data.val7 ? `${parseInt(data.val7, 16)}` : ''}</Table.Cell>
<Table.Cell>{data.timestamp ? convertTime(data.timestamp, true) : ''}</Table.Cell>
</Table.Row>
)
}
export default ListItem;

View File

@ -0,0 +1,90 @@
import React from 'react';
import {Container, Segment, Table, Label, Checkbox} from 'semantic-ui-react';
import {getRequest} from '../../../../actions';
import ListItem from './ListItem';
class LocStatus extends React.Component{
state = {
autoRefresh: false,
list: []
}
tick = null
componentDidMount(){
this.getList();
}
componentWillUnmount(){
clearInterval(this.tick);
}
changeRefresh = () => {
this.setState({
autoRefresh: !this.state.autoRefresh
}, ()=>{
this.checkRefresh();
})
}
checkRefresh = () => {
if(this.state.autoRefresh) {
this.tick = setInterval(this.runTick, 2000);
}else{
clearInterval(this.tick);
}
}
runTick = () => {
this.getList();
}
getList = () => {
let {toggleLoading, showDialog} = this.props;
fetch('/api/wristband/getstatus', getRequest())
.then(response=>response.json())
.then(json => {
if(json.status != 1) return showDialog(json.message);
this.setState({
list: [...(json.data.record || [])]
})
});
}
render (){
let {i18n} = this.props;
return (
<Container>
<Segment className="clearfix">
<Checkbox toggle checked={this.state.autoRefresh} onChange={(e,d) => {this.changeRefresh()}} label="自動更新" />
<Table>
<Table.Header>
<Table.Row>
<Table.HeaderCell>手環ID</Table.HeaderCell>
<Table.HeaderCell>地點</Table.HeaderCell>
<Table.HeaderCell>步數</Table.HeaderCell>
<Table.HeaderCell>剩餘電量</Table.HeaderCell>
<Table.HeaderCell>HR</Table.HeaderCell>
<Table.HeaderCell>SBP</Table.HeaderCell>
<Table.HeaderCell>DBP</Table.HeaderCell>
<Table.HeaderCell>卡路里</Table.HeaderCell>
<Table.HeaderCell>時間</Table.HeaderCell>
{/*<Table.HeaderCell></Table.HeaderCell>*/}
</Table.Row>
</Table.Header>
<Table.Body>
{
this.state.list.map((t,idx)=>(
<ListItem key={idx}
i18n={i18n}
data={t} />
))
}
</Table.Body>
</Table>
</Segment>
</Container>
)
}
}
export default LocStatus;

View File

@ -0,0 +1,51 @@
import React from 'react';
import {Grid, Container, Segment, Menu, List} from 'semantic-ui-react';
import LocStatus from '../../../containers/AdminPage/Wristband/LocStatus';
class WristbandPage extends React.Component{
state = {
page: ''
}
changePage = (page) => {
this.setState({
page
})
}
getRenderPage = () => {
switch(this.state.page) {
case 'locstatus':
return <LocStatus />;
default:
return null;
}
}
render(){
return (
<Container>
<Grid>
<Grid.Column width={4}>
<Menu vertical={true}>
<Menu.Item>
<Menu.Header>主選單</Menu.Header>
<Menu.Menu>
<Menu.Item active={this.state.page == 'locstatus'} onClick={()=>{ this.changePage('locstatus'); }}>
位置資訊
</Menu.Item>
</Menu.Menu>
</Menu.Item>
</Menu>
</Grid.Column>
<Grid.Column width={12}>
{this.getRenderPage()}
</Grid.Column>
</Grid>
</Container>
)
}
}
export default WristbandPage;

View File

@ -20,6 +20,7 @@ const MainMenu = ({i18n, show, toggleMenu, children, permissions, showDashboard,
<MItem toLink="/admin/modbuslog" txt={i18n && 't' in i18n ? i18n.t('menu.item.modbuslog') : ''} permission={permissions.modbus} onClick={()=>toggleMenu()} /> <MItem toLink="/admin/modbuslog" txt={i18n && 't' in i18n ? i18n.t('menu.item.modbuslog') : ''} 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/link" txt={i18n && 't' in i18n ? i18n.t('menu.item.link') : ''} permission={permissions.link} onClick={()=>toggleMenu()} />
<MItem toLink="/admin/ipcam" txt={i18n && 't' in i18n ? i18n.t('menu.item.ipcam') : ''} permission={permissions.ipcam} onClick={()=>toggleMenu()} /> <MItem toLink="/admin/ipcam" txt={i18n && 't' in i18n ? i18n.t('menu.item.ipcam') : ''} permission={permissions.ipcam} onClick={()=>toggleMenu()} />
<MItem toLink="/admin/wristband" txt={i18n && 't' in i18n ? i18n.t('menu.item.wristband') : ''} permission={permissions.wristband} onClick={()=>toggleMenu()} />
<MItem toLink="/admin" txt={i18n && 't' in i18n ? i18n.t('menu.item.logout') : ''} permission={true} onClick={()=>{ <MItem toLink="/admin" txt={i18n && 't' in i18n ? i18n.t('menu.item.logout') : ''} permission={true} onClick={()=>{
sessionStorage.clear(); sessionStorage.clear();
location.replace('/'); location.replace('/');

View File

@ -0,0 +1,19 @@
import {connect} from 'react-redux';
import {add_dialog_msg, toggle_loading} from '../../../actions';
import LocStatusPage from '../../../components/AdminPage/Wristband/LocStatus';
const mapStateToProps = (state) => ({
i18n: state.i18n
});
const mapDispatchToProps = (dispatch, ownProps) => ({
showDialog: (msg) => {
dispatch(add_dialog_msg(msg));
},
toggleLoading: (flag = false) => {
dispatch(toggle_loading(flag));
}
})
export default connect(mapStateToProps, mapDispatchToProps)(LocStatusPage);

View File

@ -0,0 +1,19 @@
import {connect} from 'react-redux';
import {add_dialog_msg, toggle_loading} from '../../../actions';
import WristbandPage from '../../../components/AdminPage/Wristband';
const mapStateToProps = (state) => ({
i18n: state.i18n
});
const mapDispatchToProps = (dispatch, ownProps) => ({
showDialog: (msg) => {
dispatch(add_dialog_msg(msg));
},
toggleLoading: (flag = false) => {
dispatch(toggle_loading(flag));
}
})
export default connect(mapStateToProps, mapDispatchToProps)(WristbandPage);

View File

@ -15,6 +15,7 @@ import ModbusLog from './containers/AdminPage/ModbusLog';
import ActionLink from './containers/AdminPage/ActionLink'; import ActionLink from './containers/AdminPage/ActionLink';
import ActionLinkAdd from './containers/AdminPage/ActionLinkAdd'; import ActionLinkAdd from './containers/AdminPage/ActionLinkAdd';
import IPCam from './containers/AdminPage/IPCam'; import IPCam from './containers/AdminPage/IPCam';
import Wristband from './containers/AdminPage/Wristband';
const Routes = ( const Routes = (
<Route path="/admin" component={AdminPage}> <Route path="/admin" component={AdminPage}>
@ -32,6 +33,7 @@ const Routes = (
<Route path="modbuscmd" component={ModbusCmd} /> <Route path="modbuscmd" component={ModbusCmd} />
<Route path="modbuslog" component={ModbusLog} /> <Route path="modbuslog" component={ModbusLog} />
<Route path="ipcam" component={IPCam} /> <Route path="ipcam" component={IPCam} />
<Route path="wristband" component={Wristband} />
</Route> </Route>
); );