add del event, add download event, add download event video

This commit is contained in:
Jay 2017-05-05 17:24:45 +08:00
parent 0cd5667f63
commit 7826befe8e
7 changed files with 125 additions and 14 deletions

43
app.js
View File

@ -9,6 +9,7 @@ const config = require('./config');
const so = require('./includes/storeObject'); const so = require('./includes/storeObject');
const exec = require('child_process').exec; const exec = require('child_process').exec;
const fs = require('fs'); const fs = require('fs');
const archiver = require('archiver');
const app = express(); const app = express();
@ -63,13 +64,13 @@ app.get('/camevent', (req, res) => {
res.send({ ip }); res.send({ ip });
}); });
}) })
app.get('/viewcamimg/:dir/:img', async(req, res) => { app.get(['/viewcamimg/:dir/:file', '/dlcamvideo/:dir/:file'], async(req, res) => {
let dir = req.params.dir; let dir = req.params.dir;
let img = req.params.img; let file = req.params.file;
if (!dir || !img) return res.sendStatus(404); if (!dir || !file) return res.sendStatus(404);
try { try {
let stat = await new Promise((resolve, reject) => { let stat = await new Promise((resolve, reject) => {
fs.stat(path.resolve(config.cmdpath.ipcamsave, dir, img), (err, stats) => { fs.stat(path.resolve(config.cmdpath.ipcamsave, dir, file), (err, stats) => {
if (err) return reject(err); if (err) return reject(err);
return resolve(stats); return resolve(stats);
}) })
@ -78,7 +79,39 @@ app.get('/viewcamimg/:dir/:img', async(req, res) => {
} catch (e) { } catch (e) {
return res.sendStatus(404); return res.sendStatus(404);
} }
res.sendfile(path.resolve(config.cmdpath.ipcamsave, dir, img)) res.sendfile(path.resolve(config.cmdpath.ipcamsave, dir, file))
})
app.get('/dlevent/:dir', async(req, res) => {
let dir = req.params.dir;
if (!dir) return res.sendStatus(404);
let list = [];
try {
let stat = await new Promise((resolve, reject) => {
fs.stat(path.resolve(config.cmdpath.ipcamsave, dir), (err, stats) => {
if (err) return reject(err);
return resolve(stats);
})
});
if (!stat.isDirectory()) return res.sendStatus(404);
list = await new Promise((resolve, reject) => {
fs.readdir(path.resolve(config.cmdpath.ipcamsave, dir), (err, fis) => {
if (err) return reject(err);
return resolve(fis);
})
})
} catch (e) {
return res.sendStatus(404);
}
res.writeHead(200, {
'Content-Type': 'application/zip',
'Content-disposition': 'attachment; filename=cam_event.zip'
});
let zip = archiver('zip', { store: true });
zip.pipe(res);
for (let i of list) {
zip.file(path.resolve(config.cmdpath.ipcamsave, dir, i), { name: i })
}
zip.finalize();
}) })
app.get('/servcmd', (req, res) => { app.get('/servcmd', (req, res) => {

View File

@ -72,6 +72,7 @@
"ERR0070": "IPCam 裝置已達上限", "ERR0070": "IPCam 裝置已達上限",
"ERR0071": "無此裝置資料", "ERR0071": "無此裝置資料",
"ERR0072": "目錄資訊取得失敗", "ERR0072": "目錄資訊取得失敗",
"ERR0073": "目錄輸入錯誤",
"ERR7000": "命令執行失敗", "ERR7000": "命令執行失敗",

View File

@ -12,6 +12,7 @@
"author": "", "author": "",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"archiver": "^1.3.0",
"body-parser": "^1.16.1", "body-parser": "^1.16.1",
"cookie-parser": "^1.4.3", "cookie-parser": "^1.4.3",
"cors": "^2.8.1", "cors": "^2.8.1",

View File

@ -285,6 +285,38 @@ router
} }
return n(); return n();
}) })
.post('/delevent', async(req, res, n) => {
if (!config.permission.ipcam) return n('ERR9000');
if (!tool.checkPermission(req)) return n('ERR9000');
let arr = req.body;
if (!arr.data) return n('ERR0000');
if (!arr.data.dir) return n('ERR0073');
let rp = config.cmdpath.ipcamsave;
let dp = path.resolve(rp, arr.data.dir);
try {
let stat = await new Promise((resolve, reject) => {
fs.stat(dp, (err, stats) => {
if (err) return reject(err);
return resolve(stats);
});
});
if (dp.split(' ')[0] == '/') return n('ERR0073');
await new Promise((resolve, reject) => {
exec(`rm -rf ${dp}`, (err, sout, serr) => {
if (err) return reject(err);
return resolve(null);
})
})
} catch (e) {
return rt.err(res, e, n, 'ERR0072');
}
res.api_res = {
record: []
}
return n();
})
.all('*', rt.send); .all('*', rt.send);
module.exports = router; module.exports = router;

View File

@ -1,9 +1,9 @@
import React from 'react'; import React from 'react';
import { Modal, Grid, List, Menu, Icon } from 'semantic-ui-react'; import { Modal, Grid, List, Menu, Icon, Message } from 'semantic-ui-react';
import {convertTime} from '../../../tools'; import {convertTime} from '../../../tools';
import ImgGrid from './EvtImgGrid'; import ImgGrid from './EvtImgGrid';
const EventModal = ({ i18n, open, name, list, sel, closeEventModal, changeSelectEvent,refreshEvt }) => { const EventModal = ({ i18n, open, name, list, sel, closeEventModal, changeSelectEvent,refreshEvt, delEvent }) => {
return ( return (
<Modal open={open} onClose={()=>{closeEventModal()}} size="fullscreen"> <Modal open={open} onClose={()=>{closeEventModal()}} size="fullscreen">
@ -26,8 +26,17 @@ const EventModal = ({ i18n, open, name, list, sel, closeEventModal, changeSelect
let n = t.name; let n = t.name;
let time = n.split('-')[1]; let time = n.split('-')[1];
return ( return (
<Menu.Item key={idx} active={sel == idx} onClick={()=>{changeSelectEvent(idx)}}> <Menu.Item key={idx} active={sel == idx} >
{convertTime(time, true)} <span onClick={()=>{changeSelectEvent(idx)}}
style={{cursor: "pointer"}}>{convertTime(time, true)}</span>
<Icon name="download" title="下載事件" style={{
cursor: "pointer",
float: 'right'
}} onClick={()=>{window.open(`/dlevent/${t.name}`, '_blank')}}/>
<Icon name="trash" title="刪除事件" style={{
cursor: "pointer",
float: 'right'
}} onClick={()=>{delEvent(t.name)}}/>
</Menu.Item> </Menu.Item>
)}) )})
} }
@ -36,6 +45,25 @@ const EventModal = ({ i18n, open, name, list, sel, closeEventModal, changeSelect
</Menu> </Menu>
</Grid.Column> </Grid.Column>
<Grid.Column width={12}> <Grid.Column width={12}>
{
sel != -1 && list[sel].files.video.length > 0 ? (
<Message>
<Message.Header>影片下載</Message.Header>
<p>
{
list[sel].files.video.map((t, idx) => {
return (
<div key={idx}>
<a href={`/dlcamvideo/${list[sel].name}/${t}`} target="_blank">{t}</a>
</div>
)
})
}
</p>
</Message>
) :null
}
{ {
sel != -1 ? sel != -1 ?
( (

View File

@ -46,10 +46,10 @@ const IPCamModal = ({ i18n, open, type, data, closeModal, submitModal }) => {
</select> </select>
</Form.Field> </Form.Field>
<Form.Field> <Form.Field>
<Input name="maxevents" label="最大儲存事件數量(1-5)" defaultValue={data.maxevents} /> <Input name="maxevents" label="最大儲存事件數量(1-10)" defaultValue={data.maxevents} />
</Form.Field> </Form.Field>
<Form.Field> <Form.Field>
<Input name="maximg" label="最大儲存圖片數量(1-10)" defaultValue={data.maximg} /> <Input name="maximg" label="最大儲存圖片數量(1-20)" defaultValue={data.maximg} />
</Form.Field> </Form.Field>
<Grid columns={2}> <Grid columns={2}>
<Grid.Column> <Grid.Column>

View File

@ -77,8 +77,8 @@ class IPCamPage extends React.Component {
submitModal = (type, data = {}) => { submitModal = (type, data = {}) => {
let {toggleLoading,showDialog} = this.props; let {toggleLoading,showDialog} = this.props;
if(type == 1 && !data.id) return showDialog('資料讀取錯誤'); if(type == 1 && !data.id) return showDialog('資料讀取錯誤');
if(!data.maxevents || data.maxevents < 1 || data.maxevents > 5) return showDialog('事件數量請介於1-5間'); if(!data.maxevents || data.maxevents < 1 || data.maxevents > 10) return showDialog('事件數量請介於1-5間');
if(!data.maximg || data.maximg < 1 || data.maximg > 10) return showDialog('圖片數量請介於1-5間'); if(!data.maximg || data.maximg < 1 || data.maximg > 20) return showDialog('圖片數量請介於1-5間');
if(!data.name) return showDialog('請輸入名稱'); if(!data.name) return showDialog('請輸入名稱');
if(!data.ip) return showDialog('請輸入IP'); if(!data.ip) return showDialog('請輸入IP');
if(!data.model) return showDialog('請選擇型號'); if(!data.model) return showDialog('請選擇型號');
@ -146,6 +146,21 @@ class IPCamPage extends React.Component {
}) })
} }
delEvent = (dir) => {
if(!dir) return ;
let {callConfirm, toggleLoading, showDialog} = this.props;
callConfirm('確定刪除這筆事件?', ()=>{
toggleLoading(1);
fetch('/api/ipcam/delevent', getRequest({dir}))
.then(response=>response.json())
.then(json => {
toggleLoading(0);
if(json.status != 1) return showDialog(json.message);
this.getEvents(-1);
})
})
}
render() { render() {
let {i18n} = this.props; let {i18n} = this.props;
return ( return (
@ -197,7 +212,8 @@ class IPCamPage extends React.Component {
name={this.state.evt.name} name={this.state.evt.name}
refreshEvt={this.getEvents} refreshEvt={this.getEvents}
closeEventModal={this.closeEventModal} closeEventModal={this.closeEventModal}
changeSelectEvent={this.changeSelectEvent} /> changeSelectEvent={this.changeSelectEvent}
delEvent={this.delEvent} />
</Container> </Container>
) )
} }