Browse Source

Merge branch 'dev_trial' of ssh://gitea.free-sun.vip:2022/free-sun/FS-IOT into dev_trial

release_0.0.1
wenlele 3 years ago
parent
commit
2bee6dc9a3
  1. 11
      code/VideoAccess-VCMP/api/.vscode/launch.json
  2. 189
      code/VideoAccess-VCMP/api/app/lib/controllers/auth/index.js
  3. 68
      code/VideoAccess-VCMP/api/app/lib/controllers/nvr/index.js
  4. 5
      code/VideoAccess-VCMP/api/app/lib/index.js
  5. 25
      code/VideoAccess-VCMP/api/app/lib/middlewares/authenticator.js
  6. 32
      code/VideoAccess-VCMP/api/app/lib/routes/auth/index.js
  7. 11
      code/VideoAccess-VCMP/api/app/lib/routes/nvr/index.js
  8. 29
      code/VideoAccess-VCMP/api/app/lib/service/redis.js
  9. 14
      code/VideoAccess-VCMP/api/config.js
  10. 4
      code/VideoAccess-VCMP/api/package.json
  11. BIN
      code/VideoAccess-VCMP/web/client/assets/images/background/Reset.png
  12. BIN
      code/VideoAccess-VCMP/web/client/assets/images/background/cascade.png
  13. BIN
      code/VideoAccess-VCMP/web/client/assets/images/background/formchoose.png
  14. BIN
      code/VideoAccess-VCMP/web/client/assets/images/background/ipc.png
  15. BIN
      code/VideoAccess-VCMP/web/client/assets/images/background/nvr.png
  16. BIN
      code/VideoAccess-VCMP/web/client/assets/images/background/test.png
  17. BIN
      code/VideoAccess-VCMP/web/client/assets/images/background/topchoose.png
  18. BIN
      code/VideoAccess-VCMP/web/client/assets/images/background/ysy.png
  19. 202
      code/VideoAccess-VCMP/web/client/src/sections/equipmentWarehouse/components/cameraModal.jsx
  20. 45
      code/VideoAccess-VCMP/web/client/src/sections/equipmentWarehouse/containers/camera.jsx
  21. 24
      code/VideoAccess-VCMP/web/client/src/sections/equipmentWarehouse/containers/nvr.jsx

11
code/VideoAccess-VCMP/api/.vscode/launch.json

@ -13,12 +13,11 @@
"NODE_ENV": "development"
},
"args": [
"-p 14000",
"-f http://localhost:14000",
// "-g postgres://postgres:123@10.8.30.32:5432/yinjiguanli",
// "-g postgres://postgres:123456@221.230.55.27:5432/yinjiguanli",
// "-g postgres://FashionAdmin:123456@10.8.30.156:5432/SmartEmergency",
"-g postgres://postgres:Mantis1921@116.63.50.139:54327/smartYingji"
"-p 4000",
"-f http://localhost:4000",
"-g postgres://postgres:123@10.8.30.32:5432/video_access",
"--redisHost 127.0.0.1",
"--redisPort 6379"
]
},
{

189
code/VideoAccess-VCMP/api/app/lib/controllers/auth/index.js

@ -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
};

68
code/VideoAccess-VCMP/api/app/lib/controllers/nvr/index.js

@ -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,
};

5
code/VideoAccess-VCMP/api/app/lib/index.js

