diff --git a/code/VideoAccess-VCMP/api/app/lib/controllers/status/push.js b/code/VideoAccess-VCMP/api/app/lib/controllers/status/push.js index 2a98d81..2607e74 100644 --- a/code/VideoAccess-VCMP/api/app/lib/controllers/status/push.js +++ b/code/VideoAccess-VCMP/api/app/lib/controllers/status/push.js @@ -2,15 +2,86 @@ const moment = require('moment') async function edit (ctx) { + const transaction = await ctx.fs.dc.orm.transaction(); try { const models = ctx.fs.dc.models; const { userId, token } = ctx.fs.api + const { + configId, name, pushWay, noticeWay, timing, + receiver, cameraId + } = ctx.request.body; + let configId_ = configId + // 判重 + + + let config = { + name, pushWay, noticeWay, timing + } + if (configId) { + const configRes = await models.CameraStatusConfig.findOne({ + where: { + id: configId + } + }) + if (!configRes) { + throw '参数错误' + } else { + // DO UPDATE + await models.CameraStatusPushConfig.update(config, { + where: { id: configId }, + transaction + }) + await models.CameraStatusPushReceiver.destroy({ + where: { configId }, + transaction + }) + await models.CameraStatusPushMonitor.destroy({ + where: { configId }, + transaction + }) + } + } else { + // DO CREATE + config.createUser = userId + config.forbidden = false + const createConfigRes = await models.CameraStatusPushConfig.create(config, { + transaction + }) + configId_ = createConfigRes.id + } + if (receiver && receiver.length) { + await models.CameraStatusPushReceiver.bulkCreate( + receiver.map(item => ({ + configId: configId_, + receiver: item, + })), + { + transaction + } + ) + } + if (cameraId && cameraId.length) { + await models.CameraStatusPushMonitor.bulkCreate( + cameraId.map(item => ({ + configId: configId_, + cameraId: item, + })), + { + 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 = {} + ctx.body = { + message: typeof error == 'string' ? error : undefined + } } } @@ -18,8 +89,67 @@ async function get (ctx) { try { const models = ctx.fs.dc.models; const { userId, token } = ctx.fs.api + const { limit, page, orderBy, orderDirection, keyword, pushWay } = ctx.query - ctx.status = 204; + const sequelize = ctx.fs.dc.ORM; + let findOption = { + attributes: { + include: [ + [sequelize.fn('COUNT', sequelize.col('cameraStatusPushMonitors.id')), 'monitorCount'], + [sequelize.fn('COUNT', sequelize.col('cameraStatusPushLogs.id')), 'logCount'] + ], + }, + where: {}, + order: [ + [orderBy || 'id', orderDirection || 'DESC'] + ], + distinct: true, + subQuery: false, + group: [ + 'cameraStatusPushConfig.id', + 'cameraStatusPushMonitors.id', + 'cameraStatusPushLogs.id', + 'cameraStatusPushReceivers.id', + ], + include: [ + { + model: models.CameraStatusPushMonitor, + attributes: ['cameraId'], + required: false, + duplicating: true + }, + { + model: models.CameraStatusPushLog, + attributes: [], + duplicating: false, + required: false, + }, + { + model: models.CameraStatusPushReceiver, + attributes: ['receiver'], + duplicating: false, + required: false, + }, + ], + } + if (limit) { + findOption.limit = limit + } + if (page && limit) { + findOption.offset = page * limit + } + if (keyword) { + findOption.where['$or'] = { + name: { + $like: `%${keyword}%` + }, + } + } + + const configRes = await models.CameraStatusPushConfig.findAll(findOption) + + ctx.status = 200; + ctx.body = configRes } catch (error) { ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); ctx.status = 400; @@ -31,6 +161,15 @@ async function banned (ctx) { try { const models = ctx.fs.dc.models; const { userId, token } = ctx.fs.api + const data = ctx.request.body; + + await models.CameraStatusPushConfig.update({ + forbidden: data.forbidden + }, { + where: { + id: data.configId + } + }) ctx.status = 204; } catch (error) { @@ -41,12 +180,35 @@ async function banned (ctx) { } async function del (ctx) { + const transaction = await ctx.fs.dc.orm.transaction(); try { const models = ctx.fs.dc.models; const { userId, token } = ctx.fs.api + const { configId } = ctx.params; + + await models.CameraStatusPushReceiver.destroy({ + where: { + configId + }, + transaction + }) + await models.CameraStatusPushMonitor.destroy({ + where: { + configId + }, + transaction + }) + await models.CameraStatusPushConfig.destroy({ + where: { + id: configId + }, + 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 = {} @@ -54,32 +216,118 @@ async function del (ctx) { } async function copy (ctx) { + const transaction = await ctx.fs.dc.orm.transaction(); try { const models = ctx.fs.dc.models; const { userId, token } = ctx.fs.api + const { configId } = ctx.params; - ctx.status = 204; + const configRes = await models.CameraStatusPushConfig.findOne({ + where: { + id: configId + }, + include: [ + { + model: models.CameraStatusPushMonitor, + attributes: ['cameraId'], + required: false, + duplicating: true + }, + { + model: models.CameraStatusPushLog, + attributes: [], + duplicating: false, + required: false, + }, + { + model: models.CameraStatusPushReceiver, + attributes: ['receiver'], + duplicating: false, + required: false, + }, + ], + }) + + if (!configRes) { + throw '参数错误' + } + + let copyConfig = JSON.parse(JSON.stringify(configRes.dataValues)) + let returnConfig = JSON.parse(JSON.stringify(configRes.dataValues)) + delete copyConfig.id + delete copyConfig.id + let cameraStatusPushMonitors = copyConfig.cameraStatusPushMonitors + let cameraStatusPushReceiver = copyConfig.cameraStatusPushReceivers + delete copyConfig.cameraStatusPushMonitors + delete copyConfig.cameraStatusPushReceivers + copyConfig.createUser = userId + let newConfig = await models.CameraStatusPushConfig.create(copyConfig, { + transaction + }) + + if (cameraStatusPushMonitors && cameraStatusPushMonitors.length) { + await models.CameraStatusPushMonitor.bulkCreate( + cameraStatusPushMonitors.map(item => ({ + configId: newConfig.id, + cameraId: item.cameraId, + })), + { + transaction + } + ) + } + if (cameraStatusPushReceiver && cameraStatusPushReceiver.length) { + await models.CameraStatusPushReceiver.bulkCreate( + cameraStatusPushReceiver.map(item => ({ + configId: newConfig.id, + receiver: item.receiver, + })), + { + transaction + } + ) + } + + returnConfig.id = newConfig.id + + await transaction.commit(); + ctx.status = 200; + ctx.body = returnConfig } catch (error) { + await transaction.rollback(); ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); ctx.status = 400; - ctx.body = {} + ctx.body = { + message: typeof error == 'string' ? error : undefined + } } } -async function detail (ctx) { +async function pushLog (ctx) { try { const models = ctx.fs.dc.models; const { userId, token } = ctx.fs.api + const { configId } = ctx.params; + const sequelize = ctx.fs.dc.ORM; + const logRes = await models.CameraStatusPushLog.findAll({ + where: { + pushConfigId: configId + }, + order: [['time', 'DESC']], + }) - ctx.status = 204; + ctx.status = 200; + ctx.body = logRes } catch (error) { ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); ctx.status = 400; - ctx.body = {} + ctx.body = { + message: typeof error == 'string' ? error : undefined + } } } module.exports = { - edit, get, banned, del, copy, detail + edit, get, banned, del, copy, pushLog }; \ No newline at end of file diff --git a/code/VideoAccess-VCMP/api/app/lib/index.js b/code/VideoAccess-VCMP/api/app/lib/index.js index 40f46c3..b50280c 100644 --- a/code/VideoAccess-VCMP/api/app/lib/index.js +++ b/code/VideoAccess-VCMP/api/app/lib/index.js @@ -63,7 +63,8 @@ module.exports.models = function (dc) { // dc = { orm: Sequelize对象, ORM: Seq const { Nvr, Camera, CameraAbility, CameraAbilityBind, CameraKind, CameraRemark, - GbCamera, SecretYingshi, Vender, CameraStatus, CameraStatusResolve, CameraStatusLog + GbCamera, SecretYingshi, Vender, CameraStatus, CameraStatusResolve, CameraStatusLog, + CameraStatusPushConfig, CameraStatusPushMonitor, CameraStatusPushLog, CameraStatusPushReceiver, } = dc.models; // Nvr.belongsTo(User, { foreignKey: 'userId', targetKey: 'id' }); @@ -100,4 +101,13 @@ module.exports.models = function (dc) { // dc = { orm: Sequelize对象, ORM: Seq CameraStatusLog.belongsTo(CameraStatus, { foreignKey: 'statusId', targetKey: 'id' }); CameraStatus.hasMany(CameraStatusLog, { foreignKey: 'statusId', sourceKey: 'id' }); + + CameraStatusPushMonitor.belongsTo(CameraStatusPushConfig, { foreignKey: 'configId', targetKey: 'id' }); + CameraStatusPushConfig.hasMany(CameraStatusPushMonitor, { foreignKey: 'configId', sourceKey: 'id' }); + + CameraStatusPushLog.belongsTo(CameraStatusPushConfig, { foreignKey: 'pushConfigId', targetKey: 'id' }); + CameraStatusPushConfig.hasMany(CameraStatusPushLog, { foreignKey: 'pushConfigId', sourceKey: 'id' }); + + CameraStatusPushReceiver.belongsTo(CameraStatusPushConfig, { foreignKey: 'configId', targetKey: 'id' }); + CameraStatusPushConfig.hasMany(CameraStatusPushReceiver, { foreignKey: 'configId', sourceKey: 'id' }); }; diff --git a/code/VideoAccess-VCMP/api/app/lib/models/camera_status_push_config.js b/code/VideoAccess-VCMP/api/app/lib/models/camera_status_push_config.js index da64099..828a2ec 100644 --- a/code/VideoAccess-VCMP/api/app/lib/models/camera_status_push_config.js +++ b/code/VideoAccess-VCMP/api/app/lib/models/camera_status_push_config.js @@ -2,78 +2,78 @@ '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; + 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.ARRAY(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; }; \ No newline at end of file diff --git a/code/VideoAccess-VCMP/api/app/lib/models/camera_status_push_log.js b/code/VideoAccess-VCMP/api/app/lib/models/camera_status_push_log.js index 10ff326..1a8d9c7 100644 --- a/code/VideoAccess-VCMP/api/app/lib/models/camera_status_push_log.js +++ b/code/VideoAccess-VCMP/api/app/lib/models/camera_status_push_log.js @@ -2,60 +2,78 @@ '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; + 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.ARRAY(DataTypes.STRING), + 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 + }, + camera: { + type: DataTypes.ARRAY(DataTypes.INTEGER), + allowNull: false, + defaultValue: null, + comment: null, + primaryKey: false, + field: "camera", + autoIncrement: false + }, + timing: { + type: DataTypes.STRING, + allowNull: true, + defaultValue: null, + comment: "定时推送时间", + primaryKey: false, + field: "timing", + autoIncrement: false + } + }, { + tableName: "camera_status_push_log", + comment: "", + indexes: [] + }); + dc.models.CameraStatusPushLog = CameraStatusPushLog; + return CameraStatusPushLog; }; \ No newline at end of file diff --git a/code/VideoAccess-VCMP/api/app/lib/models/camera_status_push_receiver.js b/code/VideoAccess-VCMP/api/app/lib/models/camera_status_push_receiver.js index 48d68ce..53a34ee 100644 --- a/code/VideoAccess-VCMP/api/app/lib/models/camera_status_push_receiver.js +++ b/code/VideoAccess-VCMP/api/app/lib/models/camera_status_push_receiver.js @@ -2,46 +2,46 @@ '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" + 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 } - }, - 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; + }, { + tableName: "camera_status_push_receiver", + comment: "", + indexes: [] + }); + dc.models.CameraStatusPushReceiver = CameraStatusPushReceiver; + return CameraStatusPushReceiver; }; \ No newline at end of file diff --git a/code/VideoAccess-VCMP/api/app/lib/routes/status/index.js b/code/VideoAccess-VCMP/api/app/lib/routes/status/index.js index 61394f9..0b8083d 100644 --- a/code/VideoAccess-VCMP/api/app/lib/routes/status/index.js +++ b/code/VideoAccess-VCMP/api/app/lib/routes/status/index.js @@ -23,8 +23,8 @@ module.exports = function (app, router, opts) { 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['PUT/status/push'] = { content: '编辑推送配置', visible: false }; + router.put('/sasdtatus/push', push.edit); app.fs.api.logAttr['GET/status/push'] = { content: '获取推送配置', visible: false }; router.get('/status/push', push.get); @@ -32,13 +32,13 @@ module.exports = function (app, router, opts) { 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['DEL/status/push/:configId'] = { content: '删除推送配置', visible: false }; + router.del('/status/push/:configId', 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/:configId/copy'] = { content: '复制推送配置', visible: false }; + router.get('/status/push/:configId/copy', push.copy); - app.fs.api.logAttr['GET/status/push/:pushId/detail'] = { content: '获取推送配置详情', visible: false }; - router.get('/status/push/:pushId/detail', push.detail); + app.fs.api.logAttr['GET/status/push/:configId/detail'] = { content: '获取推送记录', visible: false }; + router.get('/status/push/:configId/log', push.pushLog); // 信鸽推送 END }; diff --git a/code/VideoAccess-VCMP/api/app/lib/schedule/cameraStatePush.js b/code/VideoAccess-VCMP/api/app/lib/schedule/cameraStatePush.js new file mode 100644 index 0000000..72c389e --- /dev/null +++ b/code/VideoAccess-VCMP/api/app/lib/schedule/cameraStatePush.js @@ -0,0 +1,23 @@ +const moment = require('moment') + +module.exports = function (app, opts) { + const cameraOnlinePush = app.fs.scheduleInit( + { + // interval: '* * 4 * * *', + interval: '*/15 * * * *', + immediate: false, + }, + async () => { + try { + + console.log('cameraOnlinePush') + } catch (error) { + + } + } + ) + + return { + cameraOnlinePush, + } +} \ No newline at end of file diff --git a/code/VideoAccess-VCMP/script/1.1.2/schema/1.update_camera_status_config.sql b/code/VideoAccess-VCMP/script/1.1.2/schema/1.update_camera_status_config.sql new file mode 100644 index 0000000..f8db2b1 --- /dev/null +++ b/code/VideoAccess-VCMP/script/1.1.2/schema/1.update_camera_status_config.sql @@ -0,0 +1,21 @@ +alter table camera_status_push_config alter column notice_way type varchar[32] using notice_way::varchar[32]; + + + +DROP TABLE if exists camera_status_push_log +create table if not exists camera_status_push_log +( + id serial not null, + push_config_id integer, + time timestamp, + push_way varchar(128) not null, + camera integer[] not null, + receiver character varying[] 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);