Browse Source

Merge branch 'dev_trial' of https://gitea.anxinyun.cn/free-sun/FS-IOT into dev_trial

release_1.1.1
wenlele 3 years ago
parent
commit
396458a380
  1. 2
      code/VideoAccess-VCMP/api/app/lib/controllers/camera/index.js
  2. 257
      code/VideoAccess-VCMP/api/app/lib/controllers/status/index.js
  3. 85
      code/VideoAccess-VCMP/api/app/lib/controllers/status/push.js
  4. 71
      code/VideoAccess-VCMP/api/app/lib/index.js
  5. 5
      code/VideoAccess-VCMP/api/app/lib/models/ax_project.js
  6. 8
      code/VideoAccess-VCMP/api/app/lib/models/camera.js
  7. 4
      code/VideoAccess-VCMP/api/app/lib/models/camera_ability_bind.js
  8. 4
      code/VideoAccess-VCMP/api/app/lib/models/camera_remark.js
  9. 79
      code/VideoAccess-VCMP/api/app/lib/models/camera_status.js
  10. 47
      code/VideoAccess-VCMP/api/app/lib/models/camera_status_log.js
  11. 79
      code/VideoAccess-VCMP/api/app/lib/models/camera_status_push_config.js
  12. 61
      code/VideoAccess-VCMP/api/app/lib/models/camera_status_push_log.js
  13. 51
      code/VideoAccess-VCMP/api/app/lib/models/camera_status_push_monitor.js
  14. 47
      code/VideoAccess-VCMP/api/app/lib/models/camera_status_push_receiver.js
  15. 47
      code/VideoAccess-VCMP/api/app/lib/models/camera_status_resolve.js
  16. 8
      code/VideoAccess-VCMP/api/app/lib/models/gb_camera.js
  17. 4
      code/VideoAccess-VCMP/api/app/lib/models/secret_yingshi.js
  18. 66
      code/VideoAccess-VCMP/api/app/lib/models/vender.js
  19. 44
      code/VideoAccess-VCMP/api/app/lib/routes/status/index.js
  20. 2
      code/VideoAccess-VCMP/api/app/lib/service/socket.js
  21. 2
      code/VideoAccess-VCMP/api/sequelize-automate.config.js
  22. 3
      code/VideoAccess-VCMP/script/.vscode/settings.json
  23. 17
      code/VideoAccess-VCMP/script/1.1.1/data/1_update_status_code_data/.vscode/launch.json
  24. 69
      code/VideoAccess-VCMP/script/1.1.1/data/1_update_status_code_data/index.js
  25. 16
      code/VideoAccess-VCMP/script/1.1.1/data/1_update_status_code_data/package.json
  26. BIN
      code/VideoAccess-VCMP/script/1.1.1/data/1_update_status_code_data/云录制错误码.xlsx
  27. 141
      code/VideoAccess-VCMP/script/1.1.1/data/2.insert_camera_status.sql
  28. 140
      code/VideoAccess-VCMP/script/1.1.1/schema/1.create_camera_status_table.sql
  29. BIN
      code/VideoAccess-VCMP/web/client/assets/images/background/codeAfter.png
  30. BIN
      code/VideoAccess-VCMP/web/client/assets/images/background/codeArrow.png
  31. BIN
      code/VideoAccess-VCMP/web/client/assets/images/background/codeBefore.png
  32. BIN
      code/VideoAccess-VCMP/web/client/assets/images/favicon.ico
  33. BIN
      code/VideoAccess-VCMP/web/client/assets/video/37ov3-lit2e.mp4
  34. 2
      code/VideoAccess-VCMP/web/client/src/components/index.js
  35. 121
      code/VideoAccess-VCMP/web/client/src/components/setup.jsx
  36. 2
      code/VideoAccess-VCMP/web/client/src/layout/actions/webSocket.js
  37. 6
      code/VideoAccess-VCMP/web/client/src/sections/equipmentWarehouse/components/remarksModal.jsx
  38. 191
      code/VideoAccess-VCMP/web/client/src/sections/equipmentWarehouse/components/setup.jsx
  39. 34
      code/VideoAccess-VCMP/web/client/src/sections/equipmentWarehouse/containers/camera.jsx
  40. 31
      code/VideoAccess-VCMP/web/client/src/sections/equipmentWarehouse/containers/nvr.jsx
  41. 6
      code/VideoAccess-VCMP/web/client/src/sections/offline/actions/index.js
  42. 65
      code/VideoAccess-VCMP/web/client/src/sections/offline/actions/statuscode.js
  43. 178
      code/VideoAccess-VCMP/web/client/src/sections/offline/components/notesModal.jsx
  44. 85
      code/VideoAccess-VCMP/web/client/src/sections/offline/components/programmeModal.jsx
  45. 299
      code/VideoAccess-VCMP/web/client/src/sections/offline/components/pushModal.jsx
  46. 570
      code/VideoAccess-VCMP/web/client/src/sections/offline/containers/carrierpigeon.jsx
  47. 554
      code/VideoAccess-VCMP/web/client/src/sections/offline/containers/statuscode.jsx
  48. 6
      code/VideoAccess-VCMP/web/client/src/utils/webapi.js
  49. 4
      code/VideoAccess-VCMP/web/config.js
  50. 2
      code/VideoAccess-VCMP/web/package.json

2
code/VideoAccess-VCMP/api/app/lib/controllers/camera/index.js

