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 ( +
Hi, bytedance dance dance. This is the docsite of Semi UI.
+ + + +