@ -1,6 +1,7 @@
'use strict';
const routes = require('./routes');
const redisConnect = require('./service/redis')
const authenticator = require('./middlewares/authenticator');
// const apiLog = require('./middlewares/api-log');
const businessRest = require('./middlewares/business-rest');
@ -12,8 +13,10 @@ module.exports.entry = function (app, router, opts) {
app.fs.api.authAttr = app.fs.api.authAttr || {};
app.fs.api.logAttr = app.fs.api.logAttr || {};
redisConnect(app, opts)
router.use(authenticator(app, opts));
router.use(businessRest(app, router, opts));
// router.use(businessRest(app, router, opts));
// router.use(apiLog(app, opts));
router = routes(app, router, opts);

25
code/VideoAccess-VCMP/api/app/lib/middlewares/authenticator.js

@ -13,13 +13,13 @@ class ExcludesUrls {
this.reload(opts);
}
sanitizePath(path) {
sanitizePath (path) {
if (!path) return '/';
const p = '/' + path.replace(/^\/+/i, '').replace(/\/+$/, '').replace(/\/{2,}/, '/');
return p;
}
reload(opts) {
reload (opts) {
// load all url
if (!this.allUrls) {
this.allUrls = opts;
@ -37,7 +37,7 @@ class ExcludesUrls {
}
}
isExcluded(path, method) {
isExcluded (path, method) {
return this.allUrls.some(function (url) {
return !url.auth
&& url.pregexp.test(path)
@ -58,9 +58,7 @@ let isPathExcluded = function (opts, path, method) {
if (!excludeAll) {
let excludeOpts = opts.exclude || [];
excludeOpts.push({ p: '/login', o: 'POST' });
excludeOpts.push({ p: '/wxLogin', o: 'POST' });
excludeOpts.push({ p: '/logout', o: 'PUT' });
excludeOpts.push({ p: '/wxLogout', o: 'PUT' });
excludes = new ExcludesUrls(excludeOpts);
}
let excluded = excludeAll || excludes.isExcluded(path, method);
@ -72,14 +70,10 @@ let authorizeToken = async function (ctx, token) {
const tokenFormatRegexp = /^(\{{0,1}([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}\}{0,1})$/g;
if (token && tokenFormatRegexp.test(token)) {
try {
const axyRes = await ctx.fs.dc.models.UserToken.findOne({
where: {
token: token,
expired: { $gte: moment().format('YYYY-MM-DD HH:mm:ss') }
}
});
const { userInfo, expired } = axyRes;
if (!expired || moment().valueOf() <= moment(expired).valueOf()) {
const expired = await ctx.redis.hget(token, 'expired');
if (expired && moment().valueOf() <= moment(expired).valueOf()) {
const userInfo = JSON.parse(await ctx.redis.hget(token, 'userInfo'));
rslt = {
'authorized': userInfo.authorized,
'resources': (userInfo || {}).resources || [],
@ -112,13 +106,14 @@ let isResourceAvailable = function (resources, options) {
return !authCode || (resources || []).some(code => code === authCode);
};
function factory(app, opts) {
return async function auth(ctx, next) {
function factory (app, opts) {
return async function auth (ctx, next) {
const { path, method, header, query } = ctx;
ctx.fs.logger.log('[AUTH] start', path, method);
ctx.fs.api = ctx.fs.api || {};
ctx.fs.port = opts.port;
ctx.redis = app.redis;
ctx.redisTools = app.redisTools;
let error = null;
if (path) {
if (!isPathExcluded(opts, path, method)) {

32
code/VideoAccess-VCMP/api/app/lib/routes/auth/index.js

@ -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);
};

11
code/VideoAccess-VCMP/api/app/lib/routes/nvr/index.js

@ -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);
};

29
code/VideoAccess-VCMP/api/app/lib/service/redis.js

@ -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,
}
}

14
code/VideoAccess-VCMP/api/config.js

@ -11,13 +11,20 @@ const dev = process.env.NODE_ENV == 'development';
args.option(['p', 'port'], '启动端口');
args.option(['g', 'pg'], 'postgre服务URL');
args.option(['f', 'fileHost'], '文件中心本地化存储: WebApi 服务器地址(必填), 该服务器提供文件上传Web服务');
args.option('redisHost', 'redisHost');
args.option('redisPort', 'redisPort');
args.option('redisPswd', 'redisPassword');
const flags = args.parse(process.argv);
const IOT_VIDEO_ACCESS_DB = process.env.IOT_VIDEO_ACCESS_DB || flags.pg;
const IOT_VIDEO_ACCESS_LOCAL_SVR_ORIGIN = process.env.IOT_VIDEO_ACCESS_LOCAL_SVR_ORIGIN || flags.fileHost;
if (!IOT_VIDEO_ACCESS_DB) {
const IOTA_REDIS_SERVER_HOST = process.env.IOTA_REDIS_SERVER_HOST || flags.redisHost || "localhost";//redis IP
const IOTA_REDIS_SERVER_PORT = process.env.IOTA_REDIS_SERVER_PORT || flags.redisPort || "6379";//redis 端口
const IOTA_REDIS_SERVER_PWD = process.env.IOTA_REDIS_SERVER_PWD || flags.redisPswd || "";//redis 密码
if (!IOT_VIDEO_ACCESS_DB || !IOTA_REDIS_SERVER_HOST || !IOTA_REDIS_SERVER_PORT) {
console.log('缺少启动参数,异常退出');
args.showHelp();
process.exit(-1);
@ -41,6 +48,11 @@ const product = {
entry: require('./app').entry,
opts: {
exclude: [], // 不做认证的路由,也可以使用 exclude: ["*"] 跳过所有路由
redis: {
host: IOTA_REDIS_SERVER_HOST,
port: IOTA_REDIS_SERVER_PORT,
pwd: IOTA_REDIS_SERVER_PWD
},
}
}
],

4
code/VideoAccess-VCMP/api/package.json

@ -5,7 +5,7 @@
"main": "server.js",
"scripts": {
"test": "set DEBUG=true&&\"node_modules/.bin/mocha\" --harmony --reporter spec app/test/*.test.js",
"start": "set NODE_ENV=development&&node server -p 14000 -g postgres://postgres:123@10.8.30.32:5432/yinjiguanli -f http://localhost:14000",
"start": "set NODE_ENV=development&&node server -p 4000 -g postgres://postgres:123@10.8.30.32:5432/video_access -f http://localhost:4000",
"start:linux": "export NODE_ENV=development&&node server -p 4000 -g postgres://FashionAdmin:123456@10.8.30.39:5432/pm1",
"automate": "sequelize-automate -c sequelize-automate.config.js"
},
@ -18,7 +18,7 @@
"crypto-js": "^4.0.0",
"file-saver": "^2.0.2",
"fs-web-server-scaffold": "^2.0.2",
"ioredis": "^4.19.4",
"ioredis": "^5.0.4",
"koa-convert": "^1.2.0",
"koa-proxy": "^0.9.0",
"moment": "^2.24.0",

BIN
code/VideoAccess-VCMP/web/client/assets/images/background/Reset.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 350 B

BIN
code/VideoAccess-VCMP/web/client/assets/images/background/cascade.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

BIN
code/VideoAccess-VCMP/web/client/assets/images/background/formchoose.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 354 B

BIN
code/VideoAccess-VCMP/web/client/assets/images/background/ipc.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

BIN
code/VideoAccess-VCMP/web/client/assets/images/background/nvr.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

BIN
code/VideoAccess-VCMP/web/client/assets/images/background/test.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 B

BIN
code/VideoAccess-VCMP/web/client/assets/images/background/topchoose.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
code/VideoAccess-VCMP/web/client/assets/images/background/ysy.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

202
code/VideoAccess-VCMP/web/client/src/sections/equipmentWarehouse/components/cameraModal.jsx

@ -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('测试校验')//oktext
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

45
code/VideoAccess-VCMP/web/client/src/sections/equipmentWarehouse/containers/camera.jsx

@ -2,57 +2,72 @@ import React, { useState, useEffect } from "react";
import { connect } from "react-redux";
import { Button, Form, Input, Row, Table } from "@douyinfe/semi-ui";
import "../style.less";
import CameraModal from "../components/cameraModal";
const CameraHeader = (props) => {
const [cameraModal,setCameraModal] = useState(false)
const [modalName,setModalName] = useState('')
return (
<>
<div style={{ position: "" }}>
<video
id="nvrBanner"
id="cameraBanner"
autoPlay
loop
muted
style={{ width: "100%", objectFit: "cover", height: 171 }}
src="/assets/video/nvr_banner.mp4"
src="/assets/video/camera_banner.mp4"
type="video/mp4"
/>
<div style={{ position: "absolute", top: 12 }}>
<div
style={{
fontSize: 22 + "px",
paddingTop: 15 + "px",
marginLeft: 21 + "px",
fontSize: 22,
paddingTop: 15,
marginLeft: 21,
}}
>
摄像头管理
</div>
<div
style={{
fontSize: 14 + "px",
paddingTop: 18 + "px",
marginLeft: 20 + "px",
fontSize: 14,
paddingTop: 18,
marginLeft: 20,
}}
>
NVR网络硬盘录像机设备节点的管理
监控摄像设备设备添加修改删除的硬件管理页面
</div>
<div
style={{
fontSize: 14 + "px",
marginTop: 28 + "px",
marginLeft: 21 + "px",
width: 89 + "px",
height: 32 + "px",
fontSize: 14,
marginTop: 28,
marginLeft: 21,
width: 89,
height: 32,
lineHeight: 32 + "px",
textAlign: "center",
backgroundColor: "#D9EAFF",
color: "#1859C1",
cursor: "pointer",
}}
onClick={() => {
setModalName('add')
setCameraModal(true);
}}
>
{/* <NvrModal modalName="add" /> */}
添加摄像头
</div>
</div>
</div>
{cameraModal?
<CameraModal
visible={true}
close={() => {
setCameraModal(false);
// setEditData(null)
}}
modalName={modalName} />:''}
</>
);
};

24
code/VideoAccess-VCMP/web/client/src/sections/equipmentWarehouse/containers/nvr.jsx

@ -190,30 +190,30 @@ const NvrHeader = (props) => {
<div style={{ position: "absolute", top: 12 }}>
<div
style={{
fontSize: 22 + "px",
paddingTop: 15 + "px",
marginLeft: 21 + "px",
fontSize: 22,
paddingTop: 15,
marginLeft: 21,
}}
>
NVR管理
</div>
<div
style={{
fontSize: 14 + "px",
paddingTop: 18 + "px",
marginLeft: 20 + "px",
fontSize: 14,
paddingTop: 18,
marginLeft: 20,
}}
>
对NVR网络硬盘录像机设备节点的管理
</div>
<div
style={{
fontSize: 14 + "px",
marginTop: 28 + "px",
marginLeft: 21 + "px",
width: 89 + "px",
height: 32 + "px",
lineHeight: 32 + "px",
fontSize: 14,
marginTop: 28,
marginLeft: 21,
width: 89,
height: 32,
lineHeight: "32px",
textAlign: "center",
backgroundColor: "#D9EAFF",
color: "#1859C1",

Loading…
Cancel
Save