@ -284,7 +284,7 @@ async function banned (ctx) {
const { models } = ctx.fs.dc; const { models } = ctx.fs.dc;
const data = ctx.request.body; const data = ctx.request.body;
// 向视频服务发送通知 // TODO 向视频服务发送通知
// 库记录 // 库记录
await models.Camera.update({ await models.Camera.update({

257
code/VideoAccess-VCMP/api/app/lib/controllers/status/index.js

@ -0,0 +1,257 @@
'use strict';
const moment = require('moment')
async function get (ctx) {
try {
const models = ctx.fs.dc.models;
const { userId, token } = ctx.fs.api
const { limit, page, orderBy, orderDirection, keyword, forbidden, paraphraseCustom } = ctx.query
const sequelize = ctx.fs.dc.ORM;
let findOption = {
attributes: {
include: [
[sequelize.fn('COUNT', sequelize.col('cameraStatusLogs.id')), 'logCount']
]
},
where: {},
order: [
[orderBy || 'id', orderDirection || 'DESC']
],
distinct: true,
subQuery: false,
group: [
'cameraStatus.id',
'cameraStatusLogs.status_id',
// 'cameraStatusResolves.id'
],
include: [
// {
// model: models.CameraStatusResolve,
// attributes: { exclude: ['statusId'] },
// required: false,
// duplicating: true
// },
{
model: models.CameraStatusLog,
attributes: [],
duplicating: false,
required: false,
}
],
}
if (orderBy) {
if (orderBy == 'logCount') {
findOption.order = sequelize.literal(`"logCount" ${orderDirection || 'DESC'}`)
}
}
if (limit) {
findOption.limit = limit
}
if (page && limit) {
findOption.offset = page * limit
}
if (keyword) {
findOption.where['$or'] = {
describe: {
$like: `%${keyword}%`
},
paraphrase: {
$like: `%${keyword}%`
},
paraphraseCustom: {
$like: `%${keyword}%`
},
}
}
if (forbidden) {
if (forbidden === 'true') {
findOption.where.forbidden = true
} else if (forbidden === 'false') {
findOption.where.forbidden = false
}
}
if (paraphraseCustom) {
if (paraphraseCustom === 'true') {
findOption.where.paraphraseCustom = null
} else if (paraphraseCustom === 'false') {
findOption.where.paraphraseCustom = {
$ne: null
}
}
}
const statusRes = await models.CameraStatus.findAll(findOption)
delete findOption.order
delete findOption.limit
delete findOption.offset
delete findOption.attributes
delete findOption.group
const count = await models.CameraStatus.count(findOption)
const statusIds = statusRes.map(r => r.id)
const statusResolveRes = await models.CameraStatusResolve.findAll({
where: {
statusId: {
$in: statusIds
}
}
})
for (let { dataValues: s } of statusRes) {
const corResolve = statusResolveRes.filter(r => r.statusId === s.id)
s.resolve = corResolve
}
ctx.status = 200;
ctx.body = {
count,
rows: statusRes,
}
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {}
}
}
async function getSimpleAll (ctx) {
try {
const models = ctx.fs.dc.models;
const statusRes = await models.CameraStatus.findAll({
attributes: ['id', 'platform', 'status', 'describe'],
})
ctx.status = 200;
ctx.body = statusRes
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {}
}
}
async function banned (ctx) {
try {
const { models } = ctx.fs.dc;
const data = ctx.request.body;
// 库记录
await models.CameraStatus.update({
forbidden: data.forbidden
}, {
where: {
id: data.statusId
}
})
ctx.status = 204;
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {}
}
}
async function paraphraseCustom (ctx) {
try {
const models = ctx.fs.dc.models;
const { userId, token } = ctx.fs.api
const data = ctx.request.body
await models.CameraStatus.update({
paraphraseCustom: data.paraphrase,
}, {
where: {
id: { $in: data.statusId }
}
})
ctx.status = 204;
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {}
}
}
async function resolveEdit (ctx) {
const transaction = await ctx.fs.dc.orm.transaction();
try {
const models = ctx.fs.dc.models;
const { userId, token } = ctx.fs.api
const data = ctx.request.body
await models.CameraStatusResolve.destroy({
where: {
statusId: data.statusId
},
transaction
})
await models.CameraStatusResolve.bulkCreate(
data.resolve.map(r => {
return {
statusId: data.statusId,
resolve: r
}
}),
{ 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 statusCheck (ctx) {
try {
const models = ctx.fs.dc.models;
const { userId, token } = ctx.fs.api
const { status, platform, describe } = ctx.query
if (!status || !platform) {
throw 'status and platform is required'
}
const statusRes = await models.CameraStatus.findOne({
where: {
status,
platform,
},
include: [{
model: models.CameraStatusResolve,
attributes: { exclude: ['statusId'] },
}],
})
if (!statusRes && describe) {
await models.CameraStatus.create({
status, platform, describe
})
}
ctx.status = 200;
ctx.body = statusRes
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {
message: typeof error == 'string' ? error : undefined
}
}
}
module.exports = {
get,
getSimpleAll,
banned,
paraphraseCustom,
resolveEdit,
statusCheck,
};

85
code/VideoAccess-VCMP/api/app/lib/controllers/status/push.js

@ -0,0 +1,85 @@
'use strict';
const moment = require('moment')
async function edit (ctx) {
try {
const models = ctx.fs.dc.models;
const { userId, token } = ctx.fs.api
ctx.status = 204;
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {}
}
}
async function get (ctx) {
try {
const models = ctx.fs.dc.models;
const { userId, token } = ctx.fs.api
ctx.status = 204;
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {}
}
}
async function banned (ctx) {
try {
const models = ctx.fs.dc.models;
const { userId, token } = ctx.fs.api
ctx.status = 204;
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {}
}
}
async function del (ctx) {
try {
const models = ctx.fs.dc.models;
const { userId, token } = ctx.fs.api
ctx.status = 204;
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {}
}
}
async function copy (ctx) {
try {
const models = ctx.fs.dc.models;
const { userId, token } = ctx.fs.api
ctx.status = 204;
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {}
}
}
async function detail (ctx) {
try {
const models = ctx.fs.dc.models;
const { userId, token } = ctx.fs.api
ctx.status = 204;
} catch (error) {
ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`);
ctx.status = 400;
ctx.body = {}
}
}
module.exports = {
edit, get, banned, del, copy, detail
};

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

@ -44,19 +44,60 @@ module.exports.entry = function (app, router, opts) {
}; };
module.exports.models = function (dc) { // dc = { orm: Sequelize对象, ORM: Sequelize, models: {} } module.exports.models = function (dc) { // dc = { orm: Sequelize对象, ORM: Sequelize, models: {} }
require('./models/nvr')(dc); // 加载定义模型 历史写法
require('./models/camera_ability')(dc); // require('./models/nvr')(dc);
require('./models/camera_kind')(dc); // require('./models/camera_ability')(dc);
require('./models/camera')(dc); // require('./models/camera_kind')(dc);
require('./models/camera_ability_bind')(dc); // require('./models/camera')(dc);
require('./models/vender')(dc); // require('./models/camera_ability_bind')(dc);
require('./models/secret_yingshi')(dc); // require('./models/vender')(dc);
require('./models/gb_camera')(dc); // require('./models/secret_yingshi')(dc);
require('./models/ax_project')(dc); // require('./models/gb_camera')(dc);
require('./models/camera_remark')(dc); // require('./models/ax_project')(dc);
// require('./models/camera_remark')(dc);
// TODO 模型关系摘出来 初始化之后再定义关系才行
// fs.readdirSync(path.join(__dirname, '/models')).forEach((filename) => { // 模型关系摘出来 初始化之后再定义关系才行
// require(`./models/${filename}`)(dc) fs.readdirSync(path.join(__dirname, '/models')).forEach((filename) => {
// }); require(`./models/${filename}`)(dc)
});
const {
Nvr, Camera, CameraAbility, CameraAbilityBind, CameraKind, CameraRemark,
GbCamera, SecretYingshi, Vender, CameraStatus, CameraStatusResolve, CameraStatusLog
} = dc.models;
// Nvr.belongsTo(User, { foreignKey: 'userId', targetKey: 'id' });
// User.hasMany(Nvr, { foreignKey: 'userId', sourceKey: 'id' });
Camera.belongsToMany(CameraAbility, { through: CameraAbilityBind, foreignKey: 'cameraId', otherKey: 'abilityId' });
CameraRemark.belongsTo(Camera, { foreignKey: 'cameraId', targetKey: 'id' });
Camera.hasMany(CameraRemark, { foreignKey: 'cameraId', sourceKey: 'id' });
Camera.belongsTo(CameraKind, { foreignKey: 'kindId', targetKey: 'id' });
CameraKind.hasMany(Camera, { foreignKey: 'kindId', sourceKey: 'id' });
Camera.belongsTo(Nvr, { foreignKey: 'nvrId', targetKey: 'id' });
Nvr.hasMany(Camera, { foreignKey: 'nvrId', sourceKey: 'id' });
Nvr.belongsTo(GbCamera, { foreignKey: 'serialNo', targetKey: 'streamid', as: 'gbNvr' });
GbCamera.hasMany(Nvr, { foreignKey: 'serialNo', sourceKey: 'streamid', as: 'gbNvr' });
Camera.belongsTo(GbCamera, { foreignKey: 'gbId', targetKey: 'id' });
GbCamera.hasMany(Camera, { foreignKey: 'gbId', sourceKey: 'id' });
Camera.belongsTo(SecretYingshi, { foreignKey: 'yingshiSecretId', targetKey: 'id' });
SecretYingshi.hasMany(Camera, { foreignKey: 'yingshiSecretId', sourceKey: 'id' });
Camera.belongsTo(Vender, { foreignKey: 'venderId', targetKey: 'id' });
Vender.hasMany(Camera, { foreignKey: 'venderId', sourceKey: 'id' });
Nvr.belongsTo(Vender, { foreignKey: 'venderId', targetKey: 'id' });
Vender.hasMany(Nvr, { foreignKey: 'venderId', sourceKey: 'id' });
CameraStatusResolve.belongsTo(CameraStatus, { foreignKey: 'statusId', targetKey: 'id' });
CameraStatus.hasMany(CameraStatusResolve, { foreignKey: 'statusId', sourceKey: 'id' });
CameraStatusLog.belongsTo(CameraStatus, { foreignKey: 'statusId', targetKey: 'id' });
CameraStatus.hasMany(CameraStatusLog, { foreignKey: 'statusId', sourceKey: 'id' });
}; };

5
code/VideoAccess-VCMP/api/app/lib/models/ax_project.js

@ -30,11 +30,6 @@ module.exports = dc => {
indexes: [] indexes: []
}); });
const Nvr = dc.models.Nvr;
// Nvr.belongsTo(User, { foreignKey: 'userId', targetKey: 'id' });
// User.hasMany(Nvr, { foreignKey: 'userId', sourceKey: 'id' });
dc.models.AxProject = AxProject; dc.models.AxProject = AxProject;
return AxProject; return AxProject;
}; };

8
code/VideoAccess-VCMP/api/app/lib/models/camera.js

@ -272,13 +272,5 @@ module.exports = dc => {
}); });
dc.models.Camera = Camera; dc.models.Camera = Camera;
const CameraKind = dc.models.CameraKind;
Camera.belongsTo(CameraKind, { foreignKey: 'kindId', targetKey: 'id' });
CameraKind.hasMany(Camera, { foreignKey: 'kindId', sourceKey: 'id' });
const Nvr = dc.models.Nvr;
Camera.belongsTo(Nvr, { foreignKey: 'nvrId', targetKey: 'id' });
Nvr.hasMany(Camera, { foreignKey: 'nvrId', sourceKey: 'id' });
return Camera; return Camera;
}; };

4
code/VideoAccess-VCMP/api/app/lib/models/camera_ability_bind.js

@ -48,9 +48,5 @@ module.exports = dc => {
}); });
dc.models.CameraAbilityBind = CameraAbilityBind; dc.models.CameraAbilityBind = CameraAbilityBind;
const Camera = dc.models.Camera;
const CameraAbility = dc.models.CameraAbility;
Camera.belongsToMany(CameraAbility, { through: CameraAbilityBind, foreignKey: 'cameraId', otherKey: 'abilityId' });
return CameraAbilityBind; return CameraAbilityBind;
}; };

4
code/VideoAccess-VCMP/api/app/lib/models/camera_remark.js

@ -44,9 +44,5 @@ module.exports = dc => {
}); });
dc.models.CameraRemark = CameraRemark; dc.models.CameraRemark = CameraRemark;
const Camera = dc.models.Camera;
CameraRemark.belongsTo(Camera, { foreignKey: 'cameraId', targetKey: 'id' });
Camera.hasMany(CameraRemark, { foreignKey: 'cameraId', sourceKey: 'id' });
return CameraRemark; return CameraRemark;
}; };

79
code/VideoAccess-VCMP/api/app/lib/models/camera_status.js

@ -0,0 +1,79 @@
/* eslint-disable*/
'use strict';
module.exports = dc => {
const DataTypes = dc.ORM;
const sequelize = dc.orm;
const CameraStatus = sequelize.define("cameraStatus", {
id: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: null,
comment: null,
primaryKey: true,
field: "id",
autoIncrement: true,
unique: "camera_status_id_uindex"
},
platform: {
type: DataTypes.STRING,
allowNull: false,
defaultValue: null,
comment: "平台分类 yingshi gb",
primaryKey: false,
field: "platform",
autoIncrement: false
},
status: {
type: DataTypes.STRING,
allowNull: false,
defaultValue: null,
comment: null,
primaryKey: false,
field: "status",
autoIncrement: false
},
describe: {
type: DataTypes.STRING,
allowNull: true,
defaultValue: null,
comment: "错误描述",
primaryKey: false,
field: "describe",
autoIncrement: false
},
paraphrase: {
type: DataTypes.STRING,
allowNull: true,
defaultValue: null,
comment: "释义",
primaryKey: false,
field: "paraphrase",
autoIncrement: false
},
forbidden: {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: null,
comment: "是否禁用",
primaryKey: false,
field: "forbidden",
autoIncrement: false
},
paraphraseCustom: {
type: DataTypes.STRING,
allowNull: true,
defaultValue: null,
comment: "自定义释义",
primaryKey: false,
field: "paraphrase_custom",
autoIncrement: false
}
}, {
tableName: "camera_status",
comment: "",
indexes: []
});
dc.models.CameraStatus = CameraStatus;
return CameraStatus;
};

47
code/VideoAccess-VCMP/api/app/lib/models/camera_status_log.js

@ -0,0 +1,47 @@
/* eslint-disable*/
'use strict';
module.exports = dc => {
const DataTypes = dc.ORM;
const sequelize = dc.orm;
const CameraStatusLog = sequelize.define("cameraStatusLog", {
id: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: null,
comment: null,
primaryKey: true,
field: "id",
autoIncrement: true,
unique: "camera_status_log_id_uindex_2"
},
statusId: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: null,
comment: null,
primaryKey: false,
field: "status_id",
autoIncrement: false,
references: {
key: "id",
model: "cameraStatus"
}
},
time: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: null,
comment: null,
primaryKey: false,
field: "time",
autoIncrement: false
}
}, {
tableName: "camera_status_log",
comment: "",
indexes: []
});
dc.models.CameraStatusLog = CameraStatusLog;
return CameraStatusLog;
};

79
code/VideoAccess-VCMP/api/app/lib/models/camera_status_push_config.js

@ -0,0 +1,79 @@
/* eslint-disable*/
'use strict';
module.exports = dc => {
const DataTypes = dc.ORM;
const sequelize = dc.orm;
const CameraStatusPushConfig = sequelize.define("cameraStatusPushConfig", {
id: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: null,
comment: null,
primaryKey: true,
field: "id",
autoIncrement: true,
unique: "camera_online_status_push_config_id_uindex"
},
name: {
type: DataTypes.STRING,
allowNull: false,
defaultValue: null,
comment: null,
primaryKey: false,
field: "name",
autoIncrement: false
},
pushWay: {
type: DataTypes.STRING,
allowNull: false,
defaultValue: null,
comment: "推送方式 email / phone",
primaryKey: false,
field: "push_way",
autoIncrement: false
},
noticeWay: {
type: DataTypes.STRING,
allowNull: false,
defaultValue: null,
comment: "通知方式 offline / online / timing",
primaryKey: false,
field: "notice_way",
autoIncrement: false
},
createUser: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: null,
comment: null,
primaryKey: false,
field: "create_user",
autoIncrement: false
},
forbidden: {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: null,
comment: null,
primaryKey: false,
field: "forbidden",
autoIncrement: false
},
timing: {
type: DataTypes.STRING,
allowNull: true,
defaultValue: null,
comment: "定时推送时间",
primaryKey: false,
field: "timing",
autoIncrement: false
}
}, {
tableName: "camera_status_push_config",
comment: "",
indexes: []
});
dc.models.CameraStatusPushConfig = CameraStatusPushConfig;
return CameraStatusPushConfig;
};

61
code/VideoAccess-VCMP/api/app/lib/models/camera_status_push_log.js

@ -0,0 +1,61 @@
/* eslint-disable*/
'use strict';
module.exports = dc => {
const DataTypes = dc.ORM;
const sequelize = dc.orm;
const CameraStatusPushLog = sequelize.define("cameraStatusPushLog", {
id: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: null,
comment: null,
primaryKey: true,
field: "id",
autoIncrement: true,
unique: "camera_status_push_log_id_uindex"
},
pushConfigId: {
type: DataTypes.INTEGER,
allowNull: true,
defaultValue: null,
comment: null,
primaryKey: false,
field: "push_config_id",
autoIncrement: false
},
receiver: {
type: DataTypes.JSONB,
allowNull: false,
defaultValue: null,
comment: null,
primaryKey: false,
field: "receiver",
autoIncrement: false
},
time: {
type: DataTypes.DATE,
allowNull: true,
defaultValue: null,
comment: null,
primaryKey: false,
field: "time",
autoIncrement: false
},
pushWay: {
type: DataTypes.STRING,
allowNull: false,
defaultValue: null,
comment: null,
primaryKey: false,
field: "push_way",
autoIncrement: false
}
}, {
tableName: "camera_status_push_log",
comment: "",
indexes: []
});
dc.models.CameraStatusPushLog = CameraStatusPushLog;
return CameraStatusPushLog;
};

51
code/VideoAccess-VCMP/api/app/lib/models/camera_status_push_monitor.js

@ -0,0 +1,51 @@
/* eslint-disable*/
'use strict';
module.exports = dc => {
const DataTypes = dc.ORM;
const sequelize = dc.orm;
const CameraStatusPushMonitor = sequelize.define("cameraStatusPushMonitor", {
id: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: null,
comment: null,
primaryKey: true,
field: "id",
autoIncrement: true,
unique: "camera_status_push_monitor_id_uindex"
},
configId: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: null,
comment: null,
primaryKey: false,
field: "config_id",
autoIncrement: false,
references: {
key: "id",
model: "cameraStatusPushConfig"
}
},
cameraId: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: null,
comment: null,
primaryKey: false,
field: "camera_id",
autoIncrement: false,
references: {
key: "id",
model: "camera"
}
}
}, {
tableName: "camera_status_push_monitor",
comment: "",
indexes: []
});
dc.models.CameraStatusPushMonitor = CameraStatusPushMonitor;
return CameraStatusPushMonitor;
};

47
code/VideoAccess-VCMP/api/app/lib/models/camera_status_push_receiver.js

@ -0,0 +1,47 @@
/* eslint-disable*/
'use strict';
module.exports = dc => {
const DataTypes = dc.ORM;
const sequelize = dc.orm;
const CameraStatusPushReceiver = sequelize.define("cameraStatusPushReceiver", {
id: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: null,
comment: null,
primaryKey: true,
field: "id",
autoIncrement: true,
unique: "camera_status_push_receiver_id_uindex"
},
configId: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: null,
comment: null,
primaryKey: false,
field: "config_id",
autoIncrement: false,
references: {
key: "id",
model: "cameraStatusPushConfig"
}
},
receiver: {
type: DataTypes.STRING,
allowNull: false,
defaultValue: null,
comment: "接受者信息 邮箱或者电话号码",
primaryKey: false,
field: "receiver",
autoIncrement: false
}
}, {
tableName: "camera_status_push_receiver",
comment: "",
indexes: []
});
dc.models.CameraStatusPushReceiver = CameraStatusPushReceiver;
return CameraStatusPushReceiver;
};

47
code/VideoAccess-VCMP/api/app/lib/models/camera_status_resolve.js

@ -0,0 +1,47 @@
/* eslint-disable*/
'use strict';
module.exports = dc => {
const DataTypes = dc.ORM;
const sequelize = dc.orm;
const CameraStatusResolve = sequelize.define("cameraStatusResolve", {
id: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: null,
comment: null,
primaryKey: true,
field: "id",
autoIncrement: true,
unique: "camera_status_resolve_id_uindex"
},
statusId: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: null,
comment: null,
primaryKey: false,
field: "status_id",
autoIncrement: false,
references: {
key: "id",
model: "cameraStatus"
}
},
resolve: {
type: DataTypes.STRING,
allowNull: false,
defaultValue: null,
comment: null,
primaryKey: false,
field: "resolve",
autoIncrement: false
}
}, {
tableName: "camera_status_resolve",
comment: "",
indexes: []
});
dc.models.CameraStatusResolve = CameraStatusResolve;
return CameraStatusResolve;
};

8
code/VideoAccess-VCMP/api/app/lib/models/gb_camera.js

@ -156,14 +156,6 @@ module.exports = dc => {
indexes: [] indexes: []
}); });
const Nvr = dc.models.Nvr;
Nvr.belongsTo(GbCamera, { foreignKey: 'serialNo', targetKey: 'streamid', as: 'gbNvr' });
GbCamera.hasMany(Nvr, { foreignKey: 'serialNo', sourceKey: 'streamid', as: 'gbNvr' });
const Camera = dc.models.Camera;
Camera.belongsTo(GbCamera, { foreignKey: 'gbId', targetKey: 'id' });
GbCamera.hasMany(Camera, { foreignKey: 'gbId', sourceKey: 'id' });
dc.models.GbCamera = GbCamera; dc.models.GbCamera = GbCamera;
return GbCamera; return GbCamera;
}; };

4
code/VideoAccess-VCMP/api/app/lib/models/secret_yingshi.js

@ -57,10 +57,6 @@ module.exports = dc => {
indexes: [] indexes: []
}); });
const Camera = dc.models.Camera;
Camera.belongsTo(SecretYingshi, { foreignKey: 'yingshiSecretId', targetKey: 'id' });
SecretYingshi.hasMany(Camera, { foreignKey: 'yingshiSecretId', sourceKey: 'id' });
dc.models.SecretYingshi = SecretYingshi; dc.models.SecretYingshi = SecretYingshi;
return SecretYingshi; return SecretYingshi;

66
code/VideoAccess-VCMP/api/app/lib/models/vender.js

@ -2,43 +2,35 @@
'use strict'; 'use strict';
module.exports = dc => { module.exports = dc => {
const DataTypes = dc.ORM; const DataTypes = dc.ORM;
const sequelize = dc.orm; const sequelize = dc.orm;
const Vender = sequelize.define("vender", { const Vender = sequelize.define("vender", {
id: { id: {
type: DataTypes.INTEGER, type: DataTypes.INTEGER,
allowNull: false, allowNull: false,
defaultValue: null, defaultValue: null,
comment: null, comment: null,
primaryKey: true, primaryKey: true,
field: "id", field: "id",
autoIncrement: true, autoIncrement: true,
unique: "vender_id_uindex" unique: "vender_id_uindex"
}, },
name: { name: {
type: DataTypes.STRING, type: DataTypes.STRING,
allowNull: false, allowNull: false,
defaultValue: null, defaultValue: null,
comment: null, comment: null,
primaryKey: false, primaryKey: false,
field: "name", field: "name",
autoIncrement: false autoIncrement: false
} }
}, { }, {
tableName: "vender", tableName: "vender",
comment: "", comment: "",
indexes: [] indexes: []
}); });
const Camera = dc.models.Camera;
Camera.belongsTo(Vender, { foreignKey: 'venderId', targetKey: 'id' });
Vender.hasMany(Camera, { foreignKey: 'venderId', sourceKey: 'id' });
const Nvr = dc.models.Nvr; dc.models.Vender = Vender;
Nvr.belongsTo(Vender, { foreignKey: 'venderId', targetKey: 'id' });
Vender.hasMany(Nvr, { foreignKey: 'venderId', sourceKey: 'id' });
dc.models.Vender = Vender; return Vender;
return Vender;
}; };

44
code/VideoAccess-VCMP/api/app/lib/routes/status/index.js

@ -0,0 +1,44 @@
'use strict';
const status = require('../../controllers/status');
const push = require('../../controllers/status/push');
module.exports = function (app, router, opts) {
app.fs.api.logAttr['GET/status'] = { content: '获取状态码', visible: false };
router.get('/status', status.get);
app.fs.api.logAttr['GET/status/simple_all'] = { content: '获取全部状态码简略信息', visible: false };
router.get('/status/simple_all', status.getSimpleAll);
app.fs.api.logAttr['PUT/status/banned'] = { content: '禁用状态码自定义', visible: false };
router.put('/status/banned', status.banned);
app.fs.api.logAttr['POST/status/custom'] = { content: '自定义状态码释义', visible: false };
router.post('/status/custom', status.paraphraseCustom);
app.fs.api.logAttr['POST/status/resolve'] = { content: '编辑解决方案', visible: false };
router.post('/status/resolve', status.resolveEdit);
app.fs.api.logAttr['GET/status/check'] = { content: '查取指定状态码信息', visible: false };
router.get('/status/check', status.statusCheck);
// 信鸽推送
app.fs.api.logAttr['POST/status/push'] = { content: '编辑推送配置', visible: false };
router.post('/status/push', push.edit);
app.fs.api.logAttr['GET/status/push'] = { content: '获取推送配置', visible: false };
router.get('/status/push', push.get);
app.fs.api.logAttr['PUT/status/push/banned'] = { content: '禁用推送配置', visible: false };
router.put('/status/push/banned', push.banned);
app.fs.api.logAttr['DEL/status/push/:pushId'] = { content: '删除推送配置', visible: false };
router.delete('/status/push/:pushId', push.del);
app.fs.api.logAttr['GET/status/push/:pushId/copy'] = { content: '赋值推送配置', visible: false };
router.get('/status/push/:pushId/copy', push.copy);
app.fs.api.logAttr['GET/status/push/:pushId/detail'] = { content: '获取推送配置详情', visible: false };
router.get('/status/push/:pushId/detail', push.detail);
// 信鸽推送 END
};

2
code/VideoAccess-VCMP/api/app/lib/service/socket.js

@ -21,7 +21,7 @@ module.exports = async function factory (app, opts) {
// app.socket.to(roomId).emit('TEST', { someProperty: `【星域 ROOM:${roomId}】呼叫自然选择号!!!`, }) // app.socket.to(roomId).emit('TEST', { someProperty: `【星域 ROOM:${roomId}】呼叫自然选择号!!!`, })
// } // }
// app.socket.emit('TEST', { someProperty: '【广播】呼叫青铜时代号!!!', }) app.socket.emit('TEST', { someProperty: '【广播】呼叫青铜时代号!!!', })
// app.socket.emit('CAMERA_ONLINE', { // app.socket.emit('CAMERA_ONLINE', {
// ipctype: 'yingshi', // ipctype: 'yingshi',

2
code/VideoAccess-VCMP/api/sequelize-automate.config.js

@ -26,7 +26,7 @@ module.exports = {
dir: './app/lib/models', // 指定输出 models 文件的目录 dir: './app/lib/models', // 指定输出 models 文件的目录
typesDir: 'models', // 指定输出 TypeScript 类型定义的文件目录,只有 TypeScript / Midway 等会有类型定义 typesDir: 'models', // 指定输出 TypeScript 类型定义的文件目录,只有 TypeScript / Midway 等会有类型定义
emptyDir: false, // !!! 谨慎操作 生成 models 之前是否清空 `dir` 以及 `typesDir` emptyDir: false, // !!! 谨慎操作 生成 models 之前是否清空 `dir` 以及 `typesDir`
tables: ['camera_remark'], // 指定生成哪些表的 models,如 ['user', 'user_post'];如果为 null,则忽略改属性 tables: ['camera_status_push_log'], // 指定生成哪些表的 models,如 ['user', 'user_post'];如果为 null,则忽略改属性
skipTables: [], // 指定跳过哪些表的 models,如 ['user'];如果为 null,则忽略改属性 skipTables: [], // 指定跳过哪些表的 models,如 ['user'];如果为 null,则忽略改属性
tsNoCheck: false, // 是否添加 `@ts-nocheck` 注释到 models 文件中 tsNoCheck: false, // 是否添加 `@ts-nocheck` 注释到 models 文件中
ignorePrefix: [], // 生成的模型名称忽略的前缀,因为 项目中有以下表名是以 t_ 开头的,在实际模型中不需要, 可以添加多个 [ 't_data_', 't_',] ,长度较长的 前缀放前面 ignorePrefix: [], // 生成的模型名称忽略的前缀,因为 项目中有以下表名是以 t_ 开头的,在实际模型中不需要, 可以添加多个 [ 't_data_', 't_',] ,长度较长的 前缀放前面

3
code/VideoAccess-VCMP/script/.vscode/settings.json

@ -0,0 +1,3 @@
{
"editor.wordWrap": "on"
}

17
code/VideoAccess-VCMP/script/1.1.1/data/1_update_status_code_data/.vscode/launch.json

@ -0,0 +1,17 @@
{
// 使 IntelliSense
//
// 访: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "启动程序",
"skipFiles": [
"<node_internals>/**"
],
"program": "${workspaceFolder}\\index.js"
}
]
}

69
code/VideoAccess-VCMP/script/1.1.1/data/1_update_status_code_data/index.js

@ -0,0 +1,69 @@
try {
const { Pool, Client } = require('pg')
const XLSX = require('xlsx')
const path = require('path')
// 连接数据库
const pool = new Pool({
user: 'postgres',
host: '10.8.30.32',
database: 'video_access',
password: '123',
port: 5432,
})
const fun = async () => {
// note: we don't try/catch this because if connecting throws an exception
// we don't need to dispose of the client (it will be undefined)
const client = await pool.connect()
try {
await client.query('BEGIN')
// 读取数据文件
let workbook = XLSX.readFile(path.join(__dirname, '云录制错误码.xlsx'))
let firstSheetName = workbook.SheetNames[0];
let worksheet = workbook.Sheets[firstSheetName];
let res = XLSX.utils.sheet_to_json(worksheet);
// console.log(res);
for (let d of res) {
let statusRes = await client.query(`SELECT * FROM camera_status WHERE status=$1`, [d['错误码']]);
let statusRows = statusRes.rows
if (statusRows.length) {
} else {
console.log(`增加${d['错误码']}`);
const statusInQuery = `INSERT INTO "camera_status" (platform, status, describe, paraphrase) VALUES($1, $2, $3, $4) RETURNING id;`
const statusRows = (await client.query(statusInQuery, ['yingshi', d['错误码'], d['错误描述'], d['释义']])).rows
// console.log(statusRows);
if (d['解决方案']) {
let resolveArr = d['解决方案'].split(';');
// await client.query(`DELETE FROM "camera_status_solution" WHERE status_id=$1`, [statusRows[0].id]);
for (let r of resolveArr) {
await client.query(
`INSERT INTO "camera_status_resolve" (status_id, resolve) VALUES($1, $2) RETURNING id;`,
[statusRows[0].id, r]
)
}
}
}
}
// await client.query('ROLLBACK')
await client.query('COMMIT')
console.log('执行完毕~')
} catch (e) {
await client.query('ROLLBACK')
console.log('执行错误~')
throw e
} finally {
client.release();
}
}
fun()
} catch (error) {
console.error(error)
}

16
code/VideoAccess-VCMP/script/1.1.1/data/1_update_status_code_data/package.json

@ -0,0 +1,16 @@
{
"name": "appkey-generator",
"version": "1.0.0",
"description": "tool",
"main": "index.js",
"scripts": {
"test": "mocha",
"start": "set NODE_ENV=development&&node index"
},
"author": "liu",
"license": "ISC",
"dependencies": {
"pg": "^7.18.2",
"xlsx": "^0.17.1"
}
}

BIN
code/VideoAccess-VCMP/script/1.1.1/data/1_update_status_code_data/云录制错误码.xlsx

Binary file not shown.

141
code/VideoAccess-VCMP/script/1.1.1/data/2.insert_camera_status.sql

@ -0,0 +1,141 @@
-- ----------------------------
-- Records of camera_status
-- ----------------------------
INSERT INTO "public"."camera_status" VALUES (2, 'yingshi', '5000', '服务端内部处理异常', '服务端内部错误码', 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (3, 'yingshi', '5400', '私有化协议vtm检测私有化协议中码流类型小于0或者设备序列号为空等非法参数场景返回(app不重试取流)', '客户端参数出错', 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (4, 'yingshi', '5402', '回放找不到录像文件', '设备回放找不到录像文件', 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (5, 'yingshi', '5403', '操作码或信令密钥与设备不匹配', '操作码或信令密钥与设备不匹配', 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (6, 'yingshi', '5404', '设备不在线', '设备不在线', 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (7, 'yingshi', '5405', '流媒体向设备发送或接受信令超时/cas响应超时', '设备回应信令10秒超时', 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (8, 'yingshi', '5406', 'token失效', 'token失效', 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (9, 'yingshi', '5407', '客户端的URL格式错误', '客户端的URL格式错误', 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (10, 'yingshi', '5409', '预览开启隐私保护', '预览开启隐私保护', 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (11, 'yingshi', '5411', 'token无权限', 'token无权限、用户无权限', 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (12, 'yingshi', '5412', 'session不存在', 'session不存在', 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (13, 'yingshi', '5413', '验证token的他异常(不具体)', 'token验证失败', 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (14, 'yingshi', '5415', '设备通道错', '设备判断请求通道不存在', 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (15, 'yingshi', '5416', '设备资源受限', '设备资源受限', 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (16, 'yingshi', '5451', '设备不支持的码流类型', '设备不支持的码流类型', 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (17, 'yingshi', '5452', '设备链接流媒体服务器失败', '设备链接流媒体服务器失败', 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (18, 'yingshi', '5454', '流媒体中关于设备取流会话不存在', '流媒体中关于设备取流会话不存在', 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (19, 'yingshi', '5455', '设备通道未关联', '设备通道未关联', 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (20, 'yingshi', '5456', '设备通道关联设备不在线', '设备通道关联设备不在线', 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (21, 'yingshi', '5457', '客户端不支持端到端加密', '客户端不支持端到端加密', 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (22, 'yingshi', '5458', '设备不支持当前并发ECDH密', '设备不支持当前并发ECDH密', 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (23, 'yingshi', '5459', 'VTDU 处理ECDH 加密失败', NULL, 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (24, 'yingshi', '5492', '设备不支持的命令', '设备不支持的命令', 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (25, 'yingshi', '5500', '服务器处理失败', '服务器处理失败', 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (26, 'yingshi', '5503', 'vtm返回分配vtdu失败', 'vtm返回分配vtdu失败', 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (27, 'yingshi', '5504', '流媒体vtdu达到最大负载', '流媒体vtdu达到最大负载', 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (28, 'yingshi', '5544', '设备返回无视频源', NULL, 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (29, 'yingshi', '5545', '视频分享时间已经结束', NULL, 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (30, 'yingshi', '5546', 'vtdu返回达到取流并发路数限制', NULL, 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (31, 'yingshi', '5547', 'vtdu返回开放平台用户并发限制', NULL, 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (32, 'yingshi', '5556', 'ticket校验失败', NULL, 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (33, 'yingshi', '5557', '回放服务器等待流头超时', NULL, 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (34, 'yingshi', '5558', '查找录像开始时间错误', NULL, 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (35, 'yingshi', '5560', '群组分享取流二次验证失败', NULL, 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (36, 'yingshi', '5561', '分享群组用户被锁住', NULL, 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (37, 'yingshi', '5562', '群组分享用户权限变更', NULL, 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (38, 'yingshi', '5563', '认证服务连接失败', NULL, 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (39, 'yingshi', '5564', '认证超时', NULL, 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (40, 'yingshi', '5565', '缓存无效', NULL, 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (41, 'yingshi', '5566', '不在分享时间内预览', NULL, 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (42, 'yingshi', '5567', '分享通道被锁定', NULL, 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (43, 'yingshi', '5568', '未找到认证类型', NULL, 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (44, 'yingshi', '5569', '认证返回的参数异常', NULL, 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (45, 'yingshi', '5600', '分享设备不在分享时间内', NULL, 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (46, 'yingshi', '5601', '群组分享用户没权限', NULL, 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (47, 'yingshi', '5602', '群组分享权限变更', NULL, 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (48, 'yingshi', '5530', '机房故障不可用', NULL, 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (49, 'yingshi', '5701', 'cas信令返回格式错误', NULL, 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (50, 'yingshi', '5702', 'SPGW请求Cas、Status透传超时', NULL, 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (51, 'yingshi', '5703', 'SPGW请求http不通', NULL, 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (52, 'yingshi', '6001', '客户端参数出错', NULL, 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (53, 'yingshi', '6099', '客户端默认错误', NULL, 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (54, 'yingshi', '6101', '不支持的命令', NULL, 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (55, 'yingshi', '6102', '设备流头发送失败', NULL, 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (56, 'yingshi', '6103', 'cas/设备返回错误1', NULL, 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (57, 'yingshi', '6104', 'cas/设备返回错误-1', NULL, 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (58, 'yingshi', '6105', '设备返回错误码3', NULL, 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (59, 'yingshi', '6106', '设备返回错误码4', '一般常见于多通道设 备预览 1、通道不存在 2、通道子码流不存在 3、通道不在线', 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (60, 'yingshi', '6107', '设备返回错误码5', NULL, 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (61, 'yingshi', '6108', 'cas信令回应重复', NULL, 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (62, 'yingshi', '6109', '视频广场取消分享', NULL, 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (63, 'yingshi', '6110', '设备信令默认错误', '设备错误返回的错误码,不具体', 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (64, 'yingshi', '6501', '设备数据链路和实际链路不匹配', NULL, 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (65, 'yingshi', '6502', '设备数据链路重复建立连接', NULL, 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (66, 'yingshi', '6503', '设备数据链路端口不匹配', NULL, 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (67, 'yingshi', '6504', '缓存设备数据链路失败(内存块不足)', NULL, 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (68, 'yingshi', '6505', '设备发送确认头消息重复', NULL, 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (69, 'yingshi', '6506', '设备数据先于确定头部到达', NULL, 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (70, 'yingshi', '6508', '设备数据头部长度非法', NULL, 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (71, 'yingshi', '6509', '索引找不到设备数据管理块', NULL, 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (72, 'yingshi', '6510', '设备数据链路vtdu内存块协议状态不匹配', NULL, 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (73, 'yingshi', '6511', '设备数据头部没有streamkey错误', NULL, 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (74, 'yingshi', '6512', '设备数据头部非法(较笼统)', NULL, 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (75, 'yingshi', '6513', '设备数据长度过小', NULL, 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (76, 'yingshi', '6514', '设备老协议推流头部没有streamkey错误', NULL, 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (77, 'yingshi', '6515', '设备老协议推流数据非法', NULL, 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (78, 'yingshi', '6516', '设备老协议索引找不到内存管理块', NULL, 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (79, 'yingshi', '6517', '设备老协议推流数据非法', NULL, 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (80, 'yingshi', '6518', '设备数据包过大', NULL, 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (81, 'yingshi', '6519', '设备推流链路网络不稳定', '设备长时间未推流超时', 'f', NULL);
INSERT INTO "public"."camera_status" VALUES (82, 'yingshi', '6520', '设备推流链路网络不稳定(默认)', '设备网络异常', 'f', NULL);
-- ----------------------------
-- Records of camera_status_resolve
-- ----------------------------
INSERT INTO "public"."camera_status_resolve" VALUES (2, 2, '检测服务端是否正常');
INSERT INTO "public"."camera_status_resolve" VALUES (3, 3, '刷新重试');
INSERT INTO "public"."camera_status_resolve" VALUES (4, 4, '检查是否有存储卡并且接触良好');
INSERT INTO "public"."camera_status_resolve" VALUES (5, 6, '检查设备网络');
INSERT INTO "public"."camera_status_resolve" VALUES (6, 6, '重启设备接入萤石云');
INSERT INTO "public"."camera_status_resolve" VALUES (7, 7, '检查设备网络');
INSERT INTO "public"."camera_status_resolve" VALUES (8, 7, '重启设备');
INSERT INTO "public"."camera_status_resolve" VALUES (9, 8, '刷新重试或者重启设备');
INSERT INTO "public"."camera_status_resolve" VALUES (10, 9, '刷新重试');
INSERT INTO "public"."camera_status_resolve" VALUES (11, 13, '刷新重试');
INSERT INTO "public"."camera_status_resolve" VALUES (12, 14, '刷新重试');
INSERT INTO "public"."camera_status_resolve" VALUES (13, 15, '刷新重试');
INSERT INTO "public"."camera_status_resolve" VALUES (14, 16, '刷新重试或者切换到高清模式');
INSERT INTO "public"."camera_status_resolve" VALUES (15, 17, '检查设备网络,重启设备,刷新重试');
INSERT INTO "public"."camera_status_resolve" VALUES (16, 19, '检查设备通道是否关联');
INSERT INTO "public"."camera_status_resolve" VALUES (17, 20, '检查设备通道是否上线');
INSERT INTO "public"."camera_status_resolve" VALUES (18, 25, '刷新重试');
INSERT INTO "public"."camera_status_resolve" VALUES (19, 26, 'vtdu服务异常,请请稍后重试');
INSERT INTO "public"."camera_status_resolve" VALUES (20, 27, '服务器负载达到上限,请稍后重试');
INSERT INTO "public"."camera_status_resolve" VALUES (21, 28, '设备是否接触良好');
INSERT INTO "public"."camera_status_resolve" VALUES (22, 28, '如果一直无法解决,请联系技术支持');
INSERT INTO "public"."camera_status_resolve" VALUES (23, 30, '请升级为企业版,放开并发限制');
INSERT INTO "public"."camera_status_resolve" VALUES (24, 31, '请确定开放平台用户预览是否超过用户并发数量限制');
INSERT INTO "public"."camera_status_resolve" VALUES (25, 33, '刷新重试,检测设备网络,重启设备');
INSERT INTO "public"."camera_status_resolve" VALUES (26, 48, '刷新重试');
INSERT INTO "public"."camera_status_resolve" VALUES (27, 49, '刷新重试');
INSERT INTO "public"."camera_status_resolve" VALUES (28, 50, '刷新重试');
INSERT INTO "public"."camera_status_resolve" VALUES (29, 51, '刷新重试');
INSERT INTO "public"."camera_status_resolve" VALUES (30, 52, '刷新重试');
INSERT INTO "public"."camera_status_resolve" VALUES (31, 54, '刷新重试');
INSERT INTO "public"."camera_status_resolve" VALUES (32, 55, '刷新重试');
INSERT INTO "public"."camera_status_resolve" VALUES (33, 56, '刷新重试');
INSERT INTO "public"."camera_status_resolve" VALUES (34, 57, '刷新重试');
INSERT INTO "public"."camera_status_resolve" VALUES (35, 58, '刷新重试');
INSERT INTO "public"."camera_status_resolve" VALUES (36, 59, '刷新重试');
INSERT INTO "public"."camera_status_resolve" VALUES (37, 60, '刷新重试');
INSERT INTO "public"."camera_status_resolve" VALUES (38, 61, '刷新重试');
INSERT INTO "public"."camera_status_resolve" VALUES (39, 63, '刷新重试,或者重启设备');
INSERT INTO "public"."camera_status_resolve" VALUES (40, 64, '刷新重试');
INSERT INTO "public"."camera_status_resolve" VALUES (41, 65, '刷新重试');
INSERT INTO "public"."camera_status_resolve" VALUES (42, 66, '刷新重试');
INSERT INTO "public"."camera_status_resolve" VALUES (43, 67, '刷新重试');
INSERT INTO "public"."camera_status_resolve" VALUES (44, 68, '刷新重试');
INSERT INTO "public"."camera_status_resolve" VALUES (45, 69, '刷新重试');
INSERT INTO "public"."camera_status_resolve" VALUES (46, 70, '刷新重试,或者重启设备');
INSERT INTO "public"."camera_status_resolve" VALUES (47, 71, '刷新重试');
INSERT INTO "public"."camera_status_resolve" VALUES (48, 80, '刷新重试,或者重启设备');

140
code/VideoAccess-VCMP/script/1.1.1/schema/1.create_camera_status_table.sql

@ -0,0 +1,140 @@
create table if not exists camera_status
(
id serial not null,
platform varchar(32) not null,
status varchar(32) not null,
describe varchar(1024),
paraphrase varchar(1024),
forbidden boolean default false not null,
paraphrase_custom varchar(1024),
constraint camera_status_pk
primary key (id)
);
comment on column camera_status.platform is '平台分类 yingshi gb';
comment on column camera_status.describe is '错误描述';
comment on column camera_status.paraphrase is '释义';
comment on column camera_status.forbidden is '是否禁用';
comment on column camera_status.paraphrase_custom is '自定义释义';
create unique index if not exists camera_status_id_uindex
on camera_status (id);
create table if not exists camera_status_log
(
id serial not null,
status_id integer not null,
time timestamp not null,
constraint camera_status_log_pk
primary key (id),
constraint camera_status_log_camera_status_id_fk
foreign key (status_id) references camera_status
);
create unique index if not exists camera_status_log_id_uindex
on camera_status_log (id);
create unique index if not exists camera_status_log_id_uindex_2
on camera_status_log (id);
create table if not exists camera_status_push_config
(
id serial not null,
name varchar(64) not null,
push_way varchar(32) not null,
notice_way varchar(32) not null,
create_user integer not null,
forbidden boolean default false not null,
timing varchar(32),
constraint camera_online_status_push_config_pk
primary key (id)
);
comment on column camera_status_push_config.push_way is '推送方式 email / phone';
comment on column camera_status_push_config.notice_way is '通知方式 offline / online / timing';
comment on column camera_status_push_config.timing is '定时推送时间';
create unique index if not exists camera_online_status_push_config_id_uindex
on camera_status_push_config (id);
create table if not exists camera_status_push_log
(
id serial not null,
push_config_id integer,
receiver jsonb not null,
time timestamp,
push_way varchar(128) not null,
constraint camera_status_push_log_pk
primary key (id)
);
comment on table camera_status_push_log is '上下线推送日志';
create unique index if not exists camera_status_push_log_id_uindex
on camera_status_push_log (id);
create table if not exists camera_status_push_monitor
(
id serial not null,
config_id integer not null,
camera_id integer not null,
constraint camera_status_push_monitor_pk
primary key (id),
constraint camera_status_push_monitor_camera_id_fk
foreign key (camera_id) references camera,
constraint camera_status_push_monitor_camera_status_push_config_id_fk
foreign key (config_id) references camera_status_push_config
);
create unique index if not exists camera_status_push_monitor_id_uindex
on camera_status_push_monitor (id);
create table if not exists camera_status_push_receiver
(
id serial not null,
config_id integer not null,
receiver varchar(64) not null,
constraint camera_status_push_receiver_pk
primary key (id),
constraint camera_status_push_receiver_camera_status_push_config_id_fk
foreign key (config_id) references camera_status_push_config
);
comment on column camera_status_push_receiver.receiver is '接受者信息 邮箱或者电话号码';
create unique index if not exists camera_status_push_receiver_id_uindex
on camera_status_push_receiver (id);
create table if not exists camera_status_resolve
(
id serial not null,
status_id integer not null,
resolve varchar(1024) not null,
constraint camera_status_resolve_pk
primary key (id),
constraint camera_status_resolve_camera_status_id_fk
foreign key (status_id) references camera_status
);
comment on table camera_status_resolve is '错误码解决方案';
create unique index if not exists camera_status_resolve_id_uindex
on camera_status_resolve (id);

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 387 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

BIN
code/VideoAccess-VCMP/web/client/assets/images/favicon.ico

Binary file not shown.

After

Width:  |  Height:  |  Size: 205 KiB

BIN
code/VideoAccess-VCMP/web/client/assets/video/37ov3-lit2e.mp4

Binary file not shown.

2
code/VideoAccess-VCMP/web/client/src/components/index.js

@ -4,6 +4,7 @@ import Coming from './coming'
import ReminderBox from './reminderBox' import ReminderBox from './reminderBox'
import VideoPlay from './videoPlayer/videoPlay' import VideoPlay from './videoPlayer/videoPlay'
import VideoPlayModal from './videoPlayer/videoPlayModal' import VideoPlayModal from './videoPlayer/videoPlayModal'
import Setup from './setup'
export { export {
SimpleFileDownButton, SimpleFileDownButton,
@ -11,4 +12,5 @@ export {
ReminderBox, ReminderBox,
VideoPlay, VideoPlay,
VideoPlayModal, VideoPlayModal,
Setup
}; };

121
code/VideoAccess-VCMP/web/client/src/components/setup.jsx

@ -0,0 +1,121 @@
import React, { useState, useEffect } from "react";
import {
Modal,
CheckboxGroup,
Checkbox,
} from "@douyinfe/semi-ui";
function Setup(props) {
const {
close,
tableType,
tableList
} = props;
const [check, setCheck] = useState([]);
const checkboxcss = { width: "25%", height: 16, margin: "0 0 20px 0" };
useEffect(() => {
//
const checkItem = localStorage.getItem(tableType);
setCheck(checkItem?JSON.parse(checkItem) : [])
ischeck();
}, []);
function ischeck(value) {
if (check.length >= 8) {
if (check.includes(value)) {
return false;
} else {
return true;
}
}
}
return (
<Modal
title={
<div>
表格属性设置
<span
style={{
width: 50,
lineHeight: "19px",
display: "inline-block",
color: "white",
textAlign: "center",
marginLeft: 6,
background:
check.length == 8
? "rgba(40, 123, 255, 1)"
: "rgba(176, 176, 176, 1)",
}}
>
{check.length}/8
</span>
</div>
}
visible={true}
style={{ width: 600 }}
onOk={() => {
localStorage.setItem(tableType, JSON.stringify(check));
close();
}}
onCancel={() => {
close();
}}
>
<CheckboxGroup
style={{ width: "100%", fontSize: 14 }}
key="primary1"
direction="horizontal"
defaultValue={check}
aria-label="表格属性设置"
onChange={(check) => {
setCheck(check);
ischeck();
}}
>
{tableList.map((item,index)=>{
return(
<div
key={index}
style={{
width: 550,
border: "1px solid #EAEAEA",
padding: "0px 5px",
borderRadius: 4,
marginBottom: "20px",
}}
>
<div
style={{
borderBottom: "1px solid #EAEAEA",
marginLeft: "10px",
padding: "8px 0px",
}}
>
{item.title}
</div>
<div style={{ padding: "15px 12px", width: 530 }}>
{item.list.map((itm) => {
return (
<Checkbox
key={itm.value}
value={itm.value}
style={checkboxcss}
disabled={ischeck(itm.value)}
>
{itm.name}
</Checkbox>
);
})}
</div>
</div>
)})}
</CheckboxGroup>
</Modal>
);
}
export default Setup;

2
code/VideoAccess-VCMP/web/client/src/layout/actions/webSocket.js

@ -22,7 +22,7 @@ export function initWebSocket ({ ioUrl, token }) {
return dispatch => { return dispatch => {
const socket = io( const socket = io(
ioUrl ioUrl
// 'http://127.0.0.1:4000' // 'http://10.8.30.7:4000'
, { , {
query: { query: {
token: token token: token

6
code/VideoAccess-VCMP/web/client/src/sections/equipmentWarehouse/components/remarksModal.jsx

@ -114,8 +114,8 @@ function remarksModal (props) {
))} ))}
</div> </div>
</div> </div>
<div style={{width:306,marginLeft:20}}> <div style={{width:308,marginLeft:20,border:'1px solid #F5F6F7'}}>
<div style={{ position: "absolute",background:'rgba(0, 0, 0, 0.15)',width:306}}> <div style={{ position: "absolute",background:'rgba(24,89,193,0.8)',width:306}}>
<TextScroll content={showScrollList} roll={roll} duration={6} /> <TextScroll content={showScrollList} roll={roll} duration={6} />
</div> </div>
<video <video
@ -124,7 +124,7 @@ function remarksModal (props) {
loop loop
muted muted
style={{ width: 306,height:185, objectFit: "cover", }} style={{ width: 306,height:185, objectFit: "cover", }}
src="/assets/video/remarks.mp4" src="/assets/video/37ov3-lit2e.mp4"
type="video/mp4" type="video/mp4"
/> />
</div> </div>

191
code/VideoAccess-VCMP/web/client/src/sections/equipmentWarehouse/components/setup.jsx

@ -1,191 +0,0 @@
import React, { useState, useEffect } from "react";
import {
Modal,
CheckboxGroup,
Checkbox,
} from "@douyinfe/semi-ui";
function Setup(props) {
const {
visible,
close,
SETUPS,
CAMERAS,
cameraSetup,
} = props;
const [check, setCheck] = useState([]);
const checkboxcss = { width: "25%", height: 16, margin: "0 0 20px 0" };
useEffect(() => {
//
const nvrItem = localStorage.getItem(SETUPS);
const cameraItem = localStorage.getItem(CAMERAS);
if (cameraSetup) {
setCheck(cameraItem ? JSON.parse(cameraItem) : []);
} else {
setCheck(nvrItem ? JSON.parse(nvrItem) : []);
}
ischeck();
}, []);
const equipmentNVR = [
{ name: "设备厂家", value: "manufactor" },
{ name: "添加账号", value: "accountNumber" },
{ name: "通道数", value: "passageway" },
{ name: "端口", value: "port" },
{ name: "设备状态", value: "state" },
{ name: "创建时间", value: "time" },
];
const projectNVR = [
{ name: "项目名称", value: "name" },
{ name: "pcode", value: "pcode" },
{ name: "结构物", value: "structure" },
];
const equipmentCamera = [
{ name: "设备厂家", value: "manufactor" },
{ name: "接入类型", value: "type" },
{ name: "设备状态", value: "state" },
{ name: "云台支持", value: "support" },
{ name: "内存卡信息", value: "memoryCard" },
{ name: "设备创建时间", value: "time" },
{ name: "设备添加账号", value: "account" },
];
const projectCamera = [
{ name: "项目名称", value: "name" },
{ name: "pcode", value: "pcode" },
{ name: "结构物", value: "structure" },
{ name: "测点", value: "measuringPoint" },
{ name: "监测因素", value: "factor" },
];
function ischeck(value) {
if (check.length >= 8) {
if (check.includes(value)) {
return false;
} else {
return true;
}
}
}
return (
<Modal
title={
<div>
表格属性设置
<span
style={{
width: 50,
lineHeight: "19px",
display: "inline-block",
color: "white",
textAlign: "center",
marginLeft: 6,
background:
check.length == 8
? "rgba(40, 123, 255, 1)"
: "rgba(176, 176, 176, 1)",
}}
>
{check.length}/8
</span>
</div>
}
visible={visible}
style={{ width: 600 }}
onOk={() => {
cameraSetup
? localStorage.setItem(CAMERAS, JSON.stringify(check))
: localStorage.setItem(SETUPS, JSON.stringify(check));
close();
}}
onCancel={() => {
close();
}}
>
<CheckboxGroup
style={{ width: "100%", fontSize: 14 }}
key="primary1"
direction="horizontal"
defaultValue={check}
aria-label="表格属性设置"
onChange={(check) => {
setCheck(check);
ischeck();
}}
>
<div
style={{
width: 550,
border: "1px solid #EAEAEA",
padding: "0px 5px",
borderRadius: 4,
marginBottom: "20px",
}}
>
<div
style={{
borderBottom: "1px solid #EAEAEA",
marginLeft: "10px",
padding: "8px 0px",
}}
>
设备信息
</div>
<div style={{ padding: "15px 12px", width: 530 }}>
{(cameraSetup ? equipmentCamera : equipmentNVR).map((item) => {
return (
<Checkbox
key={item.value}
value={item.value}
style={checkboxcss}
disabled={ischeck(item.value)}
>
{item.name}
</Checkbox>
);
})}
</div>
</div>
<div
style={{
width: 550,
border: "1px solid #EAEAEA",
padding: "0px 5px",
borderRadius: 4,
}}
>
<div
style={{
borderBottom: "1px solid #EAEAEA",
marginLeft: "10px",
padding: "8px 0px",
}}
>
项目信息
</div>
<div style={{ padding: "15px 12px", width: 530 }}>
{(cameraSetup ? projectCamera : projectNVR).map((item) => {
return (
<Checkbox
key={item.value}
value={item.value}
style={checkboxcss}
disabled={ischeck(item.value)}
>
{item.name}
</Checkbox>
);
})}
</div>
</div>
</CheckboxGroup>
</Modal>
);
}
export default Setup;

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

@ -17,7 +17,7 @@ import { SimpleFileDownButton, VideoPlayModal } from "$components";
import "../style.less"; import "../style.less";
import CameraModal from "../components/cameraModal"; import CameraModal from "../components/cameraModal";
import RemarksModal from "../components/remarksModal"; import RemarksModal from "../components/remarksModal";
import Setup from "../components/setup"; import {Setup} from "$components";
import SideSheets from "../components/sideSheet"; import SideSheets from "../components/sideSheet";
import { skeletonScreen } from "../components/skeletonScreen"; import { skeletonScreen } from "../components/skeletonScreen";
import { accessType } from "./nvr"; import { accessType } from "./nvr";
@ -51,7 +51,30 @@ const CameraHeader = (props) => {
const page = useRef(query.page); const page = useRef(query.page);
const deviceClickb = useRef(true) const deviceClickb = useRef(true)
const CAMERAS = "cameras"; const CAMERAS = "cameras";
const tableList = [//
{
title:'设备信息',
list:[
{ name: "设备厂家", value: "manufactor" },
{ name: "接入类型", value: "type" },
{ name: "设备状态", value: "state" },
{ name: "云台支持", value: "support" },
{ name: "内存卡信息", value: "memoryCard" },
{ name: "设备创建时间", value: "time" },
{ name: "设备添加账号", value: "account" },
]
},
{
title:'项目信息',
list:[
{ name: "项目名称", value: "name" },
{ name: "pcode", value: "pcode" },
{ name: "结构物", value: "structure" },
{ name: "测点", value: "measuringPoint" },
{ name: "监测因素", value: "factor" },
]
},
];
useEffect(() => { useEffect(() => {
// //
let isAxyData = props.location.search let isAxyData = props.location.search
@ -659,7 +682,7 @@ const CameraHeader = (props) => {
}); });
}} }}
> >
</Button> </Button>
<Button <Button
theme="light" theme="light"
@ -771,9 +794,8 @@ const CameraHeader = (props) => {
{setup ? ( {setup ? (
<Setup <Setup
visible={true} tableType={CAMERAS}
CAMERAS={CAMERAS} tableList={tableList}
cameraSetup={cameraSetup}
close={() => { close={() => {
setSetup(false); setSetup(false);
attribute(venderList); attribute(venderList);

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

@ -5,7 +5,7 @@ import { Button, Form, Table, Pagination, Skeleton, Popconfirm, Popover, Tag, }
import "../style.less"; import "../style.less";
import { ApiTable } from "$utils"; import { ApiTable } from "$utils";
import NvrModal from "../components/nvrModal"; import NvrModal from "../components/nvrModal";
import Setup from "../components/setup"; import {Setup} from "$components";
import SideSheets from "../components/sideSheet"; import SideSheets from "../components/sideSheet";
import { skeletonScreen } from "../components/skeletonScreen"; import { skeletonScreen } from "../components/skeletonScreen";
import { ReminderBox } from "../../../components/index"; import { ReminderBox } from "../../../components/index";
@ -36,6 +36,27 @@ const NvrHeader = (props) => {
const SETUPS = "setups"; const SETUPS = "setups";
const USER = "user" + props.user.id const USER = "user" + props.user.id
const nvrRef = useRef(); // const nvrRef = useRef(); //
const tableList = [//
{
title:'设备信息',
list:[
{ name: "设备厂家", value: "manufactor" },
{ name: "添加账号", value: "accountNumber" },
{ name: "通道数", value: "passageway" },
{ name: "端口", value: "port" },
{ name: "设备状态", value: "state" },
{ name: "创建时间", value: "time" },
]
},
{
title:'项目信息',
list:[
{ name: "项目名称", value: "name" },
{ name: "pcode", value: "pcode" },
{ name: "结构物", value: "structure" },
]
},
];
useEffect(() => { useEffect(() => {
dispatch(actions.equipmentWarehouse.getVender()).then((res) => { dispatch(actions.equipmentWarehouse.getVender()).then((res) => {
@ -72,7 +93,7 @@ const NvrHeader = (props) => {
return "离线" return "离线"
default: default:
return "未知" return "未知"
}F }
} }
function colorStatus (data) { function colorStatus (data) {
@ -463,7 +484,7 @@ const NvrHeader = (props) => {
}); });
}} }}
> >
</Button> </Button>
<Button <Button
theme="light" theme="light"
@ -574,8 +595,8 @@ const NvrHeader = (props) => {
{setup ? ( {setup ? (
<Setup <Setup
visible={true} tableType={SETUPS}
SETUPS={SETUPS} tableList={tableList}
close={() => { close={() => {
setSetup(false); setSetup(false);
attribute(venderList); attribute(venderList);

6
code/VideoAccess-VCMP/web/client/src/sections/offline/actions/index.js

@ -1,5 +1,9 @@
'use strict'; 'use strict';
export default { import * as statuscode from './statuscode'
// import * as camera from './camera'
export default {
// ...statuscode,...camera
...statuscode
} }

65
code/VideoAccess-VCMP/web/client/src/sections/offline/actions/statuscode.js

@ -0,0 +1,65 @@
"use strict";
import { basicAction } from "@peace/utils";
import { ApiTable } from "$utils";
export function getStatus(query) {
return (dispatch) =>
basicAction({
type: "get",
dispatch: dispatch,
actionType: "GET_STATUS",
query: query,
url: `${ApiTable.getStatus}`,
msg: { option: "获取状态码列表信息" },
reducer: { name: "StatusList" },
});
}
export function putStatueBanned(data, forbidden) {
return (dispatch) =>
basicAction({
type: "put",
dispatch: dispatch,
actionType: "PUT_STATUEBANNED",
data,
url: `${ApiTable.putStatueBanned}`,
msg: { option: forbidden ? "启用" : "禁用" }, //禁用状态码自定义
reducer: {},
});
}
export function postStatusResolve(data) {
return (dispatch) =>
basicAction({
type: "post",
dispatch: dispatch,
data,
actionType: "POST_STATUS_RESOLVE",
url: `${ApiTable.postStatusResolve}`,
msg: { option: "" }, //编辑解决方案
reducer: { name: "" },
});
}
export function postStatusCustom(data) {
return (dispatch) =>
basicAction({
type: "post",
dispatch: dispatch,
data,
actionType: "POST_STATUS_CUSTOM",
url: `${ApiTable.postStatusCustom}`,
msg: { option: "" }, //自定义状态码释义
reducer: { name: "" },
});
}
export function getStatusSimpleAll() {
return (dispatch) =>
basicAction({
type: "get",
dispatch: dispatch,
actionType: "GET_STATUS_SIMPLE_ALL",
url: `${ApiTable.getStatusSimpleAll}`,
msg: { option: "" }, //获取摄像头能力列表
reducer: { name: "" },
});
}

178
code/VideoAccess-VCMP/web/client/src/sections/offline/components/notesModal.jsx

@ -0,0 +1,178 @@
import React, { useState, useRef, useEffect } from "react";
import { connect } from "react-redux";
import { Modal, Spin,Input,TagInput ,Select} from "@douyinfe/semi-ui";
function programmeModal (props) {
const {
close,
rowId,
dispatch,
actions,
nodesAll,//
tableNews,//
} = props;
const { offline } = actions;
const [notesValue, setNotesValue] = useState('');//
const [codeList, setCodeList] = useState([]);//
const [codeIdList, setcodeIdList] = useState([]);//id
const [platform, setPlatform] = useState(['yingshi']);//
//
useEffect(() => {
setNotesValue(tableNews.paraphraseCustom||'')
dispatch(
offline.getStatusSimpleAll()
).then((res) => {
let mycodeList=[];
if(res.payload&&res.payload.data){
for (let index = 0; index < res.payload.data.length; index++) {
mycodeList.push({id:res.payload.data[index].id,status:res.payload.data[index].status+' '+res.payload.data[index].describe,platform:res.payload.data[index].platform})
}
}
setCodeList(mycodeList)
})
}, []);
function handleOk () {
//
if(nodesAll){
dispatch(
offline.postStatusCustom({
statusId:codeIdList,
paraphrase:notesValue
})
).then((res) => {
close();
})
}
else{
dispatch(
offline.postStatusCustom({
statusId:[rowId],
paraphrase:notesValue
})
).then((res) => {
close();
})
}
}
function handleCancel () {
close();
//
}
function onChange(value){//
if(value!==''){
setNotesValue(value)
}
else{
setNotesValue(null)
}
}
function onSelect(value){//
setcodeIdList(value)
}
function oneSelect(value){//
setPlatform(value)
}
return (
<>
<Modal
title={nodesAll?'批量设置':'释义'}
okText="确定"
cancelText="取消"
visible={true}
onOk={handleOk}
width={607}
onCancel={handleCancel}
>
{nodesAll?(
<div style={{margin:"17px 32px 28px 32px"}}>
<div style={{display: 'flex',alignItems: 'center'}}>
<div style={{width:84,textAlign:'right',color: 'rgba(0,0,0,0.65)'}}>状态码</div>
<div>
<Select defaultValue='yingshi' onChange={oneSelect} style={{ width: 108 }}>
<Select.Option value='yingshi'>萤石云</Select.Option>
<Select.Option value='gb'>国标摄像头</Select.Option>
</Select>
</div>
<div style={{marginLeft:12}}>
<Select filter multiple style={{ width: 300 }} onChange={onSelect} placeholder='请选择状态码' maxTagCount={1} autoClearSearchValue={false}>
{codeList.map((item) => {
return(
item.platform==platform ? (
<Select.Option key={item.id} value={item.id}>
{item.status}
</Select.Option>
) : (
""
)
)
})}
</Select>
</div>
</div>
<div style={{display: 'flex',alignItems: 'center',marginTop:21}}>
<div style={{width:84,textAlign:'right',color: 'rgba(0,0,0,0.65)'}}>修改释义</div>
<div style={{width:'100%'}}><Input
style={{width:'100%'}}
value={notesValue}
onChange={onChange}
maxLength={18}
placeholder="请输入自定义释义"
showClear>
</Input></div>
</div>
</div>
):(
<div style={{margin:"17px 32px 28px 32px"}}>
<div style={{color: 'rgba(0,0,0,0.65)',fontWeight: 600}}>当视频出错时提示以下内容</div>
<div style={{marginTop:12}}><Input
style={{width:'100%'}}
value={notesValue}
onChange={onChange}
maxLength={18}
placeholder="请输入自定义释义"
showClear>
</Input>
</div>
</div>
)}
<div style={{display:'flex',margin:'0px 20px',alignItems: 'center',justifyContent: 'space-between'}}>
<div style={{display:'flex',justifyContent: 'center',
alignItems:'center', width: 240, height: 146 ,
background: "url(/assets/images/background/codeBefore.png)",backgroundSize: "100% 100%",}}>
<div style={{color: 'rgba(255,255,255,0.8)',textShadow: '0px 1px 1px rgba(0,0,0,0)',textAlign: 'center',width: 130}}>
{tableNews.paraphrase||'初始化释义'}
</div>
</div>
<div>
<img
src="/assets/images/background/codeArrow.png"
alt="设置"
style={{ width: 18, height: 15 }}
/>
</div>
<div style={{ display:'flex',justifyContent: 'center',
alignItems:'center', width: 240, height: 146 ,
background: "url(/assets/images/background/codeAfter.png)",backgroundSize: "100% 100%",}}>
<div style={{color: 'rgba(255,255,255,1)',textShadow: '0px 1px 1px #001969',textAlign: 'center',width: 130}}>
{notesValue}
</div>
</div>
</div>
</Modal>
</>
);
}
function mapStateToProps (state) {
const { auth, global, members, CameraKind, CameraAbility } = state;
return {
loading: members.isRequesting,
user: auth.user,
actions: global.actions,
CameraKind: CameraKind.data || [],
CameraAbility: CameraAbility.data || [],
};
}
export default connect(mapStateToProps)(programmeModal);

85
code/VideoAccess-VCMP/web/client/src/sections/offline/components/programmeModal.jsx

@ -0,0 +1,85 @@
import React, { useState, useRef, useEffect } from "react";
import { connect } from "react-redux";
import { Modal, Spin,Input,TagInput } from "@douyinfe/semi-ui";
function programmeModal (props) {
const {
close,
rowId,
dispatch,
actions,
resolve,//
} = props;
const { offline } = actions;//
const [myresolve, setMyResolve] = useState([]);//
//
useEffect(() => {
let resolvearr=[]
for (let index = 0; index < resolve.length; index++) {
resolvearr.push(resolve[index].resolve)
}
setMyResolve(resolvearr)
}, []);
function handleOk () {
//
dispatch(
offline.postStatusResolve({
statusId:rowId,
resolve:myresolve
})
).then((res) => {
close();
})
}
function handleCancel () {
close();
//
}
function onChange(value){
setMyResolve(value)
}
return (
<>
<Modal
title="方案"
okText="确定"
cancelText="取消"
visible={true}
onOk={handleOk}
width={607}
onCancel={handleCancel}
>
<div style={{margin:"17px 56px 18px 31px"}}>
<div style={{color:'rgba(0, 0, 0, 0.65)',}}>
解决方案设置
</div>
<div style={{color:'rgba(0, 0, 0, 0.45)',fontSize:12,marginTop:4}}>
敲击回车键后输入内容将成为标签
</div>
<div style={{marginTop:10}}>
<TagInput
defaultValue={myresolve}
placeholder='请输入解决方案'
size='large'
maxLength={18}
onChange={onChange}
/>
</div>
</div>
</Modal>
</>
);
}
function mapStateToProps (state) {
const { auth, global, members, CameraKind, CameraAbility } = state;
return {
loading: members.isRequesting,
user: auth.user,
actions: global.actions,
CameraKind: CameraKind.data || [],
CameraAbility: CameraAbility.data || [],
};
}
export default connect(mapStateToProps)(programmeModal);

299
code/VideoAccess-VCMP/web/client/src/sections/offline/components/pushModal.jsx

@ -0,0 +1,299 @@
import React, { useState, useRef, useEffect, useImperativeHandle } from "react";
import { connect } from "react-redux";
import { Modal, Form, Row, Col, Spin } from "@douyinfe/semi-ui";
import { IconTickCircle } from "@douyinfe/semi-icons";
import moment from "moment";
function pushModal (props) {
const { modalName, pushRef } = props;
const { dispatch, actions, vender, close } = props;
const pushData = props.pushData || {}; //
const form = useRef();
const [visible, setVisible] = useState(false); //
const [isloading, setloading] = useState(false); //loading
const [loadingTip, setloadingTip] = useState("获取中...请稍后..."); //loading tip
const [step, setstep] = useState("none"); //
const [okText, setokText] = useState("测试校验"); //oktext
const [cancelText, setcancelText] = useState("取消"); //text
const [formObj, setformObj] = useState(); //
function showDialog () {
//
setVisible(true);
}
function positionForm (val) {
let zz = /^(-?\d+)(\.\d+)?$/;
if (!val) {
return "请输入或拾取高德经纬度坐标";
} else if (val.split(",").length != 2) {
return "请输入格式为116.354169,39.835452的经纬度坐标";
} else if (!zz.test(val.split(",")[0])) {
return "只能填写数字";
} else if (!zz.test(val.split(",")[1])) {
return "只能填写数字";
} else {
return "";
}
}
function handleOk () {
//
if (step == "none") {
form.current
.validate()
.then((values) => {
//
console.log(values)
let valuesObj = JSON.parse(JSON.stringify(values));
valuesObj.longitude = values.position.split(",")[0];
valuesObj.latitude = values.position.split(",")[1];
delete valuesObj.position;
if (pushData.id) {
valuesObj.id = pushData.id;
}
var front = new moment(); //
setloading(true);
dispatch(
actions.equipmentWarehouse.getCheck({
serialNo: valuesObj.serialNo,
})
).then((res) => {
var after = new moment(); //
var duration = moment.duration(after.diff(front))._data.milliseconds;
if (res.success) {
setTimeout(
() => {
setloadingTip("已完成");
setTimeout(() => {
setstep("block");
setloading(false);
setokText("确认");
setcancelText("上一步");
setloadingTip("获取中...请稍后...");
}, 1000);
},
duration > 2000 ? 0 : 2000 - duration
);
} else {
setTimeout(
() => {
setloadingTip("校验失败");
setTimeout(() => {
setstep("none");
setloading(false);
setokText("测试校验");
setcancelText("取消");
setloadingTip("获取中...请稍后...");
}, 1000);
},
duration > 2000 ? 0 : 2000 - duration
);
}
});
setformObj(valuesObj);
})
.catch((errors) => {
//
console.log("errors", errors);
});
} else {
dispatch(actions.equipmentWarehouse.addchangepush(formObj)).then((res) => {
setVisible(false);
close();
});
}
}
function handleAfterClose () {
//
setstep("none");
setokText("测试校验");
setcancelText("取消");
}
function handleCancel () {
//
if (step == "none") {
setVisible(false);
} else {
setstep("none");
setokText("测试校验");
setcancelText("取消");
}
}
function handleLocation () {
//
window.open("https://lbs.amap.com/tools/picker", "_blank");
}
useImperativeHandle(pushRef, () => ({
//
//aa
pushNumber: () => formObj.serialNo
}));
return (
<>
<div onClick={showDialog}>{modalName == "add" ? "创建推送" : "修改"}</div>
<Modal
title={modalName == "add" ? "创建推送" : "修改"}
okText={okText}
cancelText={cancelText} //
visible={visible}
onOk={handleOk}
width={782}
height={720}
afterClose={handleAfterClose}
onCancel={handleCancel}
>
<Spin tip={loadingTip} spinning={isloading}>
<div
style={{
paddingLeft: 16,
display: step == "none" ? "block" : "none",
}}
>
<Form
allowEmpty
labelPosition="left"
labelAlign="left"
labelWidth="90px"
onValueChange={(values) => console.log(values)}
getFormApi={(formApi) => (form.current = formApi)}
>
<Row>
<Col span={12}>
<Form.Input
maxLength="39"
field="serialNo"
label="设备编号:"
initValue={pushData.serialNo || ""}
placeholder="请输入设备编号"
style={{ width: 149 }}
rules={[{ required: true, message: "请输入设备编号" }]}
/>
</Col>
<Col span={12}>
<Form.InputNumber
formatter={(value) => `${value}`.replace(/\D/g, "")}
hideButtons={true}
maxLength="15"
field="regionCode"
label="行政区区码:"
initValue={pushData.regionCode || ""}
placeholder="请输入行政区区码"
style={{ width: 149 }}
/>
</Col>
<Col span={24}>
<Form.Input
maxLength="36"
field="name"
label="设备名称:"
initValue={pushData.name || ""}
placeholder="请输入设备名称"
style={{ width: 421 }}
rules={[
{
required: true,
message: "请输入设备名称、常用项目或位置定义",
},
]}
/>
</Col>
<Col span={24}>
<Form.Select
label="设备厂家:"
field="venderId"
initValue={pushData.venderId || null}
placeholder="请选择设备厂家"
style={{ width: 421 }}
rules={[{ required: true, message: "请选择设备厂家" }]}
>
{vender.map((item, index) => (
<Form.Select.Option key={index} value={item.id}>
{item.name}
</Form.Select.Option>
))}
</Form.Select>
</Col>
<Col span={24} style={{ display: "flex" }}>
<Form.Input
maxLength="39"
field="position"
label="安装位置:"
initValue={
pushData.longitude && pushData.latitude
? pushData.longitude + "," + pushData.latitude
: ""
}
placeholder="请输入或拾取高德经纬度坐标"
style={{ width: 386 }}
validate={positionForm}
rules={[
{
required: true,
message: "请输入或拾取高德经纬度坐标",
},
]}
/>
<div
style={{
width: 32,
height: 32,
background: "#1859C1",
marginLeft: 4,
display: "flex",
justifyContent: "center",
alignItems: "center",
cursor: "pointer",
marginTop: 12,
borderRadius: 3 + "px",
}}
onClick={handleLocation}
>
<img
src="../../../assets/images/background/location.png"
width={16}
height={20}
/>
</div>
</Col>
</Row>
</Form>
</div>
<div style={{ height: 224, display: step }}>
<div
style={{
paddingTop: 50,
display: "flex",
justifyContent: "center",
}}
>
<IconTickCircle style={{ color: "#04B234", fontSize: 60 }} />
</div>
<div
style={{
marginTop: 20,
display: "flex",
justifyContent: "center",
}}
>
是否确认创建推送
</div>
</div>
</Spin>
</Modal>
</>
);
}
function mapStateToProps (state) {
const { auth, global, members, vender } = state;
return {
loading: members.isRequesting,
user: auth.user,
actions: global.actions,
members: members.data,
vender: vender.data || [], //
};
}
export default connect(mapStateToProps)(pushModal);

570
code/VideoAccess-VCMP/web/client/src/sections/offline/containers/carrierpigeon.jsx

@ -1,20 +1,566 @@
import React, { useEffect } from 'react'; import React, { useState, useEffect, useRef } from "react";
import { connect } from 'react-redux'; import { connect } from "react-redux";
import { Coming } from '$components' import moment from "moment";
import '../style.less' import { Button, Form, Table, Pagination, Skeleton, Popconfirm, Popover, Tag, } from "@douyinfe/semi-ui";
import "../style.less";
import { ApiTable } from "$utils";
import { Setup } from "$components";
import PushModal from "../components/pushModal";
// import SideSheets from "../components/sideSheet";
// import { skeletonScreen } from "../components/skeletonScreen";
// import { ReminderBox } from "../../../components/index";
export const accessType = [
{ name: "萤石云", key: "yingshi" },
{ name: "NVR", key: "nvr" },
{ name: "IPC", key: "ipc" },
{ name: "级联", key: "cascade" },
];
const Carrierpigeon = (props) => { const Carrierpigeon = (props) => {
const { history, dispatch, actions, user, loading, equipmentWarehouseNvr } = props;
const { equipmentWarehouse } = actions;
const [setup, setSetup] = useState(false);
const [sideSheet, setSideSheet] = useState(false);
const [setupp, setSetupp] = useState([]);
const [venderList, setvenderList] = useState([]); //
const [query, setQuery] = useState({ limit: 10, page: 0 }); //
const [search, setearch] = useState({}); //
const [rowId, setRowId] = useState(); //id
const [reminder, setReminder] = useState(false); //
const api = useRef();
const searchData = useRef(search)
const limits = useRef(); //
const page = useRef(query.page);
const PIGEON = "pigeon";
const USER = "user" + props.user.id
const nvrRef = useRef(); //
const tableList = [//
{
title: '推送信息',
list: [
{ name: "策略类型", value: "PolicyType" },
{ name: "推送机制", value: "PushMechanism" },
{ name: "监听设备数量", value: "DevicesNumber" },
{ name: "累计推送次数", value: "PushNumber" },
]
},
];
useEffect(() => {
dispatch(actions.equipmentWarehouse.getVender()).then((res) => {
setvenderList(res.payload.data);
attribute(res.payload.data);
});
//
localStorage.getItem(PIGEON) == null
? localStorage.setItem(
PIGEON,
JSON.stringify(["PolicyType", "PushMechanism", "DevicesNumber", "PushNumber"])
)
: "";
}, []);
return ( useEffect(() => {
<Coming /> equipmentGetNvr();
) }, [query, search]);
}
const equipmentGetNvr = () => {
searchData.current = { ...query, ...search }
dispatch(equipmentWarehouse.getNvr(searchData.current)).then((res) => {
limits.current = res.payload.data.data.length
});
}
function equipmentStatus (data) {
switch (data) {
case "email":
return "邮件通知"
case "note":
return "短信通知"
default:
return "未知"
}
}
function colorStatus (data) {
switch (data) {
case "ON":
return "#04B234"
case "ONLINE":
return "#04B234"
case "OFF":
return "rgba(0, 0, 0, 0.45)"
default:
return "#1859C1"
}
}
const columns = [
{
title: "序号",
render: (_, record, index) => {
return index + 1;
},
},
{
title: "策略名称",
dataIndex: "name",
render: (_, r, index) => {
console.log("r:" + r.name);
return r.name
},
},
{
title: "操作",
width: "20%",
dataIndex: "",
render: (_, row) => {
return (
<div style={{ display: "flex" }}>
<Button theme="borderless">
<PushModal
modalName="revise"
/>
</Button>
<Button
theme="borderless"
onClick={() => {
setSideSheet(true);
setRowId(row.id);
}}
>
禁用
</Button>
<Popconfirm
title="是否确定删除?"
arrowPointAtCenter={false}
showArrow={true}
position="topRight"
onConfirm={() => {
dispatch(equipmentWarehouse.delNvr(row.id)).then(() => {
if (page.current > 0 && limits.current < 2) {
setQuery({ limit: 10, page: page.current - 1 })
} else {
setQuery({ limit: 10, page: page.current })
}
});
}}
>
<Button theme="borderless">删除</Button>
</Popconfirm>
<Button theme="borderless">
复制
</Button>
<Button theme="borderless">
日志
</Button>
</div>
);
},
},
];
//
function attribute (data) {
const arr = localStorage.getItem(PIGEON)
? JSON.parse(localStorage.getItem(PIGEON))
: [];
const column = [
{
title: "推送机制",
dataIndex: "venderId",
key: "PushMechanism",
render: (_, r, index) => {
let manufactorName = data.find((item) => item.id == r.venderId);
return manufactorName ? manufactorName.name : "";
},
},
{
title: "监听设备数量",
dataIndex: "DevicesNum",
key: "DevicesNumber",
render: (_, r, index) => {
return r.name
},
},
{
title: "累计推送次数",
dataIndex: "PushNum",
key: "PushNumber",
render: (_, r, index) => {
return (r.name + '次')
},
},
{
title: "策略类型",
dataIndex: "size",
key: "PolicyType",
render: (_, r, index) => {
let status = r.gbNvr;
return (
<div>
<span
style={{
width: 8,
height: 8,
display: "inline-block",
borderRadius: "50%",
backgroundColor: status ? colorStatus(status.online) : "",
margin: "0 8px 0 0",
}}
/>
{status ? "邮件通知" : equipmentStatus(status.email)}
</div>
);
},
},
];
for (let i = 0; i < arr.length; i++) {
let colum = column.filter((item) => {
return item.key === arr[i];
});
columns.splice(i + 2, 0, colum[0]);
}
setSetupp(columns);
}
//station
// function station (r, name, projects) {
// let data = []
// if (projects == "projects") {
// r.station.map((v) => {
// if (v.structure.projects.length > 0) {
// v.structure.projects.map((item) => data.push(item[name]))
// }
// })
// } else {
// r.station.map((v, index) => data.push(v.structure[name]))
// }
// let dataSet = [...(new Set(data))]
// return dataSet.length > 0 ? <Popover
// key="updateTime"
// position="top"
// content={
// dataSet.length > 1 ? <article style={{ padding: 12 }}>{dataSet.map((v, index) => <div key={index}>{v}</div>)}</article> : ""
// }
// >
// <Tag>{dataSet.length > 1 ? `${dataSet[0]}...` : dataSet.length > 0 ? dataSet[0] : ""}</Tag>
// </Popover> : ""
// }
//
const screen = {
width: 193,
marginRight: 20,
marginBottom: 16,
color: "rgba(0, 0, 0, 0.65)",
};
return (
<>
<div>
<video
id="nvrBanner"
autoPlay
loop
muted
style={{ width: "100%", objectFit: "cover", height: 171 }}
src="/assets/video/nvr_banner.mp4"
type="video/mp4"
/>
<div style={{ position: "absolute", top: 12 }}>
<div
style={{
fontSize: 22,
paddingTop: 15,
marginLeft: 21,
}}
>
信鸽服务
</div>
<div
style={{
fontSize: 14,
paddingTop: 18,
marginLeft: 20,
}}
>
对设备状态变更进行监听通过短信或邮件通知指定人员
</div>
<div
style={{
fontSize: 14,
marginTop: 28,
marginLeft: 21,
width: 89,
height: 32,
lineHeight: "32px",
textAlign: "center",
backgroundColor: "#D9EAFF",
color: "#1859C1",
cursor: "pointer",
}}
>
<PushModal
modalName="add"
/>
{/* <NvrModal
modalName="add"
venderList={venderList}
nvrRef={nvrRef}
close={() => {
const remind = localStorage.getItem(USER);
console.log(remind)
if (!remind) {
setReminder(true)
}
equipmentGetNvr();
}}
/> */}
</div>
</div>
</div>
<div
style={{
width: "100%",
background: "#FFFFFF",
borderRadius: 3,
padding: "8px 20px",
marginTop: 20,
}}
>
<div
style={{
height: 22,
fontSize: 16,
fontFamily: "PingFangSC-Medium, PingFang SC",
fontWeight: "bold",
color: " rgba(0, 0, 0, 0.85)",
lineHeight: "22px",
marginBottom: 16,
}}
>
筛选条件
</div>
<div style={{ display: "flex" }}>
<Form
onSubmit={(values) => console.log(values)}
// onValueChange={values=>console.log(values)}
getFormApi={(formApi) => (api.current = formApi)}
layout="horizontal"
style={{ position: "relative", width: "100%", flex: 1 }}
>
<Form.Input
label="策略名称:"
field="keyword"
maxLength="36"
placeholder="请输入策略名称"
labelPosition="left"
style={screen}
/>
<Form.Select
label="策略类型:"
labelPosition="left"
field="PolicyType"
style={screen}
placeholder="全部"
showClear
>
<Form.Select.Option value="ALL">全部</Form.Select.Option>
<Form.Select.Option value="OFF">短信通知</Form.Select.Option>
<Form.Select.Option value="UNKONW">邮件通知</Form.Select.Option>
</Form.Select>
</Form>
<div
style={{
width: 150,
display: "flex",
justifyContent: "flex-end",
alignItems: "flex-end",
}}
>
<Button
theme="solid"
type="primary"
style={{
width: 65,
height: 30,
borderRadius: 3,
marginBottom: 20,
marginRight: 20,
}}
onClick={() => {
api.current.validate().then((v) => {
setearch(v);
setQuery({ limit: 10, page: 0 })
});
}}
>
搜索
</Button>
<Button
theme="light"
type="primary"
style={{
width: 65,
height: 30,
backGround: "#FFFFFF",
borderRadius: 3,
border: "1px solid #D9D9D9",
marginBottom: 20,
}}
onClick={() => {
api.current.reset();
setearch({});
setQuery({ limit: 10, page: 0 })
}}
>
重置
</Button>
</div>
</div>
</div>
<div style={{ background: "#FFFFFF", marginTop: 5 }}>
<div
style={{
width: "100%",
display: "flex",
justifyContent: "space-between",
padding: "13px 20px",
}}
>
<div
style={{
width: 64,
height: 22,
fontSize: 16,
fontfAmily: "PingFangSC-Medium, PingFang SC",
fontWeight: "bold",
color: "rgba(0, 0, 0, 0.85)",
lineHeight: "22px",
}}
>
策略详情
</div>
<div>
<Button
style={{
width: 32,
height: 32,
background: "#D9D9D9",
borderadius: 3,
marginRight: 20,
}}
type="primary"
key="primary"
onClick={() => {
setSetup(true);
}}
>
<img
src="/assets/images/background/setup.png"
alt="设置"
style={{ width: 18, height: 18 }}
/>
</Button>
</div>
</div>
<Skeleton
loading={loading}
// placeholder={skeletonScreen()}
active={true}
>
<Table
columns={setupp.filter((s) => s)}
dataSource={equipmentWarehouseNvr.data}
bordered={false}
empty="暂无数据"
style={{
padding: "0px 20px",
}}
pagination={false}
/>
</Skeleton>
<div
style={{
display: "flex",
justifyContent: "flex-end",
padding: "20px 20px",
}}
>
<span style={{ lineHeight: "30px" }}>
{equipmentWarehouseNvr.total}条策略
</span>
<Pagination
total={equipmentWarehouseNvr.total}
showSizeChanger
currentPage={query.page + 1}
pageSizeOpts={[10, 20, 30, 40]}
onChange={(currentPage, pageSize) => {
setQuery({ limit: pageSize, page: currentPage - 1 });
page.current = currentPage - 1
}}
/>
</div>
{setup ? (
<Setup
tableType={PIGEON}
tableList={tableList}
close={() => {
setSetup(false);
attribute(venderList);
}}
/>
) : (
""
)}
{/* {sideSheet ? (
<SideSheets
visible={true}
rowId={rowId}
accessType={accessType}
venderList={venderList}
close={() => {
setSideSheet(false);
}}
/>
) : (
[]
)} */}
{/* <ReminderBox
title="是否继续添加NVR摄像头?"
wait="再等等"
toadd="去添加"
visible={reminder}
USER={USER}
onOk={() => {
history.push({ pathname: '/equipmentWarehouse/camera', query: { addNvr: true, serialNo: nvrRef.current.nvrNumber() } });
localStorage.setItem('vcmp_selected_sider', JSON.stringify("camera"))
setReminder(false)
}}
close={() => {
setReminder(false)
}}
/> */}
</div>
</>
);
};
function mapStateToProps (state) { function mapStateToProps (state) {
const { auth } = state; const { auth, global, members, equipmentWarehouseNvr } = state;
return { return {
user: auth.user, loading: equipmentWarehouseNvr.isRequesting && !equipmentWarehouseNvr.data,
}; user: auth.user,
actions: global.actions,
members: members.data,
equipmentWarehouseNvr: equipmentWarehouseNvr.data || {},
};
} }
export default connect(mapStateToProps)(Carrierpigeon); export default connect(mapStateToProps)(Carrierpigeon);

554
code/VideoAccess-VCMP/web/client/src/sections/offline/containers/statuscode.jsx

@ -1,20 +1,550 @@
import React, { useEffect } from 'react'; import React, { useState, useEffect, useRef } from "react";
import { connect } from 'react-redux'; import { connect } from "react-redux";
import { Coming } from '$components' import moment from "moment";
import '../style.less' import { Button, Form, Table, Pagination, Skeleton, Popconfirm, Popover, Tag, } from "@douyinfe/semi-ui";
import { IconSort,IconCaretdown,IconCaretup } from '@douyinfe/semi-icons';
import "../style.less";
import {Setup} from "$components";
import ProgrammeModal from "../components/programmeModal";
import NotesModal from "../components/notesModal";
// import { skeletonScreen } from "../components/skeletonScreen";
export const accessType = {
"yingshi": "萤石云",
"nvr": "NVR",
"ipc": "IPC",
"cascade": "级联"
};
const Statuscode = (props) => { const Statuscode = (props) => {
const { history, dispatch, actions, user, loading, StatusList } = props;
const { offline } = actions;
const [setup, setSetup] = useState(false);//
const [programme, setProgramme] = useState(false);//
const [notes, setNotes] = useState(false);//
const [setupp, setSetupp] = useState([]);
const [query, setQuery] = useState({ limit: 10, page: 0 }); //
const [search, setearch] = useState({}); //
const [rowId, setRowId] = useState(); //id
const api = useRef();
const searchData = useRef(search)
const page = useRef(query.page);
const CODE = "code";
const [nodesAll, setNodesAll] = useState(true);//
const [mysorter, setMysorter] = useState(true);//
const sorter = useRef(false);//
const [resolve, setResolve] = useState([]);//
const [tableNews, setTableNews] = useState([]);//
const tableList = [//
{
title:'状态码信息',
list:[
{ name: "常规解决方案", value: "resolve" },
{ name: "状态频率", value: "logCount" },
]
},
];
useEffect(() => {
//
attribute();
localStorage.getItem(CODE) == null
? localStorage.setItem(
CODE,
JSON.stringify(["resolve", "logCount"])
)
: "";
}, [sorter.current]);
return ( useEffect(() => {
<Coming /> codegetStatus();
) }, [query, search]);
}
const codegetStatus = () => {
searchData.current = { ...query, ...search }
dispatch(offline.getStatus(searchData.current)).then((res) => {
});
}
const columns = [
{
title: "状态码",
dataIndex: "status",
render: (_, record, index) => {
return record.status
},
},
{
title: "平台",
dataIndex: "platform",
render: (_, r, index) => {
let platform=r.platform
return accessType[platform]
},
},
{
title: "错误描述",
dataIndex: "describe",
render: (_, r, index) => {
return r.describe
},
},
{
title: "释义",
dataIndex: "paraphrase",
render: (_, r, index) => {
return r.paraphrase
},
},
{
title: "我的自定义释义",
dataIndex: "paraphraseCustom",
render: (_, r, index) => {
return r.paraphraseCustom
},
},
{
title: "操作",
width: "20%",
dataIndex: "",
render: (_, row) => {
return (
<div style={{ display: "flex" }}>
{row.forbidden ? (
<Button
theme="borderless"
onClick={() => {
dispatch(
offline.putStatueBanned(
{
statusId: row.id,
forbidden: !row.forbidden,
},
row.forbidden
)
).then(() => {
codegetStatus();
});
}}
>
启用
</Button>
) : (
<Popconfirm
title="禁用后下级业务系统将无法获取该视频流的所有信息。"
arrowPointAtCenter={false}
showArrow={true}
position="topRight"
onConfirm={() => {
dispatch(
offline.putStatueBanned(
{
statusId: row.id,
forbidden: !row.forbidden,
},
row.forbidden
)
).then(() => {
codegetStatus();
});
}}
>
<Button theme="borderless">禁用</Button>
</Popconfirm>
)}
<Button
theme="borderless"
onClick={() => {
setNotes(true);
setNodesAll(false);
setTableNews(row);
setRowId(row.id);
}}
>
释义
</Button>
<Button theme="borderless"
onClick={() => {
setProgramme(true);
setRowId(row.id);
setResolve(row.resolve);
}}>
方案
</Button>
</div>
);
},
},
];
function tosorter(){
setMysorter(false)
if(sorter.current=="descend"){
searchData.current = { ...query, ...search, orderDirection:'ASC',orderBy:'logCount'}
dispatch(offline.getStatus(searchData.current)).then((res) => {
sorter.current='ascend'
setMysorter('ascend')
});
}
else if(sorter.current=="ascend"){
searchData.current = { ...query, ...search}
dispatch(offline.getStatus(searchData.current)).then((res) => {
sorter.current=''
setMysorter('')
});
}
else{
searchData.current = { ...query, ...search, orderDirection:'DESC',orderBy:'logCount'}
dispatch(offline.getStatus(searchData.current)).then((res) => {
sorter.current='descend'
setMysorter('descend')
});
}
}
//
function attribute () {
const arr = localStorage.getItem(CODE)
? JSON.parse(localStorage.getItem(CODE))
: [];
const column = [
{
title: "常规解决方案",
dataIndex: "resolve",
key:'resolve',
render: (_, r, index) => {
let myresolve=''
if(r.resolve.length>0){
let myresolveList=[];
for (let index = 0; index < r.resolve.length; index++) {
if(r.resolve[index]&&r.resolve[index].resolve){
myresolveList.push(r.resolve[index].resolve)
}
}
myresolve=myresolveList.join(';');
}
return myresolve
},
},
{
title:(<span onClick={tosorter}>
状态频率近30日
{mysorter=='descend'?<IconCaretdown />:mysorter=='ascend'?<IconCaretup />:<IconSort />}
</span>),
dataIndex: "logCount",
key:'logCount',
render: (_, r, index) => {
return r.logCount
},
},
];
let mycolumns=columns
for (let i = 0; i < arr.length; i++) {
let colum = column.filter((item) => {
return item.key === arr[i];
});
mycolumns.splice(i + 5, 0, colum[0]);
}
setSetupp(mycolumns);
}
//
const screen = {
width: 193,
marginRight: 20,
marginBottom: 16,
color: "rgba(0, 0, 0, 0.65)",
};
return (
<>
<div>
<video
id="nvrBanner"
autoPlay
loop
muted
style={{ width: "100%", objectFit: "cover", height: 171 }}
src="/assets/video/nvr_banner.mp4"
type="video/mp4"
/>
<div style={{ position: "absolute", top: 12 }}>
<div
style={{
fontSize: 22,
paddingTop: 15,
marginLeft: 21,
}}
>
状态码管理
</div>
<div
style={{
fontSize: 14,
paddingTop: 18,
marginLeft: 20,
}}
>
系统支持状态码显示内容的释义修改当设备异常时会为您显示自定义释义内容
</div>
</div>
</div>
<div
style={{
width: "100%",
background: "#FFFFFF",
borderRadius: 3,
padding: "8px 20px",
marginTop: 20,
}}
>
<div
style={{
height: 22,
fontSize: 16,
fontFamily: "PingFangSC-Medium, PingFang SC",
fontWeight: "bold",
color: " rgba(0, 0, 0, 0.85)",
lineHeight: "22px",
marginBottom: 16,
}}
>
筛选条件
</div>
<div style={{ display: "flex" }}>
<Form
onSubmit={(values) => console.log(values)}
// onValueChange={values=>console.log(values)}
getFormApi={(formApi) => (api.current = formApi)}
layout="horizontal"
style={{ position: "relative", width: "100%", flex: 1 }}
>
<Form.Input
label="释义搜索:"
field="keyword"
maxLength="36"
placeholder="请输入错误描述、释义或自定义释义"
labelPosition="left"
style={screen}
/>
<Form.Select
label="启用状态:"
labelPosition="left"
style={screen}
field="forbidden"
placeholder="全部"
showClear
>
<Form.Select.Option value="">全部</Form.Select.Option>
<Form.Select.Option value="false">启用</Form.Select.Option>
<Form.Select.Option value="true">禁用</Form.Select.Option>
</Form.Select>
<Form.Select
label="状态查询:"
labelPosition="left"
field="paraphraseCustom"
style={screen}
placeholder="全部"
showClear
>
<Form.Select.Option value="">全部</Form.Select.Option>
<Form.Select.Option value="false">已设置</Form.Select.Option>
<Form.Select.Option value="true">未设置</Form.Select.Option>
</Form.Select>
</Form>
<div
style={{
width: 150,
display: "flex",
justifyContent: "flex-end",
alignItems: "flex-end",
}}
>
<Button
theme="solid"
type="primary"
style={{
width: 65,
height: 30,
borderRadius: 3,
marginBottom: 20,
marginRight: 20,
}}
onClick={() => {
api.current.validate().then((v) => {
setearch(v);
setQuery({ limit: 10, page: 0 })
});
}}
>
搜索
</Button>
<Button
theme="light"
type="primary"
style={{
width: 65,
height: 30,
backGround: "#FFFFFF",
borderRadius: 3,
border: "1px solid #D9D9D9",
marginBottom: 20,
}}
onClick={() => {
api.current.reset();
setearch({});
setQuery({ limit: 10, page: 0 })
}}
>
重置
</Button>
</div>
</div>
</div>
<div style={{ background: "#FFFFFF", marginTop: 5 }}>
<div
style={{
width: "100%",
display: "flex",
justifyContent: "space-between",
padding: "13px 20px",
}}
>
<div
style={{
width: 84,
height: 22,
fontSize: 16,
fontfAmily: "PingFangSC-Medium, PingFang SC",
fontWeight: "bold",
color: "rgba(0, 0, 0, 0.85)",
lineHeight: "22px",
}}
>
状态码详情
</div>
<div>
<Button
style={{
width: 32,
height: 32,
background: "#D9D9D9",
borderadius: 3,
marginRight: 20,
}}
type="primary"
key="primary"
onClick={() => {
setSetup(true);
}}
>
<img
src="/assets/images/background/setup.png"
alt="设置"
style={{ width: 18, height: 18 }}
/>
</Button>
<Button
theme="solid"
type="primary"
style={{
width: 65,
height: 32,
borderRadius: 3,
}}
onClick={() => {
setNotes(true);
setNodesAll(true);
setTableNews([]);
}}
>
批量设置
</Button>
</div>
</div>
<Skeleton
loading={loading}
// placeholder={skeletonScreen()}
active={true}
>
<Table
columns={setupp.filter((s) => s)}
dataSource={StatusList.rows}
bordered={false}
empty="暂无数据"
style={{
padding: "0px 20px",
}}
pagination={false}
/>
</Skeleton>
<div
style={{
display: "flex",
justifyContent: "flex-end",
padding: "20px 20px",
}}
>
<span style={{ lineHeight: "30px" }}>
{StatusList.count}个状态码
</span>
<Pagination
total={StatusList.count}
showSizeChanger
currentPage={query.page + 1}
pageSizeOpts={[10, 20, 30, 40]}
onChange={(currentPage, pageSize) => {
setQuery({ limit: pageSize, page: currentPage - 1 });
page.current = currentPage - 1
}}
/>
</div>
{setup ? (
<Setup
tableType={CODE}
tableList={tableList}
close={() => {
setSetup(false);
attribute();
}}
/>
) : (
""
)}
{programme&&<ProgrammeModal
rowId={rowId}
resolve={resolve}
close={() => {
setProgramme(false);
setRowId();
codegetStatus();
}}
/>}
{notes&&<NotesModal
rowId={rowId}
nodesAll={nodesAll}
tableNews={tableNews}
close={() => {
setNotes(false);
setRowId();
codegetStatus();
}}
/>}
</div>
</>
);
};
function mapStateToProps (state) { function mapStateToProps (state) {
const { auth } = state; const { auth, global, members, StatusList } = state;
return { return {
user: auth.user, loading: StatusList.isRequesting && !StatusList.data,
}; user: auth.user,
actions: global.actions,
members: members.data,
StatusList: StatusList.data || {},
};
} }
export default connect(mapStateToProps)(Statuscode); export default connect(mapStateToProps)(Statuscode);

6
code/VideoAccess-VCMP/web/client/src/utils/webapi.js

@ -39,6 +39,12 @@ export const ApiTable = {
getCascadeStream: "camera/cascade_stream", //获取级联视频流 getCascadeStream: "camera/cascade_stream", //获取级联视频流
uploadYingshiVoice: 'camera/yingshi_voice/upload', //上传萤石语音 uploadYingshiVoice: 'camera/yingshi_voice/upload', //上传萤石语音
postCameraRemark: 'camera/remark',//编辑摄像头备注 postCameraRemark: 'camera/remark',//编辑摄像头备注
//获取状态码
getStatus: 'status',//获取状态码
putStatueBanned:'status/banned',//禁用状态码自定义
postStatusResolve:'status/resolve',//编辑解决方案
postStatusCustom:'status/custom',//自定义状态码释义
getStatusSimpleAll:'status/simple_all',//获取全部状态码简略信息
}; };
export const VideoServeApi = { export const VideoServeApi = {

4
code/VideoAccess-VCMP/web/config.js

@ -12,6 +12,7 @@ dev && console.log('\x1B[33m%s\x1b[0m', '请遵循并及时更新 readme.md,
// // 启动参数 // // 启动参数
args.option(['p', 'port'], '启动端口'); args.option(['p', 'port'], '启动端口');
args.option(['u', 'api-url'], 'webapi的URL'); args.option(['u', 'api-url'], 'webapi的URL');
args.option('apiVcmpUrl', 'webapi的URL 外网可访问');
args.option('apiAuthUrl', 'IOT 鉴权 api'); args.option('apiAuthUrl', 'IOT 鉴权 api');
args.option('apiAnxinyunUrl', '安心云 api'); args.option('apiAnxinyunUrl', '安心云 api');
args.option('iotAuthWeb', 'IOT 鉴权 web'); args.option('iotAuthWeb', 'IOT 鉴权 web');
@ -20,6 +21,7 @@ args.option('iotVideoServer', 'IOT 后端视频服务鉴权');
const flags = args.parse(process.argv); const flags = args.parse(process.argv);
const API_URL = process.env.API_URL || flags.apiUrl; const API_URL = process.env.API_URL || flags.apiUrl;
const API_VCMP_URL = process.env.API_VCMP_URL || flags.apiVcmpUrl;
const API_AUTH_URL = process.env.API_AUTH_URL || flags.apiAuthUrl; const API_AUTH_URL = process.env.API_AUTH_URL || flags.apiAuthUrl;
const IOT_AUTH_WEB = process.env.IOT_AUTH_WEB || flags.iotAuthWeb; const IOT_AUTH_WEB = process.env.IOT_AUTH_WEB || flags.iotAuthWeb;
const API_ANXINYUN_URL = process.env.API_ANXINYUN_URL || flags.apiAnxinyunUrl; const API_ANXINYUN_URL = process.env.API_ANXINYUN_URL || flags.apiAnxinyunUrl;
@ -68,7 +70,7 @@ const product = {
}, { }, {
entry: require('./routes').entry, entry: require('./routes').entry,
opts: { opts: {
apiUrl: API_URL, apiUrl: API_VCMP_URL,
iotAuthWeb: IOT_AUTH_WEB, iotAuthWeb: IOT_AUTH_WEB,
iotVideoServer: IOT_VIDEO_SERVER, iotVideoServer: IOT_VIDEO_SERVER,
staticRoot: './client', staticRoot: './client',

2
code/VideoAccess-VCMP/web/package.json

@ -7,7 +7,7 @@
"test": "mocha", "test": "mocha",
"start-vite": "cross-env NODE_ENV=developmentVite npm run start-params", "start-vite": "cross-env NODE_ENV=developmentVite npm run start-params",
"start": "cross-env NODE_ENV=development npm run start-params", "start": "cross-env NODE_ENV=development npm run start-params",
"start-params": "node server -p 5000 -u http://10.8.30.7:4000 --apiAuthUrl http://10.8.30.7:4200 --apiAnxinyunUrl http://10.8.30.7:4100 --iotAuthWeb http://localhost:5200 --iotVideoServer http://221.230.55.27:8081", "start-params": "node server -p 5000 -u http://10.8.30.7:4000 --apiVcmpUrl http://localhost:4000 --apiAuthUrl http://10.8.30.7:4200 --apiAnxinyunUrl http://10.8.30.7:4100 --iotAuthWeb http://localhost:5200 --iotVideoServer http://221.230.55.27:8081",
"deploy": "export NODE_ENV=production&& npm run build && node server", "deploy": "export NODE_ENV=production&& npm run build && node server",
"build-dev": "cross-env NODE_ENV=development&&webpack --config webpack.config.js", "build-dev": "cross-env NODE_ENV=development&&webpack --config webpack.config.js",
"build": "export NODE_ENV=production&&webpack --config webpack.config.prod.js" "build": "export NODE_ENV=production&&webpack --config webpack.config.prod.js"

Loading…
Cancel
Save