From 4815c20e84e2e918e7099b3a83dbcfd586f7d306 Mon Sep 17 00:00:00 2001 From: liujiangyong Date: Tue, 22 Aug 2023 18:37:03 +0800 Subject: [PATCH] =?UTF-8?q?(*)=20=E6=B6=88=E9=98=B2-=E8=AE=BE=E5=A4=87?= =?UTF-8?q?=E7=BB=9F=E8=AE=A1=E3=80=81=E7=81=AB=E6=83=85=E8=B6=8B=E5=8A=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/.vscode/launch.json | 1 + api/app/lib/controllers/superScreen/fire.js | 49 ++- api/app/lib/middlewares/authenticator.js | 2 + api/app/lib/routes/superScreen/fire.js | 8 + api/config.js | 7 +- .../src/sections/fire-control/actions/fire.js | 20 ++ .../fire-control/components/left-bottom.js | 149 ++++++--- .../fire-control/components/left-middle.js | 285 ++++++++++-------- .../fire-control/components/style.less | 47 +++ .../fire-control/containers/homePage.js | 24 +- super-screen/client/src/utils/webapi.js | 2 + 11 files changed, 417 insertions(+), 177 deletions(-) diff --git a/api/.vscode/launch.json b/api/.vscode/launch.json index 5433cf2..6bf3afa 100644 --- a/api/.vscode/launch.json +++ b/api/.vscode/launch.json @@ -22,6 +22,7 @@ "-d postgres/example/10.8.30.160/30432", "-w https://smartwater.anxinyun.cn", "-a https://smartworksafety.anxinyun.cn", + "--tf http://91mogo.com/onecity/v5", ] }, { diff --git a/api/app/lib/controllers/superScreen/fire.js b/api/app/lib/controllers/superScreen/fire.js index 8bc189a..f39a986 100644 --- a/api/app/lib/controllers/superScreen/fire.js +++ b/api/app/lib/controllers/superScreen/fire.js @@ -1,4 +1,6 @@ 'use strict'; +const request = require("superagent"); +const moment = require("moment"); function getFireAlarmList(opts) { return async function (ctx, next) { @@ -56,8 +58,53 @@ function updateAlarm(opts) { } } +// 获取消防设备 +function getFireDevice(opts) { + return async function (ctx, next) { + let rslt = {}; + try { + let url = `${opts.tfApi}/device/alarm/statistic?_timeStamp=${new Date().getTime()}`; + const res = (await request.get(url).set("X-API-TOKEN", "9911510d-9dae-438d-9b6e-0545ef003c58")).body.data; + rslt = res.items; + ctx.status = 200; + ctx.body = rslt; + } catch (error) { + ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); + ctx.status = 400; + ctx.body = { message: '获取消防设备失败' } + } + } +} + +// 获取火情趋势 +function getFireTrend(opts) { + return async function (ctx, next) { + let rslt = []; + try { + let url = `${opts.tfApi}/alarms/trend?key=1`; + const res = (await request.get(url).set("X-API-TOKEN", "9911510d-9dae-438d-9b6e-0545ef003c58")).body.data; + let start = moment().add(-6, 'day').startOf('day').valueOf(); + let end = moment().endOf('day').valueOf(); + res.map(item => { + const time = moment(item.time).valueOf(); + if (time >= start && time <= end) { + rslt.push({ time: item.time, count: item.val }) + } + }) + ctx.status = 200; + ctx.body = rslt; + } catch (error) { + ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); + ctx.status = 400; + ctx.body = { message: '获取火情趋势失败' } + } + } +} + module.exports = { addAlarm, updateAlarm, - getFireAlarmList + getFireAlarmList, + getFireDevice, + getFireTrend } \ No newline at end of file diff --git a/api/app/lib/middlewares/authenticator.js b/api/app/lib/middlewares/authenticator.js index 07df3ec..cc625f3 100644 --- a/api/app/lib/middlewares/authenticator.js +++ b/api/app/lib/middlewares/authenticator.js @@ -64,6 +64,8 @@ let isPathExcluded = function (opts, path, method) { excludeOpts.push({ p: '/fire/alarm', o: 'GET' }); excludeOpts.push({ p: '/fire/alarm', o: 'POST' }); excludeOpts.push({ p: '/fire/alarm/:id', o: 'PUT' }); + excludeOpts.push({ p: '/fire/device', o: 'GET' }); + excludeOpts.push({ p: '/fire/trend', o: 'GET' }); excludes = new ExcludesUrls(excludeOpts); } diff --git a/api/app/lib/routes/superScreen/fire.js b/api/app/lib/routes/superScreen/fire.js index b134d95..dfa6c17 100644 --- a/api/app/lib/routes/superScreen/fire.js +++ b/api/app/lib/routes/superScreen/fire.js @@ -15,4 +15,12 @@ module.exports = function (app, router, opts, AuthCode) { //修改消防告警状态 app.fs.api.logAttr['PUT/fire/alarm/:id'] = { content: '修改消防告警状态', visible: true }; router.put('/fire/alarm/:id', fire.updateAlarm(opts)); + + //获取消防设备 + app.fs.api.logAttr['GET/fire/device'] = { content: '获取消防设备', visible: true }; + router.get('/fire/device', fire.getFireDevice(opts)); + + //获取火情趋势 + app.fs.api.logAttr['GET/fire/trend'] = { content: '获取火情趋势', visible: true }; + router.get('/fire/trend', fire.getFireTrend(opts)); }; diff --git a/api/config.js b/api/config.js index 155f150..8b4200d 100644 --- a/api/config.js +++ b/api/config.js @@ -15,6 +15,7 @@ args.option(['s', 'kubesphere'], 'kubesphere地址'); args.option(['d', 'dbconfig'], '后台同步数据库host示例:postgres/example/10.8.30.160/30432 格式:用户名/密码/host/port'); args.option(['w', 'water'], '水环境api地址'); args.option(['a', 'worksafety'], '安监api地址'); +args.option('tf', '消防第三方接口 THIRD_FIRECONTROL'); const flags = args.parse(process.argv); @@ -33,7 +34,9 @@ const DATABASE_CONFIG = process.env.DATABASE_HOST || flags.dbconfig;//同步数 const WATER_URL = process.env.WATER_URL || flags.water; const WORKSAFETY_URL = process.env.WORKSAFETY_URL || flags.worksafety; -if (!DB || !BACKUPS_URL || !KUBESPHERE_URL || !DATABASE_CONFIG || !WATER_URL || !WORKSAFETY_URL) { +const THIRD_FIRECONTROL = process.env.THIRD_FIRECONTROL || flags.tf; + +if (!DB || !BACKUPS_URL || !KUBESPHERE_URL || !DATABASE_CONFIG || !WATER_URL || !WORKSAFETY_URL || !THIRD_FIRECONTROL) { console.log('缺少启动参数,异常退出'); args.showHelp(); process.exit(-1); @@ -81,7 +84,7 @@ const product = { backupsUrl: BACKUPS_URL, k8s: KUBESPHERE_URL, dbConfig: DATABASE_CONFIG, - + tfApi: THIRD_FIRECONTROL, } }, { entry: require('./app/lib/middlewares/proxy').entry, diff --git a/super-screen/client/src/sections/fire-control/actions/fire.js b/super-screen/client/src/sections/fire-control/actions/fire.js index 3b5b12c..4a823a0 100644 --- a/super-screen/client/src/sections/fire-control/actions/fire.js +++ b/super-screen/client/src/sections/fire-control/actions/fire.js @@ -40,3 +40,23 @@ export function modifyFireAlarm(id, params) { }, }); } + +export function getFireDevice() { + return dispatch => basicAction({ + type: 'get', + dispatch: dispatch, + actionType: 'GET_FIRE_DEVICE', + url: `${ApiTable.getFireDevice}`, + msg: { error: '获取消防设备失败' }, + }); +} + +export function getFireTrend() { + return dispatch => basicAction({ + type: 'get', + dispatch: dispatch, + actionType: 'GET_FIRE_TREND', + url: `${ApiTable.getFireTrend}`, + msg: { error: '获取火情趋势失败' }, + }); +} diff --git a/super-screen/client/src/sections/fire-control/components/left-bottom.js b/super-screen/client/src/sections/fire-control/components/left-bottom.js index 37af56e..bd25625 100644 --- a/super-screen/client/src/sections/fire-control/components/left-bottom.js +++ b/super-screen/client/src/sections/fire-control/components/left-bottom.js @@ -1,49 +1,114 @@ import React from 'react' -import { Box, AutoRollComponent } from '$components'; +import { Box, NoData } from '$components'; +import ReactEcharts from 'echarts-for-react'; +import moment from 'moment'; function Infrastructure(props) { + const { fireTrend } = props; + let Ydata = fireTrend.map(t => t.count); + let Xdata = fireTrend.map(t => moment(t.time).format('MM月DD日')); - const getContent = () => { - return
-
-
14:22
-
红花岗区大队
-
划龙桥路77号
-
-
-
14:22
-
红花岗区大队
-
划龙桥路77号
-
-
-
14:22
-
红花岗区大队
-
划龙桥路77号
-
-
-
14:22
-
红花岗区大队
-
划龙桥路77号
-
-
-
14:22
-
红花岗区大队
-
划龙桥路77号
-
-
-
14:22
-
红花岗区大队
-
划龙桥路77号
-
-
-
14:22
-
红花岗区大队
-
划龙桥路77号
-
-
- } - return - + const option = { + tooltip: { + trigger: "axis", + axisPointer: { + type: "shadow", + }, + backgroundColor: "rgba(255,255,255,0.75)", + extraCssText: "box-shadow: 2px 2px 4px 0px rgba(0,0,0,0.3);", + textStyle: { + fontSize: 14, + color: "#000", + }, + formatter: (params) => { + const item = params[0]; + return item.name + " : " + item.value + " 次"; + }, + }, + legend: { + top: 10, + itemWidth: 20, + itemHeight: 10, + left: "center", + padding: 0, + textStyle: { + color: "#E6E6E7", + fontSize: 14, + padding: [2, 0, 0, 0], + }, + }, + xAxis: [ + { + type: "category", + axisLabel: { + interval: 0, + color: "rgba(195, 230, 255, 1)", + fontSize: 10, + }, + axisLine: { + show: true, + lineStyle: { + type: 'solid', + color: "rgba(184, 185, 188, 0.5)", + width: 1, + }, + }, + data: Xdata, + }, + ], + yAxis: [ + { + splitNumber: 5, // 刻度段数 + type: "value", + nameTextStyle: { + color: "rgba(195, 230, 255, 1)", + fontWeight: 400, + fontSize: 14, + padding: [-20, 20, 0, 0] + }, + splitLine: { + show: true, + lineStyle: { + type: 'dashed', + color: 'rgba(89, 153, 200, 0.5)' + } + }, + axisLabel: { + show: true, + fontSize: 12, + color: "rgba(195, 230, 255, 1)", + }, + }, + ], + series: [ + { + type: "line", + symbol: "none", + barWidth: 16, + label: { + show: false, + position: "top", + color: "#00A8FF", + }, + data: Ydata, + }, + ], + grid: { + x: 50, + y: 25, + x2: 30, + y2: 20 + }, + }; + return + { + fireTrend.length ? : + } } diff --git a/super-screen/client/src/sections/fire-control/components/left-middle.js b/super-screen/client/src/sections/fire-control/components/left-middle.js index c03c914..2b757ae 100644 --- a/super-screen/client/src/sections/fire-control/components/left-middle.js +++ b/super-screen/client/src/sections/fire-control/components/left-middle.js @@ -1,141 +1,166 @@ import React from 'react' -import { Box } from '$components'; -import ReactEcharts from 'echarts-for-react'; +import { Box, AutoRollComponent, NoData } from '$components'; +// import ReactEcharts from 'echarts-for-react'; +import { Progress } from 'antd'; -function PopulationDynamics() { +function PopulationDynamics(props) { + const { fireDevice } = props; + const total = fireDevice.reduce((p, n) => p + n.device_count, 0); - let Ydata = ['火灾扑救', '抢险救援', '公务执勤', '社会救助', '其他出动']; - let Xdata = [12, 19, 19, 13, 15] - const options = { - xAxis: { - type: 'value', - show: false, - }, - grid: { - left: -10, - top: 20, - bottom: 0, - right: 20, - containLabel: true, - }, - yAxis: [ - { - type: 'category', - inverse: true, - axisLabel: { - show: true, - margin: 25, - // textStyle: { - color: '#ECF7FF', - fontSize: 12, - // }, - // 调整左侧文字的3个属性,缺一不可 - verticalAlign: 'center', - align: 'left', - //调整文字上右下左 - padding: [0, 0, 0, -30], + // let Ydata = fireDevice.map(d => d.type_name); + // let Xdata = fireDevice.map(d => d.device_count); + // const options = { + // xAxis: { + // type: 'value', + // show: false, + // }, + // grid: { + // left: -10, + // top: 20, + // bottom: 0, + // right: 20, + // containLabel: true, + // }, + // yAxis: [ + // { + // type: 'category', + // inverse: true, + // axisLabel: { + // show: true, + // margin: 25, + // // textStyle: { + // color: '#ECF7FF', + // fontSize: 12, + // // }, + // // 调整左侧文字的3个属性,缺一不可 + // verticalAlign: 'center', + // align: 'left', + // //调整文字上右下左 + // padding: [0, 0, 0, -30], + // }, + // splitLine: { + // show: false, + // }, + // axisTick: { + // show: false, + // }, + // axisLine: { + // show: false, + // }, + // data: Ydata + // }, + // { + // inverse: true, + // // y轴最右侧的文字 + // axisTick: "none", + // axisLine: "none", + // type: "category", + // axisLabel: { + // // margin: 10, + // // textStyle: { + // color: "#24DCF7", + // fontSize: "12", + // // }, + // rich: { + // a1: { + // color: '#24DCF7', + // width: 5, + // height: 5, + // fontSize: 16, + // }, + // a2: { + // color: '#5999C8', + // width: 5, + // height: 5, + // fontSize: 12, + // }, + // }, + // formatter: function (value) { + // return [`{a1|${value}} {a2|个}`]; + // }, + // }, + // data: Xdata, + // }, + // ], + // series: [ + // { + // type: 'bar', + // barWidth: 12, + // zlevel: 2, + // z: 2, + // showBackground: true, + // backgroundStyle: { + // color: '#2B375C' + // }, + // color: '#005AC6', - }, - splitLine: { - show: false, - }, - axisTick: { - show: false, - }, - axisLine: { - show: false, - }, - data: Ydata - }, - { - inverse: true, - // y轴最右侧的文字 - axisTick: "none", - axisLine: "none", - type: "category", - axisLabel: { - // margin: 10, - // textStyle: { - color: "#24DCF7", - fontSize: "12", - // }, - rich: { + // label: { + // show: false, - a1: { - color: '#24DCF7', - width: 5, - height: 5, - fontSize: 16, - }, - a2: { - color: '#5999C8', - width: 5, - height: 5, - fontSize: 12, - }, - }, - formatter: function (value) { - return [`{a1|${value}} {a2|次}`]; - }, - }, - data: Xdata, - }, + // }, + // data: Xdata, + // }, + // { + // type: "pictorialBar", + // // symbol: 'image://data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADoAAAA6CAMAAADWZboaAAAAZlBMVEUAAABe3uVe3+Vf3uVf3+Zf3uVg3+Zg3+Zf3+Vi4OZh4OZg3+Z86/Bh3+Zi4Odj4Odi4OZ86/B76/B86/Bj4ed56+9x5+xn4umB7/N87PB36e+A7/N+7fF/7vJ/7vJ+7fGA7/OB7/PReX+lAAAAIXRSTlMABQkVDREmIhk3MR10LEFFPHh7cUprXE35h2XnqMLAp+mHAG9cAAAB5ElEQVRIx83WjU7CMBQFYIoiKMqU/XUboHv/l/Tce7t2XamDNSacETEmX86tlK2rx4py150o+MstMBLwWRfHKo6JCVxLnvmFGBjFQ58oF1//sUZhGy/ClSTWObgnL4O+bkeN4nY2okfNMbkRt9/vtxz8InoTsWplJSCzFxPmO8+GpSIByX3YQAuGDWtRKhKjCnxDXhF6Z4yxnZ20Wgko7BMRDmxtSGVaI4kdTIgb+zTYoJQlIMlDlmUFgrcDWWC201qSayqlTkiCddWWeV62VU0YlnpRi9VOKaSUsiyq/N0krwq2Ugt7lVpZl5BfHNiytjagMi+XYp0kCR45hMlivVQrE/uU5pXSrCB5bM6d1t2lOZItMqmliT3q5uVxqxzyW/ccfYLNKx7ZTeykMvNyac2yt2Fbc61MHLSC0rwoxbiNdlQ3GBm1NLHQsHUrtEXppR/ljNpW6DbSCoqlFiVoN6YdaFlgsSFVPs1BdT8OaB5QyQzVcaqWDows/zepxR8ObLglTrdtCRVuRNj4Rrxh+//0ke2f8KVL+Kon3GCSbmsJN9OUW3j6g0Ns+LgCij2u0h+Sghc8mlMPBMgdx5DFh59VmOVHrvmDnoNxCz3J7MFWsMuaLyR089xz/xhlfijvwutR8gv3zk6BLUUeCgAAAABJRU5ErkJggg==', + // symbolSize: [15, 15], + // symbolOffset: [0, 0], + // symbolPosition: "right", + // z: 20, + // zlevel: 20, + // itemStyle: { + // // normal: { + // color: "#fff" + // // } + // }, + // data: (function () { + // var list = []; + // for (var i = 0; i < Xdata.length; i++) { + // list.push(2.02 * Xdata[i]); + // } + // console.log(list) + // return list; + // })() + // }, + // ], + // }; + const getContent = () => { + return
{ + fireDevice.map(d =>
+
{d.type_name}
+
+ +
+
+
{d.device_count}
+
) + }
+ // + } - ], - series: [ - { - type: 'bar', - barWidth: 12, - zlevel: 2, - z: 2, - showBackground: true, - backgroundStyle: { - color: '#2B375C' - }, - color: '#005AC6', - - label: { - show: false, - - }, - data: Xdata, - }, - { - type: "pictorialBar", - // symbol: 'image://data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADoAAAA6CAMAAADWZboaAAAAZlBMVEUAAABe3uVe3+Vf3uVf3+Zf3uVg3+Zg3+Zf3+Vi4OZh4OZg3+Z86/Bh3+Zi4Odj4Odi4OZ86/B76/B86/Bj4ed56+9x5+xn4umB7/N87PB36e+A7/N+7fF/7vJ/7vJ+7fGA7/OB7/PReX+lAAAAIXRSTlMABQkVDREmIhk3MR10LEFFPHh7cUprXE35h2XnqMLAp+mHAG9cAAAB5ElEQVRIx83WjU7CMBQFYIoiKMqU/XUboHv/l/Tce7t2XamDNSacETEmX86tlK2rx4py150o+MstMBLwWRfHKo6JCVxLnvmFGBjFQ58oF1//sUZhGy/ClSTWObgnL4O+bkeN4nY2okfNMbkRt9/vtxz8InoTsWplJSCzFxPmO8+GpSIByX3YQAuGDWtRKhKjCnxDXhF6Z4yxnZ20Wgko7BMRDmxtSGVaI4kdTIgb+zTYoJQlIMlDlmUFgrcDWWC201qSayqlTkiCddWWeV62VU0YlnpRi9VOKaSUsiyq/N0krwq2Ugt7lVpZl5BfHNiytjagMi+XYp0kCR45hMlivVQrE/uU5pXSrCB5bM6d1t2lOZItMqmliT3q5uVxqxzyW/ccfYLNKx7ZTeykMvNyac2yt2Fbc61MHLSC0rwoxbiNdlQ3GBm1NLHQsHUrtEXppR/ljNpW6DbSCoqlFiVoN6YdaFlgsSFVPs1BdT8OaB5QyQzVcaqWDows/zepxR8ObLglTrdtCRVuRNj4Rrxh+//0ke2f8KVL+Kon3GCSbmsJN9OUW3j6g0Ns+LgCij2u0h+Sghc8mlMPBMgdx5DFh59VmOVHrvmDnoNxCz3J7MFWsMuaLyR089xz/xhlfijvwutR8gv3zk6BLUUeCgAAAABJRU5ErkJggg==', - symbolSize: [15, 15], - symbolOffset: [0, 0], - symbolPosition: "right", - z: 20, - zlevel: 20, - itemStyle: { - // normal: { - color: "#fff" - // } - }, - data: (function () { - var list = []; - for (var i = 0; i < Xdata.length; i++) { - list.push(2.02 * Xdata[i]); - } - console.log(list) - return list; - })() - }, - - ], - - }; - - return - + return + { + fireDevice.length + ? + : + } } diff --git a/super-screen/client/src/sections/fire-control/components/style.less b/super-screen/client/src/sections/fire-control/components/style.less index 7d15713..55681ed 100644 --- a/super-screen/client/src/sections/fire-control/components/style.less +++ b/super-screen/client/src/sections/fire-control/components/style.less @@ -290,6 +290,53 @@ } } +// 接入消防设备 +.fire-device-item { + display: flex; + height: 30px; + align-items: center; + justify-content: space-around; + + ._name { + width: 80px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + font-family: SourceHanSansSC-Regular; + font-weight: 400; + font-size: 14px; + color: #ECF7FF; + letter-spacing: 0; + text-align: right; + } + + ._progress { + position: relative; + width: 200px; + + ._round { + position: absolute; + width: 12px; + height: 12px; + background: #fff; + border-radius: 6px; + top: 7px; + } + } + + ._count { + width: 75px; + font-family: D-DINExp-Italic; + font-weight: Italic; + font-size: 18px; + color: #24DCF7; + + ._unit { + font-size: 14px; + } + } +} + //实时数据 .realtime_data { // height: 100%; diff --git a/super-screen/client/src/sections/fire-control/containers/homePage.js b/super-screen/client/src/sections/fire-control/containers/homePage.js index 3c51e86..9e88019 100644 --- a/super-screen/client/src/sections/fire-control/containers/homePage.js +++ b/super-screen/client/src/sections/fire-control/containers/homePage.js @@ -23,6 +23,8 @@ function homePage(props) { const [tab, setTab] = useState('overview') const [emengencyTab, setEmengencyTab] = useState('xfyjwz'); const [alarmInfo, setAlarmInfo] = useState({}) + const [fireDevice, setFireDevice] = useState([]) + const [fireTrend, setFireTrend] = useState([]) const { data: emergencyList = {} } = useFsRequest({ url: 'water/emergency' }); const endEvent = () => { @@ -33,6 +35,24 @@ function homePage(props) { }) } + useEffect(() => { + getFireData(); + }, []) + + const getFireData = () => { + dispatch(actions.firecontrol?.getFireDevice()).then(res => { + if (res?.payload?.data?.length) { + const filterData = res.payload.data.filter(d => d.device_count) + setFireDevice(filterData) + } + }) + dispatch(actions.firecontrol?.getFireTrend()).then(res => { + if (res?.payload?.data) { + setFireTrend(res.payload.data) + } + }) + } + return <>
@@ -53,10 +73,10 @@ function homePage(props) {
- +
- +
: diff --git a/super-screen/client/src/utils/webapi.js b/super-screen/client/src/utils/webapi.js index 9b322f0..09a54bb 100644 --- a/super-screen/client/src/utils/webapi.js +++ b/super-screen/client/src/utils/webapi.js @@ -134,6 +134,8 @@ export const ApiTable = { //消防 getFireAlarmList: 'fire/alarm', modifyFireAlarm: 'fire/alarm/{id}', + getFireDevice: 'fire/device', + getFireTrend: 'fire/trend', }; export const RouteTable = {