@ -1,189 +0,0 @@ |
|||||
'use strict'; |
|
||||
const Hex = require('crypto-js/enc-hex'); |
|
||||
const MD5 = require('crypto-js/md5'); |
|
||||
const moment = require('moment'); |
|
||||
const uuid = require('uuid'); |
|
||||
|
|
||||
async function login(ctx, next) { |
|
||||
const transaction = await ctx.fs.dc.orm.transaction(); |
|
||||
try { |
|
||||
const models = ctx.fs.dc.models; |
|
||||
const params = ctx.request.body; |
|
||||
let password = Hex.stringify(MD5(params.password)); |
|
||||
|
|
||||
const userRes = await models.User.findOne({ |
|
||||
where: { |
|
||||
username: params.username, |
|
||||
password: password, |
|
||||
delete: false, |
|
||||
}, |
|
||||
attributes: { exclude: ['password'] }, |
|
||||
include: [{ |
|
||||
attributes: ["resourceId"], |
|
||||
model: models.UserResource |
|
||||
}] |
|
||||
}); |
|
||||
|
|
||||
if (!userRes) { |
|
||||
ctx.status = 400; |
|
||||
ctx.body = { |
|
||||
"message": "账号或密码错误" |
|
||||
} |
|
||||
} else if (!userRes.enable) { |
|
||||
ctx.status = 400; |
|
||||
ctx.body = { message: "该用户已被禁用" } |
|
||||
} else { |
|
||||
const token = uuid.v4(); |
|
||||
|
|
||||
let userRslt = Object.assign(userRes.dataValues, { |
|
||||
authorized: true, |
|
||||
token: token, |
|
||||
userResources: userRes.userResources.map(r => r.resourceId), |
|
||||
}); |
|
||||
|
|
||||
await models.UserToken.create({ |
|
||||
token: token, |
|
||||
userInfo: userRslt, |
|
||||
expired: moment().add(30, 'days').format() |
|
||||
}); |
|
||||
|
|
||||
ctx.status = 200; |
|
||||
ctx.body = userRslt; |
|
||||
} |
|
||||
await transaction.commit(); |
|
||||
} catch (error) { |
|
||||
await transaction.rollback(); |
|
||||
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); |
|
||||
ctx.status = 400; |
|
||||
ctx.body = { |
|
||||
"message": "登录失败" |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 微信小程序登录 |
|
||||
* @@requires.body {phone-手机号, password-密码} ctx |
|
||||
*/ |
|
||||
async function wxLogin(ctx, next) { |
|
||||
const transaction = await ctx.fs.dc.orm.transaction(); |
|
||||
try { |
|
||||
const models = ctx.fs.dc.models; |
|
||||
const params = ctx.request.body; |
|
||||
let password = Hex.stringify(MD5(params.password)); |
|
||||
const userRes = await models.User.findOne({ |
|
||||
where: { |
|
||||
phone: params.phone, |
|
||||
password: password, |
|
||||
delete: false, |
|
||||
}, |
|
||||
attributes: { exclude: ['password'] } |
|
||||
}); |
|
||||
if (!userRes) { |
|
||||
ctx.status = 400; |
|
||||
ctx.body = { message: "手机号或密码错误" } |
|
||||
} else if (!userRes.enable) { |
|
||||
ctx.status = 400; |
|
||||
ctx.body = { message: "该用户已被禁用" } |
|
||||
} else { |
|
||||
const token = uuid.v4(); |
|
||||
//获取用户关注区域信息
|
|
||||
const departmentRes = await models.Department.findOne({ where: { id: userRes.departmentId } }); |
|
||||
let attentionRegion = departmentRes; |
|
||||
while (attentionRegion.dependence && attentionRegion.type != 1) { |
|
||||
const departmentParent = await models.Department.findOne({ where: { id: attentionRegion.dependence } }); |
|
||||
attentionRegion = { |
|
||||
...departmentParent.dataValues, |
|
||||
nextRegin: attentionRegion |
|
||||
} |
|
||||
} |
|
||||
//获取用户权限信息
|
|
||||
const resourceRes = await models.UserResource.findAll({ |
|
||||
where: { |
|
||||
userId: userRes.id |
|
||||
}, |
|
||||
include: [{ |
|
||||
model: models.Resource, |
|
||||
attributes: ['code', 'name'], |
|
||||
}], |
|
||||
attributes: [] |
|
||||
}); |
|
||||
let userRslt = Object.assign({ |
|
||||
authorized: true, |
|
||||
token: token, |
|
||||
...userRes.dataValues |
|
||||
}); |
|
||||
await models.UserToken.create({ |
|
||||
token: token, |
|
||||
userInfo: userRslt, |
|
||||
expired: moment().add(30, 'day').format('YYYY-MM-DD HH:mm:ss') |
|
||||
}, { transaction: transaction }); |
|
||||
ctx.status = 200; |
|
||||
ctx.body = Object.assign({ |
|
||||
...userRslt, |
|
||||
userRegionType: departmentRes.type,//1-市级,2-区县级,3-乡镇级,4-村级
|
|
||||
attentionRegion: attentionRegion, |
|
||||
resources: resourceRes.map(r => r.resource) |
|
||||
}); |
|
||||
} |
|
||||
await transaction.commit(); |
|
||||
} catch (error) { |
|
||||
await transaction.rollback(); |
|
||||
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); |
|
||||
ctx.status = 400; |
|
||||
ctx.body = { |
|
||||
"message": "登录失败" |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
async function logout(ctx) { |
|
||||
try { |
|
||||
const { token, code } = ctx.request.body; |
|
||||
const models = ctx.fs.dc.models; |
|
||||
|
|
||||
await models.UserToken.destroy({ |
|
||||
where: { |
|
||||
token: token, |
|
||||
}, |
|
||||
}); |
|
||||
|
|
||||
ctx.status = 204; |
|
||||
} catch (error) { |
|
||||
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); |
|
||||
ctx.status = 400; |
|
||||
ctx.body = { |
|
||||
"message": "登出失败" |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* 微信小程序登出 |
|
||||
* @request.body {token-用户登录Token} ctx |
|
||||
*/ |
|
||||
async function wxLogout(ctx) { |
|
||||
try { |
|
||||
const { token } = ctx.request.body; |
|
||||
const models = ctx.fs.dc.models; |
|
||||
await models.UserToken.destroy({ |
|
||||
where: { |
|
||||
token: token, |
|
||||
}, |
|
||||
}); |
|
||||
ctx.status = 204; |
|
||||
} catch (error) { |
|
||||
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); |
|
||||
ctx.status = 400; |
|
||||
ctx.body = { |
|
||||
"message": "登出失败" |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
module.exports = { |
|
||||
login, |
|
||||
wxLogin, |
|
||||
logout, |
|
||||
wxLogout |
|
||||
}; |
|
@ -0,0 +1,68 @@ |
|||||
|
'use strict'; |
||||
|
const moment = require('moment') |
||||
|
|
||||
|
async function edit (ctx, next) { |
||||
|
const transaction = await ctx.fs.dc.orm.transaction(); |
||||
|
try { |
||||
|
const models = ctx.fs.dc.models; |
||||
|
const { userId } = ctx.fs.api |
||||
|
const data = ctx.request.body; |
||||
|
|
||||
|
// 或取其他服务信息
|
||||
|
const nvrData = { |
||||
|
channelCount: 8, |
||||
|
port: 8080, |
||||
|
} |
||||
|
|
||||
|
if (data.id) { |
||||
|
// 修改
|
||||
|
const storageData = Object.assign({}, data, nvrData) |
||||
|
await models.Nvr.update(storageData, { |
||||
|
where: { |
||||
|
id: data.id |
||||
|
}, |
||||
|
transaction |
||||
|
}) |
||||
|
} else { |
||||
|
// 添加
|
||||
|
const storageData = Object.assign({}, data, nvrData, { |
||||
|
createTime: moment().format(), |
||||
|
createUserId: userId, |
||||
|
delete: false, |
||||
|
}) |
||||
|
await models.Nvr.create(storageData, { transaction }) |
||||
|
} |
||||
|
|
||||
|
await transaction.commit(); |
||||
|
ctx.status = 204; |
||||
|
} catch (error) { |
||||
|
await transaction.rollback(); |
||||
|
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); |
||||
|
ctx.status = 400; |
||||
|
ctx.body = {} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
async function del (ctx, next) { |
||||
|
try { |
||||
|
const models = ctx.fs.dc.models; |
||||
|
const { nvrId } = ctx.params |
||||
|
|
||||
|
await models.Nvr.destroy({ |
||||
|
where: { |
||||
|
id: nvrId |
||||
|
} |
||||
|
}) |
||||
|
|
||||
|
ctx.status = 204; |
||||
|
} catch (error) { |
||||
|
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); |
||||
|
ctx.status = 400; |
||||
|
ctx.body = {} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
module.exports = { |
||||
|
edit, |
||||
|
del, |
||||
|
}; |
@ -1,32 +0,0 @@ |
|||||
'use strict'; |
|
||||
|
|
||||
const auth = require('../../controllers/auth'); |
|
||||
|
|
||||
module.exports = function (app, router, opts) { |
|
||||
/** |
|
||||
* @api {Post} login 登录. |
|
||||
* @apiVersion 1.0.0 |
|
||||
* @apiGroup Auth |
|
||||
*/ |
|
||||
app.fs.api.logAttr['POST/login'] = { content: '登录', visible: true }; |
|
||||
router.post('/login', auth.login); |
|
||||
|
|
||||
/** |
|
||||
* @api {POST} wxLogin 微信小程序登录.(使用手机号、密码登录) |
|
||||
* @apiVersion 1.0.0 |
|
||||
* @apiGroup Auth |
|
||||
*/ |
|
||||
app.fs.api.logAttr['POST/wxLogin'] = { content: '微信小程序登录', visible: true }; |
|
||||
router.post('/wxLogin', auth.wxLogin); |
|
||||
|
|
||||
app.fs.api.logAttr['PUT/logout'] = { content: '登出', visible: false }; |
|
||||
router.put('/logout', auth.logout); |
|
||||
|
|
||||
/** |
|
||||
* @api {PUT} wxLogout 微信小程序登出 |
|
||||
* @apiVersion 1.0.0 |
|
||||
* @apiGroup Auth |
|
||||
*/ |
|
||||
app.fs.api.logAttr['PUT/wxLogout'] = { content: '登出', visible: false }; |
|
||||
router.put('/wxLogout', auth.wxLogout); |
|
||||
}; |
|
@ -0,0 +1,11 @@ |
|||||
|
'use strict'; |
||||
|
|
||||
|
const nvr = require('../../controllers/nvr'); |
||||
|
|
||||
|
module.exports = function (app, router, opts) { |
||||
|
app.fs.api.logAttr['POST/nvr'] = { content: '添加/修改nvr', visible: false }; |
||||
|
router.post('/nvr', nvr.edit); |
||||
|
|
||||
|
app.fs.api.logAttr['DEL/nvr'] = { content: '删除nvr', visible: false }; |
||||
|
router.del('/nvr/:nvrId', nvr.del); |
||||
|
}; |
@ -0,0 +1,29 @@ |
|||||
|
'use strict'; |
||||
|
const redis = require("ioredis") |
||||
|
const moment = require('moment') |
||||
|
|
||||
|
module.exports = async function factory (app, opts) { |
||||
|
let client = new redis(opts.redis.port, opts.redis.host); |
||||
|
|
||||
|
client.on("error", function (err) { |
||||
|
app.fs.logger.error('info', '[FS-AUTH-REDIS]', 'redis connect error.'); |
||||
|
console.error("Error :", err); |
||||
|
process.exit(-1); |
||||
|
}); |
||||
|
|
||||
|
client.on('connect', function () { |
||||
|
console.log(`redis connect success ${opts.redis.host + ':' + opts.redis.port}`); |
||||
|
}) |
||||
|
|
||||
|
// 自定义方法
|
||||
|
async function hdelall (key) { |
||||
|
const obj = await client.hgetall(key); |
||||
|
const hkeys = Object.keys(obj) |
||||
|
await client.hdel(key, hkeys) |
||||
|
} |
||||
|
|
||||
|
app.redis = client |
||||
|
app.redisTools = { |
||||
|
hdelall, |
||||
|
} |
||||
|
} |
After Width: | Height: | Size: 350 B |
After Width: | Height: | Size: 4.2 KiB |
After Width: | Height: | Size: 354 B |
After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 6.0 KiB |
After Width: | Height: | Size: 125 B |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 5.0 KiB |
@ -0,0 +1,202 @@ |
|||||
|
import React, { useState ,useRef} from 'react' |
||||
|
import { Modal,Form,Row,Col,Spin,Notification,Button } from '@douyinfe/semi-ui'; |
||||
|
import { IconChevronLeft,IconChevronRight } from '@douyinfe/semi-icons'; |
||||
|
function nvrModal(props){ |
||||
|
const {modalName,visible,close}=props |
||||
|
const form = useRef(); |
||||
|
// const [visible, setVisible] = useState(false);//是否显示弹框 |
||||
|
const [isloading,setloading] = useState(false);//是否显示loading |
||||
|
const [loadingTip,setloadingTip] = useState('获取中...请稍后...');//loading tip的值 |
||||
|
const [step,setstep] = useState(0)//第几步 |
||||
|
const [okText,setokText] = useState('测试校验')//ok弹框text 右边 |
||||
|
const [cancelText,setcancelText] = useState('取消')//取消弹框text 左边 |
||||
|
const opts ={//添加完成确认后通知 |
||||
|
title:'Hi', |
||||
|
content:'添加成功', |
||||
|
duration:3 |
||||
|
} |
||||
|
const [clickNum,setclickNum] = useState(1);//点击的第几个 |
||||
|
const cameraList=[//循环摄像头列表 |
||||
|
{ |
||||
|
id:1, |
||||
|
img:'/assets/images/background/ysy.png', |
||||
|
title:'萤石云平台摄像头', |
||||
|
text:'通过萤石云平台rtmp地址配置完成推流的平台摄像头。' |
||||
|
},{ |
||||
|
id:2, |
||||
|
img:'/assets/images/background/nvr.png', |
||||
|
title:'NVR摄像头', |
||||
|
text:'通过连接NVR(网络硬盘录像机)进行视频流推送的摄像头' |
||||
|
},{ |
||||
|
id:3, |
||||
|
img:'/assets/images/background/ipc.png', |
||||
|
title:'IPC网络摄像头', |
||||
|
text:'通过网络与监控设备直连完成视频流推送的摄像头设备' |
||||
|
},{ |
||||
|
id:4, |
||||
|
img:'/assets/images/background/cascade.png', |
||||
|
title:'级联摄像头', |
||||
|
text:'通过GB/T28181协议级联的平台摄像头,常用于平台对接推送' |
||||
|
}, |
||||
|
] |
||||
|
const [showcameraList,setcameraList]=useState(cameraList.slice(0,3)); |
||||
|
function handleOk() {//点击弹框确定 右边按钮 |
||||
|
if(step==0){ |
||||
|
form.current.validate() |
||||
|
.then(values=>{//表单校验成功 |
||||
|
setloading(true); |
||||
|
setTimeout(() => { |
||||
|
setloadingTip('...接受成功') |
||||
|
setTimeout(()=>{ |
||||
|
setloadingTip('已完成') |
||||
|
setTimeout(() => { |
||||
|
setstep(1); |
||||
|
setokText('确认'); |
||||
|
setcancelText('上一步'); |
||||
|
setloading(false); |
||||
|
}, 2000); |
||||
|
},2000) |
||||
|
}, 2000); |
||||
|
}) |
||||
|
.catch(errors=>{//表单校验失败 |
||||
|
console.log('errors',errors); |
||||
|
}) |
||||
|
|
||||
|
} |
||||
|
else{ |
||||
|
Notification.success(opts) |
||||
|
// setVisible(false); |
||||
|
close(); |
||||
|
} |
||||
|
} |
||||
|
function handleAfterClose(){//在关闭之后 |
||||
|
setstep(0); |
||||
|
setokText('测试校验'); |
||||
|
setcancelText('取消'); |
||||
|
} |
||||
|
function handleCancel() {//点击弹框取消 左边按钮 |
||||
|
if(step==0){ |
||||
|
// setVisible(false); |
||||
|
close(); |
||||
|
} |
||||
|
else{ |
||||
|
setstep(0); |
||||
|
setokText('测试校验'); |
||||
|
setcancelText('取消'); |
||||
|
} |
||||
|
} |
||||
|
function handleLocation(){//高德经纬度 |
||||
|
console.log('handleLocationhandleLocation'); |
||||
|
} |
||||
|
function handleChoose(id){//选择摄像头接入类型 |
||||
|
setclickNum(id); |
||||
|
} |
||||
|
function turnLift(){ |
||||
|
setcameraList(cameraList.slice(0,3)) |
||||
|
} |
||||
|
function turnRight(){ |
||||
|
setcameraList(cameraList.slice(1,4)) |
||||
|
} |
||||
|
return ( |
||||
|
<> |
||||
|
{/* <div onClick={showDialog}>{modalName=='add'?'添加NVR':'修改'}</div> */} |
||||
|
<Modal |
||||
|
title={modalName=='add'?'添加摄像头':'修改摄像头'} |
||||
|
okText={okText} |
||||
|
cancelText={cancelText} //取消按钮 |
||||
|
visible={visible} |
||||
|
onOk={handleOk} |
||||
|
width={921} |
||||
|
afterClose={handleAfterClose} |
||||
|
onCancel={handleCancel} |
||||
|
> |
||||
|
<Spin tip={loadingTip} spinning={isloading}> |
||||
|
<div style={{marginLeft:'-24px',marginRight:'-24px',marginTop:8}}> |
||||
|
<div style={{marginLeft:29,color:'#1859C1',fontSize:14,fontWeight:500}}>接入类型</div> |
||||
|
<div style={{marginTop:5,display:'flex',alignItems:'center',justifyContent:'space-between'}}> |
||||
|
<IconChevronLeft |
||||
|
style={{color:'rgba(0, 0, 0, 0.45)',fontSize:16,marginLeft:29,cursor: "pointer",}} |
||||
|
onClick={turnLift}/> |
||||
|
<div |
||||
|
style={{display:'flex',alignItems:'center',height:146}}> |
||||
|
{showcameraList.map((item,index)=>( |
||||
|
<div |
||||
|
key={item.id} |
||||
|
style={{ |
||||
|
width:266, |
||||
|
height:146, |
||||
|
marginRight:12, |
||||
|
border:clickNum===item.id?'1px solid #1859C1':'1px solid #F9F9F9', |
||||
|
borderRadius:3, |
||||
|
display: 'flex', |
||||
|
flexDirection: 'column', |
||||
|
alignItems: 'center', |
||||
|
cursor: "pointer", |
||||
|
position: 'relative'}} |
||||
|
onClick={()=>handleChoose(item.id)}> |
||||
|
<div |
||||
|
style={{marginTop:5, |
||||
|
height:65, |
||||
|
width:116, |
||||
|
display: 'flex', |
||||
|
justifyContent: 'center', |
||||
|
alignItems: 'center'}}> |
||||
|
<img |
||||
|
src={item.img} |
||||
|
alt="设置" |
||||
|
/> |
||||
|
</div> |
||||
|
<div style={{marginTop:2,fontSize:14,color:'rgba(0, 0, 0, 0.85)',}}>{item.title}</div> |
||||
|
<div style={{width:210,height:34,marginTop:9,fontSize:12,color:'rgba(0, 0, 0, 0.45)',textAlign:'center'}}>{item.text}</div> |
||||
|
{clickNum===item.id?<div style={{ position: 'absolute', top: '-3px', right: '-5px'}}> |
||||
|
<img src="/assets/images/background/topchoose.png" alt="1" /> |
||||
|
</div>:''} |
||||
|
</div> |
||||
|
))} |
||||
|
</div> |
||||
|
<IconChevronRight |
||||
|
style={{color:'rgba(0, 0, 0, 0.45)',fontSize:16,marginRight:18,cursor: "pointer",}} |
||||
|
onClick={turnRight}/> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div style={{marginLeft:'-24px',marginRight:'-24px',marginTop:48,display:'flex',alignItems: 'center',justifyContent: 'space-between'}}> |
||||
|
<div style={{marginLeft:29,color:'#1859C1',fontSize:14,fontWeight:500}}>配置属性</div> |
||||
|
<div style={{display:'flex',marginRight:43,}}> |
||||
|
<div style={{ |
||||
|
height:30, |
||||
|
width:64, |
||||
|
border:'1px solid #D9D9D9', |
||||
|
borderRadius: '3px', |
||||
|
color:'rgba(0, 0, 0, 0.65)', |
||||
|
display:'flex', |
||||
|
justifyContent: 'center', |
||||
|
alignItems: 'center', |
||||
|
cursor: "pointer", |
||||
|
marginRight:16 |
||||
|
}}> |
||||
|
<img src="/assets/images/background/Reset.png" alt="1" style={{marginRight:4}}/> |
||||
|
重置 |
||||
|
</div> |
||||
|
<div style={{ |
||||
|
height:30, |
||||
|
width:64, |
||||
|
border:'1px solid #1859C1', |
||||
|
borderRadius: '3px', |
||||
|
color:'#1859C1', |
||||
|
display:'flex', |
||||
|
justifyContent: 'center', |
||||
|
alignItems: 'center', |
||||
|
cursor: "pointer", |
||||
|
}}> |
||||
|
<img src="/assets/images/background/test.png" alt="1" style={{marginRight:4}} /> |
||||
|
测试 |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</Spin> |
||||
|
</Modal> |
||||
|
</> |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
export default nvrModal |