diff --git a/code/VideoAccess-VCMP/web/client/assets/images/background/createdSuccessfully.png b/code/VideoAccess-VCMP/web/client/assets/images/background/createdSuccessfully.png new file mode 100644 index 0000000..3d50763 Binary files /dev/null and b/code/VideoAccess-VCMP/web/client/assets/images/background/createdSuccessfully.png differ diff --git a/code/VideoAccess-VCMP/web/client/assets/images/background/icon_choose.png b/code/VideoAccess-VCMP/web/client/assets/images/background/icon_choose.png new file mode 100644 index 0000000..5bcc017 Binary files /dev/null and b/code/VideoAccess-VCMP/web/client/assets/images/background/icon_choose.png differ diff --git a/code/VideoAccess-VCMP/web/client/assets/images/background/icon_four.png b/code/VideoAccess-VCMP/web/client/assets/images/background/icon_four.png new file mode 100644 index 0000000..cd49238 Binary files /dev/null and b/code/VideoAccess-VCMP/web/client/assets/images/background/icon_four.png differ diff --git a/code/VideoAccess-VCMP/web/client/assets/images/background/icon_four_choose.png b/code/VideoAccess-VCMP/web/client/assets/images/background/icon_four_choose.png new file mode 100644 index 0000000..6e275c0 Binary files /dev/null and b/code/VideoAccess-VCMP/web/client/assets/images/background/icon_four_choose.png differ diff --git a/code/VideoAccess-VCMP/web/client/assets/images/background/icon_offLine.png b/code/VideoAccess-VCMP/web/client/assets/images/background/icon_offLine.png new file mode 100644 index 0000000..b75d9a4 Binary files /dev/null and b/code/VideoAccess-VCMP/web/client/assets/images/background/icon_offLine.png differ diff --git a/code/VideoAccess-VCMP/web/client/assets/images/background/icon_one.png b/code/VideoAccess-VCMP/web/client/assets/images/background/icon_one.png new file mode 100644 index 0000000..82e184d Binary files /dev/null and b/code/VideoAccess-VCMP/web/client/assets/images/background/icon_one.png differ diff --git a/code/VideoAccess-VCMP/web/client/assets/images/background/icon_online.png b/code/VideoAccess-VCMP/web/client/assets/images/background/icon_online.png new file mode 100644 index 0000000..4a727cf Binary files /dev/null and b/code/VideoAccess-VCMP/web/client/assets/images/background/icon_online.png differ diff --git a/code/VideoAccess-VCMP/web/client/assets/images/background/icon_three.png b/code/VideoAccess-VCMP/web/client/assets/images/background/icon_three.png new file mode 100644 index 0000000..1aaab4a Binary files /dev/null and b/code/VideoAccess-VCMP/web/client/assets/images/background/icon_three.png differ diff --git a/code/VideoAccess-VCMP/web/client/assets/images/background/icon_three_choose.png b/code/VideoAccess-VCMP/web/client/assets/images/background/icon_three_choose.png new file mode 100644 index 0000000..63208f0 Binary files /dev/null and b/code/VideoAccess-VCMP/web/client/assets/images/background/icon_three_choose.png differ diff --git a/code/VideoAccess-VCMP/web/client/assets/images/background/icon_timing.png b/code/VideoAccess-VCMP/web/client/assets/images/background/icon_timing.png new file mode 100644 index 0000000..6c5e1db Binary files /dev/null and b/code/VideoAccess-VCMP/web/client/assets/images/background/icon_timing.png differ diff --git a/code/VideoAccess-VCMP/web/client/assets/images/background/icon_two.png b/code/VideoAccess-VCMP/web/client/assets/images/background/icon_two.png new file mode 100644 index 0000000..c326f4a Binary files /dev/null and b/code/VideoAccess-VCMP/web/client/assets/images/background/icon_two.png differ diff --git a/code/VideoAccess-VCMP/web/client/assets/images/background/icon_two_choose.png b/code/VideoAccess-VCMP/web/client/assets/images/background/icon_two_choose.png new file mode 100644 index 0000000..c49707c Binary files /dev/null and b/code/VideoAccess-VCMP/web/client/assets/images/background/icon_two_choose.png differ diff --git a/code/VideoAccess-VCMP/web/client/assets/images/background/noteTopChoose.png b/code/VideoAccess-VCMP/web/client/assets/images/background/noteTopChoose.png new file mode 100644 index 0000000..8815029 Binary files /dev/null and b/code/VideoAccess-VCMP/web/client/assets/images/background/noteTopChoose.png differ diff --git a/code/VideoAccess-VCMP/web/client/assets/images/background/triangle.png b/code/VideoAccess-VCMP/web/client/assets/images/background/triangle.png new file mode 100644 index 0000000..e574900 Binary files /dev/null and b/code/VideoAccess-VCMP/web/client/assets/images/background/triangle.png differ diff --git a/code/VideoAccess-VCMP/web/client/src/index.less b/code/VideoAccess-VCMP/web/client/src/index.less index bf199fb..0dadb89 100644 --- a/code/VideoAccess-VCMP/web/client/src/index.less +++ b/code/VideoAccess-VCMP/web/client/src/index.less @@ -19,6 +19,16 @@ body { #App{ height: 100%; } + .semi-timepicker-panel{//时间选择器不显示滚动栏 + ::-webkit-scrollbar { + display: none; /* Chrome Safari */ + + } + scrollbar-width: none; /* firefox */ + -ms-overflow-style: none; /* IE 10+ */ + overflow-x: hidden; + overflow-y: auto; + } a:link { text-decoration: none; color: unset diff --git a/code/VideoAccess-VCMP/web/client/src/sections/offline/actions/carrierpigeon.js b/code/VideoAccess-VCMP/web/client/src/sections/offline/actions/carrierpigeon.js new file mode 100644 index 0000000..1d3147b --- /dev/null +++ b/code/VideoAccess-VCMP/web/client/src/sections/offline/actions/carrierpigeon.js @@ -0,0 +1,88 @@ +"use strict"; + +import { basicAction } from "@peace/utils"; +import { ApiTable } from "$utils"; + +export function getCameraListAll() {//获取摄像头能力列表 + return (dispatch) => + basicAction({ + type: "get", + dispatch: dispatch, + actionType: "GET_CAMERA_LIST_ALL", + url: `${ApiTable.getCameraListAll}`, + msg: { option: "" }, + reducer: { name: "" }, + }); +} +export function getStatusPush(query) {//获取推送配置 + return (dispatch) => + basicAction({ + type: "get", + dispatch: dispatch, + actionType: "GET_STATUS_PUSH", + query: query, + url: `${ApiTable.getStatusPush}`, + msg: { option: "获取推送配置" }, + reducer: { name: "StatusPushList" }, + }); +} +export function putSasdtatusPush(data) { //编辑推送配置 + return (dispatch) => + basicAction({ + type: "put", + dispatch: dispatch, + actionType: "PUT_SASDTATUS_PUSH", + data, + url: `${ApiTable.putSasdtatusPush}`, + msg: { option: '编辑推送配置' }, + reducer: {}, + }); +} +export function delPush(orgId) {//删除推送配置 + return (dispatch) => + basicAction({ + type: "del", + dispatch: dispatch, + actionType: "DEL_PUSH", + url: `${ApiTable.delPush.replace("{configId}", orgId)}`, + msg: { + option: + "删除推送配置", + }, + reducer: { name: "" }, + }); +} +export function putPushBanned(data, forbidden) {//禁用推送配置 + return (dispatch) => + basicAction({ + type: "put", + dispatch: dispatch, + actionType: "PUT_PUSH_BANNED", + data, + url: `${ApiTable.putPushBanned}`, + msg: { option: forbidden ? "启用" : "禁用" }, + reducer: {}, + }); +} +export function getPushCopy(orgId) {//复制推送配置 + return (dispatch) => + basicAction({ + type: "get", + dispatch: dispatch, + actionType: "GET_PUSH_COPY", + url: `${ApiTable.getPushCopy.replace("{configId}", orgId)}`, + msg: { option: "复制推送配置" }, + reducer: { name: "" }, + }); +} +export function getPushLog(orgId) {//获取推送记录 + return (dispatch) => + basicAction({ + type: "get", + dispatch: dispatch, + actionType: "GET_PUSH_LOG", + url: `${ApiTable.getPushLog.replace("{configId}", orgId)}`, + msg: { option: "获取推送记录" }, + reducer: { name: "" }, + }); +} \ No newline at end of file diff --git a/code/VideoAccess-VCMP/web/client/src/sections/offline/actions/index.js b/code/VideoAccess-VCMP/web/client/src/sections/offline/actions/index.js index 73e9f6c..7a6f5a2 100644 --- a/code/VideoAccess-VCMP/web/client/src/sections/offline/actions/index.js +++ b/code/VideoAccess-VCMP/web/client/src/sections/offline/actions/index.js @@ -1,9 +1,8 @@ 'use strict'; import * as statuscode from './statuscode' -// import * as camera from './camera' +import * as carrierpigeon from './carrierpigeon' export default { - // ...statuscode,...camera - ...statuscode + ...statuscode,...carrierpigeon } \ No newline at end of file diff --git a/code/VideoAccess-VCMP/web/client/src/sections/offline/actions/statuscode.js b/code/VideoAccess-VCMP/web/client/src/sections/offline/actions/statuscode.js index b615334..8539f07 100644 --- a/code/VideoAccess-VCMP/web/client/src/sections/offline/actions/statuscode.js +++ b/code/VideoAccess-VCMP/web/client/src/sections/offline/actions/statuscode.js @@ -36,7 +36,7 @@ export function postStatusResolve(data) { data, actionType: "POST_STATUS_RESOLVE", url: `${ApiTable.postStatusResolve}`, - msg: { option: "" }, //编辑解决方案 + msg: { option: "编辑解决方案" }, //编辑解决方案 reducer: { name: "" }, }); } @@ -48,7 +48,7 @@ export function postStatusCustom(data) { data, actionType: "POST_STATUS_CUSTOM", url: `${ApiTable.postStatusCustom}`, - msg: { option: "" }, //自定义状态码释义 + msg: { option: "自定义状态码释义" }, //自定义状态码释义 reducer: { name: "" }, }); } diff --git a/code/VideoAccess-VCMP/web/client/src/sections/offline/components/pushModal.jsx b/code/VideoAccess-VCMP/web/client/src/sections/offline/components/pushModal.jsx index 1c722db..4ecd79e 100644 --- a/code/VideoAccess-VCMP/web/client/src/sections/offline/components/pushModal.jsx +++ b/code/VideoAccess-VCMP/web/client/src/sections/offline/components/pushModal.jsx @@ -1,299 +1,583 @@ -import React, { useState, useRef, useEffect, useImperativeHandle } from "react"; +import React, { useState, useRef, useEffect } 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"; - +import { Modal, Form, Button,TimePicker,Transfer, Checkbox, Avatar } from "@douyinfe/semi-ui"; +import { IconClose } from '@douyinfe/semi-icons'; +import './pushModal.less' 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("测试校验"); //ok弹框text 右边 - const [cancelText, setcancelText] = useState("取消"); //取消弹框text 左边 - const [formObj, setformObj] = useState(); //接口入参 + const { + close, + rowId, + dispatch, + actions, + title,//是编辑还是修改 + pushData,//数据值 + cameraList, + } = props; + const { offline } = actions;//接口 + const form = useRef();//第一步表单 + const [stepNum, setStepNum] = useState(0);//第几步 + const [okText, setOkText] = useState('下一步');//右边的按钮显示名称 + const [cancelText, setCancelText] = useState('取消');//左边的按钮显示名称 + const [finishSrc, setFinishSrc] = useState('/assets/images/background/icon_choose.png');//步骤完成图片 + const [stepList, setStepList] = useState([ + { + chooseSrc: '/assets/images/background/icon_one.png', + unCheckedSrc: '/assets/images/background/icon_one.png', + title: '推送策略', + text: '基本信息配置' + }, { + chooseSrc: '/assets/images/background/icon_two_choose.png', + unCheckedSrc: '/assets/images/background/icon_two.png', + title: '通知策略', + text: '选择推送方式及周期' + }, { + chooseSrc: '/assets/images/background/icon_three_choose.png', + unCheckedSrc: '/assets/images/background/icon_three.png', + title: '监听范围', + text: '选择跟踪状态的设备' + }, { + chooseSrc: '/assets/images/background/icon_four_choose.png', + unCheckedSrc: '/assets/images/background/icon_four.png', + title: '创建完成', + text: '完成' + }, + ]);//阶段信息 + // const [pushWay, setPushWay] = useState('email');//策略类型 - 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 ""; + const pushWay = useRef('email');//策略类型 + const emailList = useRef([]);//邮箱列表 + const phoneList = useRef([]);//电话列表 + + const strategyList = [ + //循环摄像头列表 + { + id: 1, + img: "/assets/images/background/icon_offLine.png", + title: "离线即时通知", + value: "offline", + }, + { + id: 2, + img: "/assets/images/background/icon_online.png", + title: "上线即时通知", + value: "online", + }, + { + id: 3, + img: "/assets/images/background/icon_timing.png", + title: "定时统计", + value: "timing", + }, + ]; + const [showList, setShowList] = useState([false, false, false]);//选中通知策略 + const showstrategyListList = useRef(strategyList);//通知策略列表 + const [timevalue, setTimevalue] = useState('18:00');//选中通知策略时间 + const [noticeNum, setNoticeNum] = useState(0);//最新点击的通知策略 + const [policyList, setPolicyList] = useState([//通知策略备注 + { + strategy: '系统监听到设备离线时,进行一次邮件推送,并将当前所 有离线的设备一同推送至信息邮箱,每次起始推送间隔不少于15分钟。', + example: '【superadmin】账号下的设备:【智慧小蓝排涝-乡山站排口】于【2022年22时00分】掉线,【智慧小蓝排涝-乡山站排口】于【2022年22时00分】掉线,【智慧小蓝排涝-乡山站排口】于【2022年22时00分】掉线,请及时处理!', + }, + { + strategy: '系统监听到设备上线时,推送至信息邮箱,每次推送间隔 不少于15分钟。', + example: '【superadmin】账号下的设备:【智慧小蓝排涝-乡山站排口】于【2022年22时00分】掉线,【2022年22时00分】已恢复!', + }, + { + strategy: '系统在设定时间前统计所有离线的设备信息,并推送至信 息邮箱。', + example: '【superadmin】账号下的设备,截止【2022年22时00分】,有15个设备掉线:【智慧小蓝排涝-乡山站排口】于【2022年22时00分】掉线,【智慧小蓝排涝-乡山站排口】于【2022年22时00分】掉线,【智慧小蓝排涝-乡山站排口】于【2022年22时00分】掉线,请及时处理!', + }, + ]);//阶段信息 + const [chooseCameraList, setChooseCameraList] = useState([]);//第三阶段选中监听范围摄像头列表 + const [mypushData, setMypushData] = useState({});//修改过格式的props的值 + //初始化 + useEffect(() => { + let pushDataObj= JSON.parse(JSON.stringify(pushData)) + let cameraIdList=[] + let receiverList=[] + if(pushDataObj.cameraStatusPushMonitors){//摄像头默认选择 + for (let index = 0; index < pushDataObj.cameraStatusPushMonitors.length; index++) { + cameraIdList.push(String(pushDataObj.cameraStatusPushMonitors[index].cameraId)) + } } - } + if(pushDataObj.cameraStatusPushReceivers){//邮箱或者手机号默认 + for (let index = 0; index < pushDataObj.cameraStatusPushReceivers.length; index++) { + receiverList.push(pushDataObj.cameraStatusPushReceivers[index].receiver) + } + } + if(pushDataObj.pushWay){ + pushWay.current=pushDataObj.pushWay + if(pushDataObj.pushWay=='email'){ + emailList.current=receiverList + } + else{ + phoneList.current=receiverList + } + } + if(pushDataObj.timing){//定时推送时间 + setTimevalue(pushDataObj.timing) + } + setChooseCameraList(cameraIdList) + setMypushData({ + ...pushDataObj, + receiverList:receiverList, + }) + if(pushDataObj.noticeWay){//通知策略 + let arr = ['offline','online','timing'] + let arr2 = [false,false,false] + for (let i = 0; i < arr.length; i++) { + for (let j = 0; j < pushDataObj.noticeWay.length; j++) { + if(arr[i]==pushDataObj.noticeWay[j]){ + arr2[i]=true + } + } + } + setShowList(arr2) + } + }, []); + function handleOk () { - //点击弹框确定 右边按钮 - if (step == "none") { + let num = stepNum + if (num == 0) { 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; + setStepNum(num + 1) + setOkText('下一步') + setCancelText('上一步') + if(showList.indexOf(true)>-1){ + setRightDisabled(false) + } + else{ + setRightDisabled(true) } - 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); + } + else if (num == 1) { + setStepNum(num + 1) + setOkText('下一步') + setCancelText('上一步') + if(chooseCameraList.length>0){ + setRightDisabled(false) + } + else{ + setRightDisabled(true) + } + } + else if (num == 2) { + setStepNum(num + 1) + setOkText('确认并启用') + setCancelText('上一步') + } + else if (num == 3) { + //点击弹框确定 右边按钮 + let arr = ['offline','online','timing'] + let noticeWay =[] + for (let index = 0; index < showList.length; index++) { + if(showList[index]){ + noticeWay.push(arr[index]) + } + } + let pushobj={} + if(showList[2]){ + pushobj={ + ...form.current.getValues(), + noticeWay:noticeWay, + timing:timevalue, + cameraId:chooseCameraList, + } + } + else{ + pushobj={ + ...form.current.getValues(), + noticeWay:noticeWay, + cameraId:chooseCameraList, + } + } + if(rowId){ + pushobj.configId=rowId + } + dispatch( + offline.putSasdtatusPush(pushobj) + ).then((res) => { close(); - }); + }) } } - function handleAfterClose () { - //在关闭之后 - setstep("none"); - setokText("测试校验"); - setcancelText("取消"); - } function handleCancel () { //点击弹框取消 左边按钮 - if (step == "none") { - setVisible(false); - } else { - setstep("none"); - setokText("测试校验"); - setcancelText("取消"); + let num = stepNum + if (num == 0) { + close(); + } + else if (num == 1) { + setStepNum(num - 1) + setOkText('下一步') + setCancelText('取消') + setRightDisabled(false) + } + else if (num == 2) { + setStepNum(num - 1) + setOkText('下一步') + setCancelText('上一步') + setRightDisabled(false) + } + else if (num == 3) { + setStepNum(num - 1) + setOkText('下一步') + setCancelText('上一步') + setRightDisabled(false) + } + } + function handleClose () { + close(); + } + function formChange (value, field) {//第一步表单变化 + if (Object.keys(field)[0] == 'receiver') { + form.current.validate(['receiver']) + } + if (value.pushWay !== pushWay.current) { + if (value.pushWay == 'phone') { + pushWay.current = value.pushWay + emailList.current = value.receiver + form.current.setValue('receiver', phoneList.current) + } + else { + pushWay.current = value.pushWay + phoneList.current = value.receiver + form.current.setValue('receiver', emailList.current) + } + } + } + const [rightDisabled, setRightDisabled] = useState(false);//选中通知策略时间 + function twohandleChoose (value,index) {//第二步选中通知策略 + let chooselist = JSON.parse(JSON.stringify(showList)) + chooselist[value - 1] = !chooselist[value - 1] + setShowList(chooselist) + let arrtrue =chooselist.indexOf(true) + if(arrtrue>-1){ + setRightDisabled(false) + }else{ + setRightDisabled(true) + } + } + function twohandleMouseOver (value,index){//第二步鼠标移入通知策略 + setNoticeNum(index) + } + function positionForm (val) {//第一步邮箱或者电话校验 + let myform = form.current.getValue() + if (!val||val.length<1) { + return "请输入接收信息"; + } + else { + if (myform.pushWay == 'email') { + let zz = /^([A-Za-z0-9_\-\.])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,8})$/; + for (let index = 0; index < val.length; index++) { + if (!zz.test(val[index])) { + return "请输入正确的邮箱"; + } + } + } + else { + let zz = /^[1][3,4,5,7,8][0-9]{9}$/; + for (let index = 0; index < val.length; index++) { + if (!zz.test(val[index])) { + return "请输入正确的手机号码"; + } + } + } } } - function handleLocation () { - //高德经纬度 - window.open("https://lbs.amap.com/tools/picker", "_blank"); + function toTimePicker(e){//阻止定时事件冒泡 + e.stopPropagation() + } + function timeChange(value){//定时统计时间 + let time = String(value).split(' ') + let timearr=time[4].split(':') + setTimevalue(timearr[0]+':'+timearr[1]) + } + function renderSourceItem(item,index){//自定义左侧单个候选项的渲染 + return ( +
+ { + item.onChange(); + }} + key={item.key} + checked={item.checked} + style={{ height: 52 }} + > + + {item.abbr} + +
+
{item.label}
+
{item.value}
+
+
+
+ ); + } + function renderSelectedItem(item,index){//自定义右侧已选面板的渲染 + return ( +
+ + {item.abbr} + +
+
{item.label}
+
{item.value}
+
+ +
+ ); + } + function customFilter(sugInput, item){//自定义筛选逻辑, 当为 false 时,不展示搜索框 + return item.value.includes(sugInput) || item.label.includes(sugInput); + } + function CameraChooseList(id, items){ + if(id.length>0){ + setRightDisabled(false) + } + else{ + setRightDisabled(true) + } + setChooseCameraList(id) } - useImperativeHandle(pushRef, () => ({ - //传给父组件方法 - //aa即为子组件暴露给父组件的方法 - pushNumber: () => formObj.serialNo - })); return ( <> -
{modalName == "add" ? "创建推送" : "修改"}
+ + + + } > - +
+ {stepList.map((item, index) => { + return ( +
+
+ 设置 +
+
+ {item.title} +
+
+ {item.text} +
+
+
+
+
+ ) + })} +
+ {/* 第一步 */} +
+
formChange(values, field)} + getFormApi={(formApi) => (form.current = formApi)} + > +
+
+ +
+
+ + + 邮件推送 + + + 短信推送 + + +
+
+
+ +
+
+
+ 敲击回车键后,输入内容将成为标签 +
+
+
+ {/* 第二步 */} +
-
console.log(values)} - getFormApi={(formApi) => (form.current = formApi)} - > - - - - - - `${value}`.replace(/\D/g, "")} - hideButtons={true} - maxLength="15" - field="regionCode" - label="行政区区码:" - initValue={pushData.regionCode || ""} - placeholder="请输入行政区区码" - style={{ width: 149 }} - /> - - - - - - - {vender.map((item, index) => ( - - {item.name} - - ))} - - - - + {showstrategyListList.current.map((item, index) => ( +
twohandleChoose(item.id,index)} + onMouseOver={() => twohandleMouseOver(item.id,index)} + > + 设置 + { + item.id==3?( +
+
+ {item.title} +
+
toTimePicker(e)}> + +
+
+ ):( +
+ {item.title} +
+ ) + } + {showList[index] ? (
1
- - - + ) : ( + "" + )} +
+ ))}
- -
-
- -
-
- 是否确认创建推送? +
+ {showstrategyListList.current.map((item, index) => ( +
+ { + noticeNum==index?( + 1 + ):'' + } +
+ ))} +
+
+
+
+ 策略: + {policyList[noticeNum].strategy} +
+
+ 实例: + {policyList[noticeNum].example} +
- +
+
+ {/* 第三步 */} +
+ CameraChooseList(id, items)} + /> +
+
+ {/* 第四步 */} +
+ 设置 +
创建完成
+
+
); } - function mapStateToProps (state) { - const { auth, global, members, vender } = state; + const { auth, global, members, CameraKind, CameraAbility } = state; return { loading: members.isRequesting, user: auth.user, actions: global.actions, - members: members.data, - vender: vender.data || [], //设备厂家 + CameraKind: CameraKind.data || [], + CameraAbility: CameraAbility.data || [], }; } -export default connect(mapStateToProps)(pushModal); +export default connect(mapStateToProps)(pushModal); \ No newline at end of file diff --git a/code/VideoAccess-VCMP/web/client/src/sections/offline/components/pushModal.less b/code/VideoAccess-VCMP/web/client/src/sections/offline/components/pushModal.less new file mode 100644 index 0000000..b1f80b2 --- /dev/null +++ b/code/VideoAccess-VCMP/web/client/src/sections/offline/components/pushModal.less @@ -0,0 +1,44 @@ +.myChoose{ + background: #F9FBFF; + .myChooseButton{ + height: 4px; + background: #0058C8; + } +} +.components-transfer-demo-selected-item { + .semi-icon-close { + visibility: hidden; + color: var(--semi-color-tertiary); + } + &:hover { + .semi-icon-close { + visibility: visible; + } + } +} + +.components-transfer-demo-selected-item, +.components-transfer-demo-source-item { + height: 52px; + box-sizing: border-box; + display: flex; + align-items: center; + justify-content: space-between; + padding: 10px 12px; + &:hover { + background-color: var(--semi-color-fill-0); + } + .info { + margin-left: 8px; + flex-grow: 1; + } + .name { + font-size: 14px; + line-height: 20px; + } + .email { + font-size: 12px; + line-height: 16px; + color: var(--semi-color-text-2); + } +} \ No newline at end of file diff --git a/code/VideoAccess-VCMP/web/client/src/sections/offline/components/pushSideSheet.jsx b/code/VideoAccess-VCMP/web/client/src/sections/offline/components/pushSideSheet.jsx new file mode 100644 index 0000000..033ef44 --- /dev/null +++ b/code/VideoAccess-VCMP/web/client/src/sections/offline/components/pushSideSheet.jsx @@ -0,0 +1,77 @@ +import React, { useState, useRef, useEffect } from "react"; +import { connect } from "react-redux"; +import { Modal, Spin,Input,Collapse ,SideSheet,Tabs, TabPane} from "@douyinfe/semi-ui"; +import moment from "moment"; +import './pushSideSheet.less' +function pushSideSheet (props) { + const { + close, + actions, + pushData,//表格信息 + journal//日志信息 + } = props; + const { offline } = actions; + const [notesValue, setNotesValue] = useState('');//释义 + + //初始化 + useEffect(() => { + let timeList = [] + for (let index = 0; index < journal.length; index++) { + timeList.push( + { + title:getTimeTitle(journal[index].time), + time:getTimeData(journal[index].time) + } + ) + } + console.log('timeList',timeList); + }, []); + function getTimeTitle(date){ + let year = moment(date).year()+'年' + let month = (moment(date).month()+1)>10?(moment(date).month()+1)+'月':'0'+(moment(date).month()+1)+'月' + return year+month + } + function getTimeData(date){ + let day=moment(date).date()>10?moment(date).date()+'日':'0'+moment(date).date()+'日'; + let hour=moment(date).hour()>10?moment(date).hour():'0'+moment(date).hour(); + let minute=moment(date).minute()>10?moment(date).minute():'0'+moment(date).minute(); + let second=moment(date).second()>10?moment(date).second():'0'+moment(date).second(); + return day+' '+hour+':'+minute+':'+second + } + function sideSheetChange(){ + close() + } + return ( + <> + + + + + 11111111
} itemKey="1"> +

Hi, bytedance dance dance. This is the docsite of Semi UI.

+ + + + + 22 + + + 33 + + + + + ); +} +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)(pushSideSheet); \ No newline at end of file diff --git a/code/VideoAccess-VCMP/web/client/src/sections/offline/components/pushSideSheet.less b/code/VideoAccess-VCMP/web/client/src/sections/offline/components/pushSideSheet.less new file mode 100644 index 0000000..a831f80 --- /dev/null +++ b/code/VideoAccess-VCMP/web/client/src/sections/offline/components/pushSideSheet.less @@ -0,0 +1,8 @@ +.sideSheet{ + .semi-tabs-tab{ + font-size: 16px; + } + .semi-tabs-tab-active{ + color: #1859C1; + } +} \ No newline at end of file diff --git a/code/VideoAccess-VCMP/web/client/src/sections/offline/containers/carrierpigeon.jsx b/code/VideoAccess-VCMP/web/client/src/sections/offline/containers/carrierpigeon.jsx index aec40a3..f42b9c0 100644 --- a/code/VideoAccess-VCMP/web/client/src/sections/offline/containers/carrierpigeon.jsx +++ b/code/VideoAccess-VCMP/web/client/src/sections/offline/containers/carrierpigeon.jsx @@ -1,14 +1,13 @@ import React, { useState, useEffect, useRef } from "react"; import { connect } from "react-redux"; import moment from "moment"; -import { Button, Form, Table, Pagination, Skeleton, Popconfirm, Popover, Tag, } from "@douyinfe/semi-ui"; +import { Button, Form, Table, Pagination, Skeleton, Popconfirm, SideSheet, Tag, } from "@douyinfe/semi-ui"; import "../style.less"; import { ApiTable } from "$utils"; import { Setup } from "$components"; import PushModal from "../components/pushModal"; +import PushSideSheet from "../components/pushSideSheet"; // import SideSheets from "../components/sideSheet"; -// import { skeletonScreen } from "../components/skeletonScreen"; -// import { ReminderBox } from "../../../components/index"; export const accessType = [ { name: "萤石云", key: "yingshi" }, @@ -18,82 +17,86 @@ export const accessType = [ ]; const Carrierpigeon = (props) => { - const { history, dispatch, actions, user, loading, equipmentWarehouseNvr } = props; - const { equipmentWarehouse } = actions; + const { history, dispatch, actions, user, loading, StatusPushList } = props; + const { offline } = 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 [pigeonPush, setPigeonPush] = useState(false); //推送弹框 + const [pushTitle, setPushTitle] = useState(''); //提醒弹框 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 cameraList = useRef([]);//第三阶段监听范围摄像头列表 + const [sideSheetVisible, setSideSheetVisible] = useState(false); + const [pushData, setPushData] = useState({}); + const [journal, setJournal] = useState([]); const tableList = [//表格属性 { title: '推送信息', list: [ - { name: "策略类型", value: "PolicyType" }, - { name: "推送机制", value: "PushMechanism" }, - { name: "监听设备数量", value: "DevicesNumber" }, - { name: "累计推送次数", value: "PushNumber" }, + { name: "策略类型", value: "pushWay" }, + { name: "推送机制", value: "noticeWay" }, + { name: "监听设备数量", value: "logCount" }, + { name: "累计推送次数", value: "monitorCount" }, ] }, ]; + const noticeWayObj = { + 'offline':'离线及时通知', + 'online':'上线及时通知', + 'timing':'定时统计', + } useEffect(() => { - dispatch(actions.equipmentWarehouse.getVender()).then((res) => { - setvenderList(res.payload.data); - attribute(res.payload.data); + attribute(); + dispatch(offline.getCameraListAll()).then((res) => {//第三步 + let mycameraList = res.payload.data + for (let index = 0; index < mycameraList.length; index++) { + mycameraList[index].label=mycameraList[index].name + mycameraList[index].key=index+1 + mycameraList[index].value=String(mycameraList[index].id) + if(mycameraList[index].type=='cascade'){ + mycameraList[index].color='#808FD3' + mycameraList[index].abbr='级联' + } + else if(mycameraList[index].type=='nvr'){ + mycameraList[index].color='#F6D86F' + mycameraList[index].abbr='NVR' + } + else if(mycameraList[index].type=='ipc'){ + mycameraList[index].color='#1859C1' + mycameraList[index].abbr='IPC' + } + else{ + mycameraList[index].color='#57CBD3' + mycameraList[index].abbr='莹石' + } + } + cameraList.current=mycameraList }); //初始化表格显示设置 localStorage.getItem(PIGEON) == null ? localStorage.setItem( PIGEON, - JSON.stringify(["PolicyType", "PushMechanism", "DevicesNumber", "PushNumber"]) + JSON.stringify(['pushWay','noticeWay','logCount','monitorCount']) ) : ""; }, []); useEffect(() => { - equipmentGetNvr(); + equipmentGetStatusPush(); }, [query, search]); - const equipmentGetNvr = () => { + const equipmentGetStatusPush = () => { searchData.current = { ...query, ...search } - dispatch(equipmentWarehouse.getNvr(searchData.current)).then((res) => { - limits.current = res.payload.data.data.length + dispatch(offline.getStatusPush(searchData.current)).then((res) => { + limits.current = res.payload.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: "序号", @@ -105,7 +108,6 @@ const Carrierpigeon = (props) => { title: "策略名称", dataIndex: "name", render: (_, r, index) => { - console.log("r:" + r.name); return r.name }, }, @@ -116,27 +118,67 @@ const Carrierpigeon = (props) => { render: (_, row) => { return (
- + {row.forbidden ? ( + + ) : ( + { + dispatch( + offline.putPushBanned( + { + configId: row.id, + forbidden: !row.forbidden, + }, + row.forbidden + ) + ).then(() => { + equipmentGetStatusPush(); + }); + }} + > + + + )} { - dispatch(equipmentWarehouse.delNvr(row.id)).then(() => { + dispatch(offline.delPush(row.id)).then(() => { if (page.current > 0 && limits.current < 2) { setQuery({ limit: 10, page: page.current - 1 }) } else { @@ -147,10 +189,21 @@ const Carrierpigeon = (props) => { > - -
@@ -160,7 +213,7 @@ const Carrierpigeon = (props) => { ]; //获取表格属性设置 - function attribute (data) { + function attribute () { const arr = localStorage.getItem(PIGEON) ? JSON.parse(localStorage.getItem(PIGEON)) : []; @@ -168,51 +221,41 @@ const Carrierpigeon = (props) => { const column = [ { title: "推送机制", - dataIndex: "venderId", - key: "PushMechanism", + dataIndex: "noticeWay", + key: "noticeWay", render: (_, r, index) => { - let manufactorName = data.find((item) => item.id == r.venderId); - return manufactorName ? manufactorName.name : ""; + let noticeWayValue=[] + for (let index = 0; index < r.noticeWay.length; index++) { + let val = r.noticeWay[index] + noticeWayValue.push(noticeWayObj[val]) + } + let noticeWayString=noticeWayValue.join(';') + return noticeWayString; }, }, { title: "监听设备数量", - dataIndex: "DevicesNum", - key: "DevicesNumber", + dataIndex: "logCount", + key: "logCount", render: (_, r, index) => { - return r.name + return r.logCount }, }, { title: "累计推送次数", - dataIndex: "PushNum", - key: "PushNumber", + dataIndex: "monitorCount", + key: "monitorCount", render: (_, r, index) => { - return (r.name + '次') + return (r.monitorCount + '次') }, }, { title: "策略类型", - dataIndex: "size", - key: "PolicyType", + dataIndex: "pushWay", + key: "pushWay", render: (_, r, index) => { - let status = r.gbNvr; - return ( -
- - {status ? "邮件通知" : equipmentStatus(status.email)} -
- ); + return r.pushWay=='email' ? '邮件通知' : '短信通知'; }, }, ]; @@ -224,32 +267,6 @@ const Carrierpigeon = (props) => { } 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 ? 1 ?
{dataSet.map((v, index) =>
{v}
)}
: "" - // } - // > - // {dataSet.length > 1 ? `${dataSet[0]}...` : dataSet.length > 0 ? dataSet[0] : ""} - //
: "" - - // } - //条件赛选样式 const screen = { width: 193, @@ -302,23 +319,12 @@ const Carrierpigeon = (props) => { color: "#1859C1", cursor: "pointer", }} + onClick={() => { + setPigeonPush(true); + setPushTitle('创建推送') + }} > - - {/* { - const remind = localStorage.getItem(USER); - console.log(remind) - if (!remind) { - setReminder(true) - } - equipmentGetNvr(); - }} - /> */} + 创建推送
@@ -354,7 +360,7 @@ const Carrierpigeon = (props) => { > { - 全部 - 短信通知 - 邮件通知 + 全部 + 短信通知 + 邮件通知
{
s)} - dataSource={equipmentWarehouseNvr.data} + // dataSource={StatusPushList.data} + dataSource={StatusPushList} bordered={false} empty="暂无数据" style={{ @@ -492,10 +498,10 @@ const Carrierpigeon = (props) => { }} > - 共{equipmentWarehouseNvr.total}条策略 + 共{StatusPushList.total}条策略 { tableList={tableList} close={() => { setSetup(false); - attribute(venderList); + attribute(); }} /> ) : ( "" )} - - {/* {sideSheet ? ( - { - setSideSheet(false); - }} - /> - ) : ( - [] - )} */} - {/* { - history.push({ pathname: '/equipmentWarehouse/camera', query: { addNvr: true, serialNo: nvrRef.current.nvrNumber() } }); - localStorage.setItem('vcmp_selected_sider', JSON.stringify("camera")) - setReminder(false) + {pigeonPush&& { + setPigeonPush(false); + setRowId(); + setPushData({}) + equipmentGetStatusPush(); }} + />} + {sideSheetVisible&& { - setReminder(false) + setSideSheetVisible(false); + setPushData({}) }} - /> */} + />} ); }; function mapStateToProps (state) { - const { auth, global, members, equipmentWarehouseNvr } = state; + const { auth, global, members, StatusPushList } = state; return { - loading: equipmentWarehouseNvr.isRequesting && !equipmentWarehouseNvr.data, + loading: StatusPushList.isRequesting && !StatusPushList.data, user: auth.user, actions: global.actions, members: members.data, - equipmentWarehouseNvr: equipmentWarehouseNvr.data || {}, + StatusPushList: StatusPushList.data || [], + // StatusPushList: StatusPushList.data || {}, }; } diff --git a/code/VideoAccess-VCMP/web/client/src/utils/webapi.js b/code/VideoAccess-VCMP/web/client/src/utils/webapi.js index 50cbea2..4f376c7 100644 --- a/code/VideoAccess-VCMP/web/client/src/utils/webapi.js +++ b/code/VideoAccess-VCMP/web/client/src/utils/webapi.js @@ -45,6 +45,13 @@ export const ApiTable = { postStatusResolve:'status/resolve',//编辑解决方案 postStatusCustom:'status/custom',//自定义状态码释义 getStatusSimpleAll:'status/simple_all',//获取全部状态码简略信息 + getCameraListAll:'camera/listAll',//获取所有摄像头信息 + getStatusPush:'status/push',//获取推送配置 + putSasdtatusPush:'sasdtatus/push',//编辑推送配置 + delPush:'status/push/{configId}',//删除推送配置 + putPushBanned:'status/push/banned',//禁用推送配置 + getPushCopy:'status/push/{configId}/copy',//复制推送配置 + getPushLog:'/status/push/{configId}/log',//获取推送记录 }; export const VideoServeApi = {